xref: /haiku/src/kits/interface/Window.cpp (revision cd552c7a15cc10c36dae8d7439ba1d6c0bb168c5)
1 /*
2  * Copyright 2001-2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Adrian Oanca <adioanca@cotty.iren.ro>
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		Stephan Aßmus, <superstippi@gmx.de>
9  */
10 
11 
12 #include <Application.h>
13 #include <Autolock.h>
14 #include <Button.h>
15 #include <MenuBar.h>
16 #include <MenuItem.h>
17 #include <MessageQueue.h>
18 #include <MessageRunner.h>
19 #include <PropertyInfo.h>
20 #include <Roster.h>
21 #include <Screen.h>
22 #include <String.h>
23 #include <Window.h>
24 
25 #include <input_globals.h>
26 #include <AppMisc.h>
27 #include <ApplicationPrivate.h>
28 #include <InputServerTypes.h>
29 #include <MenuPrivate.h>
30 #include <MessagePrivate.h>
31 #include <PortLink.h>
32 #include <ServerProtocol.h>
33 #include <TokenSpace.h>
34 #include <tracker_private.h>
35 
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <math.h>
39 
40 
41 //#define DEBUG_WIN
42 #ifdef DEBUG_WIN
43 #	include <stdio.h>
44 #	define STRACE(x) printf x
45 #else
46 #	define STRACE(x) ;
47 #endif
48 
49 
50 struct BWindow::unpack_cookie {
51 	unpack_cookie();
52 
53 	BMessage*	message;
54 	int32		index;
55 	BHandler*	focus;
56 	int32		focus_token;
57 	int32		last_view_token;
58 	bool		found_focus;
59 	bool		tokens_scanned;
60 };
61 
62 class BWindow::Shortcut {
63 	public:
64 		Shortcut(uint32 key, uint32 modifiers, BMenuItem* item);
65 		Shortcut(uint32 key, uint32 modifiers, BMessage* message, BHandler* target);
66 		~Shortcut();
67 
68 		bool Matches(uint32 key, uint32 modifiers) const;
69 
70 		BMenuItem* MenuItem() const { return fMenuItem; }
71 		BMessage* Message() const { return fMessage; }
72 		BHandler* Target() const { return fTarget; }
73 
74 		static uint32 AllowedModifiers();
75 		static uint32 PrepareKey(uint32 key);
76 		static uint32 PrepareModifiers(uint32 modifiers);
77 
78 	private:
79 		uint32		fKey;
80 		uint32		fModifiers;
81 		BMenuItem*	fMenuItem;
82 		BMessage*	fMessage;
83 		BHandler*	fTarget;
84 };
85 
86 
87 using BPrivate::gDefaultTokens;
88 
89 static property_info sWindowPropInfo[] = {
90 	{
91 		"Feel", { B_GET_PROPERTY, B_SET_PROPERTY },
92 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
93 	},
94 
95 	{
96 		"Flags", { B_GET_PROPERTY, B_SET_PROPERTY },
97 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
98 	},
99 
100 	{
101 		"Frame", { B_GET_PROPERTY, B_SET_PROPERTY },
102 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_RECT_TYPE }
103 	},
104 
105 	{
106 		"Hidden", { B_GET_PROPERTY, B_SET_PROPERTY },
107 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE }
108 	},
109 
110 	{
111 		"Look", { B_GET_PROPERTY, B_SET_PROPERTY },
112 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
113 	},
114 
115 	{
116 		"Title", { B_GET_PROPERTY, B_SET_PROPERTY },
117 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_STRING_TYPE }
118 	},
119 
120 	{
121 		"Workspaces", { B_GET_PROPERTY, B_SET_PROPERTY },
122 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE}
123 	},
124 
125 	{
126 		"MenuBar", {},
127 		{ B_DIRECT_SPECIFIER }, NULL, 0, {}
128 	},
129 
130 	{
131 		"View", {}, {}, NULL, 0, {}
132 	},
133 
134 	{
135 		"Minimize", { B_GET_PROPERTY, B_SET_PROPERTY },
136 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE }
137 	},
138 
139 	{}
140 };
141 
142 
143 void
144 _set_menu_sem_(BWindow *window, sem_id sem)
145 {
146 	if (window != NULL)
147 		window->fMenuSem = sem;
148 }
149 
150 
151 //	#pragma mark -
152 
153 
154 BWindow::unpack_cookie::unpack_cookie()
155 	:
156 	message((BMessage*)~0UL),
157 		// message == NULL is our exit condition
158 	index(0),
159 	focus_token(B_NULL_TOKEN),
160 	last_view_token(B_NULL_TOKEN),
161 	found_focus(false),
162 	tokens_scanned(false)
163 {
164 }
165 
166 
167 //	#pragma mark -
168 
169 
170 BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item)
171 	:
172 	fKey(PrepareKey(key)),
173 	fModifiers(PrepareModifiers(modifiers)),
174 	fMenuItem(item),
175 	fMessage(NULL),
176 	fTarget(NULL)
177 {
178 }
179 
180 
181 BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMessage* message,
182 	BHandler* target)
183 	:
184 	fKey(PrepareKey(key)),
185 	fModifiers(PrepareModifiers(modifiers)),
186 	fMenuItem(NULL),
187 	fMessage(message),
188 	fTarget(target)
189 {
190 }
191 
192 
193 BWindow::Shortcut::~Shortcut()
194 {
195 	// we own the message, if any
196 	delete fMessage;
197 }
198 
199 
200 bool
201 BWindow::Shortcut::Matches(uint32 key, uint32 modifiers) const
202 {
203 	return fKey == key && fModifiers == modifiers;
204 }
205 
206 
207 /*static*/
208 uint32
209 BWindow::Shortcut::AllowedModifiers()
210 {
211 	return B_COMMAND_KEY | B_OPTION_KEY | B_SHIFT_KEY
212 		| B_CONTROL_KEY | B_MENU_KEY;
213 }
214 
215 
216 /*static*/
217 uint32
218 BWindow::Shortcut::PrepareModifiers(uint32 modifiers)
219 {
220 	return (modifiers & AllowedModifiers()) | B_COMMAND_KEY;
221 }
222 
223 
224 /*static*/
225 uint32
226 BWindow::Shortcut::PrepareKey(uint32 key)
227 {
228 	return tolower(key);
229 		// TODO: support unicode and/or more intelligent key mapping
230 }
231 
232 
233 //	#pragma mark -
234 
235 
236 BWindow::BWindow(BRect frame, const char* title, window_type type,
237 	uint32 flags, uint32 workspace)
238 	: BLooper(title)
239 {
240 	window_look look;
241 	window_feel feel;
242 	_DecomposeType(type, &look, &feel);
243 
244 	_InitData(frame, title, look, feel, flags, workspace);
245 }
246 
247 
248 BWindow::BWindow(BRect frame, const char* title, window_look look, window_feel feel,
249 	uint32 flags, uint32 workspace)
250 	: BLooper(title)
251 {
252 	_InitData(frame, title, look, feel, flags, workspace);
253 }
254 
255 
256 BWindow::BWindow(BMessage* data)
257 	: BLooper(data)
258 {
259 	data->FindRect("_frame", &fFrame);
260 
261 	const char *title;
262 	data->FindString("_title", &title);
263 
264 	window_look look;
265 	data->FindInt32("_wlook", (int32 *)&look);
266 
267 	window_feel feel;
268 	data->FindInt32("_wfeel", (int32 *)&feel);
269 
270 	if (data->FindInt32("_flags", (int32 *)&fFlags) != B_OK)
271 		fFlags = 0;
272 
273 	uint32 workspaces;
274 	data->FindInt32("_wspace", (int32 *)&workspaces);
275 
276 	uint32 type;
277 	if (data->FindInt32("_type", (int32*)&type) == B_OK)
278 		_DecomposeType((window_type)type, &fLook, &fFeel);
279 
280 		// connect to app_server and initialize data
281 	_InitData(fFrame, title, look, feel, fFlags, workspaces);
282 
283 	if (data->FindFloat("_zoom", 0, &fMaxZoomWidth) == B_OK
284 		&& data->FindFloat("_zoom", 1, &fMaxZoomHeight) == B_OK)
285 		SetZoomLimits(fMaxZoomWidth, fMaxZoomHeight);
286 
287 	if (data->FindFloat("_sizel", 0, &fMinWidth) == B_OK
288 		&& data->FindFloat("_sizel", 1, &fMinHeight) == B_OK
289 		&& data->FindFloat("_sizel", 2, &fMaxWidth) == B_OK
290 		&& data->FindFloat("_sizel", 3, &fMaxHeight) == B_OK)
291 		SetSizeLimits(fMinWidth, fMaxWidth,
292 			fMinHeight, fMaxHeight);
293 
294 	if (data->FindInt64("_pulse", &fPulseRate) == B_OK)
295 		SetPulseRate(fPulseRate);
296 
297 	BMessage msg;
298 	int32 i = 0;
299 	while (data->FindMessage("_views", i++, &msg) == B_OK) {
300 		BArchivable *obj = instantiate_object(&msg);
301 		BView *child = dynamic_cast<BView *>(obj);
302 		if (child)
303 			AddChild(child);
304 	}
305 }
306 
307 
308 BWindow::BWindow(BRect frame, int32 bitmapToken)
309 	: BLooper("offscreen bitmap")
310 {
311 	// TODO: Implement for real
312 	_DecomposeType(B_UNTYPED_WINDOW, &fLook, &fFeel);
313 	_InitData(frame, "offscreen", fLook, fFeel, 0, 0, bitmapToken);
314 }
315 
316 
317 BWindow::~BWindow()
318 {
319 	Lock();
320 
321 	if (BMenu *menu = dynamic_cast<BMenu *>(fFocus)) {
322 		menu->QuitTracking();
323 	}
324 
325 	// Wait if a menu is still tracking
326 	if (fMenuSem > 0) {
327 		while (acquire_sem(fMenuSem) == B_INTERRUPTED)
328 			;
329 	}
330 
331 	fTopView->RemoveSelf();
332 	delete fTopView;
333 
334 	// remove all remaining shortcuts
335 	int32 shortCutCount = fShortcuts.CountItems();
336 	for (int32 i = 0; i < shortCutCount; i++) {
337 		delete (Shortcut*)fShortcuts.ItemAtFast(i);
338 	}
339 
340 	// TODO: release other dynamically-allocated objects
341 	free(fTitle);
342 
343 	// disable pulsing
344 	SetPulseRate(0);
345 
346 	// tell app_server about our demise
347 	fLink->StartMessage(AS_DELETE_WINDOW);
348 	// sync with the server so that for example
349 	// a BBitmap can be sure that there are no
350 	// more pending messages that are executed
351 	// after the bitmap is deleted (which uses
352 	// a different link and server side thread)
353 	int32 code;
354 	fLink->FlushWithReply(code);
355 
356 	// the sender port belongs to the app_server
357 	delete_port(fLink->ReceiverPort());
358 	delete fLink;
359 }
360 
361 
362 BArchivable *
363 BWindow::Instantiate(BMessage *data)
364 {
365 	if (!validate_instantiation(data , "BWindow"))
366 		return NULL;
367 
368 	return new BWindow(data);
369 }
370 
371 
372 status_t
373 BWindow::Archive(BMessage* data, bool deep) const
374 {
375 	status_t ret = BLooper::Archive(data, deep);
376 
377 	if (ret == B_OK)
378 		ret = data->AddRect("_frame", fFrame);
379 	if (ret == B_OK)
380 		ret = data->AddString("_title", fTitle);
381 	if (ret == B_OK)
382 		ret = data->AddInt32("_wlook", fLook);
383 	if (ret == B_OK)
384 		ret = data->AddInt32("_wfeel", fFeel);
385 	if (ret == B_OK && fFlags != 0)
386 		ret = data->AddInt32("_flags", fFlags);
387 	if (ret == B_OK)
388 		ret = data->AddInt32("_wspace", (uint32)Workspaces());
389 
390 	if (ret == B_OK && !_ComposeType(fLook, fFeel))
391 		ret = data->AddInt32("_type", (uint32)Type());
392 
393 	if (fMaxZoomWidth != 32768.0 || fMaxZoomHeight != 32768.0) {
394 		if (ret == B_OK)
395 			ret = data->AddFloat("_zoom", fMaxZoomWidth);
396 		if (ret == B_OK)
397 			ret = data->AddFloat("_zoom", fMaxZoomHeight);
398 	}
399 
400 	if (fMinWidth != 0.0 || fMinHeight != 0.0
401 		|| fMaxWidth != 32768.0 || fMaxHeight != 32768.0) {
402 		if (ret == B_OK)
403 			ret = data->AddFloat("_sizel", fMinWidth);
404 		if (ret == B_OK)
405 			ret = data->AddFloat("_sizel", fMinHeight);
406 		if (ret == B_OK)
407 			ret = data->AddFloat("_sizel", fMaxWidth);
408 		if (ret == B_OK)
409 			ret = data->AddFloat("_sizel", fMaxHeight);
410 	}
411 
412 	if (ret == B_OK && fPulseRate != 500000)
413 		data->AddInt64("_pulse", fPulseRate);
414 
415 	if (ret == B_OK && deep) {
416 		int32 noOfViews = CountChildren();
417 		for (int32 i = 0; i < noOfViews; i++){
418 			BMessage childArchive;
419 			ret = ChildAt(i)->Archive(&childArchive, true);
420 			if (ret == B_OK)
421 				ret = data->AddMessage("_views", &childArchive);
422 			if (ret != B_OK)
423 				break;
424 		}
425 	}
426 
427 	if (ret == B_OK)
428 		ret = data->AddString("class", "BWindow");
429 
430 	return ret;
431 }
432 
433 
434 void
435 BWindow::Quit()
436 {
437 	if (!IsLocked()) {
438 		const char *name = Name();
439 		if (!name)
440 			name = "no-name";
441 
442 		printf("ERROR - you must Lock a looper before calling Quit(), "
443 			   "team=%ld, looper=%s\n", Team(), name);
444 	}
445 
446 	// Try to lock
447 	if (!Lock()){
448 		// We're toast already
449 		return;
450 	}
451 
452 	while (!IsHidden())	{
453 		Hide();
454 	}
455 
456 	if (fFlags & B_QUIT_ON_WINDOW_CLOSE)
457 		be_app->PostMessage(B_QUIT_REQUESTED);
458 
459 	BLooper::Quit();
460 }
461 
462 
463 void
464 BWindow::AddChild(BView *child, BView *before)
465 {
466 	BAutolock locker(this);
467 	fTopView->AddChild(child, before);
468 }
469 
470 
471 bool
472 BWindow::RemoveChild(BView *child)
473 {
474 	BAutolock locker(this);
475 	return fTopView->RemoveChild(child);
476 }
477 
478 
479 int32
480 BWindow::CountChildren() const
481 {
482 	BAutolock _(const_cast<BWindow*>(this));
483 	return fTopView->CountChildren();
484 }
485 
486 
487 BView *
488 BWindow::ChildAt(int32 index) const
489 {
490 	BAutolock _(const_cast<BWindow*>(this));
491 	return fTopView->ChildAt(index);
492 }
493 
494 
495 void
496 BWindow::Minimize(bool minimize)
497 {
498 	if (IsModal() || IsFloating() || fMinimized == minimize || !Lock())
499 		return;
500 
501 	fMinimized = minimize;
502 
503 	fLink->StartMessage(AS_MINIMIZE_WINDOW);
504 	fLink->Attach<bool>(minimize);
505 	fLink->Attach<int32>(fShowLevel);
506 	fLink->Flush();
507 
508 	Unlock();
509 }
510 
511 
512 status_t
513 BWindow::SendBehind(const BWindow *window)
514 {
515 	if (!window || !Lock())
516 		return B_ERROR;
517 
518 	fLink->StartMessage(AS_SEND_BEHIND);
519 	fLink->Attach<int32>(_get_object_token_(window));
520 	fLink->Attach<team_id>(Team());
521 
522 	status_t status = B_ERROR;
523 	fLink->FlushWithReply(status);
524 
525 	Unlock();
526 
527 	return status;
528 }
529 
530 
531 void
532 BWindow::Flush() const
533 {
534 	if (const_cast<BWindow *>(this)->Lock()) {
535 		fLink->Flush();
536 		const_cast<BWindow *>(this)->Unlock();
537 	}
538 }
539 
540 
541 void
542 BWindow::Sync() const
543 {
544 	if (!const_cast<BWindow*>(this)->Lock())
545 		return;
546 
547 	fLink->StartMessage(AS_SYNC);
548 
549 	// waiting for the reply is the actual syncing
550 	int32 code;
551 	fLink->FlushWithReply(code);
552 
553 	const_cast<BWindow*>(this)->Unlock();
554 }
555 
556 
557 void
558 BWindow::DisableUpdates()
559 {
560 	if (Lock()) {
561 		fLink->StartMessage(AS_DISABLE_UPDATES);
562 		fLink->Flush();
563 		Unlock();
564 	}
565 }
566 
567 
568 void
569 BWindow::EnableUpdates()
570 {
571 	if (Lock()) {
572 		fLink->StartMessage(AS_ENABLE_UPDATES);
573 		fLink->Flush();
574 		Unlock();
575 	}
576 }
577 
578 
579 void
580 BWindow::BeginViewTransaction()
581 {
582 	if (Lock()) {
583 		if (fInTransaction) {
584 			Unlock();
585 			return;
586 		}
587 		fInTransaction = true;
588 
589 		Unlock();
590 	}
591 }
592 
593 
594 void
595 BWindow::EndViewTransaction()
596 {
597 	if (Lock()) {
598 		if (!fInTransaction) {
599 			Unlock();
600 			return;
601 		}
602 		fLink->Flush();
603 		fInTransaction = false;
604 
605 		Unlock();
606 	}
607 }
608 
609 
610 bool
611 BWindow::IsFront() const
612 {
613 	if (IsActive())
614 		return true;
615 
616 	if (IsModal())
617 		return true;
618 
619 	return false;
620 }
621 
622 
623 void
624 BWindow::MessageReceived(BMessage *msg)
625 {
626 	if (!msg->HasSpecifiers()) {
627 		if (msg->what == B_KEY_DOWN)
628 			_KeyboardNavigation();
629 
630 		return BLooper::MessageReceived(msg);
631 	}
632 
633 	BMessage replyMsg(B_REPLY);
634 	bool handled = false;
635 
636 	switch (msg->what) {
637 		case B_GET_PROPERTY:
638 		case B_SET_PROPERTY: {
639 			BMessage specifier;
640 			int32 what;
641 			const char *prop;
642 			int32 index;
643 
644 			if (msg->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK)
645 				break;
646 
647 			if (!strcmp(prop, "Feel")) {
648 				if (msg->what == B_GET_PROPERTY) {
649 					replyMsg.AddInt32("result", (uint32)Feel());
650 					handled = true;
651 				} else {
652 					uint32 newFeel;
653 					if (msg->FindInt32("data", (int32 *)&newFeel) == B_OK) {
654 						SetFeel((window_feel)newFeel);
655 						handled = true;
656 					}
657 				}
658 			} else if (!strcmp(prop, "Flags")) {
659 				if (msg->what == B_GET_PROPERTY) {
660 					replyMsg.AddInt32("result", Flags());
661 					handled = true;
662 				} else {
663 					uint32 newFlags;
664 					if (msg->FindInt32("data", (int32 *)&newFlags) == B_OK) {
665 						SetFlags(newFlags);
666 						handled = true;
667 					}
668 				}
669 			} else if (!strcmp(prop, "Frame")) {
670 				if (msg->what == B_GET_PROPERTY) {
671 					replyMsg.AddRect("result", Frame());
672 					handled = true;
673 				} else {
674 					BRect newFrame;
675 					if (msg->FindRect("data", &newFrame) == B_OK) {
676 						MoveTo(newFrame.LeftTop());
677 						ResizeTo(newFrame.Width(), newFrame.Height());
678 						handled = true;
679 					}
680 				}
681 			} else if (!strcmp(prop, "Hidden")) {
682 				if (msg->what == B_GET_PROPERTY) {
683 					replyMsg.AddBool("result", IsHidden());
684 					handled = true;
685 				} else {
686 					bool hide;
687 					if (msg->FindBool("data", &hide) == B_OK) {
688 						if (hide) {
689 							if (!IsHidden())
690 								Hide();
691 						} else if (IsHidden())
692 							Show();
693 
694 						handled = true;
695 					}
696 				}
697 			} else if (!strcmp(prop, "Look")) {
698 				if (msg->what == B_GET_PROPERTY) {
699 					replyMsg.AddInt32("result", (uint32)Look());
700 					handled = true;
701 				} else {
702 					uint32 newLook;
703 					if (msg->FindInt32("data", (int32 *)&newLook) == B_OK) {
704 						SetLook((window_look)newLook);
705 						handled = true;
706 					}
707 				}
708 			} else if (!strcmp(prop, "Title")) {
709 				if (msg->what == B_GET_PROPERTY) {
710 					replyMsg.AddString("result", Title());
711 					handled = true;
712 				} else {
713 					const char *newTitle = NULL;
714 					if (msg->FindString("data", &newTitle) == B_OK) {
715 						SetTitle(newTitle);
716 						handled = true;
717 					}
718 				}
719 			} else if (!strcmp(prop, "Workspaces")) {
720 				if (msg->what == B_GET_PROPERTY) {
721 					replyMsg.AddInt32( "result", Workspaces());
722 					handled = true;
723 				} else {
724 					uint32 newWorkspaces;
725 					if (msg->FindInt32("data", (int32 *)&newWorkspaces) == B_OK) {
726 						SetWorkspaces(newWorkspaces);
727 						handled = true;
728 					}
729 				}
730 			} else if (!strcmp(prop, "Minimize")) {
731 				if (msg->what == B_GET_PROPERTY) {
732 					replyMsg.AddBool("result", IsMinimized());
733 					handled = true;
734 				} else {
735 					bool minimize;
736 					if (msg->FindBool("data", &minimize) == B_OK) {
737 						Minimize(minimize);
738 						handled = true;
739 					}
740 				}
741 			}
742 			break;
743 		}
744 	}
745 
746 	if (handled) {
747 		if (msg->what == B_SET_PROPERTY)
748 			replyMsg.AddInt32("error", B_OK);
749 	} else {
750 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
751 		replyMsg.AddInt32("error", B_BAD_SCRIPT_SYNTAX);
752 		replyMsg.AddString("message", "Didn't understand the specifier(s)");
753 	}
754 	msg->SendReply(&replyMsg);
755 }
756 
757 
758 void
759 BWindow::DispatchMessage(BMessage *msg, BHandler *target)
760 {
761 	if (!msg)
762 		return;
763 
764 	switch (msg->what) {
765 		case B_ZOOM:
766 			Zoom();
767 			break;
768 
769 		case B_MINIMIZE:
770 		{
771 			bool minimize;
772 			if (msg->FindBool("minimize", &minimize) == B_OK)
773 				Minimize(minimize);
774 			break;
775 		}
776 
777 		case B_WINDOW_RESIZED:
778 		{
779 			int32 width, height;
780 			if (msg->FindInt32("width", &width) == B_OK
781 				&& msg->FindInt32("height", &height) == B_OK) {
782 				// combine with pending resize notifications
783 				BMessage* pendingMessage;
784 				while ((pendingMessage = MessageQueue()->FindMessage(B_WINDOW_RESIZED, 0))) {
785 					if (pendingMessage != msg) {
786 						int32 nextWidth;
787 						if (pendingMessage->FindInt32("width", &nextWidth) == B_OK)
788 							width = nextWidth;
789 
790 						int32 nextHeight;
791 						if (pendingMessage->FindInt32("height", &nextHeight) == B_OK)
792 							height = nextHeight;
793 
794 						MessageQueue()->RemoveMessage(pendingMessage);
795 						// TODO: the BeBook says that MessageQueue::RemoveMessage() deletes the message!
796 						delete pendingMessage;
797 						// this deletes the first *additional* message
798 						// fCurrentMessage is safe
799 					} else {
800 						MessageQueue()->RemoveMessage(pendingMessage);
801 					}
802 				}
803 				if (width != fFrame.Width() || height != fFrame.Height()) {
804 					// NOTE: we might have already handled the resize
805 					// in an _UPDATE_ message
806 					fFrame.right = fFrame.left + width;
807 					fFrame.bottom = fFrame.top + height;
808 
809 					_AdoptResize();
810 //					FrameResized(width, height);
811 				}
812 // call hook function anyways
813 // TODO: When a window is resized programmatically,
814 // it receives this message, and maybe it is wise to
815 // keep the asynchronous nature of this process to
816 // not risk breaking any apps.
817 FrameResized(width, height);
818 			}
819 			break;
820 		}
821 
822 		case B_WINDOW_MOVED:
823 		{
824 			BPoint origin;
825 			if (msg->FindPoint("where", &origin) == B_OK) {
826 				if (fFrame.LeftTop() != origin) {
827 					// NOTE: we might have already handled the move
828 					// in an _UPDATE_ message
829 					fFrame.OffsetTo(origin);
830 
831 //					FrameMoved(origin);
832 				}
833 // call hook function anyways
834 // TODO: When a window is moved programmatically,
835 // it receives this message, and maybe it is wise to
836 // keep the asynchronous nature of this process to
837 // not risk breaking any apps.
838 FrameMoved(origin);
839 			}
840 			break;
841 		}
842 
843 		case B_WINDOW_ACTIVATED:
844 			if (target == this) {
845 				bool active;
846 				if (msg->FindBool("active", &active) == B_OK
847 					&& active != fActive) {
848 					fActive = active;
849 					WindowActivated(active);
850 
851 					// call hook function 'WindowActivated(bool)' for all
852 					// views attached to this window.
853 					fTopView->_Activate(active);
854 				}
855 			} else
856 				target->MessageReceived(msg);
857 			break;
858 
859 		case B_SCREEN_CHANGED:
860 			if (target == this) {
861 				BRect frame;
862 				uint32 mode;
863 				if (msg->FindRect("frame", &frame) == B_OK
864 					&& msg->FindInt32("mode", (int32 *)&mode) == B_OK)
865 					ScreenChanged(frame, (color_space)mode);
866 			} else
867 				target->MessageReceived(msg);
868 			break;
869 
870 		case B_WORKSPACE_ACTIVATED:
871 			if (target == this) {
872 				uint32 workspace;
873 				bool active;
874 				if (msg->FindInt32("workspace", (int32 *)&workspace) == B_OK
875 					&& msg->FindBool("active", &active) == B_OK)
876 					WorkspaceActivated(workspace, active);
877 			} else
878 				target->MessageReceived(msg);
879 			break;
880 
881 		case B_WORKSPACES_CHANGED:
882 			if (target == this) {
883 				uint32 oldWorkspace, newWorkspace;
884 				if (msg->FindInt32("old", (int32 *)&oldWorkspace) == B_OK
885 					&& msg->FindInt32("new", (int32 *)&newWorkspace) == B_OK)
886 					WorkspacesChanged(oldWorkspace, newWorkspace);
887 			} else
888 				target->MessageReceived(msg);
889 			break;
890 
891 		case B_KEY_DOWN:
892 		{
893 			uint32 modifiers;
894 			int32 rawChar;
895 			const char *string = NULL;
896 			msg->FindInt32("modifiers", (int32*)&modifiers);
897 			msg->FindInt32("raw_char", &rawChar);
898 			msg->FindString("bytes", &string);
899 
900 			// TODO: cannot use "string" here if we support having different
901 			//	font encoding per view (it's supposed to be converted by
902 			//	_HandleKeyDown() one day)
903 			if (!_HandleKeyDown(string[0], (uint32)modifiers)) {
904 				if (BView* view = dynamic_cast<BView*>(target))
905 					view->KeyDown(string, strlen(string));
906 				else
907 					target->MessageReceived(msg);
908 			}
909 			break;
910 		}
911 
912 		case B_KEY_UP:
913 		{
914 			const char *string = NULL;
915 			msg->FindString("bytes", &string);
916 
917 			// TODO: same as above
918 			if (BView* view = dynamic_cast<BView*>(target))
919 				view->KeyUp(string, strlen(string));
920 			else
921 				target->MessageReceived(msg);
922 			break;
923 		}
924 
925 		case B_MOUSE_DOWN:
926 		{
927 			BView *view = dynamic_cast<BView *>(target);
928 
929 			// Close an eventually opened menu, unless the target is the menu itself
930 			BMenu *menu = dynamic_cast<BMenu *>(fFocus);
931 			if (menu != NULL && menu != view)
932 				menu->QuitTracking();
933 
934 			if (view != NULL) {
935 				BPoint where;
936 				msg->FindPoint("be:view_where", &where);
937 				view->MouseDown(where);
938 			} else
939 				target->MessageReceived(msg);
940 
941 			break;
942 		}
943 
944 		case B_MOUSE_UP:
945 		{
946 			if (BView *view = dynamic_cast<BView *>(target)) {
947 				BPoint where;
948 				msg->FindPoint("be:view_where", &where);
949 				view->MouseUp(where);
950 			} else
951 				target->MessageReceived(msg);
952 
953 			break;
954 		}
955 
956 		case B_MOUSE_MOVED:
957 		{
958 			if (BView *view = dynamic_cast<BView *>(target)) {
959 				BPoint where;
960 				uint32 buttons;
961 				uint32 transit;
962 				msg->FindPoint("be:view_where", &where);
963 				msg->FindInt32("buttons", (int32*)&buttons);
964 				msg->FindInt32("be:transit", (int32*)&transit);
965 
966 #if 0
967 				bigtime_t when;
968 				if (msg->FindInt64("when", (int64*)&when) < B_OK)
969 					printf("BWindow B_MOUSE_MOVED no when\n");
970 				else if (system_time() - when > 5000)
971 					printf("BWindow B_MOUSE_MOVED lagging behind\n");
972 #endif
973 
974 				BMessage* dragMessage = NULL;
975 				if (msg->HasMessage("be:drag_message")) {
976 					dragMessage = new BMessage();
977 					if (msg->FindMessage("be:drag_message", dragMessage) != B_OK) {
978 						delete dragMessage;
979 						dragMessage = NULL;
980 					}
981 				}
982 
983 				view->MouseMoved(where, transit, dragMessage);
984 				delete dragMessage;
985 			} else
986 				target->MessageReceived(msg);
987 
988 			break;
989 		}
990 
991 		case B_PULSE:
992 			if (target == this && fPulseRunner) {
993 				fTopView->_Pulse();
994 				fLink->Flush();
995 			} else
996 				target->MessageReceived(msg);
997 			break;
998 
999 		case _UPDATE_:
1000 		{
1001 //bigtime_t now = system_time();
1002 			STRACE(("info:BWindow handling _UPDATE_.\n"));
1003 			BRect updateRect;
1004 
1005 			fLink->StartMessage(AS_BEGIN_UPDATE);
1006 			fInTransaction = true;
1007 
1008 			int32 code;
1009 			if (fLink->FlushWithReply(code) == B_OK
1010 				&& code == B_OK) {
1011 				// read current window position and size first,
1012 				// the update rect is in screen coordinates...
1013 				// so we need to be up to date
1014 				BPoint origin;
1015 				fLink->Read<BPoint>(&origin);
1016 				float width;
1017 				float height;
1018 				fLink->Read<float>(&width);
1019 				fLink->Read<float>(&height);
1020 				if (origin != fFrame.LeftTop()) {
1021 					// TODO: remove code duplicatation with
1022 					// B_WINDOW_MOVED case...
1023 //printf("window position was not up to date\n");
1024 					fFrame.OffsetTo(origin);
1025 					FrameMoved(origin);
1026 				}
1027 				if (width != fFrame.Width() || height != fFrame.Height()) {
1028 					// TODO: remove code duplicatation with
1029 					// B_WINDOW_RESIZED case...
1030 //printf("window size was not up to date\n");
1031 					fFrame.right = fFrame.left + width;
1032 					fFrame.bottom = fFrame.top + height;
1033 
1034 					_AdoptResize();
1035 					FrameResized(width, height);
1036 				}
1037 
1038 				// read culmulated update rect (is in screen coords)
1039 				fLink->Read<BRect>(&updateRect);
1040 
1041 				// read tokens for views that need to be drawn
1042 				// NOTE: we need to read the tokens completely
1043 				// first, or other calls would likely mess up the
1044 				// data in the link.
1045 				BList tokens(20);
1046 				int32 token;
1047 				status_t error = fLink->Read<int32>(&token);
1048 				while (error >= B_OK && token != B_NULL_TOKEN) {
1049 					tokens.AddItem((void*)token);
1050 					error = fLink->Read<int32>(&token);
1051 				}
1052 				// draw
1053 				int32 count = tokens.CountItems();
1054 				for (int32 i = 0; i < count; i++) {
1055 					if (BView* view = _FindView((int32)tokens.ItemAtFast(i)))
1056 						view->_Draw(updateRect);
1057 					else
1058 						printf("_UPDATE_ - didn't find view by token: %ld\n", (int32)tokens.ItemAtFast(i));
1059 				}
1060 				// TODO: the tokens are actually hirachically sorted,
1061 				// so traversing the list in revers and calling
1062 				// child->DrawAfterChildren would actually work correctly,
1063 				// only that drawing outside a view is not yet supported
1064 				// in the app_server.
1065 			}
1066 
1067 			fLink->StartMessage(AS_END_UPDATE);
1068 			fLink->Flush();
1069 			fInTransaction = false;
1070 
1071 //printf("BWindow(%s) - UPDATE took %lld usecs\n", Title(), system_time() - now);
1072 			break;
1073 		}
1074 
1075 		case _MENUS_DONE_:
1076 			MenusEnded();
1077 			break;
1078 
1079 		// These two are obviously some kind of old scripting messages
1080 		// this is NOT an app_server message and we have to be cautious
1081 		case B_WINDOW_MOVE_BY:
1082 		{
1083 			BPoint offset;
1084 			if (msg->FindPoint("data", &offset) == B_OK)
1085 				MoveBy(offset.x, offset.y);
1086 			else
1087 				msg->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
1088 			break;
1089 		}
1090 
1091 		// this is NOT an app_server message and we have to be cautious
1092 		case B_WINDOW_MOVE_TO:
1093 		{
1094 			BPoint origin;
1095 			if (msg->FindPoint("data", &origin) == B_OK)
1096 				MoveTo(origin);
1097 			else
1098 				msg->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
1099 			break;
1100 		}
1101 		case _MESSAGE_DROPPED_:
1102 		{
1103 			if (fLastMouseMovedView)
1104 				target = fLastMouseMovedView;
1105 
1106 			uint32 originalWhat;
1107 			if (msg->FindInt32("_original_what", (int32*)&originalWhat) == B_OK) {
1108 				msg->what = originalWhat;
1109 				msg->RemoveName("_original_what");
1110 			}
1111 
1112 			BLooper::DispatchMessage(msg, target);
1113 			break;
1114 		}
1115 
1116 		default:
1117 			BLooper::DispatchMessage(msg, target);
1118 			break;
1119 	}
1120 }
1121 
1122 
1123 void
1124 BWindow::FrameMoved(BPoint new_position)
1125 {
1126 	// does nothing
1127 	// Hook function
1128 }
1129 
1130 
1131 void
1132 BWindow::FrameResized(float new_width, float new_height)
1133 {
1134 	// does nothing
1135 	// Hook function
1136 }
1137 
1138 
1139 void
1140 BWindow::WorkspacesChanged(uint32 old_ws, uint32 new_ws)
1141 {
1142 	// does nothing
1143 	// Hook function
1144 }
1145 
1146 
1147 void
1148 BWindow::WorkspaceActivated(int32 ws, bool state)
1149 {
1150 	// does nothing
1151 	// Hook function
1152 }
1153 
1154 
1155 void
1156 BWindow::MenusBeginning()
1157 {
1158 	// does nothing
1159 	// Hook function
1160 }
1161 
1162 
1163 void
1164 BWindow::MenusEnded()
1165 {
1166 	// does nothing
1167 	// Hook function
1168 }
1169 
1170 
1171 void
1172 BWindow::SetSizeLimits(float minWidth, float maxWidth,
1173 	float minHeight, float maxHeight)
1174 {
1175 	if (minWidth > maxWidth || minHeight > maxHeight)
1176 		return;
1177 
1178 	if (!Lock())
1179 		return;
1180 
1181 	fLink->StartMessage(AS_SET_SIZE_LIMITS);
1182 	fLink->Attach<float>(minWidth);
1183 	fLink->Attach<float>(maxWidth);
1184 	fLink->Attach<float>(minHeight);
1185 	fLink->Attach<float>(maxHeight);
1186 
1187 	int32 code;
1188 	if (fLink->FlushWithReply(code) == B_OK
1189 		&& code == B_OK) {
1190 		// read the values that were really enforced on
1191 		// the server side (the window frame could have
1192 		// been changed, too)
1193 		fLink->Read<BRect>(&fFrame);
1194 		fLink->Read<float>(&fMinWidth);
1195 		fLink->Read<float>(&fMaxWidth);
1196 		fLink->Read<float>(&fMinHeight);
1197 		fLink->Read<float>(&fMaxHeight);
1198 
1199 		_AdoptResize();
1200 			// TODO: the same has to be done for SetLook() (that can alter
1201 			//		the size limits, and hence, the size of the window
1202 	}
1203 	Unlock();
1204 }
1205 
1206 
1207 void
1208 BWindow::GetSizeLimits(float *minWidth, float *maxWidth,
1209 	float *minHeight, float *maxHeight)
1210 {
1211 	// TODO: What about locking?!?
1212 	*minHeight = fMinHeight;
1213 	*minWidth = fMinWidth;
1214 	*maxHeight = fMaxHeight;
1215 	*maxWidth = fMaxWidth;
1216 }
1217 
1218 
1219 status_t
1220 BWindow::SetDecoratorSettings(const BMessage& settings)
1221 {
1222 	// flatten the given settings into a buffer and send
1223 	// it to the app_server to apply the settings to the
1224 	// decorator
1225 
1226 	int32 size = settings.FlattenedSize();
1227 	char buffer[size];
1228 	status_t ret = settings.Flatten(buffer, size);
1229 
1230 	if (ret < B_OK)
1231 		return ret;
1232 
1233 	if (!Lock())
1234 		return B_ERROR;
1235 
1236 	ret = fLink->StartMessage(AS_SET_DECORATOR_SETTINGS);
1237 
1238 	if (ret == B_OK)
1239 		ret = fLink->Attach<int32>(size);
1240 
1241 	if (ret == B_OK)
1242 		ret = fLink->Attach(buffer, size);
1243 
1244 	if (ret == B_OK)
1245 		ret = fLink->Flush();
1246 
1247 	Unlock();
1248 
1249 	return ret;
1250 }
1251 
1252 
1253 status_t
1254 BWindow::GetDecoratorSettings(BMessage* settings) const
1255 {
1256 	// read a flattened settings message from the app_server
1257 	// and put it into settings
1258 
1259 	if (!const_cast<BWindow*>(this)->Lock())
1260 		return B_ERROR;
1261 
1262 	status_t ret = fLink->StartMessage(AS_GET_DECORATOR_SETTINGS);
1263 
1264 	if (ret == B_OK) {
1265 		int32 code;
1266 		ret = fLink->FlushWithReply(code);
1267 		if (ret == B_OK && code != B_OK)
1268 			ret = code;
1269 	}
1270 
1271 	if (ret == B_OK) {
1272 		int32 size;
1273 		ret = fLink->Read<int32>(&size);
1274 		if (ret == B_OK) {
1275 			char buffer[size];
1276 			ret = fLink->Read(buffer, size);
1277 			if (ret == B_OK) {
1278 				ret = settings->Unflatten(buffer);
1279 			}
1280 		}
1281 	}
1282 
1283 	const_cast<BWindow*>(this)->Unlock();
1284 
1285 	return ret;
1286 }
1287 
1288 
1289 void
1290 BWindow::SetZoomLimits(float maxWidth, float maxHeight)
1291 {
1292 	// TODO: What about locking?!?
1293 	if (maxWidth > fMaxWidth)
1294 		maxWidth = fMaxWidth;
1295 	else
1296 		fMaxZoomWidth = maxWidth;
1297 
1298 	if (maxHeight > fMaxHeight)
1299 		maxHeight = fMaxHeight;
1300 	else
1301 		fMaxZoomHeight = maxHeight;
1302 }
1303 
1304 
1305 void
1306 BWindow::Zoom(BPoint leftTop, float width, float height)
1307 {
1308 	// the default implementation of this hook function
1309 	// just does the obvious:
1310 	MoveTo(leftTop);
1311 	ResizeTo(width, height);
1312 }
1313 
1314 
1315 void
1316 BWindow::Zoom()
1317 {
1318 	// TODO: What about locking?!?
1319 	/*
1320 		from BeBook:
1321 		However, if the window's rectangle already matches these "zoom" dimensions
1322 		(give or take a few pixels), Zoom() passes the window's previous
1323 		("non-zoomed") size and location. (??????)
1324 	*/
1325 
1326 	/* From BeBook:
1327 		The dimensions that non-virtual Zoom() passes to hook Zoom() are deduced from
1328 		the smallest of three rectangles:
1329 	*/
1330 
1331 	// TODO: make more elaborate (figure out this window's
1332 	// tab height and border width... maybe ask app_server)
1333 	float borderWidth = 5.0;
1334 	float tabHeight = 26.0;
1335 
1336 	// 1) the rectangle defined by SetZoomLimits(),
1337 	float zoomedWidth = fMaxZoomWidth;
1338 	float zoomedHeight = fMaxZoomHeight;
1339 
1340 	// 2) the rectangle defined by SetSizeLimits()
1341 	if (fMaxWidth < zoomedWidth)
1342 		zoomedWidth = fMaxWidth;
1343 	if (fMaxHeight < zoomedHeight)
1344 		zoomedHeight = fMaxHeight;
1345 
1346 	// 3) the screen rectangle
1347 	BScreen screen(this);
1348 	float screenWidth = screen.Frame().Width() - 2 * borderWidth;
1349 	float screenHeight = screen.Frame().Height() - (borderWidth + tabHeight);
1350 	if (screenWidth < zoomedWidth)
1351 		zoomedWidth = screenWidth;
1352 	if (screenHeight < zoomedHeight)
1353 		zoomedHeight = screenHeight;
1354 
1355 	BPoint zoomedLeftTop = screen.Frame().LeftTop() + BPoint(borderWidth, tabHeight);
1356 
1357 	// UN-ZOOM:
1358 	if (fPreviousFrame.IsValid()
1359 		// NOTE: don't check for fFrame.LeftTop() == zoomedLeftTop
1360 		// -> makes it easier on the user to get a window back into place
1361 		&& fFrame.Width() == zoomedWidth
1362 		&& fFrame.Height() == zoomedHeight) {
1363 		// already zoomed!
1364 		Zoom(fPreviousFrame.LeftTop(), fPreviousFrame.Width(), fPreviousFrame.Height());
1365 		return;
1366 	}
1367 
1368 	// ZOOM:
1369 
1370 	// remember fFrame for later "unzooming"
1371 	fPreviousFrame = fFrame;
1372 
1373 	Zoom(zoomedLeftTop, zoomedWidth, zoomedHeight);
1374 }
1375 
1376 
1377 void
1378 BWindow::ScreenChanged(BRect screen_size, color_space depth)
1379 {
1380 	// Hook function
1381 	// does nothing
1382 }
1383 
1384 
1385 void
1386 BWindow::SetPulseRate(bigtime_t rate)
1387 {
1388 	// TODO: What about locking?!?
1389 	if (rate < 0 || rate == fPulseRate)
1390 		return;
1391 
1392 	fPulseRate = rate;
1393 
1394 	if (rate > 0) {
1395 		if (fPulseRunner == NULL) {
1396 			BMessage message(B_PULSE);
1397 			fPulseRunner = new BMessageRunner(BMessenger(this),
1398 				&message, rate);
1399 		} else {
1400 			fPulseRunner->SetInterval(rate);
1401 		}
1402 	} else {
1403 		// rate == 0
1404 		delete fPulseRunner;
1405 		fPulseRunner = NULL;
1406 	}
1407 }
1408 
1409 
1410 bigtime_t
1411 BWindow::PulseRate() const
1412 {
1413 	// TODO: What about locking?!?
1414 	return fPulseRate;
1415 }
1416 
1417 
1418 void
1419 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMenuItem *item)
1420 {
1421 	Shortcut* shortcut = new Shortcut(key, modifiers, item);
1422 
1423 	// removes the shortcut if it already exists!
1424 	RemoveShortcut(key, modifiers);
1425 
1426 	fShortcuts.AddItem(shortcut);
1427 }
1428 
1429 
1430 void
1431 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage *message)
1432 {
1433 	AddShortcut(key, modifiers, message, this);
1434 }
1435 
1436 
1437 void
1438 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage *message, BHandler *target)
1439 {
1440 	if (message == NULL)
1441 		return;
1442 
1443 	Shortcut* shortcut = new Shortcut(key, modifiers, message, target);
1444 
1445 	// removes the shortcut if it already exists!
1446 	RemoveShortcut(key, modifiers);
1447 
1448 	fShortcuts.AddItem(shortcut);
1449 }
1450 
1451 
1452 void
1453 BWindow::RemoveShortcut(uint32 key, uint32 modifiers)
1454 {
1455 	Shortcut* shortcut = _FindShortcut(key, modifiers);
1456 	if (shortcut != NULL) {
1457 		fShortcuts.RemoveItem(shortcut);
1458 		delete shortcut;
1459 	} else if ((key == 'q' || key == 'Q') && modifiers == B_COMMAND_KEY) {
1460 		// the quit shortcut is a fake shortcut
1461 		fNoQuitShortcut = true;
1462 	}
1463 }
1464 
1465 
1466 BButton *
1467 BWindow::DefaultButton() const
1468 {
1469 	// TODO: What about locking?!?
1470 	return fDefaultButton;
1471 }
1472 
1473 
1474 void
1475 BWindow::SetDefaultButton(BButton *button)
1476 {
1477 	// TODO: What about locking?!?
1478 	if (fDefaultButton == button)
1479 		return;
1480 
1481 	if (fDefaultButton != NULL) {
1482 		// tell old button it's no longer the default one
1483 		BButton *oldDefault = fDefaultButton;
1484 		oldDefault->MakeDefault(false);
1485 		oldDefault->Invalidate();
1486 	}
1487 
1488 	fDefaultButton = button;
1489 
1490 	if (button != NULL) {
1491 		// notify new default button
1492 		fDefaultButton->MakeDefault(true);
1493 		fDefaultButton->Invalidate();
1494 	}
1495 }
1496 
1497 
1498 bool
1499 BWindow::NeedsUpdate() const
1500 {
1501 	if (!const_cast<BWindow *>(this)->Lock())
1502 		return false;
1503 
1504 	fLink->StartMessage(AS_NEEDS_UPDATE);
1505 
1506 	int32 code = B_ERROR;
1507 	fLink->FlushWithReply(code);
1508 
1509 	const_cast<BWindow *>(this)->Unlock();
1510 
1511 	return code == B_OK;
1512 }
1513 
1514 
1515 void
1516 BWindow::UpdateIfNeeded()
1517 {
1518 	// works only from the window thread
1519 	if (find_thread(NULL) != Thread())
1520 		return;
1521 
1522 	// if the queue is already locked we are called recursivly
1523 	// from our own dispatched update message
1524 	if (((const BMessageQueue *)MessageQueue())->IsLocked())
1525 		return;
1526 
1527 	// make sure all requests that would cause an update have
1528 	// arrived at the server
1529 	Sync();
1530 
1531 	// Since we're blocking the event loop, we need to retrieve
1532 	// all messages that are pending on the port.
1533 	_DequeueAll();
1534 
1535 	BMessageQueue *queue = MessageQueue();
1536 	queue->Lock();
1537 
1538 	// First process and remove any _UPDATE_ message in the queue
1539 	// With the current design, there can only be one at a time
1540 
1541 	BMessage *msg;
1542 	for (int32 i = 0; (msg = queue->FindMessage(i)) != NULL; i++) {
1543 		if (msg->what == _UPDATE_) {
1544 			BWindow::DispatchMessage(msg, this);
1545 				// we need to make sure that no overridden method is called
1546 				// here; for BWindow::DispatchMessage() we now exactly what
1547 				// will happen
1548 			queue->RemoveMessage(msg);
1549 			delete msg;
1550 			break;
1551 			// NOTE: "i" would have to be decreased if there were
1552 			// multiple _UPDATE_ messages and we would not break!
1553 		}
1554 	}
1555 
1556 	queue->Unlock();
1557 }
1558 
1559 
1560 BView *
1561 BWindow::FindView(const char *viewName) const
1562 {
1563 	BAutolock _(const_cast<BWindow*>(this));
1564 	return fTopView->FindView(viewName);
1565 }
1566 
1567 
1568 BView *
1569 BWindow::FindView(BPoint point) const
1570 {
1571 	BAutolock _(const_cast<BWindow*>(this));
1572 	return _FindView(fTopView, point);
1573 }
1574 
1575 
1576 BView *
1577 BWindow::CurrentFocus() const
1578 {
1579 	return fFocus;
1580 }
1581 
1582 
1583 void
1584 BWindow::Activate(bool active)
1585 {
1586 	if (!Lock())
1587 		return;
1588 
1589 	if (!IsHidden()) {
1590 		fLink->StartMessage(AS_ACTIVATE_WINDOW);
1591 		fLink->Attach<bool>(active);
1592 		fLink->Flush();
1593 	}
1594 
1595 	Unlock();
1596 }
1597 
1598 
1599 void
1600 BWindow::WindowActivated(bool state)
1601 {
1602 	// hook function
1603 	// does nothing
1604 }
1605 
1606 
1607 void
1608 BWindow::ConvertToScreen(BPoint *point) const
1609 {
1610 	point->x += fFrame.left;
1611 	point->y += fFrame.top;
1612 }
1613 
1614 
1615 BPoint
1616 BWindow::ConvertToScreen(BPoint point) const
1617 {
1618 	return point + fFrame.LeftTop();
1619 }
1620 
1621 
1622 void
1623 BWindow::ConvertFromScreen(BPoint *point) const
1624 {
1625 	point->x -= fFrame.left;
1626 	point->y -= fFrame.top;
1627 }
1628 
1629 
1630 BPoint
1631 BWindow::ConvertFromScreen(BPoint point) const
1632 {
1633 	return point - fFrame.LeftTop();
1634 }
1635 
1636 
1637 void
1638 BWindow::ConvertToScreen(BRect *rect) const
1639 {
1640 	rect->OffsetBy(fFrame.LeftTop());
1641 }
1642 
1643 
1644 BRect
1645 BWindow::ConvertToScreen(BRect rect) const
1646 {
1647 	return rect.OffsetByCopy(fFrame.LeftTop());
1648 }
1649 
1650 
1651 void
1652 BWindow::ConvertFromScreen(BRect* rect) const
1653 {
1654 	rect->OffsetBy(-fFrame.left, -fFrame.top);
1655 }
1656 
1657 
1658 BRect
1659 BWindow::ConvertFromScreen(BRect rect) const
1660 {
1661 	return rect.OffsetByCopy(-fFrame.left, -fFrame.top);
1662 }
1663 
1664 
1665 bool
1666 BWindow::IsMinimized() const
1667 {
1668 	// Hiding takes precendence over minimization!!!
1669 	if (IsHidden())
1670 		return false;
1671 
1672 	return fMinimized;
1673 }
1674 
1675 
1676 BRect
1677 BWindow::Bounds() const
1678 {
1679 	return BRect(0, 0, fFrame.Width(), fFrame.Height());
1680 }
1681 
1682 
1683 BRect
1684 BWindow::Frame() const
1685 {
1686 	return fFrame;
1687 }
1688 
1689 
1690 const char *
1691 BWindow::Title() const
1692 {
1693 	return fTitle;
1694 }
1695 
1696 
1697 void
1698 BWindow::SetTitle(const char *title)
1699 {
1700 	if (title == NULL)
1701 		title = "";
1702 
1703 	free(fTitle);
1704 	fTitle = strdup(title);
1705 
1706 	// we will change BWindow's thread name to "w>window title"
1707 
1708 	char threadName[B_OS_NAME_LENGTH];
1709 	strcpy(threadName, "w>");
1710 #ifdef __HAIKU__
1711 	strlcat(threadName, title, B_OS_NAME_LENGTH);
1712 #else
1713 	int32 length = strlen(title);
1714 	length = min_c(length, B_OS_NAME_LENGTH - 3);
1715 	memcpy(threadName + 2, title, length);
1716 	threadName[length + 2] = '\0';
1717 #endif
1718 
1719 	// change the handler's name
1720 	SetName(threadName);
1721 
1722 	// if the message loop has been started...
1723 	if (Thread() >= B_OK)
1724 		rename_thread(Thread(), threadName);
1725 
1726 	// we notify the app_server so we can actually see the change
1727 	if (Lock()) {
1728 		fLink->StartMessage(AS_SET_WINDOW_TITLE);
1729 		fLink->AttachString(fTitle);
1730 		fLink->Flush();
1731 		Unlock();
1732 	}
1733 }
1734 
1735 
1736 bool
1737 BWindow::IsActive() const
1738 {
1739 	return fActive;
1740 }
1741 
1742 
1743 void
1744 BWindow::SetKeyMenuBar(BMenuBar *bar)
1745 {
1746 	fKeyMenuBar = bar;
1747 }
1748 
1749 
1750 BMenuBar *
1751 BWindow::KeyMenuBar() const
1752 {
1753 	return fKeyMenuBar;
1754 }
1755 
1756 
1757 bool
1758 BWindow::IsModal() const
1759 {
1760 	return fFeel == B_MODAL_SUBSET_WINDOW_FEEL
1761 		|| fFeel == B_MODAL_APP_WINDOW_FEEL
1762 		|| fFeel == B_MODAL_ALL_WINDOW_FEEL;
1763 }
1764 
1765 
1766 bool
1767 BWindow::IsFloating() const
1768 {
1769 	return fFeel == B_FLOATING_SUBSET_WINDOW_FEEL
1770 		|| fFeel == B_FLOATING_APP_WINDOW_FEEL
1771 		|| fFeel == B_FLOATING_ALL_WINDOW_FEEL;
1772 }
1773 
1774 
1775 status_t
1776 BWindow::AddToSubset(BWindow *window)
1777 {
1778 	if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL
1779 		|| (fFeel != B_MODAL_SUBSET_WINDOW_FEEL
1780 			&& fFeel != B_FLOATING_SUBSET_WINDOW_FEEL))
1781 		return B_BAD_VALUE;
1782 
1783 	if (!Lock())
1784 		return B_ERROR;
1785 
1786 	status_t status = B_ERROR;
1787 	fLink->StartMessage(AS_ADD_TO_SUBSET);
1788 	fLink->Attach<int32>(_get_object_token_(window));
1789 	fLink->FlushWithReply(status);
1790 
1791 	Unlock();
1792 
1793 	return status;
1794 }
1795 
1796 
1797 status_t
1798 BWindow::RemoveFromSubset(BWindow *window)
1799 {
1800 	if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL
1801 		|| (fFeel != B_MODAL_SUBSET_WINDOW_FEEL
1802 			&& fFeel != B_FLOATING_SUBSET_WINDOW_FEEL))
1803 		return B_BAD_VALUE;
1804 
1805 	if (!Lock())
1806 		return B_ERROR;
1807 
1808 	status_t status = B_ERROR;
1809 	fLink->StartMessage(AS_REMOVE_FROM_SUBSET);
1810 	fLink->Attach<int32>(_get_object_token_(window));
1811 	fLink->FlushWithReply(status);
1812 
1813 	Unlock();
1814 
1815 	return status;
1816 }
1817 
1818 
1819 status_t
1820 BWindow::Perform(perform_code d, void *arg)
1821 {
1822 	return BLooper::Perform(d, arg);
1823 }
1824 
1825 
1826 status_t
1827 BWindow::SetType(window_type type)
1828 {
1829 	window_look look;
1830 	window_feel feel;
1831 	_DecomposeType(type, &look, &feel);
1832 
1833 	status_t status = SetLook(look);
1834 	if (status == B_OK)
1835 		status = SetFeel(feel);
1836 
1837 	return status;
1838 }
1839 
1840 
1841 window_type
1842 BWindow::Type() const
1843 {
1844 	return _ComposeType(fLook, fFeel);
1845 }
1846 
1847 
1848 status_t
1849 BWindow::SetLook(window_look look)
1850 {
1851 	BAutolock locker(this);
1852 
1853 	fLink->StartMessage(AS_SET_LOOK);
1854 	fLink->Attach<int32>((int32)look);
1855 
1856 	status_t status = B_ERROR;
1857 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
1858 		fLook = look;
1859 
1860 	// TODO: this could have changed the window size, and thus, we
1861 	//	need to get it from the server (and call _AdoptResize()).
1862 
1863 	return status;
1864 }
1865 
1866 
1867 window_look
1868 BWindow::Look() const
1869 {
1870 	return fLook;
1871 }
1872 
1873 
1874 status_t
1875 BWindow::SetFeel(window_feel feel)
1876 {
1877 	BAutolock locker(this);
1878 
1879 	fLink->StartMessage(AS_SET_FEEL);
1880 	fLink->Attach<int32>((int32)feel);
1881 
1882 	status_t status = B_ERROR;
1883 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
1884 		fFeel = feel;
1885 
1886 	return status;
1887 }
1888 
1889 
1890 window_feel
1891 BWindow::Feel() const
1892 {
1893 	return fFeel;
1894 }
1895 
1896 
1897 status_t
1898 BWindow::SetFlags(uint32 flags)
1899 {
1900 	BAutolock locker(this);
1901 
1902 	fLink->StartMessage(AS_SET_FLAGS);
1903 	fLink->Attach<uint32>(flags);
1904 
1905 	int32 status = B_ERROR;
1906 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
1907 		fFlags = flags;
1908 
1909 	return status;
1910 }
1911 
1912 
1913 uint32
1914 BWindow::Flags() const
1915 {
1916 	return fFlags;
1917 }
1918 
1919 
1920 status_t
1921 BWindow::SetWindowAlignment(window_alignment mode,
1922 	int32 h, int32 hOffset, int32 width, int32 widthOffset,
1923 	int32 v, int32 vOffset, int32 height, int32 heightOffset)
1924 {
1925 	if ((mode & (B_BYTE_ALIGNMENT | B_PIXEL_ALIGNMENT)) == 0
1926 		|| (hOffset >= 0 && hOffset <= h)
1927 		|| (vOffset >= 0 && vOffset <= v)
1928 		|| (widthOffset >= 0 && widthOffset <= width)
1929 		|| (heightOffset >= 0 && heightOffset <= height))
1930 		return B_BAD_VALUE;
1931 
1932 	// TODO: test if hOffset = 0 and set it to 1 if true.
1933 
1934 	if (!Lock())
1935 		return B_ERROR;
1936 
1937 	fLink->StartMessage(AS_SET_ALIGNMENT);
1938 	fLink->Attach<int32>((int32)mode);
1939 	fLink->Attach<int32>(h);
1940 	fLink->Attach<int32>(hOffset);
1941 	fLink->Attach<int32>(width);
1942 	fLink->Attach<int32>(widthOffset);
1943 	fLink->Attach<int32>(v);
1944 	fLink->Attach<int32>(vOffset);
1945 	fLink->Attach<int32>(height);
1946 	fLink->Attach<int32>(heightOffset);
1947 
1948 	status_t status = B_ERROR;
1949 	fLink->FlushWithReply(status);
1950 
1951 	Unlock();
1952 
1953 	return status;
1954 }
1955 
1956 
1957 status_t
1958 BWindow::GetWindowAlignment(window_alignment *mode,
1959 	int32 *h, int32 *hOffset, int32 *width, int32 *widthOffset,
1960 	int32 *v, int32 *vOffset, int32 *height, int32 *heightOffset) const
1961 {
1962 	if (!const_cast<BWindow *>(this)->Lock())
1963 		return B_ERROR;
1964 
1965 	fLink->StartMessage(AS_GET_ALIGNMENT);
1966 
1967 	status_t status;
1968 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK) {
1969 		fLink->Read<int32>((int32 *)mode);
1970 		fLink->Read<int32>(h);
1971 		fLink->Read<int32>(hOffset);
1972 		fLink->Read<int32>(width);
1973 		fLink->Read<int32>(widthOffset);
1974 		fLink->Read<int32>(v);
1975 		fLink->Read<int32>(hOffset);
1976 		fLink->Read<int32>(height);
1977 		fLink->Read<int32>(heightOffset);
1978 	}
1979 
1980 	const_cast<BWindow *>(this)->Unlock();
1981 	return status;
1982 }
1983 
1984 
1985 uint32
1986 BWindow::Workspaces() const
1987 {
1988 	if (!const_cast<BWindow *>(this)->Lock())
1989 		return 0;
1990 
1991 	uint32 workspaces = 0;
1992 
1993 	fLink->StartMessage(AS_GET_WORKSPACES);
1994 
1995 	status_t status;
1996 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
1997 		fLink->Read<uint32>(&workspaces);
1998 
1999 	const_cast<BWindow *>(this)->Unlock();
2000 	return workspaces;
2001 }
2002 
2003 
2004 void
2005 BWindow::SetWorkspaces(uint32 workspaces)
2006 {
2007 	// TODO: don't forget about Tracker's background window.
2008 	if (fFeel != B_NORMAL_WINDOW_FEEL)
2009 		return;
2010 
2011 	if (Lock()) {
2012 		fLink->StartMessage(AS_SET_WORKSPACES);
2013 		fLink->Attach<uint32>(workspaces);
2014 		fLink->Flush();
2015 		Unlock();
2016 	}
2017 }
2018 
2019 
2020 BView *
2021 BWindow::LastMouseMovedView() const
2022 {
2023 	return fLastMouseMovedView;
2024 }
2025 
2026 
2027 void
2028 BWindow::MoveBy(float dx, float dy)
2029 {
2030 	if ((dx == 0.0 && dy == 0.0) || !Lock())
2031 		return;
2032 
2033 	fLink->StartMessage(AS_WINDOW_MOVE);
2034 	fLink->Attach<float>(dx);
2035 	fLink->Attach<float>(dy);
2036 
2037 	status_t status;
2038 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
2039 		fFrame.OffsetBy(dx, dy);
2040 
2041 	Unlock();
2042 }
2043 
2044 
2045 void
2046 BWindow::MoveTo(BPoint point)
2047 {
2048 	if (!Lock())
2049 		return;
2050 
2051 	point.x = roundf(point.x);
2052 	point.y = roundf(point.y);
2053 
2054 	if (fFrame.left != point.x || fFrame.top != point.y) {
2055 		float xOffset = point.x - fFrame.left;
2056 		float yOffset = point.y - fFrame.top;
2057 
2058 		MoveBy(xOffset, yOffset);
2059 	}
2060 
2061 	Unlock();
2062 }
2063 
2064 
2065 void
2066 BWindow::MoveTo(float x, float y)
2067 {
2068 	MoveTo(BPoint(x, y));
2069 }
2070 
2071 
2072 void
2073 BWindow::ResizeBy(float dx, float dy)
2074 {
2075 	if (!Lock())
2076 		return;
2077 
2078 	dx = roundf(dx);
2079 	dy = roundf(dy);
2080 
2081 	// stay in minimum & maximum frame limits
2082 	if (fFrame.Width() + dx < fMinWidth)
2083 		dx = fMinWidth - fFrame.Width();
2084 	if (fFrame.Width() + dx > fMaxWidth)
2085 		dx = fMaxWidth - fFrame.Width();
2086 	if (fFrame.Height() + dy < fMinHeight)
2087 		dy = fMinHeight - fFrame.Height();
2088 	if (fFrame.Height() + dy > fMaxHeight)
2089 		dy = fMaxHeight - fFrame.Height();
2090 
2091 	if (dx != 0.0 || dy != 0.0) {
2092 		fLink->StartMessage(AS_WINDOW_RESIZE);
2093 		fLink->Attach<float>(dx);
2094 		fLink->Attach<float>(dy);
2095 
2096 		status_t status;
2097 		if (fLink->FlushWithReply(status) == B_OK && status == B_OK) {
2098 			fFrame.SetRightBottom(fFrame.RightBottom() + BPoint(dx, dy));
2099 			_AdoptResize();
2100 		}
2101 	}
2102 	Unlock();
2103 }
2104 
2105 
2106 void
2107 BWindow::ResizeTo(float width, float height)
2108 {
2109 	if (Lock()) {
2110 		ResizeBy(width - fFrame.Width(), height - fFrame.Height());
2111 		Unlock();
2112 	}
2113 }
2114 
2115 
2116 void
2117 BWindow::Show()
2118 {
2119 	if (!fRunCalled) {
2120 		// this is the fist time Show() is called, which implicetly runs the looper
2121 		if (fLink->SenderPort() < B_OK) {
2122 			// We don't have valid app_server connection; there is no point
2123 			// in starting our looper
2124 			fTaskID = B_ERROR;
2125 			return;
2126 		} else
2127 			Run();
2128 	}
2129 
2130 	if (Lock()) {
2131 		fShowLevel++;
2132 
2133 		if (fShowLevel == 1) {
2134 			STRACE(("BWindow(%s): sending AS_SHOW_WINDOW message...\n", Name()));
2135 			fLink->StartMessage(AS_SHOW_WINDOW);
2136 			fLink->Flush();
2137 		}
2138 
2139 		Unlock();
2140 	}
2141 }
2142 
2143 
2144 void
2145 BWindow::Hide()
2146 {
2147 	if (!Lock())
2148 		return;
2149 
2150 	if (--fShowLevel == 0) {
2151 		fLink->StartMessage(AS_HIDE_WINDOW);
2152 		fLink->Flush();
2153 	}
2154 
2155 	Unlock();
2156 }
2157 
2158 
2159 bool
2160 BWindow::IsHidden() const
2161 {
2162 	return fShowLevel <= 0;
2163 }
2164 
2165 
2166 bool
2167 BWindow::QuitRequested()
2168 {
2169 	return BLooper::QuitRequested();
2170 }
2171 
2172 
2173 thread_id
2174 BWindow::Run()
2175 {
2176 	return BLooper::Run();
2177 }
2178 
2179 
2180 status_t
2181 BWindow::GetSupportedSuites(BMessage *data)
2182 {
2183 	if (data == NULL)
2184 		return B_BAD_VALUE;
2185 
2186 	status_t status = data->AddString("Suites", "suite/vnd.Be-window");
2187 	if (status == B_OK) {
2188 		BPropertyInfo propertyInfo(sWindowPropInfo);
2189 
2190 		status = data->AddFlat("message", &propertyInfo);
2191 		if (status == B_OK)
2192 			status = BLooper::GetSupportedSuites(data);
2193 	}
2194 
2195 	return status;
2196 }
2197 
2198 
2199 BHandler *
2200 BWindow::ResolveSpecifier(BMessage *msg, int32 index, BMessage *specifier,
2201 	int32 what,	const char *property)
2202 {
2203 	if (msg->what == B_WINDOW_MOVE_BY
2204 		|| msg->what == B_WINDOW_MOVE_TO)
2205 		return this;
2206 
2207 	BPropertyInfo propertyInfo(sWindowPropInfo);
2208 	if (propertyInfo.FindMatch(msg, index, specifier, what, property) >= 0) {
2209 		if (!strcmp(property, "View")) {
2210 			// we will NOT pop the current specifier
2211 			return fTopView;
2212 		} else if (!strcmp(property, "MenuBar")) {
2213 			if (fKeyMenuBar) {
2214 				msg->PopSpecifier();
2215 				return fKeyMenuBar;
2216 			} else {
2217 				BMessage replyMsg(B_MESSAGE_NOT_UNDERSTOOD);
2218 				replyMsg.AddInt32("error", B_NAME_NOT_FOUND);
2219 				replyMsg.AddString("message", "This window doesn't have a main MenuBar");
2220 				msg->SendReply(&replyMsg);
2221 				return NULL;
2222 			}
2223 		} else
2224 			return this;
2225 	}
2226 
2227 	return BLooper::ResolveSpecifier(msg, index, specifier, what, property);
2228 }
2229 
2230 
2231 //	#pragma mark - Private Methods
2232 
2233 
2234 void
2235 BWindow::_InitData(BRect frame, const char* title, window_look look,
2236 	window_feel feel, uint32 flags,	uint32 workspace, int32 bitmapToken)
2237 {
2238 	STRACE(("BWindow::InitData()\n"));
2239 
2240 	if (be_app == NULL) {
2241 		debugger("You need a valid BApplication object before interacting with the app_server");
2242 		return;
2243 	}
2244 
2245 	frame.left = roundf(frame.left);
2246 	frame.top = roundf(frame.top);
2247 	frame.right = roundf(frame.right);
2248 	frame.bottom = roundf(frame.bottom);
2249 
2250 	fFrame = frame;
2251 
2252 	if (title == NULL)
2253 		title = "";
2254 	fTitle = strdup(title);
2255 	SetName(title);
2256 
2257 	fFeel = feel;
2258 	fLook = look;
2259 	fFlags = flags;
2260 
2261 	fInTransaction = false;
2262 	fActive = false;
2263 	fShowLevel = 0;
2264 
2265 	fTopView = NULL;
2266 	fFocus = NULL;
2267 	fLastMouseMovedView	= NULL;
2268 	fKeyMenuBar = NULL;
2269 	fDefaultButton = NULL;
2270 
2271 	// Shortcut 'Q' is handled in _HandleKeyDown() directly, as its message
2272 	// get sent to the application, and not one of our handlers
2273 	fNoQuitShortcut = false;
2274 
2275 	if ((fFlags & B_NOT_CLOSABLE) == 0)
2276 		AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
2277 
2278 	AddShortcut('X', B_COMMAND_KEY, new BMessage(B_CUT), NULL);
2279 	AddShortcut('C', B_COMMAND_KEY, new BMessage(B_COPY), NULL);
2280 	AddShortcut('V', B_COMMAND_KEY, new BMessage(B_PASTE), NULL);
2281 	AddShortcut('A', B_COMMAND_KEY, new BMessage(B_SELECT_ALL), NULL);
2282 
2283 	fPulseRate = 0;
2284 	fPulseRunner = NULL;
2285 
2286 	// TODO: is this correct??? should the thread loop be started???
2287 	//SetPulseRate( 500000 );
2288 
2289 	// TODO:  see if you can use 'fViewsNeedPulse'
2290 
2291 	fIsFilePanel = false;
2292 
2293 	// TODO: see WHEN is this used!
2294 	fMaskActivated = false;
2295 
2296 	// TODO: see WHEN is this used!
2297 	fWaitingForMenu = false;
2298 	fMenuSem = -1;
2299 
2300 	fMinimized = false;
2301 
2302 	fMaxZoomHeight = 32768.0;
2303 	fMaxZoomWidth = 32768.0;
2304 	fMinHeight = 0.0;
2305 	fMinWidth = 0.0;
2306 	fMaxHeight = 32768.0;
2307 	fMaxWidth = 32768.0;
2308 
2309 	fLastViewToken = B_NULL_TOKEN;
2310 
2311 	// TODO: other initializations!
2312 
2313 	// Create the server-side window
2314 
2315 	port_id receivePort = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY, "w<app_server");
2316 	if (receivePort < B_OK) {
2317 		// TODO: huh?
2318 		debugger("Could not create BWindow's receive port, used for interacting with the app_server!");
2319 		delete this;
2320 		return;
2321 	}
2322 
2323 	STRACE(("BWindow::InitData(): contacting app_server...\n"));
2324 
2325 	// HERE we are in BApplication's thread, so for locking we use be_app variable
2326 	// we'll lock the be_app to be sure we're the only one writing at BApplication's server port
2327 	bool locked = false;
2328 	if (!be_app->IsLocked()) {
2329 		be_app->Lock();
2330 		locked = true;
2331 	}
2332 
2333 	// let app_server know that a window has been created.
2334 	fLink = new BPrivate::PortLink(
2335 		BApplication::Private::ServerLink()->SenderPort(), receivePort);
2336 
2337 	if (bitmapToken < 0) {
2338 		fLink->StartMessage(AS_CREATE_WINDOW);
2339 	} else {
2340 		fLink->StartMessage(AS_CREATE_OFFSCREEN_WINDOW);
2341 		fLink->Attach<int32>(bitmapToken);
2342 	}
2343 
2344 	fLink->Attach<BRect>(fFrame);
2345 	fLink->Attach<uint32>((uint32)fLook);
2346 	fLink->Attach<uint32>((uint32)fFeel);
2347 	fLink->Attach<uint32>(fFlags);
2348 	fLink->Attach<uint32>(workspace);
2349 	fLink->Attach<int32>(_get_object_token_(this));
2350 	fLink->Attach<port_id>(receivePort);
2351 	fLink->Attach<port_id>(fMsgPort);
2352 	fLink->AttachString(title);
2353 
2354 	port_id sendPort;
2355 	int32 code;
2356 	if (fLink->FlushWithReply(code) == B_OK
2357 		&& code == B_OK
2358 		&& fLink->Read<port_id>(&sendPort) == B_OK) {
2359 		// read the frame size and its limits that were really
2360 		// enforced on the server side
2361 
2362 		fLink->Read<BRect>(&fFrame);
2363 		fLink->Read<float>(&fMinWidth);
2364 		fLink->Read<float>(&fMaxWidth);
2365 		fLink->Read<float>(&fMinHeight);
2366 		fLink->Read<float>(&fMaxHeight);
2367 
2368 		fMaxZoomWidth = fMaxWidth;
2369 		fMaxZoomHeight = fMaxHeight;
2370 	} else
2371 		sendPort = -1;
2372 
2373 	// Redirect our link to the new window connection
2374 	fLink->SetSenderPort(sendPort);
2375 
2376 	if (locked)
2377 		be_app->Unlock();
2378 
2379 	STRACE(("Server says that our send port is %ld\n", sendPort));
2380 	STRACE(("Window locked?: %s\n", IsLocked() ? "True" : "False"));
2381 
2382 	_CreateTopView();
2383 }
2384 
2385 
2386 //!	Reads all pending messages from the window port and put them into the queue.
2387 void
2388 BWindow::_DequeueAll()
2389 {
2390 	//	Get message count from port
2391 	int32 count = port_count(fMsgPort);
2392 
2393 	for (int32 i = 0; i < count; i++) {
2394 		BMessage *message = MessageFromPort(0);
2395 		if (message != NULL)
2396 			fQueue->AddMessage(message);
2397 	}
2398 }
2399 
2400 
2401 /*!	This here is an almost complete code duplication to BLooper::task_looper()
2402 	but with some important differences:
2403 	 a)	it uses the _DetermineTarget() method to tell what the later target of
2404 		a message will be, if no explicit target is supplied.
2405 	 b)	it calls _UnpackMessage() and _SanitizeMessage() to duplicate the message
2406 	 	to all of its intended targets, and to add all fields the target would
2407 	 	expect in such a message.
2408 
2409 	This is important because the app_server sends all input events to the
2410 	preferred handler, and expects them to be correctly distributed to their
2411 	intended targets.
2412 */
2413 void
2414 BWindow::task_looper()
2415 {
2416 	STRACE(("info: BWindow::task_looper() started.\n"));
2417 
2418 	// Check that looper is locked (should be)
2419 	AssertLocked();
2420 	Unlock();
2421 
2422 	if (IsLocked())
2423 		debugger("window must not be locked!");
2424 
2425 	// loop: As long as we are not terminating.
2426 	while (!fTerminating) {
2427 		// TODO: timeout determination algo
2428 		//	Read from message port (how do we determine what the timeout is?)
2429 		BMessage* msg = MessageFromPort();
2430 
2431 		// Did we get a message?
2432 		if (msg) {
2433 			// Add to queue
2434 			fQueue->AddMessage(msg);
2435 		} else
2436 			continue;
2437 
2438 		//	Get message count from port
2439 		int32 msgCount = port_count(fMsgPort);
2440 		for (int32 i = 0; i < msgCount; ++i) {
2441 			// Read 'count' messages from port (so we will not block)
2442 			// We use zero as our timeout since we know there is stuff there
2443 			msg = MessageFromPort(0);
2444 			// Add messages to queue
2445 			if (msg)
2446 				fQueue->AddMessage(msg);
2447 		}
2448 
2449 		// loop: As long as there are messages in the queue and the port is
2450 		//		 empty... and we are not terminating, of course.
2451 		bool dispatchNextMessage = true;
2452 		while (!fTerminating && dispatchNextMessage) {
2453 			//	Get next message from queue (assign to fLastMessage)
2454 			fLastMessage = fQueue->NextMessage();
2455 
2456 			// Lock the looper
2457 			if (!Lock())
2458 				break;
2459 
2460 			if (!fLastMessage) {
2461 				// No more messages: Unlock the looper and terminate the
2462 				// dispatch loop.
2463 				dispatchNextMessage = false;
2464 			} else {
2465 				// Get the target handler
2466 				BMessage::Private messagePrivate(fLastMessage);
2467 				bool usePreferred = messagePrivate.UsePreferredTarget();
2468 				BHandler *handler = NULL;
2469 				bool dropMessage = false;
2470 
2471 				if (usePreferred) {
2472 					handler = PreferredHandler();
2473 					if (handler == NULL)
2474 						handler = this;
2475 				} else {
2476 					gDefaultTokens.GetToken(messagePrivate.GetTarget(),
2477 						B_HANDLER_TOKEN, (void **)&handler);
2478 
2479 					// if this handler doesn't belong to us, we drop the message
2480 					if (handler != NULL && handler->Looper() != this) {
2481 						dropMessage = true;
2482 						handler = NULL;
2483 					}
2484 				}
2485 
2486 				if ((handler == NULL && !dropMessage) || usePreferred)
2487 					handler = _DetermineTarget(fLastMessage, handler);
2488 
2489 				unpack_cookie cookie;
2490 				while (_UnpackMessage(cookie, &fLastMessage, &handler, &usePreferred)) {
2491 					// if there is no target handler, the message is dropped
2492 					if (handler != NULL) {
2493 						// Is this a scripting message?
2494 						if (fLastMessage->HasSpecifiers()) {
2495 							int32 index = 0;
2496 							// Make sure the current specifier is kosher
2497 							if (fLastMessage->GetCurrentSpecifier(&index) == B_OK)
2498 								handler = resolve_specifier(handler, fLastMessage);
2499 						}
2500 
2501 						if (handler != NULL)
2502 							handler = _TopLevelFilter(fLastMessage, handler);
2503 
2504 						if (handler != NULL) {
2505 							_SanitizeMessage(fLastMessage, handler, usePreferred);
2506 							DispatchMessage(fLastMessage, handler);
2507 						}
2508 					}
2509 
2510 					// Delete the current message
2511 					delete fLastMessage;
2512 					fLastMessage = NULL;
2513 				}
2514 			}
2515 
2516 			if (fTerminating) {
2517 				// we leave the looper locked when we quit
2518 				return;
2519 			}
2520 
2521 			Unlock();
2522 
2523 			// Are any messages on the port?
2524 			if (port_count(fMsgPort) > 0) {
2525 				// Do outer loop
2526 				dispatchNextMessage = false;
2527 			}
2528 		}
2529 	}
2530 }
2531 
2532 
2533 window_type
2534 BWindow::_ComposeType(window_look look, window_feel feel) const
2535 {
2536 	switch (feel) {
2537 		case B_NORMAL_WINDOW_FEEL:
2538 			switch (look) {
2539 				case B_TITLED_WINDOW_LOOK:
2540 					return B_TITLED_WINDOW;
2541 
2542 				case B_DOCUMENT_WINDOW_LOOK:
2543 					return B_DOCUMENT_WINDOW;
2544 
2545 				case B_BORDERED_WINDOW_LOOK:
2546 					return B_BORDERED_WINDOW;
2547 
2548 				default:
2549 					return B_UNTYPED_WINDOW;
2550 			}
2551 			break;
2552 
2553 		case B_MODAL_APP_WINDOW_FEEL:
2554 			if (look == B_MODAL_WINDOW_LOOK)
2555 				return B_MODAL_WINDOW;
2556 			break;
2557 
2558 		case B_FLOATING_APP_WINDOW_FEEL:
2559 			if (look == B_FLOATING_WINDOW_LOOK)
2560 				return B_FLOATING_WINDOW;
2561 			break;
2562 
2563 		default:
2564 			return B_UNTYPED_WINDOW;
2565 	}
2566 
2567 	return B_UNTYPED_WINDOW;
2568 }
2569 
2570 
2571 void
2572 BWindow::_DecomposeType(window_type type, window_look *_look,
2573 	window_feel *_feel) const
2574 {
2575 	switch (type) {
2576 		case B_DOCUMENT_WINDOW:
2577 			*_look = B_DOCUMENT_WINDOW_LOOK;
2578 			*_feel = B_NORMAL_WINDOW_FEEL;
2579 			break;
2580 
2581 		case B_MODAL_WINDOW:
2582 			*_look = B_MODAL_WINDOW_LOOK;
2583 			*_feel = B_MODAL_APP_WINDOW_FEEL;
2584 			break;
2585 
2586 		case B_FLOATING_WINDOW:
2587 			*_look = B_FLOATING_WINDOW_LOOK;
2588 			*_feel = B_FLOATING_APP_WINDOW_FEEL;
2589 			break;
2590 
2591 		case B_BORDERED_WINDOW:
2592 			*_look = B_BORDERED_WINDOW_LOOK;
2593 			*_feel = B_NORMAL_WINDOW_FEEL;
2594 			break;
2595 
2596 		case B_TITLED_WINDOW:
2597 		case B_UNTYPED_WINDOW:
2598 		default:
2599 			*_look = B_TITLED_WINDOW_LOOK;
2600 			*_feel = B_NORMAL_WINDOW_FEEL;
2601 			break;
2602 	}
2603 }
2604 
2605 
2606 void
2607 BWindow::_CreateTopView()
2608 {
2609 	STRACE(("_CreateTopView(): enter\n"));
2610 
2611 	BRect frame = fFrame.OffsetToCopy(B_ORIGIN);
2612 	fTopView = new BView(frame, "fTopView",
2613 		B_FOLLOW_ALL, B_WILL_DRAW);
2614 	fTopView->fTopLevelView = true;
2615 
2616 	//inhibit check_lock()
2617 	fLastViewToken = _get_object_token_(fTopView);
2618 
2619 	// set fTopView's owner, add it to window's eligible handler list
2620 	// and also set its next handler to be this window.
2621 
2622 	STRACE(("Calling setowner fTopView = %p this = %p.\n",
2623 		fTopView, this));
2624 
2625 	fTopView->_SetOwner(this);
2626 
2627 	// we can't use AddChild() because this is the top view
2628   	fTopView->_CreateSelf();
2629 
2630 	STRACE(("BuildTopView ended\n"));
2631 }
2632 
2633 
2634 /*!
2635 	Resizes the top view to match the window size. This will also
2636 	adapt the size of all its child views as needed.
2637 	This method has to be called whenever the frame of the window
2638 	changes.
2639 */
2640 void
2641 BWindow::_AdoptResize()
2642 {
2643 	// Resize views according to their resize modes - this
2644 	// saves us some server communication, as the server
2645 	// does the same with our views on its side.
2646 
2647 	int32 deltaWidth = (int32)(fFrame.Width() - fTopView->Bounds().Width());
2648 	int32 deltaHeight = (int32)(fFrame.Height() - fTopView->Bounds().Height());
2649 	if (deltaWidth == 0 && deltaHeight == 0)
2650 		return;
2651 
2652 	fTopView->_ResizeBy(deltaWidth, deltaHeight);
2653 }
2654 
2655 
2656 void
2657 BWindow::_SetFocus(BView *focusView, bool notifyInputServer)
2658 {
2659 	if (fFocus == focusView)
2660 		return;
2661 
2662 	if (focusView)
2663 		focusView->MakeFocus(true);
2664 
2665 	// we notify the input server if we are passing focus
2666 	// from a view which has the B_INPUT_METHOD_AWARE to a one
2667 	// which does not, or vice-versa
2668 	if (notifyInputServer) {
2669 		bool oldIMAware = false, newIMAware = false;
2670 		if (focusView)
2671 			newIMAware = focusView->Flags() & B_INPUT_METHOD_AWARE;
2672 		if (fFocus)
2673 			oldIMAware = fFocus->Flags() & B_INPUT_METHOD_AWARE;
2674 		if (newIMAware ^ oldIMAware) {
2675 			BMessage msg(newIMAware ? IS_FOCUS_IM_AWARE_VIEW : IS_UNFOCUS_IM_AWARE_VIEW);
2676 			BMessage reply;
2677 			_control_input_server_(&msg, &reply);
2678 			// do we care return code ?
2679 		}
2680 	}
2681 
2682 	fFocus = focusView;
2683 }
2684 
2685 
2686 /*!
2687 	\brief Determines the target of a message received for the
2688 		focus view.
2689 */
2690 BHandler *
2691 BWindow::_DetermineTarget(BMessage *message, BHandler *target)
2692 {
2693 	if (target == NULL)
2694 		target = this;
2695 
2696 	switch (message->what) {
2697 		case B_KEY_DOWN:
2698 		case B_KEY_UP:
2699 		{
2700 			// if we have a default button, it might want to hear
2701 			// about pressing the <enter> key
2702 			int32 rawChar;
2703 			if (DefaultButton() != NULL
2704 				&& message->FindInt32("raw_char", &rawChar) == B_OK
2705 				&& rawChar == B_ENTER)
2706 				return DefaultButton();
2707 
2708 			// supposed to fall through
2709 		}
2710 		case B_UNMAPPED_KEY_DOWN:
2711 		case B_UNMAPPED_KEY_UP:
2712 		case B_MODIFIERS_CHANGED:
2713 			// these messages should be dispatched by the focus view
2714 			if (CurrentFocus() != NULL)
2715 				return CurrentFocus();
2716 			break;
2717 
2718 		case B_MOUSE_DOWN:
2719 		case B_MOUSE_UP:
2720 		case B_MOUSE_MOVED:
2721 		case B_MOUSE_WHEEL_CHANGED:
2722 			// is there a token of the view that is currently under the mouse?
2723 			int32 token;
2724 			if (message->FindInt32("_view_token", &token) == B_OK) {
2725 				BView* view = _FindView(token);
2726 				if (view != NULL)
2727 					return view;
2728 			}
2729 
2730 			// if there is no valid token in the message, we try our
2731 			// luck with the last target, if available
2732 			if (fLastMouseMovedView != NULL)
2733 				return fLastMouseMovedView;
2734 			break;
2735 
2736 		case B_PULSE:
2737 		case B_QUIT_REQUESTED:
2738 			// TODO: test wether R5 will let BView dispatch these messages
2739 			return this;
2740 
2741 		default:
2742 			break;
2743 	}
2744 
2745 	return target;
2746 }
2747 
2748 
2749 /*!
2750 	\brief Distributes the message to its intended targets. This is done for
2751 		all messages that should go to the preferred handler.
2752 
2753 	Returns \c true in case the message should still be dispatched
2754 */
2755 bool
2756 BWindow::_UnpackMessage(unpack_cookie& cookie, BMessage** _message, BHandler** _target,
2757 	bool* _usePreferred)
2758 {
2759 	if (cookie.message == NULL)
2760 		return false;
2761 
2762 	if (cookie.index == 0 && !cookie.tokens_scanned) {
2763 		if (!*_usePreferred) {
2764 			// we only consider messages targeted at the preferred handler
2765 			cookie.message = NULL;
2766 			return true;
2767 		}
2768 
2769 		// initialize our cookie
2770 		cookie.message = *_message;
2771 		cookie.focus = *_target;
2772 
2773 		if (cookie.focus != NULL)
2774 			cookie.focus_token = _get_object_token_(*_target);
2775 
2776 		if (fLastMouseMovedView != NULL && cookie.message->what == B_MOUSE_MOVED)
2777 			cookie.last_view_token = _get_object_token_(fLastMouseMovedView);
2778 
2779 		*_usePreferred = false;
2780 	}
2781 
2782 	_DequeueAll();
2783 
2784 	// distribute the message to all targets specified in the
2785 	// message directly (but not to the focus view)
2786 
2787 	for (int32 token; !cookie.tokens_scanned
2788 			&& cookie.message->FindInt32("_token", cookie.index, &token) == B_OK;
2789 			cookie.index++) {
2790 		// focus view is preferred and should get its message directly
2791 		if (token == cookie.focus_token) {
2792 			cookie.found_focus = true;
2793 			continue;
2794 		}
2795 		if (token == cookie.last_view_token)
2796 			continue;
2797 
2798 		BView* target = _FindView(token);
2799 		if (target == NULL)
2800 			continue;
2801 
2802 		*_message = new BMessage(*cookie.message);
2803 		*_target = target;
2804 		cookie.index++;
2805 		return true;
2806 	}
2807 
2808 	cookie.tokens_scanned = true;
2809 
2810 	// if there is a last mouse moved view, and the new focus is
2811 	// different, the previous view wants to get its B_EXITED_VIEW
2812 	// message
2813 	if (cookie.last_view_token != B_NULL_TOKEN && fLastMouseMovedView != NULL
2814 		&& fLastMouseMovedView != cookie.focus) {
2815 		*_message = new BMessage(*cookie.message);
2816 		*_target = fLastMouseMovedView;
2817 		cookie.last_view_token = B_NULL_TOKEN;
2818 		return true;
2819 	}
2820 
2821 	bool dispatchToFocus = true;
2822 
2823 	// check if the focus token is still valid (could have been removed in the mean time)
2824 	BHandler* handler;
2825 	if (gDefaultTokens.GetToken(cookie.focus_token, B_HANDLER_TOKEN, (void**)&handler) != B_OK
2826 		|| handler->Looper() != this)
2827 		dispatchToFocus = false;
2828 
2829 	if (dispatchToFocus && cookie.index > 0) {
2830 		// should this message still be dispatched by the focus view?
2831 		bool feedFocus;
2832 		if (!cookie.found_focus
2833 			&& (cookie.message->FindBool("_feed_focus", &feedFocus) != B_OK
2834 				|| feedFocus == false))
2835 			dispatchToFocus = false;
2836 	}
2837 
2838 	if (!dispatchToFocus) {
2839 		delete cookie.message;
2840 		cookie.message = NULL;
2841 		return false;
2842 	}
2843 
2844 	*_message = cookie.message;
2845 	*_target = cookie.focus;
2846 	*_usePreferred = true;
2847 	cookie.message = NULL;
2848 	return true;
2849 }
2850 
2851 
2852 void
2853 BWindow::_SanitizeMessage(BMessage* message, BHandler* target, bool usePreferred)
2854 {
2855 	if (target == NULL)
2856 		return;
2857 
2858 	switch (message->what) {
2859 		case B_MOUSE_MOVED:
2860 		case B_MOUSE_UP:
2861 		case B_MOUSE_DOWN:
2862 			BPoint where;
2863 			if (message->FindPoint("screen_where", &where) != B_OK)
2864 				break;
2865 
2866 			// add local window coordinates
2867 			message->AddPoint("where", ConvertFromScreen(where));
2868 
2869 			BView* view = dynamic_cast<BView*>(target);
2870 			if (view != NULL) {
2871 				// add local view coordinates
2872 				message->AddPoint("be:view_where", view->ConvertFromScreen(where));
2873 
2874 				if (message->what == B_MOUSE_MOVED) {
2875 					// is there a token of the view that is currently under the mouse?
2876 					BView* viewUnderMouse = NULL;
2877 					int32 token;
2878 					if (message->FindInt32("_view_token", &token) == B_OK)
2879 						viewUnderMouse = _FindView(token);
2880 
2881 					// add transit information
2882 					int32 transit;
2883 					if (viewUnderMouse == view) {
2884 						// the mouse is over the target view
2885 						if (fLastMouseMovedView != view)
2886 							transit = B_ENTERED_VIEW;
2887 						else
2888 							transit = B_INSIDE_VIEW;
2889 					} else {
2890 						// the mouse is not over the target view
2891 						if (view == fLastMouseMovedView)
2892 							transit = B_EXITED_VIEW;
2893 						else
2894 							transit = B_OUTSIDE_VIEW;
2895 					}
2896 
2897 					message->AddInt32("be:transit", transit);
2898 
2899 					if (usePreferred || viewUnderMouse == NULL)
2900 						fLastMouseMovedView = viewUnderMouse;
2901 				}
2902 			}
2903 			break;
2904 	}
2905 }
2906 
2907 
2908 bool
2909 BWindow::_HandleKeyDown(char key, uint32 modifiers)
2910 {
2911 	// TODO: ask people if using 'raw_char' is OK ?
2912 
2913 	// handle BMenuBar key
2914 	if (key == B_ESCAPE && (modifiers & B_COMMAND_KEY) != 0
2915 		&& fKeyMenuBar) {
2916 		// TODO: ask Marc about 'fWaitingForMenu' member!
2917 
2918 		// fWaitingForMenu = true;
2919 		fKeyMenuBar->StartMenuBar(0, true, false, NULL);
2920 		return true;
2921 	}
2922 
2923 	// Keyboard navigation through views
2924 	// (B_OPTION_KEY makes BTextViews and friends navigable, even in editing mode)
2925 	if (key == B_TAB && (modifiers & (B_COMMAND_KEY | B_OPTION_KEY)) != 0) {
2926 		_KeyboardNavigation();
2927 		return true;
2928 	}
2929 
2930 	// Deskbar's Switcher
2931 	if (key == B_TAB && (modifiers & B_CONTROL_KEY) != 0) {
2932 		BMessenger deskbar(kDeskbarSignature);
2933 		if (deskbar.IsValid()) {
2934 			BMessage message('TASK');
2935 			message.AddInt32("key", B_TAB);
2936 			message.AddInt32("modifiers", modifiers);
2937 			message.AddInt64("when", system_time());
2938 			message.AddInt32("team", Team());
2939 			deskbar.SendMessage(&message);
2940 		}
2941 		return true;
2942 	}
2943 
2944 	// Handle shortcuts
2945 	if ((modifiers & B_COMMAND_KEY) != 0) {
2946 		// Command+q has been pressed, so, we will quit
2947 		// the shortcut mechanism doesn't allow handlers outside the window
2948 		if (!fNoQuitShortcut && (key == 'Q' || key == 'q')) {
2949 			BMessage message(B_QUIT_REQUESTED);
2950 			message.AddBool("shortcut", true);
2951 
2952 			be_app->PostMessage(&message);
2953 			return true;
2954 		}
2955 
2956 		Shortcut* shortcut = _FindShortcut(key, modifiers);
2957 		if (shortcut != NULL) {
2958 			// TODO: would be nice to move this functionality to
2959 			//	a Shortcut::Invoke() method - but since BMenu::InvokeItem()
2960 			//	(and BMenuItem::Invoke()) are private, I didn't want
2961 			//	to mess with them (BMenuItem::Invoke() is public in
2962 			//	Dano/Zeta, though, maybe we should just follow their
2963 			//	example)
2964 			if (shortcut->MenuItem() != NULL) {
2965 				BMenu* menu = shortcut->MenuItem()->Menu();
2966 				if (menu != NULL)
2967 					menu->InvokeItem(shortcut->MenuItem(), true);
2968 			} else {
2969 				BHandler* target = shortcut->Target();
2970 				if (target == NULL)
2971 					target = CurrentFocus();
2972 
2973 				if (shortcut->Message() != NULL) {
2974 					BMessage message(*shortcut->Message());
2975 
2976 					if (message.ReplaceInt64("when", system_time()) != B_OK)
2977 						message.AddInt64("when", system_time());
2978 					if (message.ReplaceBool("shortcut", true) != B_OK)
2979 						message.AddBool("shortcut", true);
2980 
2981 					PostMessage(&message, target);
2982 				}
2983 			}
2984 
2985 			return true;
2986 		}
2987 	}
2988 
2989 	// TODO: convert keys to the encoding of the target view
2990 
2991 	return false;
2992 }
2993 
2994 
2995 void
2996 BWindow::_KeyboardNavigation()
2997 {
2998 	BMessage *message = CurrentMessage();
2999 	if (message == NULL)
3000 		return;
3001 
3002 	const char *bytes;
3003 	uint32 modifiers;
3004 	if (message->FindString("bytes", &bytes) != B_OK
3005 		|| bytes[0] != B_TAB)
3006 		return;
3007 
3008 	message->FindInt32("modifiers", (int32*)&modifiers);
3009 
3010 	BView *nextFocus;
3011 	int32 jumpGroups = modifiers & B_CONTROL_KEY ? B_NAVIGABLE_JUMP : B_NAVIGABLE;
3012 	if (modifiers & B_SHIFT_KEY)
3013 		nextFocus = _FindPreviousNavigable(fFocus, jumpGroups);
3014 	else
3015 		nextFocus = _FindNextNavigable(fFocus, jumpGroups);
3016 
3017 	if (nextFocus && nextFocus != fFocus)
3018 		_SetFocus(nextFocus, false);
3019 }
3020 
3021 
3022 BMessage *
3023 BWindow::ConvertToMessage(void *raw, int32 code)
3024 {
3025 	return BLooper::ConvertToMessage(raw, code);
3026 }
3027 
3028 
3029 BWindow::Shortcut *
3030 BWindow::_FindShortcut(uint32 key, uint32 modifiers)
3031 {
3032 	int32 count = fShortcuts.CountItems();
3033 
3034 	key = Shortcut::PrepareKey(key);
3035 	modifiers = Shortcut::PrepareModifiers(modifiers);
3036 
3037 	for (int32 index = 0; index < count; index++) {
3038 		Shortcut *shortcut = (Shortcut *)fShortcuts.ItemAt(index);
3039 
3040 		if (shortcut->Matches(key, modifiers))
3041 			return shortcut;
3042 	}
3043 
3044 	return NULL;
3045 }
3046 
3047 
3048 BView *
3049 BWindow::_FindView(int32 token)
3050 {
3051 	BHandler* handler;
3052 	if (gDefaultTokens.GetToken(token, B_HANDLER_TOKEN, (void**)&handler) != B_OK)
3053 		return NULL;
3054 
3055 	// the view must belong to us in order to be found by this method
3056 	BView* view = dynamic_cast<BView*>(handler);
3057 	if (view != NULL && view->Window() == this)
3058 		return view;
3059 
3060 	return NULL;
3061 }
3062 
3063 
3064 BView *
3065 BWindow::_FindView(BView *view, BPoint point) const
3066 {
3067 	// TODO: this is totally broken (bounds vs. frame) - since
3068 	//	BView::Bounds() potentially queries the app_server
3069 	//	anyway, we could just let the app_server answer this
3070 	//	query directly.
3071 	if (view->Bounds().Contains(point) && !view->fFirstChild)
3072 		return view;
3073 
3074 	BView *child = view->fFirstChild;
3075 
3076 	while (child != NULL) {
3077 		if ((view = _FindView(child, point)) != NULL)
3078 			return view;
3079 
3080 		child = child->fNextSibling;
3081 	}
3082 
3083 	return NULL;
3084 }
3085 
3086 
3087 BView *
3088 BWindow::_FindNextNavigable(BView* focus, uint32 flags)
3089 {
3090 	if (focus == NULL)
3091 		focus = fTopView;
3092 
3093 	BView* nextFocus = focus;
3094 
3095 	// Search the tree for views that accept focus (depth search)
3096 	while (true) {
3097 		if (nextFocus->fFirstChild)
3098 			nextFocus = nextFocus->fFirstChild;
3099 		else if (nextFocus->fNextSibling)
3100 			nextFocus = nextFocus->fNextSibling;
3101 		else {
3102 			// go to the nearest parent with a next sibling
3103 			while (!nextFocus->fNextSibling && nextFocus->fParent) {
3104 				nextFocus = nextFocus->fParent;
3105 			}
3106 
3107 			if (nextFocus == fTopView) {
3108 				// if we started with the top view, we traversed the whole tree already
3109 				if (nextFocus == focus)
3110 					return NULL;
3111 
3112 				nextFocus = nextFocus->fFirstChild;
3113 			} else
3114 				nextFocus = nextFocus->fNextSibling;
3115 		}
3116 
3117 		if (nextFocus == focus || nextFocus == NULL) {
3118 			// When we get here it means that the hole tree has been
3119 			// searched and there is no view with B_NAVIGABLE(_JUMP) flag set!
3120 			return NULL;
3121 		}
3122 
3123 		if (!nextFocus->IsHidden() && (nextFocus->Flags() & flags) != 0)
3124 			return nextFocus;
3125 	}
3126 }
3127 
3128 
3129 BView *
3130 BWindow::_FindPreviousNavigable(BView* focus, uint32 flags)
3131 {
3132 	if (focus == NULL)
3133 		focus = fTopView;
3134 
3135 	BView* previousFocus = focus;
3136 
3137 	// Search the tree for the previous view that accept focus
3138 	while (true) {
3139 		if (previousFocus->fPreviousSibling) {
3140 			// find the last child in the previous sibling
3141 			previousFocus = _LastViewChild(previousFocus->fPreviousSibling);
3142 		} else {
3143 			previousFocus = previousFocus->fParent;
3144 			if (previousFocus == fTopView)
3145 				previousFocus = _LastViewChild(fTopView);
3146 		}
3147 
3148 		if (previousFocus == focus || previousFocus == NULL) {
3149 			// When we get here it means that the hole tree has been
3150 			// searched and there is no view with B_NAVIGABLE(_JUMP) flag set!
3151 			return NULL;
3152 		}
3153 
3154 		if (!previousFocus->IsHidden() && (previousFocus->Flags() & flags) != 0)
3155 			return previousFocus;
3156 	}
3157 }
3158 
3159 
3160 /*!
3161 	Returns the last child in a view hierarchy.
3162 	Needed only by _FindPreviousNavigable().
3163 */
3164 BView *
3165 BWindow::_LastViewChild(BView *parent)
3166 {
3167 	while (true) {
3168 		BView *last = parent->fFirstChild;
3169 		if (last == NULL)
3170 			return parent;
3171 
3172 		while (last->fNextSibling) {
3173 			last = last->fNextSibling;
3174 		}
3175 
3176 		parent = last;
3177 	}
3178 }
3179 
3180 
3181 void
3182 BWindow::SetIsFilePanel(bool isFilePanel)
3183 {
3184 	fIsFilePanel = isFilePanel;
3185 }
3186 
3187 
3188 bool
3189 BWindow::IsFilePanel() const
3190 {
3191 	return fIsFilePanel;
3192 }
3193 
3194 
3195 //------------------------------------------------------------------------------
3196 // Virtual reserved Functions
3197 
3198 void BWindow::_ReservedWindow1() {}
3199 void BWindow::_ReservedWindow2() {}
3200 void BWindow::_ReservedWindow3() {}
3201 void BWindow::_ReservedWindow4() {}
3202 void BWindow::_ReservedWindow5() {}
3203 void BWindow::_ReservedWindow6() {}
3204 void BWindow::_ReservedWindow7() {}
3205 void BWindow::_ReservedWindow8() {}
3206 
3207 void
3208 BWindow::PrintToStream() const
3209 {
3210 	printf("BWindow '%s' data:\
3211 		Title			= %s\
3212 		Token			= %ld\
3213 		InTransaction 	= %s\
3214 		Active 			= %s\
3215 		fShowLevel		= %d\
3216 		Flags			= %lx\
3217 		send_port		= %ld\
3218 		receive_port	= %ld\
3219 		fTopView name	= %s\
3220 		focus view name	= %s\
3221 		lastMouseMoved	= %s\
3222 		fLink			= %p\
3223 		KeyMenuBar name	= %s\
3224 		DefaultButton	= %s\
3225 		# of shortcuts	= %ld",
3226 		Name(), fTitle,
3227 		_get_object_token_(this),
3228 		fInTransaction == true ? "yes" : "no",
3229 		fActive == true ? "yes" : "no",
3230 		fShowLevel,
3231 		fFlags,
3232 		fLink->SenderPort(),
3233 		fLink->ReceiverPort(),
3234 		fTopView != NULL ? fTopView->Name() : "NULL",
3235 		fFocus != NULL ? fFocus->Name() : "NULL",
3236 		fLastMouseMovedView != NULL ? fLastMouseMovedView->Name() : "NULL",
3237 		fLink,
3238 		fKeyMenuBar != NULL ? fKeyMenuBar->Name() : "NULL",
3239 		fDefaultButton != NULL ? fDefaultButton->Name() : "NULL",
3240 		fShortcuts.CountItems());
3241 /*
3242 	for( int32 i=0; i<accelList.CountItems(); i++){
3243 		_BCmdKey	*key = (_BCmdKey*)accelList.ItemAt(i);
3244 		printf("\tShortCut %ld: char %s\n\t\t message: \n", i, (key->key > 127)?"ASCII":"UNICODE");
3245 		key->message->PrintToStream();
3246 	}
3247 */
3248 	printf("\
3249 		topViewToken	= %ld\
3250 		isFilePanel		= %s\
3251 		MaskActivated	= %s\
3252 		pulseRate		= %lld\
3253 		waitingForMenu	= %s\
3254 		minimized		= %s\
3255 		Menu semaphore	= %ld\
3256 		maxZoomHeight	= %f\
3257 		maxZoomWidth	= %f\
3258 		minWindHeight	= %f\
3259 		minWindWidth	= %f\
3260 		maxWindHeight	= %f\
3261 		maxWindWidth	= %f\
3262 		frame			= ( %f, %f, %f, %f )\
3263 		look			= %d\
3264 		feel			= %d\
3265 		lastViewToken	= %ld\
3266 		pulseRunner		= %s\n",
3267 		fTopViewToken,
3268 		fIsFilePanel==true?"Yes":"No",
3269 		fMaskActivated==true?"Yes":"No",
3270 		fPulseRate,
3271 		fWaitingForMenu==true?"Yes":"No",
3272 		fMinimized==true?"Yes":"No",
3273 		fMenuSem,
3274 		fMaxZoomHeight,
3275 		fMaxZoomWidth,
3276 		fMinHeight,
3277 		fMinWidth,
3278 		fMaxHeight,
3279 		fMaxWidth,
3280 		fFrame.left, fFrame.top, fFrame.right, fFrame.bottom,
3281 		(int16)fLook,
3282 		(int16)fFeel,
3283 		fLastViewToken,
3284 		fPulseRunner != NULL ? "In place" : "NULL");
3285 }
3286 
3287 /*
3288 TODO list:
3289 	*) test arguments for SetWindowAligment
3290 	*) call hook functions: MenusBeginning, MenusEnded. Add menu activation code.
3291 */
3292 
3293