//------------------------------------------------------------------------------
//	Copyright (c) 2001-2002, OpenBeOS
//
//	Permission is hereby granted, free of charge, to any person obtaining a
//	copy of this software and associated documentation files (the "Software"),
//	to deal in the Software without restriction, including without limitation
//	the rights to use, copy, modify, merge, publish, distribute, sublicense,
//	and/or sell copies of the Software, and to permit persons to whom the
//	Software is furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//	DEALINGS IN THE SOFTWARE.
//
//	File Name:		Window.cpp
//	Author:			Adrian Oanca (e2joseph@hotpop.com)
//	Description:	A BWindow object represents a window that can be displayed
//					on the screen, and that can be the target of user events
//------------------------------------------------------------------------------

// System Includes -------------------------------------------------------------
#include <BeBuild.h>
#include <InterfaceDefs.h>
#include <PropertyInfo.h>
#include <Handler.h>
#include <Looper.h>
#include <Application.h>
#include <Window.h>
#include <View.h>
#include <MenuBar.h>
#include <String.h>
#include <Screen.h>
#include <Button.h>
#include <MessageQueue.h>
#include <MessageRunner.h>
#include <Roster.h>

// Project Includes ------------------------------------------------------------
#include <AppMisc.h>
#include <PortLink.h>
#include <PortMessage.h>
#include <Session.h>
#include <ServerProtocol.h>
#include <TokenSpace.h>
#include <MessageUtils.h>
#include <WindowAux.h>

// Standard Includes -----------------------------------------------------------
#include <stdio.h>
#include <math.h>
#include <posix/math.h>

// Local Includes --------------------------------------------------------------

// Local Defines ---------------------------------------------------------------
//#define DEBUG_WIN
#ifdef DEBUG_WIN
#	include <stdio.h>
#	define STRACE(x) printf x
#else
#	define STRACE(x) ;
#endif

// Globals ---------------------------------------------------------------------
static property_info windowPropInfo[] =
{
	{ "Feel", { B_GET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Returns the current feel of the window.",0 },

	{ "Feel", { B_SET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Sets the feel of the window.",0 },

	{ "Flags", { B_GET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Returns the current flags of the window.",0 },

	{ "Flags", { B_SET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Sets the window flags.",0 },

	{ "Frame", { B_GET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Returns the window's frame rectangle.",0},

	{ "Frame", { B_SET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Sets the window's frame rectangle.",0 },

	{ "Hidden", { B_GET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Returns true if the window is hidden; false otherwise.",0},

	{ "Hidden", { B_SET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Hides or shows the window.",0 },

	{ "Look", { B_GET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Returns the current look of the window.",0},

	{ "Look", { B_SET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Sets the look of the window.",0 },

	{ "Title", { B_GET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Returns a string containing the window title.",0},

	{ "Title", { B_SET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Sets the window title.",0 },

	{ "Workspaces", { B_GET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Returns int32 bitfield of the workspaces in which the window appears.",0},

	{ "Workspaces", { B_SET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Sets the workspaces in which the window appears.",0 },

	{ "MenuBar", { 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Directs the scripting message to the key menu bar.",0 },

	{ "View", { 0 },
		{ 0 }, "Directs the scripting message to the top view without popping the current specifier.",0 },

	{ "Minimize", { B_SET_PROPERTY, 0 },
		{ B_DIRECT_SPECIFIER, 0 }, "Minimizes the window if \"data\" is true; restores otherwise.",0 },

	{ 0, { 0 }, { 0 }, 0, 0 }
}; 
//------------------------------------------------------------------------------

// Constructors
//------------------------------------------------------------------------------
BWindow::BWindow(BRect frame,
				const char* title, 
				window_type type,
				uint32 flags,
				uint32 workspace)
			: BLooper( title )
{
	#ifdef DEBUG_WIN
		printf("BWindow::BWindow()\n");
	#endif
	window_look look;
	window_feel feel;
	
	decomposeType(type, &look, &feel);

	InitData( frame, title, look, feel, flags, workspace);
}

//------------------------------------------------------------------------------

BWindow::BWindow(BRect frame,
				const char* title, 
				window_look look,
				window_feel feel,
				uint32 flags,
				uint32 workspace)
			: BLooper( title )
{
	InitData( frame, title, look, feel, flags, workspace );
}

//------------------------------------------------------------------------------

BWindow::BWindow(BMessage* data)
	: BLooper(data)
{
	BMessage		msg;
	BArchivable		*obj;
	const char		*title;
	window_look		look;
	window_feel		feel;
	uint32			type;
	uint32			workspaces;

	data->FindRect("_frame", &fFrame);
	data->FindString("_title", &title);
	data->FindInt32("_wlook", (int32*)&look);
	data->FindInt32("_wfeel", (int32*)&feel);
	if ( data->FindInt32("_flags", (int32*)&fFlags) == B_OK )
		{ }
	else
		fFlags		= 0;
	data->FindInt32("_wspace", (int32*)&workspaces);

	if ( data->FindInt32("_type", (int32*)&type) == B_OK ){
		decomposeType( (window_type)type, &fLook, &fFeel );
	}

		// connect to app_server and initialize data
	InitData( fFrame, title, look, feel, fFlags, workspaces );

	if ( data->FindFloat("_zoom", 0, &fMaxZoomWidth) == B_OK )
		if ( data->FindFloat("_zoom", 1, &fMaxZoomHeight) == B_OK)
			SetZoomLimits( fMaxZoomWidth, fMaxZoomHeight );

	if (data->FindFloat("_sizel", 0, &fMinWindWidth) == B_OK )
		if (data->FindFloat("_sizel", 1, &fMinWindHeight) == B_OK )
			if (data->FindFloat("_sizel", 2, &fMaxWindWidth) == B_OK )
				if (data->FindFloat("_sizel", 3, &fMaxWindHeight) == B_OK )
					SetSizeLimits(	fMinWindWidth, fMaxWindWidth,
									fMinWindHeight, fMaxWindHeight );

	if (data->FindInt64("_pulse", &fPulseRate) == B_OK )
		SetPulseRate( fPulseRate );

	int				i = 0;
	while ( data->FindMessage("_views", i++, &msg) == B_OK){ 
		obj			= instantiate_object(&msg);

		BView		*child;
		child		= dynamic_cast<BView *>(obj);
		if (child)
			AddChild( child ); 
	}
}

//------------------------------------------------------------------------------

BWindow::~BWindow(){
		// the following lines, remove all existing shortcuts and delete accelList
	int32			noOfItems;
	
	noOfItems		= accelList.CountItems();
	for ( int index = noOfItems-1;  index >= 0; index-- ) {
		_BCmdKey		*cmdKey;

		cmdKey			= (_BCmdKey*)accelList.ItemAt( index );
		
		accelList.RemoveItem(index);
		
		delete cmdKey->message;
		delete cmdKey;
	}

// TODO: release other dinamicaly alocated objects

		// disable pulsing
	SetPulseRate( 0 );

	delete		session;
	delete_port( receive_port );
}

//------------------------------------------------------------------------------

BArchivable* BWindow::Instantiate(BMessage* data){

   if ( !validate_instantiation( data , "BWindow" ) ) 
      return NULL; 
   return new BWindow(data); 
}

//------------------------------------------------------------------------------

status_t BWindow::Archive(BMessage* data, bool deep) const{

	status_t		retval;

	retval		= BLooper::Archive( data, deep );
	if (retval != B_OK)
		return retval;

	data->AddRect("_frame", fFrame);
	data->AddString("_title", fTitle);
	data->AddInt32("_wlook", fLook);
	data->AddInt32("_wfeel", fFeel);
	if (fFlags)
		data->AddInt32("_flags", fFlags);
	data->AddInt32("_wspace", (uint32)Workspaces());

	if ( !composeType(fLook, fFeel) )
		data->AddInt32("_type", (uint32)Type());

	if (fMaxZoomWidth != 32768.0 || fMaxZoomHeight != 32768.0)
	{
		data->AddFloat("_zoom", fMaxZoomWidth);
		data->AddFloat("_zoom", fMaxZoomHeight);
	}

	if (fMinWindWidth != 0.0	 || fMinWindHeight != 0.0 ||
		fMaxWindWidth != 32768.0 || fMaxWindHeight != 32768.0)
	{
		data->AddFloat("_sizel", fMinWindWidth);
		data->AddFloat("_sizel", fMinWindHeight);
		data->AddFloat("_sizel", fMaxWindWidth);
		data->AddFloat("_sizel", fMaxWindHeight);
	}

	if (fPulseRate != 500000)
		data->AddInt64("_pulse", fPulseRate);

	if (deep)
	{
		int32		noOfViews = CountChildren();
		for (int i=0; i<noOfViews; i++){
			BMessage		childArchive;

			retval			= ChildAt(i)->Archive( &childArchive, deep );
			if (retval == B_OK)
				data->AddMessage( "_views", &childArchive );
		}
	}

	return B_OK;
}

//------------------------------------------------------------------------------

void BWindow::Quit(){

	if (!IsLocked())
	{
		const char* name = Name();
		if (!name)
			name = "no-name";

		printf("ERROR - you must Lock a looper before calling Quit(), "
			   "team=%ld, looper=%s\n", Team(), name);
	}

		// Try to lock
	if (!Lock()){
			// We're toast already
		return;
	}

	while (!IsHidden())	{ Hide(); }

		// ... also its children
	//detachTopView();
STRACE(("Trying to stop connection...\n"));
		// tell app_server, this window will finish execution
	stopConnection();
STRACE(("Connection stopped!\n"));
	if (fFlags & B_QUIT_ON_WINDOW_CLOSE)
		be_app->PostMessage( B_QUIT_REQUESTED );

	BLooper::Quit();
}

//------------------------------------------------------------------------------

void BWindow::AddChild(BView *child, BView *before){
	top_view->AddChild( child, before );
}

//------------------------------------------------------------------------------

bool BWindow::RemoveChild(BView *child){
	return top_view->RemoveChild( child );
}

//------------------------------------------------------------------------------

int32 BWindow::CountChildren() const{
	return top_view->CountChildren();
}

//------------------------------------------------------------------------------

BView* BWindow::ChildAt(int32 index) const{
	return top_view->ChildAt( index );
}

//------------------------------------------------------------------------------

void BWindow::Minimize(bool minimize){
	if (IsModal())
		return;

	if (IsFloating())
		return;		

	Lock();
	session->WriteInt32( AS_WINDOW_MINIMIZE );
	session->WriteBool( minimize );
	session->Sync( );
	Unlock();
}
//------------------------------------------------------------------------------

status_t BWindow::SendBehind(const BWindow* window){

	if (!window)
		return B_ERROR;
	
	int32		rCode;

	Lock();
	session->WriteInt32( AS_SEND_BEHIND );
	session->WriteInt32( _get_object_token_(window) );	
	session->Sync();
	session->ReadInt32( &rCode );
	Unlock();
	
	return rCode == SERVER_TRUE? B_OK : B_ERROR;
}

//------------------------------------------------------------------------------

void BWindow::Flush() const{
	const_cast<BWindow*>(this)->Lock();
	session->Sync();
	const_cast<BWindow*>(this)->Unlock();
}

//------------------------------------------------------------------------------

void BWindow::Sync() const{

	int32		rCode;

	const_cast<BWindow*>(this)->Lock();	
	session->WriteInt32( AS_SYNC );
	session->Sync();
	session->ReadInt32( &rCode );
	const_cast<BWindow*>(this)->Unlock();
}

//------------------------------------------------------------------------------

void BWindow::DisableUpdates(){

	Lock();	
	session->WriteInt32( AS_DISABLE_UPDATES );
	session->Sync();
	Unlock();
}

//------------------------------------------------------------------------------

void BWindow::EnableUpdates(){

	Lock();	
	session->WriteInt32( AS_ENABLE_UPDATES );
	session->Sync( );
	Unlock();
}

//------------------------------------------------------------------------------

void BWindow::BeginViewTransaction(){
	if ( !fInTransaction ){
		Lock();
		session->WriteInt32( AS_BEGIN_TRANSACTION );
		Unlock();
		
		fInTransaction		= true;
	}
}

//------------------------------------------------------------------------------

void BWindow::EndViewTransaction(){
	if ( fInTransaction ){
		Lock();
		session->WriteInt32( AS_END_TRANSACTION );
		session->Sync();
		Unlock();
		
		fInTransaction		= false;		
	}
}

//------------------------------------------------------------------------------

bool BWindow::IsFront() const{
	if (IsActive())
		return true;

	if (IsModal())
		return true;

	return false;
}

//------------------------------------------------------------------------------

void BWindow::MessageReceived( BMessage *msg )
{ 
	BMessage			specifier;
	int32				what;
	const char*			prop;
	int32				index;
	status_t			err;

	if (msg->HasSpecifiers()){

	err = msg->GetCurrentSpecifier(&index, &specifier, &what, &prop);
	if (err == B_OK)
	{
		BMessage			replyMsg;

		switch (msg->what)
		{
		case B_GET_PROPERTY:{
				replyMsg.what		= B_NO_ERROR;
				replyMsg.AddInt32( "error", B_OK );
				
				if (strcmp(prop, "Feel") ==0 )
				{
					replyMsg.AddInt32( "result", (uint32)Feel());
				}
				else if (strcmp(prop, "Flags") ==0 )
				{
					replyMsg.AddInt32( "result", Flags());
				}
				else if (strcmp(prop, "Frame") ==0 )
				{
					replyMsg.AddRect( "result", Frame());				
				}
				else if (strcmp(prop, "Hidden") ==0 )
				{
					replyMsg.AddBool( "result", IsHidden());				
				}
				else if (strcmp(prop, "Look") ==0 )
				{
					replyMsg.AddInt32( "result", (uint32)Look());				
				}
				else if (strcmp(prop, "Title") ==0 )
				{
					replyMsg.AddString( "result", Title());				
				}
				else if (strcmp(prop, "Workspaces") ==0 )
				{
					replyMsg.AddInt32( "result", Workspaces());				
				}
			}break;

		case B_SET_PROPERTY:{
				if (strcmp(prop, "Feel") ==0 )
				{
					uint32			newFeel;
					if (msg->FindInt32( "data", (int32*)&newFeel ) == B_OK){
						SetFeel( (window_feel)newFeel );
						
						replyMsg.what		= B_NO_ERROR;
						replyMsg.AddInt32( "error", B_OK );
					}
					else{
						replyMsg.what		= B_MESSAGE_NOT_UNDERSTOOD;
						replyMsg.AddInt32( "error", B_BAD_SCRIPT_SYNTAX );
						replyMsg.AddString( "message", "Didn't understand the specifier(s)" );
					}
				}
				
				else if (strcmp(prop, "Flags") ==0 )
				{
					uint32			newFlags;
					if (msg->FindInt32( "data", (int32*)&newFlags ) == B_OK){
						SetFlags( newFlags );
						
						replyMsg.what		= B_NO_ERROR;
						replyMsg.AddInt32( "error", B_OK );
					}
					else{
						replyMsg.what		= B_MESSAGE_NOT_UNDERSTOOD;
						replyMsg.AddInt32( "error", B_BAD_SCRIPT_SYNTAX );
						replyMsg.AddString( "message", "Didn't understand the specifier(s)" );
					}
				}
				
				else if (strcmp(prop, "Frame") ==0 )
				{
					BRect			newFrame;
					if (msg->FindRect( "data", &newFrame ) == B_OK){
						MoveTo( newFrame.LeftTop() );
						ResizeTo( newFrame.right, newFrame.bottom);
						
						replyMsg.what		= B_NO_ERROR;
						replyMsg.AddInt32( "error", B_OK );
					}
					else{
						replyMsg.what		= B_MESSAGE_NOT_UNDERSTOOD;
						replyMsg.AddInt32( "error", B_BAD_SCRIPT_SYNTAX );
						replyMsg.AddString( "message", "Didn't understand the specifier(s)" );
					}
				}
				
				else if (strcmp(prop, "Hidden") ==0 )
				{
					bool			newHiddenState;
					if (msg->FindBool( "data", &newHiddenState ) == B_OK){
						if ( !IsHidden() && newHiddenState == true ){
							Hide();
							
							replyMsg.what		= B_NO_ERROR;
							replyMsg.AddInt32( "error", B_OK );
							
						}
						else if ( IsHidden() && newHiddenState == false ){
							Show();
							
							replyMsg.what		= B_NO_ERROR;
							replyMsg.AddInt32( "error", B_OK );
						}
						else{
							replyMsg.what		= B_MESSAGE_NOT_UNDERSTOOD;
							replyMsg.AddInt32( "error", B_BAD_SCRIPT_SYNTAX );
							replyMsg.AddString( "message", "Didn't understand the specifier(s)" );
						}
					}
					else{
						replyMsg.what		= B_MESSAGE_NOT_UNDERSTOOD;
						replyMsg.AddInt32( "error", B_BAD_SCRIPT_SYNTAX );
						replyMsg.AddString( "message", "Didn't understand the specifier(s)" );
					}
				}
				
				else if (strcmp(prop, "Look") ==0 )
				{
					uint32			newLook;
					if (msg->FindInt32( "data", (int32*)&newLook ) == B_OK){
						SetLook( (window_look)newLook );
						
						replyMsg.what		= B_NO_ERROR;
						replyMsg.AddInt32( "error", B_OK );
					}
					else{
						replyMsg.what		= B_MESSAGE_NOT_UNDERSTOOD;
						replyMsg.AddInt32( "error", B_BAD_SCRIPT_SYNTAX );
						replyMsg.AddString( "message", "Didn't understand the specifier(s)" );
					}
				}
				
				else if (strcmp(prop, "Title") ==0 )
				{
					const char		*newTitle = NULL;
					if (msg->FindString( "data", &newTitle ) == B_OK){
						SetTitle( newTitle );
						
						replyMsg.what		= B_NO_ERROR;
						replyMsg.AddInt32( "error", B_OK );
					}
					else{
						replyMsg.what		= B_MESSAGE_NOT_UNDERSTOOD;
						replyMsg.AddInt32( "error", B_BAD_SCRIPT_SYNTAX );
						replyMsg.AddString( "message", "Didn't understand the specifier(s)" );
					}
					delete newTitle;
				}
				
				else if (strcmp(prop, "Workspaces") ==0 )
				{
					uint32			newWorkspaces;
					if (msg->FindInt32( "data", (int32*)&newWorkspaces ) == B_OK){
						SetWorkspaces( newWorkspaces );
						
						replyMsg.what		= B_NO_ERROR;
						replyMsg.AddInt32( "error", B_OK );
					}
					else{
						replyMsg.what		= B_MESSAGE_NOT_UNDERSTOOD;
						replyMsg.AddInt32( "error", B_BAD_SCRIPT_SYNTAX );
						replyMsg.AddString( "message", "Didn't understand the specifier(s)" );
					}
				}
				
			}break;
		}
		msg->SendReply( &replyMsg );
	}
	else{
		BMessage		replyMsg(B_MESSAGE_NOT_UNDERSTOOD);
		replyMsg.AddInt32( "error" , B_BAD_SCRIPT_SYNTAX );
		replyMsg.AddString( "message", "Didn't understand the specifier(s)" );
		
		msg->SendReply( &replyMsg );
	}

	} // END: if (msg->HasSpecifiers())
	else
		BLooper::MessageReceived( msg );
} 

//------------------------------------------------------------------------------

void BWindow::DispatchMessage(BMessage *msg, BHandler *target) 
{
	if (!msg){
		BLooper::DispatchMessage( msg, target );
		return;
	}

	switch ( msg->what ) { 
	case B_ZOOM:{
		Zoom();
		break;}

	case B_MINIMIZE:{
		bool			minimize;

		msg->FindBool("minimize", &minimize);

		fMinimized		= minimize;
		Minimize( minimize );
		break;}

	case B_WINDOW_RESIZED:{
		BPoint			offset;
		int32			width, height;

		msg->FindInt32("width", &width);
		msg->FindInt32("height", &height);
		offset.x		= width;
		offset.y		= height;

		fFrame.SetRightBottom( fFrame.LeftTop() + offset );
		FrameResized( offset.x, offset.y );
		break;}

	case B_WINDOW_MOVED:{
		BPoint			origin;

		msg->FindPoint("where", &origin);

		fFrame.OffsetTo( origin );
		FrameMoved( origin );
		break;}

		// this is NOT an app_server message and we have to be cautious
	case B_WINDOW_MOVE_BY:{
		BPoint			offset;

		if (msg->FindPoint("data", &offset) == B_OK)
			MoveBy( offset.x, offset.y );
		else
			msg->SendReply( B_MESSAGE_NOT_UNDERSTOOD );
		break;}

		// this is NOT an app_server message and we have to be cautious
	case B_WINDOW_MOVE_TO:{
		BPoint			origin;

		if (msg->FindPoint("data", &origin) == B_OK)
			MoveTo( origin );
		else
			msg->SendReply( B_MESSAGE_NOT_UNDERSTOOD );
		break;}

	case B_WINDOW_ACTIVATED:{
		bool			active;

		msg->FindBool("active", &active);

		fActive			= active; 
		handleActivation( active );
		break;}

	case B_SCREEN_CHANGED:{
		BRect			frame;
		uint32			mode;

		msg->FindRect("frame", &frame);
		msg->FindInt32("mode", (int32*)&mode);
		ScreenChanged( frame, (color_space)mode );
		break;}

	case B_WORKSPACE_ACTIVATED:{
		uint32			workspace;
		bool			active;

		msg->FindInt32( "workspace", (int32*)&workspace );
		msg->FindBool( "active", &active );
		WorkspaceActivated( workspace, active );
		break;}

	case B_WORKSPACES_CHANGED:{
		uint32			oldWorkspace;
		uint32			newWorkspace;

		msg->FindInt32( "old", (int32*)&oldWorkspace );
		msg->FindInt32( "new", (int32*)&newWorkspace );
		WorkspacesChanged( oldWorkspace, newWorkspace );
		break;}

	case B_KEY_DOWN:{
		uint32			modifiers;
		int32			raw_char;
		const char		*string;

		msg->FindInt32( "modifiers", (int32*)&modifiers );
		msg->FindInt32( "raw_char", &raw_char );
		msg->FindString( "bytes", &string );
// TODO: it is NOT "bytes" field you should pass to KeyDown(), it is "byte" field.
		if ( !handleKeyDown( raw_char, (uint32)modifiers) )
			fFocus->KeyDown( string, strlen(string)-1 );
		break;}

	case B_KEY_UP:{
		const char		*string;

		msg->FindString( "bytes", &string );
		fFocus->KeyUp( string, strlen(string)-1 );
		break;}

	case B_UNMAPPED_KEY_DOWN:{
		if (fFocus)
			fFocus->MessageReceived( msg );
		break;}

	case B_UNMAPPED_KEY_UP:{
		if (fFocus)
			fFocus->MessageReceived( msg );
		break;}

	case B_MODIFIERS_CHANGED:{
		if (fFocus)
			fFocus->MessageReceived( msg );
		break;}

	case B_MOUSE_WHEEL_CHANGED:{
		if (fFocus)
			fFocus->MessageReceived( msg );
		break;}

	case B_MOUSE_DOWN:{
		BPoint			where;
		uint32			modifiers;
		uint32			buttons;
		int32			clicks;

		msg->FindPoint( "where", &where );
		msg->FindInt32( "modifiers", (int32*)&modifiers );
		msg->FindInt32( "buttons", (int32*)&buttons );
		msg->FindInt32( "clicks", &clicks );

		sendMessageUsingEventMask( B_MOUSE_DOWN, where );
		break;}

	case B_MOUSE_UP:{
		BPoint			where;
		uint32			modifiers;

		msg->FindPoint( "where", &where );
		msg->FindInt32( "modifiers", (int32*)&modifiers );
		
		sendMessageUsingEventMask( B_MOUSE_UP, where );
		break;}

	case B_MOUSE_MOVED:{
		BPoint			where;
		uint32			buttons;

		msg->FindPoint( "where", &where );
		msg->FindInt32( "buttons", (int32*)&buttons );
		
		sendMessageUsingEventMask( B_MOUSE_MOVED, where );
		break;}

	case B_PULSE:{
		if (fPulseEnabled)
			sendPulse( top_view );
		break;}

	case B_QUIT_REQUESTED:{
		if (QuitRequested())
			Quit();
		break;}

	case _UPDATE_:{
		BRect			updateRect;
		msg->FindRect("_rect", &updateRect);

// TODO: ADD this method:
		//DrawViews( updateRect );
		break;}

	case B_VIEW_MOVED:{
			BPoint			where;
			int32			token = B_NULL_TOKEN;
			BView			*view;

			msg->FindPoint("where", &where);
			msg->FindInt32("_token", &token);
			msg->RemoveName("_token");
			
			view			= findView(top_view, token);
			if (view){
				STRACE(("Calling BView(%s)::FrameMoved( %f, %f )\n", view->Name(), where.x, where.y));
				view->FrameMoved( where );
			}
			else
				printf("***PANIC: BW: Can't find view with ID: %ld !***\n", token);

		break;}
	
	case B_VIEW_RESIZED:{
			float			newWidth,
							newHeight;
			BPoint			where;
			int32			token = B_NULL_TOKEN;
			BView			*view;

			msg->FindFloat("width", &newWidth);
			msg->FindFloat("height", &newHeight);
			msg->FindPoint("where", &where);
			msg->FindInt32("_token", &token);
			msg->RemoveName("_token");
			
			view			= findView(top_view, token);
			if (view){
				STRACE(("Calling BView(%s)::FrameResized( %f, %f )\n", view->Name(), newWidth, newHeight));
				view->FrameResized( newWidth, newHeight );
			}
			else
				printf("***PANIC: BW: Can't find view with ID: %ld !***\n", token);

		break;}
		
	default:{
		BLooper::DispatchMessage(msg, target); 
		break;}
   }
}

//------------------------------------------------------------------------------

void BWindow::FrameMoved(BPoint new_position){
	// does nothing
	// Hook function
}

//------------------------------------------------------------------------------

void BWindow::FrameResized(float new_width, float new_height){
	// does nothing
	// Hook function
}

//------------------------------------------------------------------------------

void BWindow::WorkspacesChanged(uint32 old_ws, uint32 new_ws){
	// does nothing
	// Hook function
}

//------------------------------------------------------------------------------

void BWindow::WorkspaceActivated(int32 ws, bool state){
	// does nothing
	// Hook function
}

//------------------------------------------------------------------------------

void BWindow::MenusBeginning(){
	// does nothing
	// Hook function
}

//------------------------------------------------------------------------------

void BWindow::MenusEnded(){
	// does nothing
	// Hook function
}

//------------------------------------------------------------------------------

void BWindow::SetSizeLimits(float minWidth, float maxWidth, 
							float minHeight, float maxHeight){
	int32		rCode;

	if (minWidth > maxWidth)
		return;
	if (minHeight > maxHeight)
		return;
		
	Lock();
	session->WriteInt32( AS_SET_SIZE_LIMITS );
	session->WriteFloat( fMinWindWidth );
	session->WriteFloat( fMaxWindWidth );
	session->WriteFloat( fMinWindHeight );
	session->WriteFloat( fMaxWindHeight );
	session->Sync();
	session->ReadInt32( &rCode );
	Unlock();

	if (rCode == SERVER_TRUE){
		fMinWindHeight		= minHeight;
		fMinWindWidth		= minWidth;
		fMaxWindHeight		= maxHeight;
		fMaxWindWidth		= maxWidth;
	}
}

//------------------------------------------------------------------------------

void BWindow::GetSizeLimits(float *minWidth, float *maxWidth, 
							float *minHeight, float *maxHeight){
	*minHeight			= fMinWindHeight;
	*minWidth			= fMinWindWidth;
	*maxHeight			= fMaxWindHeight;
	*maxWidth			= fMaxWindWidth;
}

//------------------------------------------------------------------------------

void BWindow::SetZoomLimits(float maxWidth, float maxHeight){
	if (maxWidth > fMaxWindWidth)
		maxWidth	= fMaxWindWidth;
	else
		fMaxZoomWidth		= maxWidth;

	if (maxHeight > fMaxWindHeight)
		maxHeight	= fMaxWindHeight;
	else
		fMaxZoomHeight		= maxHeight;
}

//------------------------------------------------------------------------------

void BWindow::Zoom(	BPoint rec_position, float rec_width, float rec_height){

		// this is also a Hook function!
		
	MoveTo( rec_position );
	ResizeTo( rec_width, rec_height );
}

//------------------------------------------------------------------------------

void BWindow::Zoom(){
	float			minWidth, minHeight;
	BScreen			screen;
/*	from BeBook:
	However, if the window's rectangle already matches these "zoom" dimensions
	(give or take a few pixels), Zoom() passes the window's previous
	("non-zoomed") size and location. (??????)
*/
	if (Frame().Width() == fMaxZoomWidth && Frame().Height() == fMaxZoomHeight) {
		BPoint position( Frame().left, Frame().top);
		Zoom( position, fMaxZoomWidth, fMaxZoomHeight );
		return;
	}
	
/*	from BeBook:
	The dimensions that non-virtual Zoom() passes to hook Zoom() are deduced from
	the smallest of three rectangles: 3) the screen rectangle, 1) the rectangle
	defined by SetZoomLimits(), 2) the rectangle defined by SetSizeLimits()
*/
		// 1
	minHeight		= fMaxZoomHeight;
	minWidth		= fMaxZoomWidth;

		// 2
	if ( fMaxWindHeight < minHeight ) { minHeight		= fMaxWindHeight; }
	if ( fMaxWindWidth  < minWidth  ) { minWidth		= fMaxWindWidth; }

		// 3
	if ( screen.Frame().Width()  < minWidth )   { minWidth		= screen.Frame().Width(); }
	if ( screen.Frame().Height() < minHeight  ) { minHeight		= screen.Frame().Height(); }

	Zoom( Frame().LeftTop(), minWidth, minHeight );
}

//------------------------------------------------------------------------------

void BWindow::ScreenChanged(BRect screen_size, color_space depth){
	// Hook function
	// does nothing
}

//------------------------------------------------------------------------------

void BWindow::SetPulseRate(bigtime_t rate){
	if ( rate < 0 )
		return;

	if (fPulseRate == 0 && !fPulseEnabled){
		fPulseRunner	= new BMessageRunner(	BMessenger(this),
												new BMessage( B_PULSE ),
												rate);
		fPulseRate		= rate;
		fPulseEnabled	= true;

		return;
	}

	if (rate == 0 && fPulseEnabled){
		delete			fPulseRunner;
		fPulseRunner	= NULL;

		fPulseRate		= rate;
		fPulseEnabled	= false;

		return;
	}

	fPulseRunner->SetInterval( rate );
}

//------------------------------------------------------------------------------

bigtime_t BWindow::PulseRate() const{
	return fPulseRate;
}

//------------------------------------------------------------------------------

void BWindow::AddShortcut(	uint32 key,	uint32 modifiers, BMessage* msg){
	AddShortcut( key, modifiers, msg, this);
}

//------------------------------------------------------------------------------

void BWindow::AddShortcut(	uint32 key,	uint32 modifiers, BMessage* msg, BHandler* target){
/*
	NOTE: I'm not sure if it is OK to use 'key'
*/
	if ( !msg )
		return;

	int64				when;
	_BCmdKey			*cmdKey;

	when				= real_time_clock_usecs();
	msg->AddInt64("when", when);

// TODO:	make sure key is a lowercase char !!!

	modifiers			= modifiers | B_COMMAND_KEY;

	cmdKey				= new _BCmdKey;
	cmdKey->key			= key;
	cmdKey->modifiers	= modifiers;
	cmdKey->message		= msg;
	if (target == NULL)
		cmdKey->targetToken	= B_ANY_TOKEN;
	else
		cmdKey->targetToken	= _get_object_token_(target);

		// removes the shortcut from accelList if it exists!
	RemoveShortcut( key, modifiers );

	accelList.AddItem( cmdKey );

}

//------------------------------------------------------------------------------

void BWindow::RemoveShortcut(uint32 key, uint32 modifiers){
	int32				index;
	
	modifiers			= modifiers | B_COMMAND_KEY;

	index				= findShortcut( key, modifiers );
	if ( index >=0 ) {
		_BCmdKey		*cmdKey;

		cmdKey			= (_BCmdKey*)accelList.ItemAt( index );

		accelList.RemoveItem(index);
		
		delete cmdKey->message;
		delete cmdKey;
	}
}

//------------------------------------------------------------------------------

BButton* BWindow::DefaultButton() const{
	return fDefaultButton;
}

//------------------------------------------------------------------------------

void BWindow::SetDefaultButton(BButton* button){
/*
Note: for developers!
	He he, if you really want to understand what is happens here, take a piece of
		paper and start taking possible values and then walk with them through
		the code.
*/
	BButton				*aux;

	if ( fDefaultButton == button )
		return;

	if ( fDefaultButton ){
		aux				= fDefaultButton;
		fDefaultButton	= NULL;
		aux->MakeDefault( false );
		aux->Invalidate();
	}
	
	if ( button == NULL ){
		fDefaultButton		= NULL;
		return;
	}
	
	fDefaultButton			= button;
	fDefaultButton->MakeDefault( true );
	fDefaultButton->Invalidate();
}

//------------------------------------------------------------------------------

bool BWindow::NeedsUpdate() const{

	int32		rCode;

	const_cast<BWindow*>(this)->Lock();	
	session->WriteInt32( AS_NEEDS_UPDATE );
	session->Sync();
	session->ReadInt32( &rCode );
	const_cast<BWindow*>(this)->Unlock();
	
	return rCode == SERVER_TRUE;
}

//------------------------------------------------------------------------------

void BWindow::UpdateIfNeeded(){
		// works only from this thread
	if (find_thread(NULL) == Thread()){
		Sync();
		drawAllViews( top_view );
	}
}

//------------------------------------------------------------------------------

BView* BWindow::FindView(const char* viewName) const{

	return findView( top_view, viewName );
}

//------------------------------------------------------------------------------

BView* BWindow::FindView(BPoint point) const{

	return findView( top_view, point );
}

//------------------------------------------------------------------------------

BView* BWindow::CurrentFocus() const{
	return fFocus;
}

//------------------------------------------------------------------------------

void BWindow::Activate(bool active){
	if (IsHidden())
		return;

	Lock();
	session->WriteInt32( AS_ACTIVATE_WINDOW );
	session->WriteBool( active );
	session->Sync( );
	Unlock();
}

//------------------------------------------------------------------------------

void BWindow::WindowActivated(bool state){
	// hook function
	// does nothing
}

//------------------------------------------------------------------------------

void BWindow::ConvertToScreen(BPoint* pt) const{
	pt->x			+= fFrame.left;
	pt->y			+= fFrame.top;
}

//------------------------------------------------------------------------------

BPoint BWindow::ConvertToScreen(BPoint pt) const{
	pt.x			+= fFrame.left;
	pt.y			+= fFrame.top;

	return pt;
}

//------------------------------------------------------------------------------

void BWindow::ConvertFromScreen(BPoint* pt) const{
	pt->x			-= fFrame.left;
	pt->y			-= fFrame.top;
}

//------------------------------------------------------------------------------

BPoint BWindow::ConvertFromScreen(BPoint pt) const{
	pt.x			-= fFrame.left;
	pt.y			-= fFrame.top;

	return pt;
}

//------------------------------------------------------------------------------

void BWindow::ConvertToScreen(BRect* rect) const{
	rect->top			+= fFrame.top;
	rect->left			+= fFrame.left;
	rect->bottom		+= fFrame.top;
	rect->right			+= fFrame.left;
}

//------------------------------------------------------------------------------

BRect BWindow::ConvertToScreen(BRect rect) const{
	rect.top			+= fFrame.top;
	rect.left			+= fFrame.left;
	rect.bottom			+= fFrame.top;
	rect.right			+= fFrame.left;

	return rect;
}

//------------------------------------------------------------------------------

void BWindow::ConvertFromScreen(BRect* rect) const{
	rect->top			-= fFrame.top;
	rect->left			-= fFrame.left;
	rect->bottom		-= fFrame.top;
	rect->right			-= fFrame.left;
}

//------------------------------------------------------------------------------

BRect BWindow::ConvertFromScreen(BRect rect) const{
	rect.top			-= fFrame.top;
	rect.left			-= fFrame.left;
	rect.bottom			-= fFrame.top;
	rect.right			-= fFrame.left;

	return rect;
}

//------------------------------------------------------------------------------

bool BWindow::IsMinimized() const{
		// Hiding takes precendence over minimization!!!
	if ( IsHidden() )
		return false;

	return fMinimized;
}

//------------------------------------------------------------------------------

BRect BWindow::Bounds() const{
	BRect			bounds( 0.0, 0.0, fFrame.Width(), fFrame.Height() );
	return bounds;
}

//------------------------------------------------------------------------------

BRect BWindow::Frame() const{
	return fFrame;
}

//------------------------------------------------------------------------------

const char* BWindow::Title() const{
	return fTitle;
}

//------------------------------------------------------------------------------

void BWindow::SetTitle(const char* title){
	if (!title)
		return;

	if (fTitle){
		delete fTitle;
		fTitle = NULL;
	}
	
	fTitle		= strdup( title );

		// we will change BWindow's thread name to "w>window_title"	
	int32		length;
	length		= strlen( fTitle );
	
	char		*threadName;
	threadName	= new char[32];
	strcpy(threadName, "w>");
	strncat(threadName, fTitle, (length>=29) ? 29: length);

		// if the message loop has been started...
	if (Thread() != B_ERROR ){
		SetName( threadName );
		rename_thread( Thread(), threadName );

			// we notify the app_server so we can actually see the change
		Lock();
		session->WriteInt32( AS_WINDOW_TITLE);
		session->WriteString( fTitle );
		session->Sync( );
		Unlock();
	}
	else
		SetName( threadName );
}

//------------------------------------------------------------------------------

bool BWindow::IsActive() const{
	return fActive;
}

//------------------------------------------------------------------------------

void BWindow::SetKeyMenuBar(BMenuBar* bar){
	fKeyMenuBar			= bar;
}

//------------------------------------------------------------------------------

BMenuBar* BWindow::KeyMenuBar() const{
	return fKeyMenuBar;
}

//------------------------------------------------------------------------------

bool BWindow::IsModal() const{
	if ( fFeel == B_MODAL_SUBSET_WINDOW_FEEL)
		return true;
	if ( fFeel == B_MODAL_APP_WINDOW_FEEL)
		return true;
	if ( fFeel == B_MODAL_ALL_WINDOW_FEEL)
		return true;

	return false;

}

//------------------------------------------------------------------------------

bool BWindow::IsFloating() const{
	if ( fFeel == B_FLOATING_SUBSET_WINDOW_FEEL)
		return true;
	if ( fFeel == B_FLOATING_APP_WINDOW_FEEL)
		return true;
	if ( fFeel == B_FLOATING_ALL_WINDOW_FEEL)
		return true;

	return false;
}

//------------------------------------------------------------------------------

status_t BWindow::AddToSubset(BWindow* window){
	if ( !window )
			return B_ERROR;
	
	int32		rCode;

	if (window->Feel() == B_NORMAL_WINDOW_FEEL &&
			(fFeel == B_MODAL_SUBSET_WINDOW_FEEL ||
				fFeel == B_FLOATING_SUBSET_WINDOW_FEEL)){

		team_id		team = Team();
		
		Lock();
		session->WriteInt32( AS_ADD_TO_SUBSET );
		session->WriteInt32( _get_object_token_(window) );
		session->WriteData( &team, sizeof(team_id) );
		session->Sync();
		session->ReadInt32( &rCode );
		Unlock();

		return rCode == SERVER_TRUE? B_OK : B_ERROR;
	}

	return B_ERROR;
}

//------------------------------------------------------------------------------

status_t BWindow::RemoveFromSubset(BWindow* window){
	if ( !window )
			return B_ERROR;
	
	int32		rCode;

	if (window->Feel() == B_NORMAL_WINDOW_FEEL &&
			(fFeel == B_MODAL_SUBSET_WINDOW_FEEL ||
				fFeel == B_FLOATING_SUBSET_WINDOW_FEEL)){

		team_id		team = Team();

		Lock();
		session->WriteInt32( AS_REM_FROM_SUBSET );
		session->WriteInt32( _get_object_token_(window) );
		session->WriteData( &team, sizeof(team_id) );
		session->Sync();
		session->ReadInt32( &rCode );
		Unlock();

		return rCode == SERVER_TRUE? B_OK : B_ERROR;
	}

	return B_ERROR;
}

//------------------------------------------------------------------------------

status_t BWindow::Perform(perform_code d, void* arg){
	return BLooper::Perform( d, arg );
}

//------------------------------------------------------------------------------

status_t BWindow::SetType(window_type type){
	decomposeType(type, &fLook, &fFeel);
	status_t stat1, stat2;
	
	stat1=SetLook( fLook );
	stat2=SetFeel( fFeel );

	if(stat1==B_OK && stat2==B_OK)
		return B_OK;
	return B_ERROR;
}

//------------------------------------------------------------------------------

window_type	BWindow::Type() const{
	return composeType( fLook, fFeel );
}

//------------------------------------------------------------------------------

status_t BWindow::SetLook(window_look look){

	int32		rCode;

	Lock();
	session->WriteInt32( AS_SET_LOOK );
	session->WriteInt32( (int32)look );
	session->Sync();
	session->ReadInt32( &rCode );
	Unlock();
	
	if (rCode == SERVER_TRUE){
		fLook		= look;
		return B_OK;
	}
	
	return B_ERROR;
}

//------------------------------------------------------------------------------

window_look	BWindow::Look() const{
	return fLook;
}

//------------------------------------------------------------------------------

status_t BWindow::SetFeel(window_feel feel){
/* TODO:	See what happens when a window that is part of a subset, changes its
			feel!? should it be removed from the subset???
*/
	int32		rCode;

	Lock();
	session->WriteInt32( AS_SET_FEEL );
	session->WriteInt32( (int32)feel );
	session->Sync();
	session->ReadInt32( &rCode );	
	Unlock();
	
	if (rCode == SERVER_TRUE){
		fFeel		= feel;
		return B_OK;
	}

	return B_ERROR;
}

//------------------------------------------------------------------------------

window_feel	BWindow::Feel() const{
	return fFeel;
}

//------------------------------------------------------------------------------

status_t BWindow::SetFlags(uint32 flags){

	int32		rCode;

	Lock();	
	session->WriteInt32( AS_SET_FLAGS );
	session->WriteUInt32( flags );
	session->Sync();
	session->ReadInt32( &rCode );
	Unlock();
	
	if (rCode == SERVER_TRUE){
		fFlags		= flags;
		return B_OK;
	}

	return B_ERROR;
}

//------------------------------------------------------------------------------

uint32	BWindow::Flags() const{
	return fFlags;
}

//------------------------------------------------------------------------------

status_t BWindow::SetWindowAlignment(window_alignment mode,
											int32 h, int32 hOffset,
											int32 width, int32 widthOffset,
											int32 v, int32 vOffset,
											int32 height, int32 heightOffset)
{
	if ( !(	(mode && B_BYTE_ALIGNMENT) ||
			(mode && B_PIXEL_ALIGNMENT) ) )
	{
		return B_ERROR;
	}

	if ( 0 <= hOffset && hOffset <=h )
		return B_ERROR;

	if ( 0 <= vOffset && vOffset <=v )
		return B_ERROR;

	if ( 0 <= widthOffset && widthOffset <=width )
		return B_ERROR;

	if ( 0 <= heightOffset && heightOffset <=height )
		return B_ERROR;

// TODO: test if hOffset = 0 and set it to 1 if true.
	int32		rCode;

	Lock();
	session->WriteInt32( AS_SET_ALIGNMENT );
	session->WriteInt32( (int32)mode );
	session->WriteInt32( h );
	session->WriteInt32( hOffset );
	session->WriteInt32( width );
	session->WriteInt32( widthOffset );
	session->WriteInt32( v );
	session->WriteInt32( vOffset );
	session->WriteInt32( height );
	session->WriteInt32( heightOffset );
	session->Sync();
	session->ReadInt32( &rCode );
	Unlock();
	
	if ( rCode == SERVER_TRUE){
		return B_NO_ERROR;
	}

	return B_ERROR;
}

//------------------------------------------------------------------------------

status_t BWindow::GetWindowAlignment(window_alignment* mode,
											int32* h, int32* hOffset,
											int32* width, int32* widthOffset,
											int32* v, int32* vOffset,
											int32* height, int32* heightOffset) const
{
	int32		rCode;

	const_cast<BWindow*>(this)->Lock();
	session->WriteInt32( AS_GET_ALIGNMENT );
	session->Sync();
	session->ReadInt32( &rCode );
	
	if (rCode == SERVER_TRUE){
		session->ReadInt32( (int32*)mode );
		session->ReadInt32( h );
		session->ReadInt32( hOffset );
		session->ReadInt32( width );
		session->ReadInt32( widthOffset );
		session->ReadInt32( v );
		session->ReadInt32( hOffset );
		session->ReadInt32( height );
		session->ReadInt32( heightOffset );		

		return B_NO_ERROR;
	}
	const_cast<BWindow*>(this)->Unlock();
	
	return B_ERROR;
}

//------------------------------------------------------------------------------

uint32 BWindow::Workspaces() const{
	uint32					workspaces;

	const_cast<BWindow*>(this)->Lock();
	session->WriteInt32( AS_GET_WORKSPACES );
	session->Sync();
	session->ReadInt32( (int32*)&workspaces );
	const_cast<BWindow*>(this)->Unlock();
	
	return workspaces;
}

//------------------------------------------------------------------------------

void BWindow::SetWorkspaces(uint32 workspaces){

	Lock();
	session->WriteInt32( AS_SET_WORKSPACES );
	session->WriteInt32( (int32)workspaces );
	session->Sync( );
	Unlock();
}

//------------------------------------------------------------------------------

BView* BWindow::LastMouseMovedView() const{
	return fLastMouseMovedView;
}

//------------------------------------------------------------------------------

void BWindow::MoveBy(float dx, float dy){

	BPoint			offset( dx, dy );

	MoveTo( fFrame.LeftTop() + offset );
}

//------------------------------------------------------------------------------

void BWindow::MoveTo( BPoint point ){
	MoveTo( point.x, point.y );
}

//------------------------------------------------------------------------------

void BWindow::MoveTo(float x, float y){

	Lock();
	session->WriteInt32( AS_WINDOW_MOVE );
	session->WriteFloat( x );
	session->WriteFloat( y );
	session->Sync();
	Unlock();
}

//------------------------------------------------------------------------------

void BWindow::ResizeBy(float dx, float dy){

		// stay in minimum & maximum frame limits
	(fFrame.Width() + dx) < fMinWindWidth ? fMinWindWidth : fFrame.Width() + dx;
	(fFrame.Width() + dx) > fMaxWindWidth ? fMaxWindWidth : fFrame.Width() + dx;

	(fFrame.Height() + dy) < fMinWindHeight ? fMinWindHeight : fFrame.Height() + dy;
	(fFrame.Height() + dy) > fMaxWindHeight ? fMaxWindHeight : fFrame.Height() + dy;

	ResizeTo( fFrame.Width() + dx, fFrame.Height() + dy );
}

//------------------------------------------------------------------------------

void BWindow::ResizeTo(float width, float height){

		// stay in minimum & maximum frame limits
	width = (width < fMinWindWidth) ? fMinWindWidth : width;
	width = (width > fMaxWindWidth) ? fMaxWindWidth : width;

	height = (height < fMinWindHeight) ? fMinWindHeight : height;
	height = (height > fMaxWindHeight) ? fMaxWindHeight : height;

	Lock();
	session->WriteInt32( AS_WINDOW_RESIZE );
	session->WriteFloat( width );
	session->WriteFloat( height );
	session->Sync( );
	Unlock();
}

//------------------------------------------------------------------------------

void BWindow::Show(){
	bool	isLocked = this->IsLocked();
		
	fShowLevel--;

	if (fShowLevel == 0){
		STRACE(("BWindow(%s): sending AS_SHOW_WINDOW message...\n", Name() ));
		if ( !isLocked ) Lock();
		session->WriteInt32( AS_SHOW_WINDOW );
		session->Sync( );
		if ( !isLocked) Unlock();
	}

		// if it's the fist time Show() is called... start the Looper thread.
	if ( Thread() == B_ERROR )
	{
			// normaly this won't happen, but I want to be sure!
		if ( !isLocked ) Lock();
		Run();
	}
	
}

//------------------------------------------------------------------------------

void BWindow::Hide(){
	if (fShowLevel == 0){
		Lock();
		session->WriteInt32( AS_HIDE_WINDOW );
		session->Sync();
		Unlock();
	}
	fShowLevel++;
}

//------------------------------------------------------------------------------

bool BWindow::IsHidden() const{
	return fShowLevel > 0; 
}

//------------------------------------------------------------------------------

bool BWindow::QuitRequested(){
	return BLooper::QuitRequested();
}

//------------------------------------------------------------------------------

thread_id BWindow::Run(){
	return BLooper::Run();
}

//------------------------------------------------------------------------------

status_t BWindow::GetSupportedSuites(BMessage* data){
	status_t err = B_OK;
	if (!data)
		err = B_BAD_VALUE;

	if (!err){
		err = data->AddString("Suites", "suite/vnd.Be-window");
		if (!err){
			BPropertyInfo propertyInfo(windowPropInfo);
			err = data->AddFlat("message", &propertyInfo);
			if (!err){
				err = BLooper::GetSupportedSuites(data);
			}
		}
	}
	return err;
}

//------------------------------------------------------------------------------

BHandler* BWindow::ResolveSpecifier(BMessage* msg, int32 index,	BMessage* specifier,
										int32 what,	const char* property)
{
	if (msg->what == B_WINDOW_MOVE_BY)
		return this;
	if (msg->what == B_WINDOW_MOVE_TO)
		return this;

	BPropertyInfo propertyInfo(windowPropInfo);
	switch (propertyInfo.FindMatch(msg, index, specifier, what, property))
	{
		case B_ERROR:
			break;
		case 0:
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
			return this;
			
		case 14:
			if (fKeyMenuBar){
				msg->PopSpecifier();
				return fKeyMenuBar;
			}
			else{
				BMessage		replyMsg(B_MESSAGE_NOT_UNDERSTOOD);
				replyMsg.AddInt32( "error", B_NAME_NOT_FOUND );
				replyMsg.AddString( "message", "This window doesn't have a main MenuBar");
				msg->SendReply( &replyMsg );
				return NULL;
			}
		case 15:
				// we will NOT pop the current specifier
			return top_view;
			
		case 16:
			return this;
	}

	return BLooper::ResolveSpecifier(msg, index, specifier, what, property);
}

// PRIVATE
//--------------------Private Methods-------------------------------------------
// PRIVATE

void BWindow::InitData(	BRect frame,
						const char* title,
						window_look look,
						window_feel feel,
						uint32 flags,
						uint32 workspace){

	STRACE(("BWindow::InitData(...)\n"));
	
	fTitle=NULL;
	if ( be_app == NULL ){
		debugger("You need a valid BApplication object before interacting with the app_server");
		return;
	}
	
	fFrame		= frame;

	if (title)
		SetTitle( title );

	fFeel			= feel;
	fLook			= look;
	fFlags			= flags;
	

	fInTransaction	= false;
	fActive			= false;
	fShowLevel		= 1;

	top_view		= NULL;
	fFocus			= NULL;
	fLastMouseMovedView	= NULL;
	fKeyMenuBar		= NULL;
	fDefaultButton	= NULL;

//	accelList		= new BList( 10 );
	AddShortcut('X', B_COMMAND_KEY, new BMessage(B_CUT), NULL);
	AddShortcut('C', B_COMMAND_KEY, new BMessage(B_COPY), NULL);
	AddShortcut('V', B_COMMAND_KEY, new BMessage(B_PASTE), NULL);
	AddShortcut('A', B_COMMAND_KEY, new BMessage(B_SELECT_ALL), NULL);
	AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));

	fPulseEnabled	= false;
	fPulseRate		= 0;
	fPulseRunner	= NULL;

// TODO: is this correct??? should the thread loop be started???
	//SetPulseRate( 500000 );

// TODO:  see if you can use 'fViewsNeedPulse'

	fIsFilePanel	= false;

// TODO: see WHEN is this used!
	fMaskActivated	= false;

// TODO: see WHEN is this used!
	fWaitingForMenu	= false;

	fMinimized		= false;

// TODO:  see WHERE you can use 'fMenuSem'

	fMaxZoomHeight	= 32768.0;
	fMaxZoomWidth	= 32768.0;
	fMinWindHeight	= 0.0;
	fMinWindWidth	= 0.0;
	fMaxWindHeight	= 32768.0;
	fMaxWindWidth	= 32768.0;

	fLastViewToken	= B_NULL_TOKEN;
// TODO: other initializations!

/*
	Here, we will contact app_server and let him know that a window has
		been created
*/
	receive_port	= create_port( B_LOOPER_PORT_DEFAULT_CAPACITY ,
						"w_rcv_port");
	if (receive_port==B_BAD_VALUE || receive_port==B_NO_MORE_PORTS){
		debugger("Could not create BWindow's receive port, used for interacting with the app_server!");
		delete this;
	}

	STRACE(("BWindow::InitData(): contacting app_server...\n"));
		// let app_server to know that a window has been created.

	session		= new BSession( receive_port, be_app->fServerFrom );

		// HERE we are in BApplication's thread, so for locking we use be_app variable
		// we'll lock the be_app to be sure we're the only one writing at BApplication's server port
	bool	locked = false;
	if ( !(be_app->IsLocked()) )
		{ be_app->Lock(); locked = true; }
	
	PortMessage		pmsg;
	PortLink		link(be_app->fServerFrom);
	link.SetOpCode(AS_CREATE_WINDOW);
	
	link.Attach<BRect>( fFrame );
	link.Attach<int32>( (int32)fLook );
	link.Attach<int32>( (int32)fFeel );
	link.Attach<uint32>( fFlags );
	link.Attach<uint32>( workspace );
	link.Attach<int32>( _get_object_token_(this) );
	link.Attach<port_id>( receive_port );
	link.Attach<port_id>( fMsgPort );
	link.AttachString( title );
	link.FlushWithReply(&pmsg);

	pmsg.Read<port_id>(&send_port);
/*
	session->WriteInt32( AS_CREATE_WINDOW );
	session->WriteRect( fFrame );
	session->WriteInt32( (int32)fLook );
	session->WriteInt32( (int32)fFeel );
	session->WriteUInt32( fFlags );
	session->WriteUInt32( workspace );
	session->WriteData( &team, sizeof(team_id));
	session->WriteInt32( _get_object_token_(this) );
	session->WriteData( &receive_port, sizeof(port_id) );
	session->WriteData( &fMsgPort, sizeof(port_id) );
	session->WriteString( title );

printf("look: %ld\n", (int32)fLook);
printf("title: %s\n", title);
	session->Sync();
		// The port on witch app_server will listen for us	
	STRACE(("here\n"));
	session->ReadData( &send_port, sizeof(port_id) );
*/
		// unlock, so other threads can do their job.
	if( locked )
		be_app->Unlock();

	session->SetSendPort(send_port);

	STRACE(("\tapp_server link established.\n"));
	STRACE(("Window locked?: %s\n", IsLocked()?"True":"False"));

		// build and register top_view with app_server
	BuildTopView();
//	top_view->PrintToStream();
}

//------------------------------------------------------------------------------

void BWindow::task_looper(){

	//	Check that looper is locked (should be)
	AssertLocked();

	Unlock();
	
	using namespace BPrivate;
	bool		dispatchNextMessage = false;
	BMessage	*msg;

	//	loop: As long as we are not terminating.
	while (!fTerminating)
	{
		msg		= MessageFromPort();

		//	Did we get a message?
		if (msg){
			//	Add to queue
			fQueue->Lock();
			fQueue->AddMessage(msg);
			fQueue->Unlock();
		}

		//	Get message count from port
		int32 msgCount = port_count(fMsgPort);
		if (msgCount > 0){
			fQueue->Lock();
			for (int32 i = 0; i < msgCount; ++i)
			{
				//	Read 'count' messages from port (so we will not block)
				//	We use zero as our timeout since we know there is stuff there
				msg = MessageFromPort(0);
				//	Add messages to queue
				if (msg)
					fQueue->AddMessage(msg);
			}
			fQueue->Unlock();
		}

		//	loop: As long as there are messages in the queue and
		//		  and we are not terminating.
		dispatchNextMessage		= true;
		while (!fTerminating && dispatchNextMessage)
		{
			fQueue->Lock();
			fLastMessage		= fQueue->NextMessage();
			fQueue->Unlock();

			Lock();

		// TODO: add code for drag & drop
			if (!fLastMessage)
			{
				// No more messages: Unlock the looper and terminate the
				// dispatch loop.
				dispatchNextMessage = false;
			}
			else
			{
				//	Get the target handler
				BHandler* handler;
				if (_use_preferred_target_(fLastMessage))
					handler = fPreferred;
				else
					gDefaultTokens.GetToken(_get_message_target_(fLastMessage),
					 						 B_HANDLER_TOKEN,
					 						 (void**)&handler);

				if (!handler)
					handler = this;

				//	Is this a scripting message?
				if (fLastMessage->HasSpecifiers())
				{
					int32 index = 0;
					// Make sure the current specifier is kosher
					if (fLastMessage->GetCurrentSpecifier(&index) == B_OK)
						handler = resolve_specifier(handler, fLastMessage);
				}
				
				if (handler)
				{
					//	Do filtering
					handler = top_level_filter(fLastMessage, handler);
					if (handler && handler->Looper() == this)
						DispatchMessage(fLastMessage, handler);
				}
			}
				// empty our message buffer
			session->Sync();

			Unlock();
printf("Lock released\n");
			//	Delete the current message (fLastMessage)
			if (fLastMessage)
			{
				delete fLastMessage;
				fLastMessage = NULL;
			}

			//	Are any messages on the port?
			if (port_count(fMsgPort) > 0)
			{
				//	Do outer loop
				dispatchNextMessage = false;
			}
		}
	}

}

//------------------------------------------------------------------------------

BMessage* BWindow::ReadMessageFromPort(bigtime_t tout){
// TODO: remove!
}

//------------------------------------------------------------------------------

window_type BWindow::composeType(window_look look,	
								 window_feel feel) const
{
	window_type returnValue = B_UNTYPED_WINDOW;

	switch(feel)
	{
	case B_NORMAL_WINDOW_FEEL:
		switch (look)
		{
		case B_TITLED_WINDOW_LOOK:
			returnValue = B_TITLED_WINDOW;
			break;

		case B_DOCUMENT_WINDOW_LOOK:
			returnValue = B_DOCUMENT_WINDOW;
			break;

		case B_BORDERED_WINDOW_LOOK:
			returnValue = B_BORDERED_WINDOW;
			break;
		
		default:
			returnValue = B_UNTYPED_WINDOW;
		}
		break;

	case B_MODAL_APP_WINDOW_FEEL:
		if (look == B_MODAL_WINDOW_LOOK)
			returnValue = B_MODAL_WINDOW;
		break;

	case B_FLOATING_APP_WINDOW_FEEL:
		if (look == B_FLOATING_WINDOW_LOOK)
			returnValue = B_FLOATING_WINDOW;
		break;
		
	default:
		returnValue = B_UNTYPED_WINDOW;
	}
	
	return returnValue;
}

//------------------------------------------------------------------------------

void BWindow::decomposeType(window_type type, 
							   window_look* look,
							   window_feel* feel) const
{
	switch (type)
	{
	case B_TITLED_WINDOW:
		*look = B_TITLED_WINDOW_LOOK;
		*feel = B_NORMAL_WINDOW_FEEL;
		break;
	case B_DOCUMENT_WINDOW:
		*look = B_DOCUMENT_WINDOW_LOOK;
		*feel = B_NORMAL_WINDOW_FEEL;
		break;
	case B_MODAL_WINDOW:
		*look = B_MODAL_WINDOW_LOOK;
		*feel = B_MODAL_APP_WINDOW_FEEL;
		break;
	case B_FLOATING_WINDOW:
		*look = B_FLOATING_WINDOW_LOOK;
		*feel = B_FLOATING_APP_WINDOW_FEEL;
		break;
	case B_BORDERED_WINDOW:
		*look = B_BORDERED_WINDOW_LOOK;
		*feel = B_NORMAL_WINDOW_FEEL;
		break;
	case B_UNTYPED_WINDOW:
		*look = B_TITLED_WINDOW_LOOK;
		*feel = B_NORMAL_WINDOW_FEEL;
		break;
	default:
		*look = B_TITLED_WINDOW_LOOK;
		*feel = B_NORMAL_WINDOW_FEEL;
		break;
	}
}

//------------------------------------------------------------------------------

void BWindow::BuildTopView(){

	top_view		= new BView( fFrame.OffsetToCopy(0,0), "top_view",
								 B_FOLLOW_ALL, B_WILL_DRAW);
	top_view->top_level_view	= true;
	//top_view->fShowLevel		= 1;

		// set top_view's owner, add it to window's eligible handler list
		// and also set its next handler to be this window.
	top_view->setOwner( this );	

	PortLink		link(send_port);
	link.SetOpCode(AS_LAYER_CREATE_ROOT);
	link.Attach<int32>(_get_object_token_( top_view ));
	link.Attach<BRect>(top_view->Frame());
	link.Attach<int32>(top_view->ResizingMode());
	link.Attach<int32>(top_view->Flags());
	link.AttachString(top_view->Name());
	link.Flush();
/*
		// send top_view's information to app_server
	session->WriteInt32( AS_LAYER_CREATE_ROOT );
	session->WriteInt32( _get_object_token_( top_view ) );
	session->WriteRect( top_view->Frame() );
	session->WriteInt32( top_view->ResizingMode() );
	session->WriteInt32( top_view->Flags() );
	session->WriteString( top_view->Name() );
		// we DO NOT send our current state; the server knows the default values!
	session->Sync();
*/
	fLastViewToken		= _get_object_token_( top_view );
STRACE(("BuildTopView ended\n"));
}

//------------------------------------------------------------------------------

void BWindow::stopConnection(){
	Lock();
	session->WriteInt32( B_QUIT_REQUESTED );
	session->Sync();
	Unlock();
}

//------------------------------------------------------------------------------

void BWindow::prepareView(BView *aView){

// TODO: implement

}

//------------------------------------------------------------------------------

void BWindow::attachView(BView *aView){

// TODO: implement

}

//------------------------------------------------------------------------------

void BWindow::detachView(BView *aView){

// TODO: implement

}
//------------------------------------------------------------------------------

void BWindow::setFocus(BView *focusView, bool notifyInputServer){
	BView* previousFocus = fFocus;

	if (previousFocus == focusView)
		return;

	fFocus			= NULL;

	if (previousFocus != NULL)
		previousFocus->Invalidate();

	fFocus			= focusView;

	if (focusView != NULL)
		focusView->Invalidate();

// TODO: find out why do we have to notify input server.
	if (notifyInputServer){
		// what am I suppose to do here??
	}
}

//------------------------------------------------------------------------------

void BWindow::handleActivation( bool active ){

	if (active){
// TODO: talk to Ingo to make BWindow a friend for BRoster	
//		be_roster->UpdateActiveApp( be_app->Team() );
	}

	WindowActivated( active );

		// recursively call hook function 'WindowActivated(bool)'
		//    for all views attached to this window.
	activateView( top_view, active );
}

//------------------------------------------------------------------------------

void BWindow::activateView( BView *aView, bool active ){

	aView->WindowActivated( active );

	BView		*child;
	if ( (child = aView->first_child) ){
		while ( child ) {
			activateView( child, active );
			child 		= child->next_sibling; 
		}
	}
}

//------------------------------------------------------------------------------

bool BWindow::handleKeyDown( int32 raw_char, uint32 modifiers){

// TODO: ask people if using 'raw_char' is OK ?

		// handle BMenuBar key
	if ( (raw_char == B_ESCAPE) && (modifiers & B_COMMAND_KEY)
		&& fKeyMenuBar)
	{

// TODO: ask Marc about 'fWaitingForMenu' member!

		// fWaitingForMenu		= true;
		fKeyMenuBar->StartMenuBar(0, true, false, NULL);
		return true;
	}

		// Command+q has been pressed, so, we will quit
	if ( (raw_char == 'Q' || raw_char == 'q') && modifiers & B_COMMAND_KEY){
		be_app->PostMessage(B_QUIT_REQUESTED); 
		return true;
	}

		// Keyboard navigation through views!!!!
	if ( raw_char == B_TAB){

			// even if we have no focus view, we'll say that we will handle TAB key
		if (!fFocus)
			return true;

		BView			*nextFocus;

		if (modifiers & B_CONTROL_KEY & B_SHIFT_KEY){
			nextFocus		= findPrevView( fFocus, B_NAVIGABLE_JUMP );
		}
		else
			if (modifiers & B_CONTROL_KEY){
				nextFocus		= findNextView( fFocus, B_NAVIGABLE_JUMP );
			}
			else
				if (modifiers & B_SHIFT_KEY){
					nextFocus		= findPrevView( fFocus, B_NAVIGABLE );
				}
				else
					nextFocus		= findNextView( fFocus, B_NAVIGABLE );

		if ( nextFocus )
			setFocus( nextFocus, false );

		return true;
	}

		// Handle shortcuts
	int			index;
	if ( (index = findShortcut(raw_char, modifiers)) >=0){
		_BCmdKey		*cmdKey;

		cmdKey			= (_BCmdKey*)accelList.ItemAt( index );

			// we'll give the message to the focus view
		if (cmdKey->targetToken == B_ANY_TOKEN){
			fFocus->MessageReceived( cmdKey->message );
			return true;
		}
		else{
			BHandler		*handler;
			BHandler		*aHandler;
			int				noOfHandlers;

				// search for a match through BLooper's list of eligible handlers
			handler			= NULL;
			noOfHandlers	= CountHandlers();
			for( int i=0; i < noOfHandlers; i++ )
					// do we have a match?
				if ( _get_object_token_( aHandler = HandlerAt(i) )
					 == cmdKey->targetToken)
				{
						// yes, we do.
					handler		= aHandler;
					break;
				}

			if ( handler )
				handler->MessageReceived( cmdKey->message );
			else
					// if no handler was found, BWindow will handle the message
				MessageReceived( cmdKey->message );
		}
		return true;
	}

		// if <ENTER> is pressed and we have a default button
	if (DefaultButton() && (raw_char == B_ENTER)){
		const char		*chars;		// just to be sure
		CurrentMessage()->FindString("bytes", &chars);

		DefaultButton()->KeyDown( chars, strlen(chars)-1 );
		return true;
	}


	return false;
}

//------------------------------------------------------------------------------

BView* BWindow::sendMessageUsingEventMask2( BView* aView, int32 message, BPoint where ){

	BView		*destView;
	destView	= NULL;

	if ( aView->fBounds.Contains( aView->ConvertFromScreen(where) ) &&
		 !aView->first_child ){
		return aView;
	}

		// Code for Event Masks
	BView *child; 
	if ( (child = aView->first_child) ){
		while ( child ) { 
				// see if a BView registered for mouse events and it's not the current focus view
			if ( child->fEventMask & B_POINTER_EVENTS &&
				 aView != fFocus ){
				switch (message){
					case B_MOUSE_DOWN:{
						child->MouseDown( child->ConvertFromScreen( where ) );
					}
					break;
					
					case B_MOUSE_UP:{
						child->MouseUp( child->ConvertFromScreen( where ) );
					}
					break;
					
					case B_MOUSE_MOVED:{
						BMessage	*dragMessage;

// TODO: get the dragMessage if any
							// for now...
						dragMessage	= NULL;

/* TODO: after you have an example working, see if a view that registered for such events,
			does reveive B_MOUSE_MOVED with other options than B_OUTDIDE_VIEW !!!
					like: B_INSIDE_VIEW, B_ENTERED_VIEW, B_EXITED_VIEW
*/
						child->MouseMoved( ConvertFromScreen(where), B_OUTSIDE_VIEW , dragMessage);
					}
					break;
				}
			}
			if (destView == NULL)
				destView = sendMessageUsingEventMask2( child, message, where );
			else
				sendMessageUsingEventMask2( child, message, where );
			child = child->next_sibling; 
		}
	}
	
	return destView;
}

//------------------------------------------------------------------------------

void BWindow::sendMessageUsingEventMask( int32 message, BPoint where ){
	BView*			destView;

	destView		= sendMessageUsingEventMask2(top_view, message, where);
	
		// I'm SURE this is NEVER going to happen, but, durring development of BWindow, it may slip a NULL value
	if (!destView){
		// debugger("There is no BView under the mouse;");
		return;
	}
	
	switch( message ){
		case B_MOUSE_DOWN:{
			setFocus( destView );
			destView->MouseDown( destView->ConvertFromScreen( where ) );
			break;}

		case B_MOUSE_UP:{
			destView->MouseUp( destView->ConvertFromScreen( where ) );
			break;}

		case B_MOUSE_MOVED:{
			BMessage	*dragMessage;

// TODO: add code for drag and drop
				// for now...
			dragMessage	= NULL;

			if (destView != fLastMouseMovedView){
				fLastMouseMovedView->MouseMoved( destView->ConvertFromScreen( where ), B_EXITED_VIEW , dragMessage);
				destView->MouseMoved( ConvertFromScreen( where ), B_ENTERED_VIEW, dragMessage);
				fLastMouseMovedView		= destView;
			}
			else{
				destView->MouseMoved( ConvertFromScreen( where ), B_INSIDE_VIEW , dragMessage);
			}

				// I'm guessing that B_OUTSIDE_VIEW is given to the view that has focus, I'll have to check
// TODO: Do a research on mouse capturing, maybe it has something to do with this
			if (fFocus != destView)
				fFocus->MouseMoved( ConvertFromScreen( where ), B_OUTSIDE_VIEW , dragMessage);
			break;}
	}
}

//------------------------------------------------------------------------------

BMessage* BWindow::ConvertToMessage(void* raw1, int32 code){

	BMessage	*msg;
	msg			= new BMessage();
		// time since 01/01/70
	int64		when;

	switch(code){
		case B_WINDOW_ACTIVATED:{
			bool		active;

			session->ReadInt64( &when );
			session->ReadBool( &active );

			msg->what	= B_WINDOW_ACTIVATED;
			msg->AddInt64("when", when);
			msg->AddBool("active", active);

			break;}

		case B_QUIT_REQUESTED:{

			msg->what	= B_QUIT_REQUESTED;
			msg->AddBool("shortcut", false);

			break;}
			
		case B_KEY_DOWN:{
			int32			physicalKeyCode,
							repeat,
							modifiers,
							ASCIIcode;
			char			*bytes = NULL;
			uint8			states;
			int8			UTF8_1, UTF8_2, UTF8_3;

			session->ReadInt64( &when );
			session->ReadInt32( &physicalKeyCode );
			session->ReadInt32( &repeat );
			session->ReadInt32( &modifiers );
			session->ReadUInt8( &states );
			session->ReadInt8( &UTF8_1 );
			session->ReadInt8( &UTF8_2 );
			session->ReadInt8( &UTF8_3 );
			session->ReadInt32( &ASCIIcode );
			bytes			= session->ReadString();
			
			msg->what		= B_KEY_DOWN;
			msg->AddInt64("when", when);
			msg->AddInt32("key", physicalKeyCode);
			msg->AddInt32("be:key_repeat", repeat);
			msg->AddInt32("modifiers", modifiers);
			msg->AddInt8("states", states);
			msg->AddInt8("byte", UTF8_1);
			msg->AddInt8("byte", UTF8_2);
			msg->AddInt8("byte", UTF8_3);
			msg->AddInt32("raw_char", ASCIIcode);
			msg->AddString("bytes", bytes);
			
			if (bytes)
				delete bytes;

			break;}

		case B_KEY_UP:{
			int32			physicalKeyCode,
							modifiers,
							ASCIIcode;
			char			*bytes;
			uint8			states;
			int8			UTF8_1, UTF8_2, UTF8_3;

			session->ReadInt64( &when );
			session->ReadInt32( &physicalKeyCode );
			session->ReadInt32( &modifiers );
			session->ReadUInt8( &states );
			session->ReadInt8( &UTF8_1 );
			session->ReadInt8( &UTF8_2 );
			session->ReadInt8( &UTF8_3 );
			session->ReadInt32( &ASCIIcode );
			bytes			= session->ReadString();

			msg->what		= B_KEY_UP;
			msg->AddInt64("when", when);
			msg->AddInt32("key", physicalKeyCode);
			msg->AddInt32("modifiers", modifiers);
			msg->AddInt8("states", states);
			msg->AddInt8("byte", UTF8_1);
			msg->AddInt8("byte", UTF8_2);
			msg->AddInt8("byte", UTF8_3);
			msg->AddInt32("raw_char", ASCIIcode);
			msg->AddString("bytes", bytes);

			if (bytes)
				delete bytes;

			break;}

		case B_UNMAPPED_KEY_DOWN:{
			int32			physicalKeyCode,
							modifiers;
			uint8			states;

			session->ReadInt64( &when );
			session->ReadInt32( &physicalKeyCode );
			session->ReadInt32( &modifiers );
			session->ReadUInt8( &states );

			msg->what		= B_UNMAPPED_KEY_DOWN;
			msg->AddInt64("when", when);
			msg->AddInt32("key", physicalKeyCode);
			msg->AddInt32("modifiers", modifiers);
			msg->AddInt8("states", states);

			break;}

		case B_UNMAPPED_KEY_UP:{
			int32			physicalKeyCode,
							modifiers;
			uint8			states;

			session->ReadInt64( &when );
			session->ReadInt32( &physicalKeyCode );
			session->ReadInt32( &modifiers );
			session->ReadUInt8( &states );

			msg->what		= B_UNMAPPED_KEY_UP;
			msg->AddInt64("when", when);
			msg->AddInt32("key", physicalKeyCode);
			msg->AddInt32("modifiers", modifiers);
			msg->AddInt8("states", states);

			break;}

		case B_MODIFIERS_CHANGED:{
			int32			modifiers,
							modifiersOld;
			uint8			states;

			session->ReadInt64( &when );
			session->ReadInt32( &modifiers );
			session->ReadInt32( &modifiersOld );
			session->ReadUInt8( &states );

			msg->what		= B_MODIFIERS_CHANGED;
			msg->AddInt64("when", when);
			msg->AddInt32("modifiers", modifiers);
			msg->AddInt32("be:old_modifiers", modifiersOld);
			msg->AddInt8("states", states);

			break;}

		case B_MINIMIZE:{
			bool			minimize;

			session->ReadInt64( &when );
			session->ReadBool( &minimize );

			msg->what		= B_MINIMIZE;
			msg->AddInt64("when", when);
			msg->AddBool("minimize", minimize);

			break;}

		case B_MOUSE_DOWN:{
			int32			modifiers,
							buttons,
							noOfClicks;
			BPoint			where;

			session->ReadInt64( &when );
			session->ReadPoint( &where );
			session->ReadInt32( &modifiers );
			session->ReadInt32( &buttons );
			session->ReadInt32( &noOfClicks );

			msg->what		= B_MOUSE_DOWN;
			msg->AddInt64("when", when);
			msg->AddPoint("where", where);
			msg->AddInt32("modifiers", modifiers);
			msg->AddInt32("buttons", buttons);
			msg->AddInt32("clicks", noOfClicks);

			break;}

		case B_MOUSE_MOVED:{
			int32			buttons;
			int32			modifiers;		// added by OBOS Team
			BPoint			where;

			session->ReadInt64( &when );
			session->ReadPoint( &where );
			session->ReadInt32( &buttons );
			session->ReadInt32( &modifiers );

			msg->what		= B_MOUSE_MOVED;
			msg->AddInt64("when", when);
			msg->AddPoint("where", where);
			msg->AddInt32("buttons", buttons);
			msg->AddInt32("modifiers", modifiers);

			break;}

		case B_MOUSE_UP:{
			int32			modifiers,
							buttons;
			BPoint			where;

			session->ReadInt64( &when );
			session->ReadPoint( &where );
			session->ReadInt32( &buttons );
			session->ReadInt32( &modifiers );

			msg->what		= B_MOUSE_UP;
			msg->AddInt64("when", when);
			msg->AddPoint("where", where);
			msg->AddInt32("modifiers", modifiers);
			msg->AddInt32("buttons", buttons);

			break;}

		case B_MOUSE_WHEEL_CHANGED:{
			float			whellChangeX,
							whellChangeY;

			session->ReadInt64( &when );
			session->ReadFloat( &whellChangeX );
			session->ReadFloat( &whellChangeY );

			msg->what		= B_MOUSE_WHEEL_CHANGED;
			msg->AddInt64("when", when);
			msg->AddFloat("be:wheel_delta_x", whellChangeX);
			msg->AddFloat("be:wheel_delta_y", whellChangeY);

			break;}

		case B_SCREEN_CHANGED:{
			int32			colorSpace;
			BRect			frame;

			session->ReadInt64( &when );
			session->ReadRect( &frame );
			session->ReadInt32( &colorSpace );

			msg->what		= B_SCREEN_CHANGED;
			msg->AddInt64("when", when);
			msg->AddRect("frame", frame);
			msg->AddInt32("mode", colorSpace);

			break;}

		case B_WINDOW_MOVED:{
			BPoint			where;

			session->ReadInt64( &when );
			session->ReadPoint( &where );

			msg->what		= B_WINDOW_MOVED;
			msg->AddInt64("when", when);
			msg->AddPoint("where", where);

			break;}

		case B_WINDOW_RESIZED:{
			int32			newWidth,
							newHeight;

			session->ReadInt64( &when );
			session->ReadInt32( &newWidth );
			session->ReadInt32( &newHeight );
			
			msg->what		= B_WINDOW_RESIZED;
			msg->AddInt64("when", when);
			msg->AddInt32("width", newWidth);
			msg->AddInt32("height", newHeight);

			break;}

		case B_WORKSPACES_CHANGED:{
			int32			newWorkSpace,
							oldWorkSpace;

			session->ReadInt64( &when );
			session->ReadInt32( &newWorkSpace );
			session->ReadInt32( &oldWorkSpace );

			msg->what		= B_WORKSPACES_CHANGED;
			msg->AddInt64("when", when);
			msg->AddInt32("old", oldWorkSpace);
			msg->AddInt32("new", newWorkSpace);

			break;}

		case B_WORKSPACE_ACTIVATED:{
			int32			workSpace;
			bool			active;

			session->ReadInt64( &when );
			session->ReadInt32( &workSpace );
			session->ReadBool( &active );

			msg->what		= B_WORKSPACE_ACTIVATED;
			msg->AddInt64("when", when);
			msg->AddInt32("workspace", workSpace);
			msg->AddBool("active", active);

			break;}

		case B_ZOOM:{

			session->ReadInt64( &when );

			msg->what		= B_ZOOM;
			msg->AddInt64("when", when);

			break;}
		
		default:{
			delete msg;
			
			msg		= BLooper::ConvertToMessage( raw1, code );
			if (!msg)
				printf("***PANIC: app_server message NOT understood: '%c%c%c%c'***\n",
					(char)((code & 0xFF000000) >> 24), (char)((code & 0x00FF0000) >> 16),
					(char)((code & 0x0000FF00) >> 8), (char)(code & 0x000000FF) );
			}
	}
	
	return msg;
}

//------------------------------------------------------------------------------

void BWindow::sendPulse( BView* aView ){
	BView *child; 
	if ( (child = aView->first_child) ){
		while ( child ) { 
			if ( child->Flags() & B_PULSE_NEEDED ) child->Pulse();
			sendPulse( child );
			child = child->next_sibling; 
		}
	}
}

//------------------------------------------------------------------------------

int32 BWindow::findShortcut( uint32 key, uint32 modifiers ){
	int32			index,
					noOfItems;

	index			= -1;
	noOfItems		= accelList.CountItems();

	for ( int32 i = 0;  i < noOfItems; i++ ) {
		_BCmdKey*		tempCmdKey;

		tempCmdKey		= (_BCmdKey*)accelList.ItemAt(i);
		if (tempCmdKey->key == key && tempCmdKey->modifiers == modifiers){
			index		= i;
			break;
		}
	}
	
	return index;
}

//------------------------------------------------------------------------------

BView* BWindow::findView(BView* aView, int32 token){

	if ( _get_object_token_(aView) == token )
		return aView;

	BView			*child;
	if ( (child = aView->first_child) ){
		while ( child ) {
			BView*		view;
			if ( (view = findView( child, token )) )
				return view;
			child 		= child->next_sibling; 
		}
	}

	return NULL;
}

//------------------------------------------------------------------------------

BView* BWindow::findView(BView* aView, const char* viewName) const{

	if ( strcmp( viewName, aView->Name() ) == 0)
		return aView;

	BView			*child;
	if ( (child = aView->first_child) ){
		while ( child ) {
			BView*		view;
			if ( (view = findView( child, viewName )) )
				return view;
			child 		= child->next_sibling; 
		}
	}

	return NULL;
}

//------------------------------------------------------------------------------

BView* BWindow::findView(BView* aView, BPoint point) const{

	if ( aView->Bounds().Contains(point) &&
		 !aView->first_child )
		return aView;

	BView			*child;
	if ( (child = aView->first_child) ){
		while ( child ) {
			BView*		view;
			if ( (view = findView( child, point )) )
				return view;
			child 		= child->next_sibling; 
		}
	}

	return NULL;
}

//------------------------------------------------------------------------------

BView* BWindow::findNextView( BView *focus, uint32 flags){
	bool		found;
	found		= false;

	BView		*nextFocus;
	nextFocus	= focus;

		/*	Ufff... this toked me some time... this is the best form I've reached.
				This algorithm searches the tree for BViews that accept focus.
		*/
	while (!found){
		if (nextFocus->first_child)
			nextFocus		= nextFocus->first_child;
		else	
			if (nextFocus->next_sibling)
				nextFocus		= nextFocus->next_sibling;
			else{
				while( !nextFocus->next_sibling && nextFocus->parent ){
					nextFocus		= nextFocus->parent;
				}

				if (nextFocus == top_view)
					nextFocus		= nextFocus->first_child;
				else
					nextFocus		= nextFocus->next_sibling;
			}

		if (nextFocus->Flags() & flags)
			found = true;

			/*	It means that the hole tree has been searched and there is no
				view with B_NAVIGABLE_JUMP flag set!
			*/
		if (nextFocus == focus)
			return NULL;
	}

	return nextFocus;
}

//------------------------------------------------------------------------------

BView* BWindow::findPrevView( BView *focus, uint32 flags){
	bool		found;
	found		= false;

	BView		*prevFocus;
	prevFocus	= focus;

	BView		*aView;

	while (!found){
		if ( (aView = findLastChild(prevFocus)) )
			prevFocus		= aView;
		else	
			if (prevFocus->prev_sibling)
				prevFocus		= prevFocus->prev_sibling;
			else{
				while( !prevFocus->prev_sibling && prevFocus->parent ){
					prevFocus		= prevFocus->parent;
				}

				if (prevFocus == top_view)
					prevFocus		= findLastChild( prevFocus );
				else
					prevFocus		= prevFocus->prev_sibling;
			}

		if (prevFocus->Flags() & flags)
			found = true;


			/*	It means that the hole tree has been searched and there is no
				view with B_NAVIGABLE_JUMP flag set!
			*/
		if (prevFocus == focus)
			return NULL;
	}

	return prevFocus;
}

//------------------------------------------------------------------------------

BView* BWindow::findLastChild(BView *parent){
	BView		*aView;
	if ( (aView = parent->first_child) ){
		while (aView->next_sibling)
			aView		= aView->next_sibling;

		return aView;
	}
	else
		return NULL;
}

//------------------------------------------------------------------------------

void BWindow::drawAllViews(BView* aView){

	BMessageQueue	*queue;
	BMessage		*msg;

	queue			= MessageQueue();

		// process all update BMessages from message queue
	queue->Lock();
	while ( (msg = queue->FindMessage( (uint32)_UPDATE_ )) )
	{
		Lock();
		DispatchMessage( msg, this );
		Unlock();

		queue->RemoveMessage( msg );
	}
	queue->Unlock();

		// we'll send a message to app_server, tell him that we want all our views updated
	Lock();
	session->WriteInt32( AS_UPDATE_IF_NEEDED );
	session->Sync();
	Unlock();

// TODO: update!!!!!!!!!!!!!!!!!!!
		// process all update messages from receive port queue
	bool			over = false;
	while (!over)
	{
		msg			= MessageFromPort(0);
		if (msg){
			switch (msg->what){
			
			case _ALL_UPDATED_:{
				over		= true;
				}break;

			case _UPDATE_:{
				Lock();
				DispatchMessage( msg, this );
				Unlock();
				}break;

			default:{
				queue->Lock();
				queue->AddMessage(msg);
				queue->Unlock();
				}break;
			}
		}
	}
}

//------------------------------------------------------------------------------

void BWindow::drawView(BView* aView, BRect area){

/* TODO: Drawing during an Update
			These settings are temporary. When the update is over, all graphics
			  parameters are reset to their initial values
*/
	aView->Draw( area );

	BView			*child;
	if ( (child = aView->first_child) ){
		while ( child ) {
			if ( area.Intersects( child->Frame() ) ){
				BRect			newArea;

				newArea			= area & child->Frame();
				child->ConvertFromParent( &newArea );
				child->Invalidate( newArea );
			}
			child 		= child->next_sibling; 
		}
	}
}

//------------------------------------------------------------------------------

void BWindow::SetIsFilePanel(bool yes){

// TODO: is this not enough?
	fIsFilePanel	= yes;
}

//------------------------------------------------------------------------------

bool BWindow::IsFilePanel() const{
	return fIsFilePanel;
}


//------------------------------------------------------------------------------
// Virtual reserved Functions

void BWindow::_ReservedWindow1() { }
//------------------------------------------------------------------------------
void BWindow::_ReservedWindow2() { }
//------------------------------------------------------------------------------
void BWindow::_ReservedWindow3() { }
//------------------------------------------------------------------------------
void BWindow::_ReservedWindow4() { }
//------------------------------------------------------------------------------
void BWindow::_ReservedWindow5() { }
//------------------------------------------------------------------------------
void BWindow::_ReservedWindow6() { }
//------------------------------------------------------------------------------
void BWindow::_ReservedWindow7() { }
//------------------------------------------------------------------------------
void BWindow::_ReservedWindow8() { }

void BWindow::PrintToStream() const{
	printf("BWindow '%s' data:\
		Title			= %s\
		Token			= %ld\
		InTransaction 	= %s\
		Active 			= %s\
		fShowLevel		= %d\
		Flags			= %lx\
		send_port		= %ld\
		receive_port	= %ld\
		top_view name	= %s\
		focus view name	= %s\
		lastMouseMoved	= %s\
		session			= %s\
		KeyMenuBar name	= %s\
		DefaultButton	= %s\
		# of shortcuts	= %ld",
		Name(),
		fTitle!=NULL? fTitle:"NULL",
		_get_object_token_(this),		
		fInTransaction==true? "yes":"no",
		fActive==true? "yes":"no",
		fShowLevel,
		fFlags,
		send_port,
		receive_port,
		top_view!=NULL? top_view->Name():"NULL",
		fFocus!=NULL? fFocus->Name():"NULL",
		fLastMouseMovedView!=NULL? fLastMouseMovedView->Name():"NULL",
		session!=NULL? "In place":"NULL",
		fKeyMenuBar!=NULL? fKeyMenuBar->Name():"NULL",
		fDefaultButton!=NULL? fDefaultButton->Name():"NULL",
		accelList.CountItems());
/*
	for( int32 i=0; i<accelList.CountItems(); i++){
		_BCmdKey	*key = (_BCmdKey*)accelList.ItemAt(i);
		printf("\tShortCut %ld: char %s\n\t\t message: \n", i, (key->key > 127)?"ASCII":"UNICODE");
		key->message->PrintToStream();
	}
*/	
	printf("\
		topViewToken	= %ld\
		pluseEnabled	= %s\
		isFilePanel		= %s\
		MaskActivated	= %s\
		pulseRate		= %lld\
		waitingForMenu	= %s\
		minimized		= %s\
		Menu semaphore	= %ld\
		maxZoomHeight	= %f\
		maxZoomWidth	= %f\
		minWindHeight	= %f\
		minWindWidth	= %f\
		maxWindHeight	= %f\
		maxWindWidth	= %f\
		frame			= ( %f, %f, %f, %f )\
		look			= %d\
		feel			= %d\
		lastViewToken	= %ld\
		pulseRUNNER		= %s\n",
		fTopViewToken,
		fPulseEnabled==true?"Yes":"No",
		fIsFilePanel==true?"Yes":"No",
		fMaskActivated==true?"Yes":"No",
		fPulseRate,
		fWaitingForMenu==true?"Yes":"No",
		fMinimized==true?"Yes":"No",
		fMenuSem,
		fMaxZoomHeight,
		fMaxZoomWidth,
		fMinWindHeight,
		fMinWindWidth,
		fMaxWindHeight,
		fMaxWindWidth,
		fFrame.left, fFrame.top, fFrame.right, fFrame.bottom, 
		(int16)fLook,
		(int16)fFeel,
		fLastViewToken,
		fPulseRunner!=NULL?"In place":"NULL");
}

/*
TODO list:

	*) take care of temporarely events mask!!!
	*) what's with this flag B_ASYNCHRONOUS_CONTROLS ?
	*) test arguments for SetWindowAligment
	*) call hook functions: MenusBeginning, MenusEnded. Add menu activation code.
	
	* add handlers for B_VIEW_MOVED/RESIZED in DispatchMessage()
	* modify _UPDATE_ handler in DispatchMessage()
*/

/*
 @log
	*modified ReadRawFromPort() and ConvertToMessage() methods to use BSession class.
	*modified/added B_VIEW_(MOVED/RESIZED) handlers in ConvertToMessage()/DispatchMessage()
*/
