xref: /haiku/src/kits/interface/Window.cpp (revision b08627f310bb2e80bca50176e7a758182384735a)
1 /*
2  * Copyright 2001-2016 Haiku, Inc. All rights reserved
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus, superstippi@gmx.de
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		Adrian Oanca, adioanca@cotty.iren.ro
9  *		John Scipione, jscipione@gmail.com
10  */
11 
12 
13 #include <Window.h>
14 
15 #include <ctype.h>
16 #include <math.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 
20 #include <Application.h>
21 #include <AppMisc.h>
22 #include <AppServerLink.h>
23 #include <ApplicationPrivate.h>
24 #include <Autolock.h>
25 #include <Bitmap.h>
26 #include <Button.h>
27 #include <Deskbar.h>
28 #include <DirectMessageTarget.h>
29 #include <FindDirectory.h>
30 #include <InputServerTypes.h>
31 #include <Layout.h>
32 #include <LayoutUtils.h>
33 #include <MenuBar.h>
34 #include <MenuItem.h>
35 #include <MenuPrivate.h>
36 #include <MessagePrivate.h>
37 #include <MessageQueue.h>
38 #include <MessageRunner.h>
39 #include <Path.h>
40 #include <PortLink.h>
41 #include <PropertyInfo.h>
42 #include <Roster.h>
43 #include <RosterPrivate.h>
44 #include <Screen.h>
45 #include <ServerProtocol.h>
46 #include <String.h>
47 #include <TextView.h>
48 #include <TokenSpace.h>
49 #include <ToolTipManager.h>
50 #include <ToolTipWindow.h>
51 #include <UnicodeChar.h>
52 #include <WindowPrivate.h>
53 
54 #include <binary_compatibility/Interface.h>
55 #include <input_globals.h>
56 #include <tracker_private.h>
57 
58 
59 //#define DEBUG_WIN
60 #ifdef DEBUG_WIN
61 #	define STRACE(x) printf x
62 #else
63 #	define STRACE(x) ;
64 #endif
65 
66 #define B_HIDE_APPLICATION '_AHD'
67 	// if we ever move this to a public namespace, we should also move the
68 	// handling of this message into BApplication
69 
70 #define _MINIMIZE_			'_WMZ'
71 #define _ZOOM_				'_WZO'
72 #define _SEND_BEHIND_		'_WSB'
73 #define _SEND_TO_FRONT_		'_WSF'
74 
75 
76 void do_minimize_team(BRect zoomRect, team_id team, bool zoom);
77 
78 
79 struct BWindow::unpack_cookie {
80 	unpack_cookie();
81 
82 	BMessage*	message;
83 	int32		index;
84 	BHandler*	focus;
85 	int32		focus_token;
86 	int32		last_view_token;
87 	bool		found_focus;
88 	bool		tokens_scanned;
89 };
90 
91 
92 class BWindow::Shortcut {
93 public:
94 							Shortcut(uint32 key, uint32 modifiers,
95 								BMenuItem* item);
96 							Shortcut(uint32 key, uint32 modifiers,
97 								BMessage* message, BHandler* target);
98 							~Shortcut();
99 
100 			bool			Matches(uint32 key, uint32 modifiers) const;
101 
102 			BMenuItem*		MenuItem() const { return fMenuItem; }
103 			BMessage*		Message() const { return fMessage; }
104 			BHandler*		Target() const { return fTarget; }
105 
106 	static	uint32			AllowedModifiers();
107 	static	uint32			PrepareKey(uint32 key);
108 	static	uint32			PrepareModifiers(uint32 modifiers);
109 
110 private:
111 			uint32			fKey;
112 			uint32			fModifiers;
113 			BMenuItem*		fMenuItem;
114 			BMessage*		fMessage;
115 			BHandler*		fTarget;
116 };
117 
118 
119 using BPrivate::gDefaultTokens;
120 using BPrivate::MenuPrivate;
121 
122 static property_info sWindowPropInfo[] = {
123 	{
124 		"Active", { B_GET_PROPERTY, B_SET_PROPERTY },
125 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE }
126 	},
127 
128 	{
129 		"Feel", { B_GET_PROPERTY, B_SET_PROPERTY },
130 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
131 	},
132 
133 	{
134 		"Flags", { B_GET_PROPERTY, B_SET_PROPERTY },
135 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
136 	},
137 
138 	{
139 		"Frame", { B_GET_PROPERTY, B_SET_PROPERTY },
140 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_RECT_TYPE }
141 	},
142 
143 	{
144 		"Hidden", { B_GET_PROPERTY, B_SET_PROPERTY },
145 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE }
146 	},
147 
148 	{
149 		"Look", { B_GET_PROPERTY, B_SET_PROPERTY },
150 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
151 	},
152 
153 	{
154 		"Title", { B_GET_PROPERTY, B_SET_PROPERTY },
155 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_STRING_TYPE }
156 	},
157 
158 	{
159 		"Workspaces", { B_GET_PROPERTY, B_SET_PROPERTY },
160 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
161 	},
162 
163 	{
164 		"MenuBar", {},
165 		{ B_DIRECT_SPECIFIER }, NULL, 0, {}
166 	},
167 
168 	{
169 		"View", { B_COUNT_PROPERTIES },
170 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
171 	},
172 
173 	{
174 		"View", {}, {}, NULL, 0, {}
175 	},
176 
177 	{
178 		"Minimize", { B_GET_PROPERTY, B_SET_PROPERTY },
179 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE }
180 	},
181 
182 	{
183 		"TabFrame", { B_GET_PROPERTY },
184 		{ B_DIRECT_SPECIFIER }, NULL, 0, { B_RECT_TYPE }
185 	},
186 
187 	{ 0 }
188 };
189 
190 static value_info sWindowValueInfo[] = {
191 	{
192 		"MoveTo", 'WDMT', B_COMMAND_KIND,
193 		"Moves to the position in the BPoint data"
194 	},
195 
196 	{
197 		"MoveBy", 'WDMB', B_COMMAND_KIND,
198 		"Moves by the offsets in the BPoint data"
199 	},
200 
201 	{
202 		"ResizeTo", 'WDRT', B_COMMAND_KIND,
203 		"Resize to the size in the BPoint data"
204 	},
205 
206 	{
207 		"ResizeBy", 'WDRB', B_COMMAND_KIND,
208 		"Resize by the offsets in the BPoint data"
209 	},
210 
211 	{ 0 }
212 };
213 
214 
215 void
216 _set_menu_sem_(BWindow* window, sem_id sem)
217 {
218 	if (window != NULL)
219 		window->fMenuSem = sem;
220 }
221 
222 
223 //	#pragma mark -
224 
225 
226 BWindow::unpack_cookie::unpack_cookie()
227 	:
228 	message((BMessage*)~0UL),
229 		// message == NULL is our exit condition
230 	index(0),
231 	focus_token(B_NULL_TOKEN),
232 	last_view_token(B_NULL_TOKEN),
233 	found_focus(false),
234 	tokens_scanned(false)
235 {
236 }
237 
238 
239 //	#pragma mark - BWindow::Shortcut
240 
241 
242 BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item)
243 	:
244 	fKey(PrepareKey(key)),
245 	fModifiers(PrepareModifiers(modifiers)),
246 	fMenuItem(item),
247 	fMessage(NULL),
248 	fTarget(NULL)
249 {
250 }
251 
252 
253 BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMessage* message,
254 	BHandler* target)
255 	:
256 	fKey(PrepareKey(key)),
257 	fModifiers(PrepareModifiers(modifiers)),
258 	fMenuItem(NULL),
259 	fMessage(message),
260 	fTarget(target)
261 {
262 }
263 
264 
265 BWindow::Shortcut::~Shortcut()
266 {
267 	// we own the message, if any
268 	delete fMessage;
269 }
270 
271 
272 bool
273 BWindow::Shortcut::Matches(uint32 key, uint32 modifiers) const
274 {
275 	return fKey == key && fModifiers == modifiers;
276 }
277 
278 
279 /*static*/
280 uint32
281 BWindow::Shortcut::AllowedModifiers()
282 {
283 	return B_COMMAND_KEY | B_OPTION_KEY | B_SHIFT_KEY | B_CONTROL_KEY
284 		| B_MENU_KEY;
285 }
286 
287 
288 /*static*/
289 uint32
290 BWindow::Shortcut::PrepareModifiers(uint32 modifiers)
291 {
292 	return (modifiers & AllowedModifiers()) | B_COMMAND_KEY;
293 }
294 
295 
296 /*static*/
297 uint32
298 BWindow::Shortcut::PrepareKey(uint32 key)
299 {
300 	return BUnicodeChar::ToLower(key);
301 }
302 
303 
304 //	#pragma mark - BWindow
305 
306 
307 BWindow::BWindow(BRect frame, const char* title, window_type type,
308 		uint32 flags, uint32 workspace)
309 	:
310 	BLooper(title, B_DISPLAY_PRIORITY)
311 {
312 	window_look look;
313 	window_feel feel;
314 	_DecomposeType(type, &look, &feel);
315 
316 	_InitData(frame, title, look, feel, flags, workspace);
317 }
318 
319 
320 BWindow::BWindow(BRect frame, const char* title, window_look look,
321 		window_feel feel, uint32 flags, uint32 workspace)
322 	:
323 	BLooper(title, B_DISPLAY_PRIORITY)
324 {
325 	_InitData(frame, title, look, feel, flags, workspace);
326 }
327 
328 
329 BWindow::BWindow(BMessage* data)
330 	:
331 	BLooper(data)
332 {
333 	data->FindRect("_frame", &fFrame);
334 
335 	const char* title;
336 	data->FindString("_title", &title);
337 
338 	window_look look;
339 	data->FindInt32("_wlook", (int32*)&look);
340 
341 	window_feel feel;
342 	data->FindInt32("_wfeel", (int32*)&feel);
343 
344 	if (data->FindInt32("_flags", (int32*)&fFlags) != B_OK)
345 		fFlags = 0;
346 
347 	uint32 workspaces;
348 	data->FindInt32("_wspace", (int32*)&workspaces);
349 
350 	uint32 type;
351 	if (data->FindInt32("_type", (int32*)&type) == B_OK)
352 		_DecomposeType((window_type)type, &fLook, &fFeel);
353 
354 		// connect to app_server and initialize data
355 	_InitData(fFrame, title, look, feel, fFlags, workspaces);
356 
357 	if (data->FindFloat("_zoom", 0, &fMaxZoomWidth) == B_OK
358 		&& data->FindFloat("_zoom", 1, &fMaxZoomHeight) == B_OK)
359 		SetZoomLimits(fMaxZoomWidth, fMaxZoomHeight);
360 
361 	if (data->FindFloat("_sizel", 0, &fMinWidth) == B_OK
362 		&& data->FindFloat("_sizel", 1, &fMinHeight) == B_OK
363 		&& data->FindFloat("_sizel", 2, &fMaxWidth) == B_OK
364 		&& data->FindFloat("_sizel", 3, &fMaxHeight) == B_OK)
365 		SetSizeLimits(fMinWidth, fMaxWidth,
366 			fMinHeight, fMaxHeight);
367 
368 	if (data->FindInt64("_pulse", &fPulseRate) == B_OK)
369 		SetPulseRate(fPulseRate);
370 
371 	BMessage msg;
372 	int32 i = 0;
373 	while (data->FindMessage("_views", i++, &msg) == B_OK) {
374 		BArchivable* obj = instantiate_object(&msg);
375 		if (BView* child = dynamic_cast<BView*>(obj))
376 			AddChild(child);
377 	}
378 }
379 
380 
381 BWindow::BWindow(BRect frame, int32 bitmapToken)
382 	:
383 	BLooper("offscreen bitmap")
384 {
385 	_DecomposeType(B_UNTYPED_WINDOW, &fLook, &fFeel);
386 	_InitData(frame, "offscreen", fLook, fFeel, 0, 0, bitmapToken);
387 }
388 
389 
390 BWindow::~BWindow()
391 {
392 	if (BMenu* menu = dynamic_cast<BMenu*>(fFocus)) {
393 		MenuPrivate(menu).QuitTracking();
394 	}
395 
396 	// The BWindow is locked when the destructor is called,
397 	// we need to unlock because the menubar thread tries
398 	// to post a message, which will deadlock otherwise.
399 	// TODO: I replaced Unlock() with UnlockFully() because the window
400 	// was kept locked after that in case it was closed using ALT-W.
401 	// There might be an extra Lock() somewhere in the quitting path...
402 	UnlockFully();
403 
404 	// Wait if a menu is still tracking
405 	if (fMenuSem > 0) {
406 		while (acquire_sem(fMenuSem) == B_INTERRUPTED)
407 			;
408 	}
409 
410 	Lock();
411 
412 	fTopView->RemoveSelf();
413 	delete fTopView;
414 
415 	// remove all remaining shortcuts
416 	int32 shortCutCount = fShortcuts.CountItems();
417 	for (int32 i = 0; i < shortCutCount; i++) {
418 		delete (Shortcut*)fShortcuts.ItemAtFast(i);
419 	}
420 
421 	// TODO: release other dynamically-allocated objects
422 	free(fTitle);
423 
424 	// disable pulsing
425 	SetPulseRate(0);
426 
427 	// tell app_server about our demise
428 	fLink->StartMessage(AS_DELETE_WINDOW);
429 	// sync with the server so that for example
430 	// a BBitmap can be sure that there are no
431 	// more pending messages that are executed
432 	// after the bitmap is deleted (which uses
433 	// a different link and server side thread)
434 	int32 code;
435 	fLink->FlushWithReply(code);
436 
437 	// the sender port belongs to the app_server
438 	delete_port(fLink->ReceiverPort());
439 	delete fLink;
440 }
441 
442 
443 BArchivable*
444 BWindow::Instantiate(BMessage* data)
445 {
446 	if (!validate_instantiation(data, "BWindow"))
447 		return NULL;
448 
449 	return new(std::nothrow) BWindow(data);
450 }
451 
452 
453 status_t
454 BWindow::Archive(BMessage* data, bool deep) const
455 {
456 	status_t ret = BLooper::Archive(data, deep);
457 
458 	if (ret == B_OK)
459 		ret = data->AddRect("_frame", fFrame);
460 	if (ret == B_OK)
461 		ret = data->AddString("_title", fTitle);
462 	if (ret == B_OK)
463 		ret = data->AddInt32("_wlook", fLook);
464 	if (ret == B_OK)
465 		ret = data->AddInt32("_wfeel", fFeel);
466 	if (ret == B_OK && fFlags != 0)
467 		ret = data->AddInt32("_flags", fFlags);
468 	if (ret == B_OK)
469 		ret = data->AddInt32("_wspace", (uint32)Workspaces());
470 
471 	if (ret == B_OK && !_ComposeType(fLook, fFeel))
472 		ret = data->AddInt32("_type", (uint32)Type());
473 
474 	if (fMaxZoomWidth != 32768.0 || fMaxZoomHeight != 32768.0) {
475 		if (ret == B_OK)
476 			ret = data->AddFloat("_zoom", fMaxZoomWidth);
477 		if (ret == B_OK)
478 			ret = data->AddFloat("_zoom", fMaxZoomHeight);
479 	}
480 
481 	if (fMinWidth != 0.0 || fMinHeight != 0.0
482 		|| fMaxWidth != 32768.0 || fMaxHeight != 32768.0) {
483 		if (ret == B_OK)
484 			ret = data->AddFloat("_sizel", fMinWidth);
485 		if (ret == B_OK)
486 			ret = data->AddFloat("_sizel", fMinHeight);
487 		if (ret == B_OK)
488 			ret = data->AddFloat("_sizel", fMaxWidth);
489 		if (ret == B_OK)
490 			ret = data->AddFloat("_sizel", fMaxHeight);
491 	}
492 
493 	if (ret == B_OK && fPulseRate != 500000)
494 		data->AddInt64("_pulse", fPulseRate);
495 
496 	if (ret == B_OK && deep) {
497 		int32 noOfViews = CountChildren();
498 		for (int32 i = 0; i < noOfViews; i++){
499 			BMessage childArchive;
500 			ret = ChildAt(i)->Archive(&childArchive, true);
501 			if (ret == B_OK)
502 				ret = data->AddMessage("_views", &childArchive);
503 			if (ret != B_OK)
504 				break;
505 		}
506 	}
507 
508 	return ret;
509 }
510 
511 
512 void
513 BWindow::Quit()
514 {
515 	if (!IsLocked()) {
516 		const char* name = Name();
517 		if (name == NULL)
518 			name = "no-name";
519 
520 		printf("ERROR - you must Lock a looper before calling Quit(), "
521 			   "team=%" B_PRId32 ", looper=%s\n", Team(), name);
522 	}
523 
524 	// Try to lock
525 	if (!Lock()){
526 		// We're toast already
527 		return;
528 	}
529 
530 	while (!IsHidden())	{
531 		Hide();
532 	}
533 
534 	if (fFlags & B_QUIT_ON_WINDOW_CLOSE)
535 		be_app->PostMessage(B_QUIT_REQUESTED);
536 
537 	BLooper::Quit();
538 }
539 
540 
541 void
542 BWindow::AddChild(BView* child, BView* before)
543 {
544 	BAutolock locker(this);
545 	if (locker.IsLocked())
546 		fTopView->AddChild(child, before);
547 }
548 
549 
550 void
551 BWindow::AddChild(BLayoutItem* child)
552 {
553 	BAutolock locker(this);
554 	if (locker.IsLocked())
555 		fTopView->AddChild(child);
556 }
557 
558 
559 bool
560 BWindow::RemoveChild(BView* child)
561 {
562 	BAutolock locker(this);
563 	if (!locker.IsLocked())
564 		return false;
565 
566 	return fTopView->RemoveChild(child);
567 }
568 
569 
570 int32
571 BWindow::CountChildren() const
572 {
573 	BAutolock locker(const_cast<BWindow*>(this));
574 	if (!locker.IsLocked())
575 		return 0;
576 
577 	return fTopView->CountChildren();
578 }
579 
580 
581 BView*
582 BWindow::ChildAt(int32 index) const
583 {
584 	BAutolock locker(const_cast<BWindow*>(this));
585 	if (!locker.IsLocked())
586 		return NULL;
587 
588 	return fTopView->ChildAt(index);
589 }
590 
591 
592 void
593 BWindow::Minimize(bool minimize)
594 {
595 	if (IsModal() || IsFloating() || IsHidden() || fMinimized == minimize
596 		|| !Lock())
597 		return;
598 
599 	fMinimized = minimize;
600 
601 	fLink->StartMessage(AS_MINIMIZE_WINDOW);
602 	fLink->Attach<bool>(minimize);
603 	fLink->Flush();
604 
605 	Unlock();
606 }
607 
608 
609 status_t
610 BWindow::SendBehind(const BWindow* window)
611 {
612 	if (!Lock())
613 		return B_ERROR;
614 
615 	fLink->StartMessage(AS_SEND_BEHIND);
616 	fLink->Attach<int32>(window != NULL ? _get_object_token_(window) : -1);
617 	fLink->Attach<team_id>(Team());
618 
619 	status_t status = B_ERROR;
620 	fLink->FlushWithReply(status);
621 
622 	Unlock();
623 
624 	return status;
625 }
626 
627 
628 void
629 BWindow::Flush() const
630 {
631 	if (const_cast<BWindow*>(this)->Lock()) {
632 		fLink->Flush();
633 		const_cast<BWindow*>(this)->Unlock();
634 	}
635 }
636 
637 
638 void
639 BWindow::Sync() const
640 {
641 	if (!const_cast<BWindow*>(this)->Lock())
642 		return;
643 
644 	fLink->StartMessage(AS_SYNC);
645 
646 	// waiting for the reply is the actual syncing
647 	int32 code;
648 	fLink->FlushWithReply(code);
649 
650 	const_cast<BWindow*>(this)->Unlock();
651 }
652 
653 
654 void
655 BWindow::DisableUpdates()
656 {
657 	if (Lock()) {
658 		fLink->StartMessage(AS_DISABLE_UPDATES);
659 		fLink->Flush();
660 		Unlock();
661 	}
662 }
663 
664 
665 void
666 BWindow::EnableUpdates()
667 {
668 	if (Lock()) {
669 		fLink->StartMessage(AS_ENABLE_UPDATES);
670 		fLink->Flush();
671 		Unlock();
672 	}
673 }
674 
675 
676 void
677 BWindow::BeginViewTransaction()
678 {
679 	if (Lock()) {
680 		fInTransaction = true;
681 		Unlock();
682 	}
683 }
684 
685 
686 void
687 BWindow::EndViewTransaction()
688 {
689 	if (Lock()) {
690 		if (fInTransaction)
691 			fLink->Flush();
692 		fInTransaction = false;
693 		Unlock();
694 	}
695 }
696 
697 
698 bool
699 BWindow::InViewTransaction() const
700 {
701 	BAutolock locker(const_cast<BWindow*>(this));
702 	return fInTransaction;
703 }
704 
705 
706 bool
707 BWindow::IsFront() const
708 {
709 	BAutolock locker(const_cast<BWindow*>(this));
710 	if (!locker.IsLocked())
711 		return false;
712 
713 	fLink->StartMessage(AS_IS_FRONT_WINDOW);
714 
715 	status_t status;
716 	if (fLink->FlushWithReply(status) == B_OK)
717 		return status >= B_OK;
718 
719 	return false;
720 }
721 
722 
723 void
724 BWindow::MessageReceived(BMessage* message)
725 {
726 	if (!message->HasSpecifiers()) {
727 		if (message->what == B_KEY_DOWN)
728 			_KeyboardNavigation();
729 
730 		if (message->what == (int32)kMsgAppServerRestarted) {
731 			fLink->SetSenderPort(
732 				BApplication::Private::ServerLink()->SenderPort());
733 
734 			BPrivate::AppServerLink lockLink;
735 				// we're talking to the server application using our own
736 				// communication channel (fLink) - we better make sure no one
737 				// interferes by locking that channel (which AppServerLink does
738 				// implicitly)
739 
740 			fLink->StartMessage(AS_CREATE_WINDOW);
741 
742 			fLink->Attach<BRect>(fFrame);
743 			fLink->Attach<uint32>((uint32)fLook);
744 			fLink->Attach<uint32>((uint32)fFeel);
745 			fLink->Attach<uint32>(fFlags);
746 			fLink->Attach<uint32>(0);
747 			fLink->Attach<int32>(_get_object_token_(this));
748 			fLink->Attach<port_id>(fLink->ReceiverPort());
749 			fLink->Attach<port_id>(fMsgPort);
750 			fLink->AttachString(fTitle);
751 
752 			port_id sendPort;
753 			int32 code;
754 			if (fLink->FlushWithReply(code) == B_OK
755 				&& code == B_OK
756 				&& fLink->Read<port_id>(&sendPort) == B_OK) {
757 				// read the frame size and its limits that were really
758 				// enforced on the server side
759 
760 				fLink->Read<BRect>(&fFrame);
761 				fLink->Read<float>(&fMinWidth);
762 				fLink->Read<float>(&fMaxWidth);
763 				fLink->Read<float>(&fMinHeight);
764 				fLink->Read<float>(&fMaxHeight);
765 
766 				fMaxZoomWidth = fMaxWidth;
767 				fMaxZoomHeight = fMaxHeight;
768 			} else
769 				sendPort = -1;
770 
771 			// Redirect our link to the new window connection
772 			fLink->SetSenderPort(sendPort);
773 
774 			// connect all views to the server again
775 			fTopView->_CreateSelf();
776 
777 			_SendShowOrHideMessage();
778 		}
779 
780 		return BLooper::MessageReceived(message);
781 	}
782 
783 	BMessage replyMsg(B_REPLY);
784 	bool handled = false;
785 
786 	BMessage specifier;
787 	int32 what;
788 	const char* prop;
789 	int32 index;
790 
791 	if (message->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK)
792 		return BLooper::MessageReceived(message);
793 
794 	BPropertyInfo propertyInfo(sWindowPropInfo);
795 	switch (propertyInfo.FindMatch(message, index, &specifier, what, prop)) {
796 		case 0:
797 			if (message->what == B_GET_PROPERTY) {
798 				replyMsg.AddBool("result", IsActive());
799 				handled = true;
800 			} else if (message->what == B_SET_PROPERTY) {
801 				bool newActive;
802 				if (message->FindBool("data", &newActive) == B_OK) {
803 					Activate(newActive);
804 					handled = true;
805 				}
806 			}
807 			break;
808 		case 1:
809 			if (message->what == B_GET_PROPERTY) {
810 				replyMsg.AddInt32("result", (uint32)Feel());
811 				handled = true;
812 			} else {
813 				uint32 newFeel;
814 				if (message->FindInt32("data", (int32*)&newFeel) == B_OK) {
815 					SetFeel((window_feel)newFeel);
816 					handled = true;
817 				}
818 			}
819 			break;
820 		case 2:
821 			if (message->what == B_GET_PROPERTY) {
822 				replyMsg.AddInt32("result", Flags());
823 				handled = true;
824 			} else {
825 				uint32 newFlags;
826 				if (message->FindInt32("data", (int32*)&newFlags) == B_OK) {
827 					SetFlags(newFlags);
828 					handled = true;
829 				}
830 			}
831 			break;
832 		case 3:
833 			if (message->what == B_GET_PROPERTY) {
834 				replyMsg.AddRect("result", Frame());
835 				handled = true;
836 			} else {
837 				BRect newFrame;
838 				if (message->FindRect("data", &newFrame) == B_OK) {
839 					MoveTo(newFrame.LeftTop());
840 					ResizeTo(newFrame.Width(), newFrame.Height());
841 					handled = true;
842 				}
843 			}
844 			break;
845 		case 4:
846 			if (message->what == B_GET_PROPERTY) {
847 				replyMsg.AddBool("result", IsHidden());
848 				handled = true;
849 			} else {
850 				bool hide;
851 				if (message->FindBool("data", &hide) == B_OK) {
852 					if (hide) {
853 						if (!IsHidden())
854 							Hide();
855 					} else if (IsHidden())
856 						Show();
857 					handled = true;
858 				}
859 			}
860 			break;
861 		case 5:
862 			if (message->what == B_GET_PROPERTY) {
863 				replyMsg.AddInt32("result", (uint32)Look());
864 				handled = true;
865 			} else {
866 				uint32 newLook;
867 				if (message->FindInt32("data", (int32*)&newLook) == B_OK) {
868 					SetLook((window_look)newLook);
869 					handled = true;
870 				}
871 			}
872 			break;
873 		case 6:
874 			if (message->what == B_GET_PROPERTY) {
875 				replyMsg.AddString("result", Title());
876 				handled = true;
877 			} else {
878 				const char* newTitle = NULL;
879 				if (message->FindString("data", &newTitle) == B_OK) {
880 					SetTitle(newTitle);
881 					handled = true;
882 				}
883 			}
884 			break;
885 		case 7:
886 			if (message->what == B_GET_PROPERTY) {
887 				replyMsg.AddInt32( "result", Workspaces());
888 				handled = true;
889 			} else {
890 				uint32 newWorkspaces;
891 				if (message->FindInt32("data", (int32*)&newWorkspaces) == B_OK) {
892 					SetWorkspaces(newWorkspaces);
893 					handled = true;
894 				}
895 			}
896 			break;
897 		case 11:
898 			if (message->what == B_GET_PROPERTY) {
899 				replyMsg.AddBool("result", IsMinimized());
900 				handled = true;
901 			} else {
902 				bool minimize;
903 				if (message->FindBool("data", &minimize) == B_OK) {
904 					Minimize(minimize);
905 					handled = true;
906 				}
907 			}
908 			break;
909 		case 12:
910 			if (message->what == B_GET_PROPERTY) {
911 				BMessage settings;
912 				if (GetDecoratorSettings(&settings) == B_OK) {
913 					BRect frame;
914 					if (settings.FindRect("tab frame", &frame) == B_OK) {
915 						replyMsg.AddRect("result", frame);
916 						handled = true;
917 					}
918 				}
919 			}
920 			break;
921 		default:
922 			return BLooper::MessageReceived(message);
923 	}
924 
925 	if (handled) {
926 		if (message->what == B_SET_PROPERTY)
927 			replyMsg.AddInt32("error", B_OK);
928 	} else {
929 		replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
930 		replyMsg.AddInt32("error", B_BAD_SCRIPT_SYNTAX);
931 		replyMsg.AddString("message", "Didn't understand the specifier(s)");
932 	}
933 	message->SendReply(&replyMsg);
934 }
935 
936 
937 void
938 BWindow::DispatchMessage(BMessage* message, BHandler* target)
939 {
940 	if (message == NULL)
941 		return;
942 
943 	switch (message->what) {
944 		case B_ZOOM:
945 			Zoom();
946 			break;
947 
948 		case _MINIMIZE_:
949 			// Used by the minimize shortcut
950 			if ((Flags() & B_NOT_MINIMIZABLE) == 0)
951 				Minimize(true);
952 			break;
953 
954 		case _ZOOM_:
955 			// Used by the zoom shortcut
956 			if ((Flags() & B_NOT_ZOOMABLE) == 0)
957 				Zoom();
958 			break;
959 
960 		case _SEND_BEHIND_:
961 			SendBehind(NULL);
962 			break;
963 
964 		case _SEND_TO_FRONT_:
965 			Activate();
966 			break;
967 
968 		case B_MINIMIZE:
969 		{
970 			bool minimize;
971 			if (message->FindBool("minimize", &minimize) == B_OK)
972 				Minimize(minimize);
973 			break;
974 		}
975 
976 		case B_HIDE_APPLICATION:
977 		{
978 			// Hide all applications with the same signature
979 			// (ie. those that are part of the same group to be consistent
980 			// to what the Deskbar shows you).
981 			app_info info;
982 			be_app->GetAppInfo(&info);
983 
984 			BList list;
985 			be_roster->GetAppList(info.signature, &list);
986 
987 			for (int32 i = 0; i < list.CountItems(); i++) {
988 				do_minimize_team(BRect(), (team_id)(addr_t)list.ItemAt(i),
989 					false);
990 			}
991 			break;
992 		}
993 
994 		case B_WINDOW_RESIZED:
995 		{
996 			int32 width, height;
997 			if (message->FindInt32("width", &width) == B_OK
998 				&& message->FindInt32("height", &height) == B_OK) {
999 				// combine with pending resize notifications
1000 				BMessage* pendingMessage;
1001 				while ((pendingMessage
1002 						= MessageQueue()->FindMessage(B_WINDOW_RESIZED, 0))) {
1003 					int32 nextWidth;
1004 					if (pendingMessage->FindInt32("width", &nextWidth) == B_OK)
1005 						width = nextWidth;
1006 
1007 					int32 nextHeight;
1008 					if (pendingMessage->FindInt32("height", &nextHeight)
1009 							== B_OK) {
1010 						height = nextHeight;
1011 					}
1012 
1013 					MessageQueue()->RemoveMessage(pendingMessage);
1014 					delete pendingMessage;
1015 						// this deletes the first *additional* message
1016 						// fCurrentMessage is safe
1017 				}
1018 				if (width != fFrame.Width() || height != fFrame.Height()) {
1019 					// NOTE: we might have already handled the resize
1020 					// in an _UPDATE_ message
1021 					fFrame.right = fFrame.left + width;
1022 					fFrame.bottom = fFrame.top + height;
1023 
1024 					_AdoptResize();
1025 //					FrameResized(width, height);
1026 				}
1027 // call hook function anyways
1028 // TODO: When a window is resized programmatically,
1029 // it receives this message, and maybe it is wise to
1030 // keep the asynchronous nature of this process to
1031 // not risk breaking any apps.
1032 FrameResized(width, height);
1033 			}
1034 			break;
1035 		}
1036 
1037 		case B_WINDOW_MOVED:
1038 		{
1039 			BPoint origin;
1040 			if (message->FindPoint("where", &origin) == B_OK) {
1041 				if (fFrame.LeftTop() != origin) {
1042 					// NOTE: we might have already handled the move
1043 					// in an _UPDATE_ message
1044 					fFrame.OffsetTo(origin);
1045 
1046 //					FrameMoved(origin);
1047 				}
1048 // call hook function anyways
1049 // TODO: When a window is moved programmatically,
1050 // it receives this message, and maybe it is wise to
1051 // keep the asynchronous nature of this process to
1052 // not risk breaking any apps.
1053 FrameMoved(origin);
1054 			}
1055 			break;
1056 		}
1057 
1058 		case B_WINDOW_ACTIVATED:
1059 			if (target != this) {
1060 				target->MessageReceived(message);
1061 				break;
1062 			}
1063 
1064 			bool active;
1065 			if (message->FindBool("active", &active) != B_OK)
1066 				break;
1067 
1068 			// find latest activation message
1069 
1070 			while (true) {
1071 				BMessage* pendingMessage = MessageQueue()->FindMessage(
1072 					B_WINDOW_ACTIVATED, 0);
1073 				if (pendingMessage == NULL)
1074 					break;
1075 
1076 				bool nextActive;
1077 				if (pendingMessage->FindBool("active", &nextActive) == B_OK)
1078 					active = nextActive;
1079 
1080 				MessageQueue()->RemoveMessage(pendingMessage);
1081 				delete pendingMessage;
1082 			}
1083 
1084 			if (active != fActive) {
1085 				fActive = active;
1086 
1087 				WindowActivated(active);
1088 
1089 				// call hook function 'WindowActivated(bool)' for all
1090 				// views attached to this window.
1091 				fTopView->_Activate(active);
1092 
1093 				// we notify the input server if we are gaining or losing focus
1094 				// from a view which has the B_INPUT_METHOD_AWARE on a window
1095 				// activation
1096 				if (!active)
1097 					break;
1098 				bool inputMethodAware = false;
1099 				if (fFocus)
1100 					inputMethodAware = fFocus->Flags() & B_INPUT_METHOD_AWARE;
1101 				BMessage message(inputMethodAware ? IS_FOCUS_IM_AWARE_VIEW : IS_UNFOCUS_IM_AWARE_VIEW);
1102 				BMessenger messenger(fFocus);
1103 				BMessage reply;
1104 				if (fFocus)
1105 					message.AddMessenger("view", messenger);
1106 				_control_input_server_(&message, &reply);
1107 			}
1108 			break;
1109 
1110 		case B_SCREEN_CHANGED:
1111 			if (target == this) {
1112 				BRect frame;
1113 				uint32 mode;
1114 				if (message->FindRect("frame", &frame) == B_OK
1115 					&& message->FindInt32("mode", (int32*)&mode) == B_OK) {
1116 					// propegate message to child views
1117 					int32 childCount = CountChildren();
1118 					for (int32 i = 0; i < childCount; i++) {
1119 						BView* view = ChildAt(i);
1120 						if (view != NULL)
1121 							view->MessageReceived(message);
1122 					}
1123 					// call hook method
1124 					ScreenChanged(frame, (color_space)mode);
1125 				}
1126 			} else
1127 				target->MessageReceived(message);
1128 			break;
1129 
1130 		case B_WORKSPACE_ACTIVATED:
1131 			if (target == this) {
1132 				uint32 workspace;
1133 				bool active;
1134 				if (message->FindInt32("workspace", (int32*)&workspace) == B_OK
1135 					&& message->FindBool("active", &active) == B_OK)
1136 					WorkspaceActivated(workspace, active);
1137 			} else
1138 				target->MessageReceived(message);
1139 			break;
1140 
1141 		case B_WORKSPACES_CHANGED:
1142 			if (target == this) {
1143 				uint32 oldWorkspace, newWorkspace;
1144 				if (message->FindInt32("old", (int32*)&oldWorkspace) == B_OK
1145 					&& message->FindInt32("new", (int32*)&newWorkspace) == B_OK)
1146 					WorkspacesChanged(oldWorkspace, newWorkspace);
1147 			} else
1148 				target->MessageReceived(message);
1149 			break;
1150 
1151 		case B_INVALIDATE:
1152 		{
1153 			if (BView* view = dynamic_cast<BView*>(target)) {
1154 				BRect rect;
1155 				if (message->FindRect("be:area", &rect) == B_OK)
1156 					view->Invalidate(rect);
1157 				else
1158 					view->Invalidate();
1159 			} else
1160 				target->MessageReceived(message);
1161 			break;
1162 		}
1163 
1164 		case B_KEY_DOWN:
1165 		{
1166 			if (!_HandleKeyDown(message)) {
1167 				if (BView* view = dynamic_cast<BView*>(target)) {
1168 					// TODO: cannot use "string" here if we support having
1169 					// different font encoding per view (it's supposed to be
1170 					// converted by _HandleKeyDown() one day)
1171 					const char* string;
1172 					ssize_t bytes;
1173 					if (message->FindData("bytes", B_STRING_TYPE,
1174 						(const void**)&string, &bytes) == B_OK) {
1175 						view->KeyDown(string, bytes - 1);
1176 					}
1177 				} else
1178 					target->MessageReceived(message);
1179 			}
1180 			break;
1181 		}
1182 
1183 		case B_KEY_UP:
1184 		{
1185 			// TODO: same as above
1186 			if (BView* view = dynamic_cast<BView*>(target)) {
1187 				const char* string;
1188 				ssize_t bytes;
1189 				if (message->FindData("bytes", B_STRING_TYPE,
1190 					(const void**)&string, &bytes) == B_OK) {
1191 					view->KeyUp(string, bytes - 1);
1192 				}
1193 			} else
1194 				target->MessageReceived(message);
1195 			break;
1196 		}
1197 
1198 		case B_UNMAPPED_KEY_DOWN:
1199 		{
1200 			if (!_HandleUnmappedKeyDown(message))
1201 				target->MessageReceived(message);
1202 			break;
1203 		}
1204 
1205 		case B_MOUSE_DOWN:
1206 		{
1207 			BView* view = dynamic_cast<BView*>(target);
1208 
1209 			if (view != NULL) {
1210 				BPoint where;
1211 				message->FindPoint("be:view_where", &where);
1212 				view->MouseDown(where);
1213 			} else
1214 				target->MessageReceived(message);
1215 
1216 			break;
1217 		}
1218 
1219 		case B_MOUSE_UP:
1220 		{
1221 			if (BView* view = dynamic_cast<BView*>(target)) {
1222 				BPoint where;
1223 				message->FindPoint("be:view_where", &where);
1224 				view->fMouseEventOptions = 0;
1225 				view->MouseUp(where);
1226 			} else
1227 				target->MessageReceived(message);
1228 
1229 			break;
1230 		}
1231 
1232 		case B_MOUSE_MOVED:
1233 		{
1234 			if (BView* view = dynamic_cast<BView*>(target)) {
1235 				uint32 eventOptions = view->fEventOptions
1236 					| view->fMouseEventOptions;
1237 				bool noHistory = eventOptions & B_NO_POINTER_HISTORY;
1238 				bool dropIfLate = !(eventOptions & B_FULL_POINTER_HISTORY);
1239 
1240 				bigtime_t eventTime;
1241 				if (message->FindInt64("when", (int64*)&eventTime) < B_OK)
1242 					eventTime = system_time();
1243 
1244 				uint32 transit;
1245 				message->FindInt32("be:transit", (int32*)&transit);
1246 				// don't drop late messages with these important transit values
1247 				if (transit == B_ENTERED_VIEW || transit == B_EXITED_VIEW)
1248 					dropIfLate = false;
1249 
1250 				// TODO: The dropping code may have the following problem:
1251 				// On slower computers, 20ms may just be to abitious a delay.
1252 				// There, we might constantly check the message queue for a
1253 				// newer message, not find any, and still use the only but
1254 				// later than 20ms message, which of course makes the whole
1255 				// thing later than need be. An adaptive delay would be
1256 				// kind of neat, but would probably use additional BWindow
1257 				// members to count the successful versus fruitless queue
1258 				// searches and the delay value itself or something similar.
1259 
1260 				if (noHistory
1261 					|| (dropIfLate && (system_time() - eventTime > 20000))) {
1262 					// filter out older mouse moved messages in the queue
1263 					_DequeueAll();
1264 					BMessageQueue* queue = MessageQueue();
1265 					queue->Lock();
1266 
1267 					BMessage* moved;
1268 					for (int32 i = 0; (moved = queue->FindMessage(i)) != NULL;
1269 							i++) {
1270 						if (moved != message && moved->what == B_MOUSE_MOVED) {
1271 							// there is a newer mouse moved message in the
1272 							// queue, just ignore the current one, the newer one
1273 							// will be handled here eventually
1274 							queue->Unlock();
1275 							return;
1276 						}
1277 					}
1278 					queue->Unlock();
1279 				}
1280 
1281 				BPoint where;
1282 				uint32 buttons;
1283 				message->FindPoint("be:view_where", &where);
1284 				message->FindInt32("buttons", (int32*)&buttons);
1285 
1286 				if (transit == B_EXITED_VIEW || transit == B_OUTSIDE_VIEW) {
1287 					if (dynamic_cast<BPrivate::ToolTipWindow*>(this) == NULL)
1288 						BToolTipManager::Manager()->HideTip();
1289 				}
1290 
1291 				BMessage* dragMessage = NULL;
1292 				if (message->HasMessage("be:drag_message")) {
1293 					dragMessage = new BMessage();
1294 					if (message->FindMessage("be:drag_message", dragMessage)
1295 							!= B_OK) {
1296 						delete dragMessage;
1297 						dragMessage = NULL;
1298 					}
1299 				}
1300 
1301 				view->MouseMoved(where, transit, dragMessage);
1302 				delete dragMessage;
1303 			} else
1304 				target->MessageReceived(message);
1305 
1306 			break;
1307 		}
1308 
1309 		case B_PULSE:
1310 			if (target == this && fPulseRunner) {
1311 				fTopView->_Pulse();
1312 				fLink->Flush();
1313 			} else
1314 				target->MessageReceived(message);
1315 			break;
1316 
1317 		case _UPDATE_:
1318 		{
1319 //bigtime_t now = system_time();
1320 //bigtime_t drawTime = 0;
1321 			STRACE(("info:BWindow handling _UPDATE_.\n"));
1322 
1323 			fLink->StartMessage(AS_BEGIN_UPDATE);
1324 			fInTransaction = true;
1325 
1326 			int32 code;
1327 			if (fLink->FlushWithReply(code) == B_OK
1328 				&& code == B_OK) {
1329 				// read current window position and size first,
1330 				// the update rect is in screen coordinates...
1331 				// so we need to be up to date
1332 				BPoint origin;
1333 				fLink->Read<BPoint>(&origin);
1334 				float width;
1335 				float height;
1336 				fLink->Read<float>(&width);
1337 				fLink->Read<float>(&height);
1338 				if (origin != fFrame.LeftTop()) {
1339 					// TODO: remove code duplicatation with
1340 					// B_WINDOW_MOVED case...
1341 					//printf("window position was not up to date\n");
1342 					fFrame.OffsetTo(origin);
1343 					FrameMoved(origin);
1344 				}
1345 				if (width != fFrame.Width() || height != fFrame.Height()) {
1346 					// TODO: remove code duplicatation with
1347 					// B_WINDOW_RESIZED case...
1348 					//printf("window size was not up to date\n");
1349 					fFrame.right = fFrame.left + width;
1350 					fFrame.bottom = fFrame.top + height;
1351 
1352 					_AdoptResize();
1353 					FrameResized(width, height);
1354 				}
1355 
1356 				// read tokens for views that need to be drawn
1357 				// NOTE: we need to read the tokens completely
1358 				// first, we cannot draw views in between reading
1359 				// the tokens, since other communication would likely
1360 				// mess up the data in the link.
1361 				struct ViewUpdateInfo {
1362 					int32 token;
1363 					BRect updateRect;
1364 				};
1365 				BList infos(20);
1366 				while (true) {
1367 					// read next token and create/add ViewUpdateInfo
1368 					int32 token;
1369 					status_t error = fLink->Read<int32>(&token);
1370 					if (error < B_OK || token == B_NULL_TOKEN)
1371 						break;
1372 					ViewUpdateInfo* info = new(std::nothrow) ViewUpdateInfo;
1373 					if (info == NULL || !infos.AddItem(info)) {
1374 						delete info;
1375 						break;
1376 					}
1377 					info->token = token;
1378 					// read culmulated update rect (is in screen coords)
1379 					error = fLink->Read<BRect>(&(info->updateRect));
1380 					if (error < B_OK)
1381 						break;
1382 				}
1383 				// draw
1384 				int32 count = infos.CountItems();
1385 				for (int32 i = 0; i < count; i++) {
1386 //bigtime_t drawStart = system_time();
1387 					ViewUpdateInfo* info
1388 						= (ViewUpdateInfo*)infos.ItemAtFast(i);
1389 					if (BView* view = _FindView(info->token))
1390 						view->_Draw(info->updateRect);
1391 					else {
1392 						printf("_UPDATE_ - didn't find view by token: %"
1393 							B_PRId32 "\n", info->token);
1394 					}
1395 //drawTime += system_time() - drawStart;
1396 				}
1397 				// NOTE: The tokens are actually hirachically sorted,
1398 				// so traversing the list in revers and calling
1399 				// child->_DrawAfterChildren() actually works like intended.
1400 				for (int32 i = count - 1; i >= 0; i--) {
1401 					ViewUpdateInfo* info
1402 						= (ViewUpdateInfo*)infos.ItemAtFast(i);
1403 					if (BView* view = _FindView(info->token))
1404 						view->_DrawAfterChildren(info->updateRect);
1405 					delete info;
1406 				}
1407 
1408 //printf("  %ld views drawn, total Draw() time: %lld\n", count, drawTime);
1409 			}
1410 
1411 			fLink->StartMessage(AS_END_UPDATE);
1412 			fLink->Flush();
1413 			fInTransaction = false;
1414 			fUpdateRequested = false;
1415 
1416 //printf("BWindow(%s) - UPDATE took %lld usecs\n", Title(), system_time() - now);
1417 			break;
1418 		}
1419 
1420 		case _MENUS_DONE_:
1421 			MenusEnded();
1422 			break;
1423 
1424 		// These two are obviously some kind of old scripting messages
1425 		// this is NOT an app_server message and we have to be cautious
1426 		case B_WINDOW_MOVE_BY:
1427 		{
1428 			BPoint offset;
1429 			if (message->FindPoint("data", &offset) == B_OK)
1430 				MoveBy(offset.x, offset.y);
1431 			else
1432 				message->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
1433 			break;
1434 		}
1435 
1436 		// this is NOT an app_server message and we have to be cautious
1437 		case B_WINDOW_MOVE_TO:
1438 		{
1439 			BPoint origin;
1440 			if (message->FindPoint("data", &origin) == B_OK)
1441 				MoveTo(origin);
1442 			else
1443 				message->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
1444 			break;
1445 		}
1446 
1447 		case B_LAYOUT_WINDOW:
1448 		{
1449 			Layout(false);
1450 			break;
1451 		}
1452 
1453 		case B_COLORS_UPDATED:
1454 		{
1455 			fTopView->_ColorsUpdated(message);
1456 			target->MessageReceived(message);
1457 			break;
1458 		}
1459 
1460 		case B_FONTS_UPDATED:
1461 		{
1462 			fTopView->_FontsUpdated(message);
1463 			target->MessageReceived(message);
1464 			break;
1465 		}
1466 
1467 		default:
1468 			BLooper::DispatchMessage(message, target);
1469 			break;
1470 	}
1471 }
1472 
1473 
1474 void
1475 BWindow::FrameMoved(BPoint newPosition)
1476 {
1477 	// does nothing
1478 	// Hook function
1479 }
1480 
1481 
1482 void
1483 BWindow::FrameResized(float newWidth, float newHeight)
1484 {
1485 	// does nothing
1486 	// Hook function
1487 }
1488 
1489 
1490 void
1491 BWindow::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces)
1492 {
1493 	// does nothing
1494 	// Hook function
1495 }
1496 
1497 
1498 void
1499 BWindow::WorkspaceActivated(int32 workspace, bool state)
1500 {
1501 	// does nothing
1502 	// Hook function
1503 }
1504 
1505 
1506 void
1507 BWindow::MenusBeginning()
1508 {
1509 	// does nothing
1510 	// Hook function
1511 }
1512 
1513 
1514 void
1515 BWindow::MenusEnded()
1516 {
1517 	// does nothing
1518 	// Hook function
1519 }
1520 
1521 
1522 void
1523 BWindow::SetSizeLimits(float minWidth, float maxWidth,
1524 	float minHeight, float maxHeight)
1525 {
1526 	if (minWidth > maxWidth || minHeight > maxHeight)
1527 		return;
1528 
1529 	if (!Lock())
1530 		return;
1531 
1532 	fLink->StartMessage(AS_SET_SIZE_LIMITS);
1533 	fLink->Attach<float>(minWidth);
1534 	fLink->Attach<float>(maxWidth);
1535 	fLink->Attach<float>(minHeight);
1536 	fLink->Attach<float>(maxHeight);
1537 
1538 	int32 code;
1539 	if (fLink->FlushWithReply(code) == B_OK
1540 		&& code == B_OK) {
1541 		// read the values that were really enforced on
1542 		// the server side (the window frame could have
1543 		// been changed, too)
1544 		fLink->Read<BRect>(&fFrame);
1545 		fLink->Read<float>(&fMinWidth);
1546 		fLink->Read<float>(&fMaxWidth);
1547 		fLink->Read<float>(&fMinHeight);
1548 		fLink->Read<float>(&fMaxHeight);
1549 
1550 		_AdoptResize();
1551 			// TODO: the same has to be done for SetLook() (that can alter
1552 			//		the size limits, and hence, the size of the window
1553 	}
1554 	Unlock();
1555 }
1556 
1557 
1558 void
1559 BWindow::GetSizeLimits(float* _minWidth, float* _maxWidth, float* _minHeight,
1560 	float* _maxHeight)
1561 {
1562 	// TODO: What about locking?!?
1563 	if (_minHeight != NULL)
1564 		*_minHeight = fMinHeight;
1565 	if (_minWidth != NULL)
1566 		*_minWidth = fMinWidth;
1567 	if (_maxHeight != NULL)
1568 		*_maxHeight = fMaxHeight;
1569 	if (_maxWidth != NULL)
1570 		*_maxWidth = fMaxWidth;
1571 }
1572 
1573 
1574 void
1575 BWindow::UpdateSizeLimits()
1576 {
1577 	BAutolock locker(this);
1578 
1579 	if ((fFlags & B_AUTO_UPDATE_SIZE_LIMITS) != 0) {
1580 		// Get min/max constraints of the top view and enforce window
1581 		// size limits respectively.
1582 		BSize minSize = fTopView->MinSize();
1583 		BSize maxSize = fTopView->MaxSize();
1584 		SetSizeLimits(minSize.width, maxSize.width,
1585 			minSize.height, maxSize.height);
1586 	}
1587 }
1588 
1589 
1590 status_t
1591 BWindow::SetDecoratorSettings(const BMessage& settings)
1592 {
1593 	// flatten the given settings into a buffer and send
1594 	// it to the app_server to apply the settings to the
1595 	// decorator
1596 
1597 	int32 size = settings.FlattenedSize();
1598 	char buffer[size];
1599 	status_t status = settings.Flatten(buffer, size);
1600 	if (status != B_OK)
1601 		return status;
1602 
1603 	if (!Lock())
1604 		return B_ERROR;
1605 
1606 	status = fLink->StartMessage(AS_SET_DECORATOR_SETTINGS);
1607 
1608 	if (status == B_OK)
1609 		status = fLink->Attach<int32>(size);
1610 
1611 	if (status == B_OK)
1612 		status = fLink->Attach(buffer, size);
1613 
1614 	if (status == B_OK)
1615 		status = fLink->Flush();
1616 
1617 	Unlock();
1618 
1619 	return status;
1620 }
1621 
1622 
1623 status_t
1624 BWindow::GetDecoratorSettings(BMessage* settings) const
1625 {
1626 	// read a flattened settings message from the app_server
1627 	// and put it into settings
1628 
1629 	if (!const_cast<BWindow*>(this)->Lock())
1630 		return B_ERROR;
1631 
1632 	status_t status = fLink->StartMessage(AS_GET_DECORATOR_SETTINGS);
1633 
1634 	if (status == B_OK) {
1635 		int32 code;
1636 		status = fLink->FlushWithReply(code);
1637 		if (status == B_OK && code != B_OK)
1638 			status = code;
1639 	}
1640 
1641 	if (status == B_OK) {
1642 		int32 size;
1643 		status = fLink->Read<int32>(&size);
1644 		if (status == B_OK) {
1645 			char buffer[size];
1646 			status = fLink->Read(buffer, size);
1647 			if (status == B_OK) {
1648 				status = settings->Unflatten(buffer);
1649 			}
1650 		}
1651 	}
1652 
1653 	const_cast<BWindow*>(this)->Unlock();
1654 
1655 	return status;
1656 }
1657 
1658 
1659 void
1660 BWindow::SetZoomLimits(float maxWidth, float maxHeight)
1661 {
1662 	// TODO: What about locking?!?
1663 	if (maxWidth > fMaxWidth)
1664 		maxWidth = fMaxWidth;
1665 	else
1666 		fMaxZoomWidth = maxWidth;
1667 
1668 	if (maxHeight > fMaxHeight)
1669 		maxHeight = fMaxHeight;
1670 	else
1671 		fMaxZoomHeight = maxHeight;
1672 }
1673 
1674 
1675 void
1676 BWindow::Zoom(BPoint origin, float width, float height)
1677 {
1678 	// the default implementation of this hook function
1679 	// just does the obvious:
1680 	MoveTo(origin);
1681 	ResizeTo(width, height);
1682 }
1683 
1684 
1685 void
1686 BWindow::Zoom()
1687 {
1688 	// TODO: What about locking?!?
1689 
1690 	// From BeBook:
1691 	// The dimensions that non-virtual Zoom() passes to hook Zoom() are deduced
1692 	// from the smallest of three rectangles:
1693 
1694 	// 1) the rectangle defined by SetZoomLimits() and,
1695 	// 2) the rectangle defined by SetSizeLimits()
1696 	float maxZoomWidth = std::min(fMaxZoomWidth, fMaxWidth);
1697 	float maxZoomHeight = std::min(fMaxZoomHeight, fMaxHeight);
1698 
1699 	// 3) the screen rectangle
1700 	BRect screenFrame = (BScreen(this)).Frame();
1701 	maxZoomWidth = std::min(maxZoomWidth, screenFrame.Width());
1702 	maxZoomHeight = std::min(maxZoomHeight, screenFrame.Height());
1703 
1704 	BRect zoomArea = screenFrame; // starts at screen size
1705 
1706 	BDeskbar deskbar;
1707 	BRect deskbarFrame = deskbar.Frame();
1708 	if (!deskbar.IsAutoHide()) {
1709 		// remove area taken up by Deskbar (if not auto-hidden)
1710 		switch (deskbar.Location()) {
1711 			case B_DESKBAR_TOP:
1712 				zoomArea.top = deskbarFrame.bottom + 2;
1713 				break;
1714 
1715 			case B_DESKBAR_BOTTOM:
1716 				zoomArea.bottom = deskbarFrame.top - 2;
1717 				break;
1718 
1719 			// in vertical mode, only if not always on top and not auto-raise
1720 			case B_DESKBAR_LEFT_TOP:
1721 			case B_DESKBAR_LEFT_BOTTOM:
1722 				if (!deskbar.IsAlwaysOnTop() && !deskbar.IsAutoRaise())
1723 					zoomArea.left = deskbarFrame.right + 2;
1724 				break;
1725 
1726 			default:
1727 			case B_DESKBAR_RIGHT_TOP:
1728 			case B_DESKBAR_RIGHT_BOTTOM:
1729 				if (!deskbar.IsAlwaysOnTop() && !deskbar.IsAutoRaise())
1730 					zoomArea.right = deskbarFrame.left - 2;
1731 				break;
1732 		}
1733 	}
1734 
1735 	// TODO: Broken for tab on left side windows...
1736 	float borderWidth;
1737 	float tabHeight;
1738 	_GetDecoratorSize(&borderWidth, &tabHeight);
1739 
1740 	// remove the area taken up by the tab and border
1741 	zoomArea.left += borderWidth;
1742 	zoomArea.top += borderWidth + tabHeight;
1743 	zoomArea.right -= borderWidth;
1744 	zoomArea.bottom -= borderWidth;
1745 
1746 	// inset towards center vertically first to see if there will be room
1747 	// above or below Deskbar
1748 	if (zoomArea.Height() > maxZoomHeight)
1749 		zoomArea.InsetBy(0, roundf((zoomArea.Height() - maxZoomHeight) / 2));
1750 
1751 	if (zoomArea.top > deskbarFrame.bottom
1752 		|| zoomArea.bottom < deskbarFrame.top) {
1753 		// there is room above or below Deskbar, start from screen width
1754 		// minus borders instead of desktop width minus borders
1755 		zoomArea.left = screenFrame.left + borderWidth;
1756 		zoomArea.right = screenFrame.right - borderWidth;
1757 	}
1758 
1759 	// inset towards center
1760 	if (zoomArea.Width() > maxZoomWidth)
1761 		zoomArea.InsetBy(roundf((zoomArea.Width() - maxZoomWidth) / 2), 0);
1762 
1763 	// Un-Zoom
1764 
1765 	if (fPreviousFrame.IsValid()
1766 		// NOTE: don't check for fFrame.LeftTop() == zoomArea.LeftTop()
1767 		// -> makes it easier on the user to get a window back into place
1768 		&& fFrame.Width() == zoomArea.Width()
1769 		&& fFrame.Height() == zoomArea.Height()) {
1770 		// already zoomed!
1771 		Zoom(fPreviousFrame.LeftTop(), fPreviousFrame.Width(),
1772 			fPreviousFrame.Height());
1773 		return;
1774 	}
1775 
1776 	// Zoom
1777 
1778 	// remember fFrame for later "unzooming"
1779 	fPreviousFrame = fFrame;
1780 
1781 	Zoom(zoomArea.LeftTop(), zoomArea.Width(), zoomArea.Height());
1782 }
1783 
1784 
1785 void
1786 BWindow::ScreenChanged(BRect screenSize, color_space depth)
1787 {
1788 	// Hook function
1789 }
1790 
1791 
1792 void
1793 BWindow::SetPulseRate(bigtime_t rate)
1794 {
1795 	// TODO: What about locking?!?
1796 	if (rate < 0
1797 		|| (rate == fPulseRate && !((rate == 0) ^ (fPulseRunner == NULL))))
1798 		return;
1799 
1800 	fPulseRate = rate;
1801 
1802 	if (rate > 0) {
1803 		if (fPulseRunner == NULL) {
1804 			BMessage message(B_PULSE);
1805 			fPulseRunner = new(std::nothrow) BMessageRunner(BMessenger(this),
1806 				&message, rate);
1807 		} else {
1808 			fPulseRunner->SetInterval(rate);
1809 		}
1810 	} else {
1811 		// rate == 0
1812 		delete fPulseRunner;
1813 		fPulseRunner = NULL;
1814 	}
1815 }
1816 
1817 
1818 bigtime_t
1819 BWindow::PulseRate() const
1820 {
1821 	return fPulseRate;
1822 }
1823 
1824 
1825 void
1826 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMenuItem* item)
1827 {
1828 	Shortcut* shortcut = new(std::nothrow) Shortcut(key, modifiers, item);
1829 	if (shortcut == NULL)
1830 		return;
1831 
1832 	// removes the shortcut if it already exists!
1833 	RemoveShortcut(key, modifiers);
1834 
1835 	fShortcuts.AddItem(shortcut);
1836 }
1837 
1838 
1839 void
1840 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage* message)
1841 {
1842 	AddShortcut(key, modifiers, message, this);
1843 }
1844 
1845 
1846 void
1847 BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage* message,
1848 	BHandler* target)
1849 {
1850 	if (message == NULL)
1851 		return;
1852 
1853 	Shortcut* shortcut = new(std::nothrow) Shortcut(key, modifiers, message,
1854 		target);
1855 	if (shortcut == NULL)
1856 		return;
1857 
1858 	// removes the shortcut if it already exists!
1859 	RemoveShortcut(key, modifiers);
1860 
1861 	fShortcuts.AddItem(shortcut);
1862 }
1863 
1864 
1865 bool
1866 BWindow::HasShortcut(uint32 key, uint32 modifiers)
1867 {
1868 	return _FindShortcut(key, modifiers) != NULL;
1869 }
1870 
1871 
1872 void
1873 BWindow::RemoveShortcut(uint32 key, uint32 modifiers)
1874 {
1875 	Shortcut* shortcut = _FindShortcut(key, modifiers);
1876 	if (shortcut != NULL) {
1877 		fShortcuts.RemoveItem(shortcut);
1878 		delete shortcut;
1879 	} else if ((key == 'q' || key == 'Q') && modifiers == B_COMMAND_KEY) {
1880 		// the quit shortcut is a fake shortcut
1881 		fNoQuitShortcut = true;
1882 	}
1883 }
1884 
1885 
1886 BButton*
1887 BWindow::DefaultButton() const
1888 {
1889 	// TODO: What about locking?!?
1890 	return fDefaultButton;
1891 }
1892 
1893 
1894 void
1895 BWindow::SetDefaultButton(BButton* button)
1896 {
1897 	// TODO: What about locking?!?
1898 	if (fDefaultButton == button)
1899 		return;
1900 
1901 	if (fDefaultButton != NULL) {
1902 		// tell old button it's no longer the default one
1903 		BButton* oldDefault = fDefaultButton;
1904 		oldDefault->MakeDefault(false);
1905 		oldDefault->Invalidate();
1906 	}
1907 
1908 	fDefaultButton = button;
1909 
1910 	if (button != NULL) {
1911 		// notify new default button
1912 		fDefaultButton->MakeDefault(true);
1913 		fDefaultButton->Invalidate();
1914 	}
1915 }
1916 
1917 
1918 bool
1919 BWindow::NeedsUpdate() const
1920 {
1921 	if (!const_cast<BWindow*>(this)->Lock())
1922 		return false;
1923 
1924 	fLink->StartMessage(AS_NEEDS_UPDATE);
1925 
1926 	int32 code = B_ERROR;
1927 	fLink->FlushWithReply(code);
1928 
1929 	const_cast<BWindow*>(this)->Unlock();
1930 
1931 	return code == B_OK;
1932 }
1933 
1934 
1935 void
1936 BWindow::UpdateIfNeeded()
1937 {
1938 	// works only from the window thread
1939 	if (find_thread(NULL) != Thread())
1940 		return;
1941 
1942 	// if the queue is already locked we are called recursivly
1943 	// from our own dispatched update message
1944 	if (((const BMessageQueue*)MessageQueue())->IsLocked())
1945 		return;
1946 
1947 	if (!Lock())
1948 		return;
1949 
1950 	// make sure all requests that would cause an update have
1951 	// arrived at the server
1952 	Sync();
1953 
1954 	// Since we're blocking the event loop, we need to retrieve
1955 	// all messages that are pending on the port.
1956 	_DequeueAll();
1957 
1958 	BMessageQueue* queue = MessageQueue();
1959 
1960 	// First process and remove any _UPDATE_ message in the queue
1961 	// With the current design, there can only be one at a time
1962 
1963 	while (true) {
1964 		queue->Lock();
1965 
1966 		BMessage* message = queue->FindMessage(_UPDATE_, 0);
1967 		queue->RemoveMessage(message);
1968 
1969 		queue->Unlock();
1970 
1971 		if (message == NULL)
1972 			break;
1973 
1974 		BWindow::DispatchMessage(message, this);
1975 		delete message;
1976 	}
1977 
1978 	Unlock();
1979 }
1980 
1981 
1982 BView*
1983 BWindow::FindView(const char* viewName) const
1984 {
1985 	BAutolock locker(const_cast<BWindow*>(this));
1986 	if (!locker.IsLocked())
1987 		return NULL;
1988 
1989 	return fTopView->FindView(viewName);
1990 }
1991 
1992 
1993 BView*
1994 BWindow::FindView(BPoint point) const
1995 {
1996 	BAutolock locker(const_cast<BWindow*>(this));
1997 	if (!locker.IsLocked())
1998 		return NULL;
1999 
2000 	// point is assumed to be in window coordinates,
2001 	// fTopView has same bounds as window
2002 	return _FindView(fTopView, point);
2003 }
2004 
2005 
2006 BView*
2007 BWindow::CurrentFocus() const
2008 {
2009 	return fFocus;
2010 }
2011 
2012 
2013 void
2014 BWindow::Activate(bool active)
2015 {
2016 	if (!Lock())
2017 		return;
2018 
2019 	if (!IsHidden()) {
2020 		fMinimized = false;
2021 			// activating a window will also unminimize it
2022 
2023 		fLink->StartMessage(AS_ACTIVATE_WINDOW);
2024 		fLink->Attach<bool>(active);
2025 		fLink->Flush();
2026 	}
2027 
2028 	Unlock();
2029 }
2030 
2031 
2032 void
2033 BWindow::WindowActivated(bool focus)
2034 {
2035 	// hook function
2036 	// does nothing
2037 }
2038 
2039 
2040 void
2041 BWindow::ConvertToScreen(BPoint* point) const
2042 {
2043 	point->x += fFrame.left;
2044 	point->y += fFrame.top;
2045 }
2046 
2047 
2048 BPoint
2049 BWindow::ConvertToScreen(BPoint point) const
2050 {
2051 	return point + fFrame.LeftTop();
2052 }
2053 
2054 
2055 void
2056 BWindow::ConvertFromScreen(BPoint* point) const
2057 {
2058 	point->x -= fFrame.left;
2059 	point->y -= fFrame.top;
2060 }
2061 
2062 
2063 BPoint
2064 BWindow::ConvertFromScreen(BPoint point) const
2065 {
2066 	return point - fFrame.LeftTop();
2067 }
2068 
2069 
2070 void
2071 BWindow::ConvertToScreen(BRect* rect) const
2072 {
2073 	rect->OffsetBy(fFrame.LeftTop());
2074 }
2075 
2076 
2077 BRect
2078 BWindow::ConvertToScreen(BRect rect) const
2079 {
2080 	return rect.OffsetByCopy(fFrame.LeftTop());
2081 }
2082 
2083 
2084 void
2085 BWindow::ConvertFromScreen(BRect* rect) const
2086 {
2087 	rect->OffsetBy(-fFrame.left, -fFrame.top);
2088 }
2089 
2090 
2091 BRect
2092 BWindow::ConvertFromScreen(BRect rect) const
2093 {
2094 	return rect.OffsetByCopy(-fFrame.left, -fFrame.top);
2095 }
2096 
2097 
2098 bool
2099 BWindow::IsMinimized() const
2100 {
2101 	BAutolock locker(const_cast<BWindow*>(this));
2102 	if (!locker.IsLocked())
2103 		return false;
2104 
2105 	return fMinimized;
2106 }
2107 
2108 
2109 BRect
2110 BWindow::Bounds() const
2111 {
2112 	return BRect(0, 0, fFrame.Width(), fFrame.Height());
2113 }
2114 
2115 
2116 BRect
2117 BWindow::Frame() const
2118 {
2119 	return fFrame;
2120 }
2121 
2122 
2123 BRect
2124 BWindow::DecoratorFrame() const
2125 {
2126 	BRect decoratorFrame(Frame());
2127 	BRect tabRect(0, 0, 0, 0);
2128 
2129 	float borderWidth = 5.0;
2130 
2131 	BMessage settings;
2132 	if (GetDecoratorSettings(&settings) == B_OK) {
2133 		settings.FindRect("tab frame", &tabRect);
2134 		settings.FindFloat("border width", &borderWidth);
2135 	} else {
2136 		// probably no-border window look
2137 		if (fLook == B_NO_BORDER_WINDOW_LOOK)
2138 			borderWidth = 0.f;
2139 		else if (fLook == B_BORDERED_WINDOW_LOOK)
2140 			borderWidth = 1.f;
2141 		// else use fall-back values from above
2142 	}
2143 
2144 	if (fLook == kLeftTitledWindowLook) {
2145 		decoratorFrame.top -= borderWidth;
2146 		decoratorFrame.left -= borderWidth + tabRect.Width();
2147 		decoratorFrame.right += borderWidth;
2148 		decoratorFrame.bottom += borderWidth;
2149 	} else {
2150 		decoratorFrame.top -= borderWidth + tabRect.Height();
2151 		decoratorFrame.left -= borderWidth;
2152 		decoratorFrame.right += borderWidth;
2153 		decoratorFrame.bottom += borderWidth;
2154 	}
2155 
2156 	return decoratorFrame;
2157 }
2158 
2159 
2160 BSize
2161 BWindow::Size() const
2162 {
2163 	return BSize(fFrame.Width(), fFrame.Height());
2164 }
2165 
2166 
2167 const char*
2168 BWindow::Title() const
2169 {
2170 	return fTitle;
2171 }
2172 
2173 
2174 void
2175 BWindow::SetTitle(const char* title)
2176 {
2177 	if (title == NULL)
2178 		title = "";
2179 
2180 	free(fTitle);
2181 	fTitle = strdup(title);
2182 
2183 	_SetName(title);
2184 
2185 	// we notify the app_server so we can actually see the change
2186 	if (Lock()) {
2187 		fLink->StartMessage(AS_SET_WINDOW_TITLE);
2188 		fLink->AttachString(fTitle);
2189 		fLink->Flush();
2190 		Unlock();
2191 	}
2192 }
2193 
2194 
2195 bool
2196 BWindow::IsActive() const
2197 {
2198 	return fActive;
2199 }
2200 
2201 
2202 void
2203 BWindow::SetKeyMenuBar(BMenuBar* bar)
2204 {
2205 	fKeyMenuBar = bar;
2206 }
2207 
2208 
2209 BMenuBar*
2210 BWindow::KeyMenuBar() const
2211 {
2212 	return fKeyMenuBar;
2213 }
2214 
2215 
2216 bool
2217 BWindow::IsModal() const
2218 {
2219 	return fFeel == B_MODAL_SUBSET_WINDOW_FEEL
2220 		|| fFeel == B_MODAL_APP_WINDOW_FEEL
2221 		|| fFeel == B_MODAL_ALL_WINDOW_FEEL
2222 		|| fFeel == kMenuWindowFeel;
2223 }
2224 
2225 
2226 bool
2227 BWindow::IsFloating() const
2228 {
2229 	return fFeel == B_FLOATING_SUBSET_WINDOW_FEEL
2230 		|| fFeel == B_FLOATING_APP_WINDOW_FEEL
2231 		|| fFeel == B_FLOATING_ALL_WINDOW_FEEL;
2232 }
2233 
2234 
2235 status_t
2236 BWindow::AddToSubset(BWindow* window)
2237 {
2238 	if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL
2239 		|| (fFeel != B_MODAL_SUBSET_WINDOW_FEEL
2240 			&& fFeel != B_FLOATING_SUBSET_WINDOW_FEEL))
2241 		return B_BAD_VALUE;
2242 
2243 	if (!Lock())
2244 		return B_ERROR;
2245 
2246 	status_t status = B_ERROR;
2247 	fLink->StartMessage(AS_ADD_TO_SUBSET);
2248 	fLink->Attach<int32>(_get_object_token_(window));
2249 	fLink->FlushWithReply(status);
2250 
2251 	Unlock();
2252 
2253 	return status;
2254 }
2255 
2256 
2257 status_t
2258 BWindow::RemoveFromSubset(BWindow* window)
2259 {
2260 	if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL
2261 		|| (fFeel != B_MODAL_SUBSET_WINDOW_FEEL
2262 			&& fFeel != B_FLOATING_SUBSET_WINDOW_FEEL))
2263 		return B_BAD_VALUE;
2264 
2265 	if (!Lock())
2266 		return B_ERROR;
2267 
2268 	status_t status = B_ERROR;
2269 	fLink->StartMessage(AS_REMOVE_FROM_SUBSET);
2270 	fLink->Attach<int32>(_get_object_token_(window));
2271 	fLink->FlushWithReply(status);
2272 
2273 	Unlock();
2274 
2275 	return status;
2276 }
2277 
2278 
2279 status_t
2280 BWindow::Perform(perform_code code, void* _data)
2281 {
2282 	switch (code) {
2283 		case PERFORM_CODE_SET_LAYOUT:
2284 		{
2285 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
2286 			BWindow::SetLayout(data->layout);
2287 			return B_OK;
2288 }
2289 	}
2290 
2291 	return BLooper::Perform(code, _data);
2292 }
2293 
2294 
2295 status_t
2296 BWindow::SetType(window_type type)
2297 {
2298 	window_look look;
2299 	window_feel feel;
2300 	_DecomposeType(type, &look, &feel);
2301 
2302 	status_t status = SetLook(look);
2303 	if (status == B_OK)
2304 		status = SetFeel(feel);
2305 
2306 	return status;
2307 }
2308 
2309 
2310 window_type
2311 BWindow::Type() const
2312 {
2313 	return _ComposeType(fLook, fFeel);
2314 }
2315 
2316 
2317 status_t
2318 BWindow::SetLook(window_look look)
2319 {
2320 	BAutolock locker(this);
2321 	if (!locker.IsLocked())
2322 		return B_BAD_VALUE;
2323 
2324 	fLink->StartMessage(AS_SET_LOOK);
2325 	fLink->Attach<int32>((int32)look);
2326 
2327 	status_t status = B_ERROR;
2328 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
2329 		fLook = look;
2330 
2331 	// TODO: this could have changed the window size, and thus, we
2332 	//	need to get it from the server (and call _AdoptResize()).
2333 
2334 	return status;
2335 }
2336 
2337 
2338 window_look
2339 BWindow::Look() const
2340 {
2341 	return fLook;
2342 }
2343 
2344 
2345 status_t
2346 BWindow::SetFeel(window_feel feel)
2347 {
2348 	BAutolock locker(this);
2349 	if (!locker.IsLocked())
2350 		return B_BAD_VALUE;
2351 
2352 	fLink->StartMessage(AS_SET_FEEL);
2353 	fLink->Attach<int32>((int32)feel);
2354 
2355 	status_t status = B_ERROR;
2356 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
2357 		fFeel = feel;
2358 
2359 	return status;
2360 }
2361 
2362 
2363 window_feel
2364 BWindow::Feel() const
2365 {
2366 	return fFeel;
2367 }
2368 
2369 
2370 status_t
2371 BWindow::SetFlags(uint32 flags)
2372 {
2373 	BAutolock locker(this);
2374 	if (!locker.IsLocked())
2375 		return B_BAD_VALUE;
2376 
2377 	fLink->StartMessage(AS_SET_FLAGS);
2378 	fLink->Attach<uint32>(flags);
2379 
2380 	int32 status = B_ERROR;
2381 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
2382 		fFlags = flags;
2383 
2384 	return status;
2385 }
2386 
2387 
2388 uint32
2389 BWindow::Flags() const
2390 {
2391 	return fFlags;
2392 }
2393 
2394 
2395 status_t
2396 BWindow::SetWindowAlignment(window_alignment mode,
2397 	int32 h, int32 hOffset, int32 width, int32 widthOffset,
2398 	int32 v, int32 vOffset, int32 height, int32 heightOffset)
2399 {
2400 	if ((mode & (B_BYTE_ALIGNMENT | B_PIXEL_ALIGNMENT)) == 0
2401 		|| (hOffset >= 0 && hOffset <= h)
2402 		|| (vOffset >= 0 && vOffset <= v)
2403 		|| (widthOffset >= 0 && widthOffset <= width)
2404 		|| (heightOffset >= 0 && heightOffset <= height))
2405 		return B_BAD_VALUE;
2406 
2407 	// TODO: test if hOffset = 0 and set it to 1 if true.
2408 
2409 	if (!Lock())
2410 		return B_ERROR;
2411 
2412 	fLink->StartMessage(AS_SET_ALIGNMENT);
2413 	fLink->Attach<int32>((int32)mode);
2414 	fLink->Attach<int32>(h);
2415 	fLink->Attach<int32>(hOffset);
2416 	fLink->Attach<int32>(width);
2417 	fLink->Attach<int32>(widthOffset);
2418 	fLink->Attach<int32>(v);
2419 	fLink->Attach<int32>(vOffset);
2420 	fLink->Attach<int32>(height);
2421 	fLink->Attach<int32>(heightOffset);
2422 
2423 	status_t status = B_ERROR;
2424 	fLink->FlushWithReply(status);
2425 
2426 	Unlock();
2427 
2428 	return status;
2429 }
2430 
2431 
2432 status_t
2433 BWindow::GetWindowAlignment(window_alignment* mode,
2434 	int32* h, int32* hOffset, int32* width, int32* widthOffset,
2435 	int32* v, int32* vOffset, int32* height, int32* heightOffset) const
2436 {
2437 	if (!const_cast<BWindow*>(this)->Lock())
2438 		return B_ERROR;
2439 
2440 	fLink->StartMessage(AS_GET_ALIGNMENT);
2441 
2442 	status_t status;
2443 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK) {
2444 		fLink->Read<int32>((int32*)mode);
2445 		fLink->Read<int32>(h);
2446 		fLink->Read<int32>(hOffset);
2447 		fLink->Read<int32>(width);
2448 		fLink->Read<int32>(widthOffset);
2449 		fLink->Read<int32>(v);
2450 		fLink->Read<int32>(hOffset);
2451 		fLink->Read<int32>(height);
2452 		fLink->Read<int32>(heightOffset);
2453 	}
2454 
2455 	const_cast<BWindow*>(this)->Unlock();
2456 	return status;
2457 }
2458 
2459 
2460 uint32
2461 BWindow::Workspaces() const
2462 {
2463 	if (!const_cast<BWindow*>(this)->Lock())
2464 		return 0;
2465 
2466 	uint32 workspaces = 0;
2467 
2468 	fLink->StartMessage(AS_GET_WORKSPACES);
2469 
2470 	status_t status;
2471 	if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
2472 		fLink->Read<uint32>(&workspaces);
2473 
2474 	const_cast<BWindow*>(this)->Unlock();
2475 	return workspaces;
2476 }
2477 
2478 
2479 void
2480 BWindow::SetWorkspaces(uint32 workspaces)
2481 {
2482 	// TODO: don't forget about Tracker's background window.
2483 	if (fFeel != B_NORMAL_WINDOW_FEEL)
2484 		return;
2485 
2486 	if (Lock()) {
2487 		fLink->StartMessage(AS_SET_WORKSPACES);
2488 		fLink->Attach<uint32>(workspaces);
2489 		fLink->Flush();
2490 		Unlock();
2491 	}
2492 }
2493 
2494 
2495 BView*
2496 BWindow::LastMouseMovedView() const
2497 {
2498 	return fLastMouseMovedView;
2499 }
2500 
2501 
2502 void
2503 BWindow::MoveBy(float dx, float dy)
2504 {
2505 	if ((dx != 0.0f || dy != 0.0f) && Lock()) {
2506 		MoveTo(fFrame.left + dx, fFrame.top + dy);
2507 		Unlock();
2508 	}
2509 }
2510 
2511 
2512 void
2513 BWindow::MoveTo(BPoint point)
2514 {
2515 	MoveTo(point.x, point.y);
2516 }
2517 
2518 
2519 void
2520 BWindow::MoveTo(float x, float y)
2521 {
2522 	if (!Lock())
2523 		return;
2524 
2525 	x = roundf(x);
2526 	y = roundf(y);
2527 
2528 	if (fFrame.left != x || fFrame.top != y) {
2529 		fLink->StartMessage(AS_WINDOW_MOVE);
2530 		fLink->Attach<float>(x);
2531 		fLink->Attach<float>(y);
2532 
2533 		status_t status;
2534 		if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
2535 			fFrame.OffsetTo(x, y);
2536 	}
2537 
2538 	Unlock();
2539 }
2540 
2541 
2542 void
2543 BWindow::ResizeBy(float dx, float dy)
2544 {
2545 	if (Lock()) {
2546 		ResizeTo(fFrame.Width() + dx, fFrame.Height() + dy);
2547 		Unlock();
2548 	}
2549 }
2550 
2551 
2552 void
2553 BWindow::ResizeTo(float width, float height)
2554 {
2555 	if (!Lock())
2556 		return;
2557 
2558 	width = roundf(width);
2559 	height = roundf(height);
2560 
2561 	// stay in minimum & maximum frame limits
2562 	if (width < fMinWidth)
2563 		width = fMinWidth;
2564 	else if (width > fMaxWidth)
2565 		width = fMaxWidth;
2566 
2567 	if (height < fMinHeight)
2568 		height = fMinHeight;
2569 	else if (height > fMaxHeight)
2570 		height = fMaxHeight;
2571 
2572 	if (width != fFrame.Width() || height != fFrame.Height()) {
2573 		fLink->StartMessage(AS_WINDOW_RESIZE);
2574 		fLink->Attach<float>(width);
2575 		fLink->Attach<float>(height);
2576 
2577 		status_t status;
2578 		if (fLink->FlushWithReply(status) == B_OK && status == B_OK) {
2579 			fFrame.right = fFrame.left + width;
2580 			fFrame.bottom = fFrame.top + height;
2581 			_AdoptResize();
2582 		}
2583 	}
2584 
2585 	Unlock();
2586 }
2587 
2588 
2589 void
2590 BWindow::ResizeToPreferred()
2591 {
2592 	BAutolock locker(this);
2593 	Layout(false);
2594 
2595 	float width = fTopView->PreferredSize().width;
2596 	width = std::min(width, fTopView->MaxSize().width);
2597 	width = std::max(width, fTopView->MinSize().width);
2598 
2599 	float height = fTopView->PreferredSize().height;
2600 	height = std::min(width, fTopView->MaxSize().height);
2601 	height = std::max(width, fTopView->MinSize().height);
2602 
2603 	if (GetLayout()->HasHeightForWidth())
2604 		GetLayout()->GetHeightForWidth(width, NULL, NULL, &height);
2605 
2606 	ResizeTo(width, height);
2607 }
2608 
2609 
2610 void
2611 BWindow::CenterIn(const BRect& rect)
2612 {
2613 	BAutolock locker(this);
2614 
2615 	// Set size limits now if needed
2616 	UpdateSizeLimits();
2617 
2618 	MoveTo(BLayoutUtils::AlignInFrame(rect, Size(),
2619 		BAlignment(B_ALIGN_HORIZONTAL_CENTER,
2620 			B_ALIGN_VERTICAL_CENTER)).LeftTop());
2621 }
2622 
2623 
2624 void
2625 BWindow::CenterOnScreen()
2626 {
2627 	CenterIn(BScreen(this).Frame());
2628 }
2629 
2630 
2631 // Centers the window on the screen with the passed in id.
2632 void
2633 BWindow::CenterOnScreen(screen_id id)
2634 {
2635 	CenterIn(BScreen(id).Frame());
2636 }
2637 
2638 
2639 void
2640 BWindow::MoveOnScreen(uint32 flags)
2641 {
2642 	// Set size limits now if needed
2643 	UpdateSizeLimits();
2644 
2645 	BRect screenFrame = BScreen(this).Frame();
2646 	BRect frame = Frame();
2647 
2648 	float borderWidth;
2649 	float tabHeight;
2650 	_GetDecoratorSize(&borderWidth, &tabHeight);
2651 
2652 	frame.InsetBy(-borderWidth, -borderWidth);
2653 	frame.top -= tabHeight;
2654 
2655 	if ((flags & B_DO_NOT_RESIZE_TO_FIT) == 0) {
2656 		// Make sure the window fits on the screen
2657 		if (frame.Width() > screenFrame.Width())
2658 			frame.right -= frame.Width() - screenFrame.Width();
2659 		if (frame.Height() > screenFrame.Height())
2660 			frame.bottom -= frame.Height() - screenFrame.Height();
2661 
2662 		BRect innerFrame = frame;
2663 		innerFrame.top += tabHeight;
2664 		innerFrame.InsetBy(borderWidth, borderWidth);
2665 		ResizeTo(innerFrame.Width(), innerFrame.Height());
2666 	}
2667 
2668 	if (((flags & B_MOVE_IF_PARTIALLY_OFFSCREEN) == 0
2669 			&& !screenFrame.Contains(frame))
2670 		|| !frame.Intersects(screenFrame)) {
2671 		// Off and away
2672 		CenterOnScreen();
2673 		return;
2674 	}
2675 
2676 	// Move such that the upper left corner, and most of the window
2677 	// will be visible.
2678 	float left = frame.left;
2679 	if (left < screenFrame.left)
2680 		left = screenFrame.left;
2681 	else if (frame.right > screenFrame.right)
2682 		left = std::max(0.f, screenFrame.right - frame.Width());
2683 
2684 	float top = frame.top;
2685 	if (top < screenFrame.top)
2686 		top = screenFrame.top;
2687 	else if (frame.bottom > screenFrame.bottom)
2688 		top = std::max(0.f, screenFrame.bottom - frame.Height());
2689 
2690 	if (top != frame.top || left != frame.left)
2691 		MoveTo(left + borderWidth, top + tabHeight + borderWidth);
2692 }
2693 
2694 
2695 void
2696 BWindow::Show()
2697 {
2698 	bool runCalled = true;
2699 	if (Lock()) {
2700 		fShowLevel--;
2701 
2702 		_SendShowOrHideMessage();
2703 
2704 		runCalled = fRunCalled;
2705 
2706 		Unlock();
2707 	}
2708 
2709 	if (!runCalled) {
2710 		// This is the fist time Show() is called, which implicitly runs the
2711 		// looper. NOTE: The window is still locked if it has not been
2712 		// run yet, so accessing members is safe.
2713 		if (fLink->SenderPort() < B_OK) {
2714 			// We don't have valid app_server connection; there is no point
2715 			// in starting our looper
2716 			fThread = B_ERROR;
2717 			return;
2718 		} else
2719 			Run();
2720 	}
2721 }
2722 
2723 
2724 void
2725 BWindow::Hide()
2726 {
2727 	if (Lock()) {
2728 		// If we are minimized and are about to be hidden, unminimize
2729 		if (IsMinimized() && fShowLevel == 0)
2730 			Minimize(false);
2731 
2732 		fShowLevel++;
2733 
2734 		_SendShowOrHideMessage();
2735 
2736 		Unlock();
2737 	}
2738 }
2739 
2740 
2741 bool
2742 BWindow::IsHidden() const
2743 {
2744 	return fShowLevel > 0;
2745 }
2746 
2747 
2748 bool
2749 BWindow::QuitRequested()
2750 {
2751 	return BLooper::QuitRequested();
2752 }
2753 
2754 
2755 thread_id
2756 BWindow::Run()
2757 {
2758 	return BLooper::Run();
2759 }
2760 
2761 
2762 void
2763 BWindow::SetLayout(BLayout* layout)
2764 {
2765 	// Adopt layout's colors for fTopView
2766 	if (layout != NULL)
2767 		fTopView->AdoptViewColors(layout->View());
2768 
2769 	fTopView->SetLayout(layout);
2770 }
2771 
2772 
2773 BLayout*
2774 BWindow::GetLayout() const
2775 {
2776 	return fTopView->GetLayout();
2777 }
2778 
2779 
2780 void
2781 BWindow::InvalidateLayout(bool descendants)
2782 {
2783 	fTopView->InvalidateLayout(descendants);
2784 }
2785 
2786 
2787 void
2788 BWindow::Layout(bool force)
2789 {
2790 	UpdateSizeLimits();
2791 
2792 	// Do the actual layout
2793 	fTopView->Layout(force);
2794 }
2795 
2796 
2797 bool
2798 BWindow::IsOffscreenWindow() const
2799 {
2800 	return fOffscreen;
2801 }
2802 
2803 
2804 status_t
2805 BWindow::GetSupportedSuites(BMessage* data)
2806 {
2807 	if (data == NULL)
2808 		return B_BAD_VALUE;
2809 
2810 	status_t status = data->AddString("suites", "suite/vnd.Be-window");
2811 	if (status == B_OK) {
2812 		BPropertyInfo propertyInfo(sWindowPropInfo, sWindowValueInfo);
2813 
2814 		status = data->AddFlat("messages", &propertyInfo);
2815 		if (status == B_OK)
2816 			status = BLooper::GetSupportedSuites(data);
2817 	}
2818 
2819 	return status;
2820 }
2821 
2822 
2823 BHandler*
2824 BWindow::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
2825 	int32 what, const char* property)
2826 {
2827 	if (message->what == B_WINDOW_MOVE_BY
2828 		|| message->what == B_WINDOW_MOVE_TO)
2829 		return this;
2830 
2831 	BPropertyInfo propertyInfo(sWindowPropInfo);
2832 	if (propertyInfo.FindMatch(message, index, specifier, what, property) >= 0) {
2833 		if (strcmp(property, "View") == 0) {
2834 			// we will NOT pop the current specifier
2835 			return fTopView;
2836 		} else if (strcmp(property, "MenuBar") == 0) {
2837 			if (fKeyMenuBar) {
2838 				message->PopSpecifier();
2839 				return fKeyMenuBar;
2840 			} else {
2841 				BMessage replyMsg(B_MESSAGE_NOT_UNDERSTOOD);
2842 				replyMsg.AddInt32("error", B_NAME_NOT_FOUND);
2843 				replyMsg.AddString("message",
2844 					"This window doesn't have a main MenuBar");
2845 				message->SendReply(&replyMsg);
2846 				return NULL;
2847 			}
2848 		} else
2849 			return this;
2850 	}
2851 
2852 	return BLooper::ResolveSpecifier(message, index, specifier, what, property);
2853 }
2854 
2855 
2856 //	#pragma mark - Private Methods
2857 
2858 
2859 void
2860 BWindow::_InitData(BRect frame, const char* title, window_look look,
2861 	window_feel feel, uint32 flags,	uint32 workspace, int32 bitmapToken)
2862 {
2863 	STRACE(("BWindow::InitData()\n"));
2864 
2865 	if (be_app == NULL) {
2866 		debugger("You need a valid BApplication object before interacting with "
2867 			"the app_server");
2868 		return;
2869 	}
2870 
2871 	frame.left = roundf(frame.left);
2872 	frame.top = roundf(frame.top);
2873 	frame.right = roundf(frame.right);
2874 	frame.bottom = roundf(frame.bottom);
2875 
2876 	fFrame = frame;
2877 
2878 	if (title == NULL)
2879 		title = "";
2880 
2881 	fTitle = strdup(title);
2882 
2883 	_SetName(title);
2884 
2885 	fFeel = feel;
2886 	fLook = look;
2887 	fFlags = flags | B_ASYNCHRONOUS_CONTROLS;
2888 
2889 	fInTransaction = bitmapToken >= 0;
2890 	fUpdateRequested = false;
2891 	fActive = false;
2892 	fShowLevel = 1;
2893 
2894 	fTopView = NULL;
2895 	fFocus = NULL;
2896 	fLastMouseMovedView	= NULL;
2897 	fKeyMenuBar = NULL;
2898 	fDefaultButton = NULL;
2899 
2900 	// Shortcut 'Q' is handled in _HandleKeyDown() directly, as its message
2901 	// get sent to the application, and not one of our handlers.
2902 	// It is only installed for non-modal windows, though.
2903 	fNoQuitShortcut = IsModal();
2904 
2905 	if ((fFlags & B_NOT_CLOSABLE) == 0 && !IsModal()) {
2906 		// Modal windows default to non-closable, but you can add the
2907 		// shortcut manually, if a different behaviour is wanted
2908 		AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
2909 	}
2910 
2911 	// Edit modifier keys
2912 
2913 	AddShortcut('X', B_COMMAND_KEY, new BMessage(B_CUT), NULL);
2914 	AddShortcut('C', B_COMMAND_KEY, new BMessage(B_COPY), NULL);
2915 	AddShortcut('V', B_COMMAND_KEY, new BMessage(B_PASTE), NULL);
2916 	AddShortcut('A', B_COMMAND_KEY, new BMessage(B_SELECT_ALL), NULL);
2917 
2918 	// Window modifier keys
2919 
2920 	AddShortcut('M', B_COMMAND_KEY | B_CONTROL_KEY,
2921 		new BMessage(_MINIMIZE_), NULL);
2922 	AddShortcut('Z', B_COMMAND_KEY | B_CONTROL_KEY,
2923 		new BMessage(_ZOOM_), NULL);
2924 	AddShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY,
2925 		new BMessage(B_HIDE_APPLICATION), NULL);
2926 	AddShortcut('F', B_COMMAND_KEY | B_CONTROL_KEY,
2927 		new BMessage(_SEND_TO_FRONT_), NULL);
2928 	AddShortcut('B', B_COMMAND_KEY | B_CONTROL_KEY,
2929 		new BMessage(_SEND_BEHIND_), NULL);
2930 
2931 	// We set the default pulse rate, but we don't start the pulse
2932 	fPulseRate = 500000;
2933 	fPulseRunner = NULL;
2934 
2935 	fIsFilePanel = false;
2936 
2937 	fMenuSem = -1;
2938 
2939 	fMinimized = false;
2940 
2941 	fMaxZoomHeight = 32768.0;
2942 	fMaxZoomWidth = 32768.0;
2943 	fMinHeight = 0.0;
2944 	fMinWidth = 0.0;
2945 	fMaxHeight = 32768.0;
2946 	fMaxWidth = 32768.0;
2947 
2948 	fLastViewToken = B_NULL_TOKEN;
2949 
2950 	// TODO: other initializations!
2951 	fOffscreen = false;
2952 
2953 	// Create the server-side window
2954 
2955 	port_id receivePort = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY,
2956 		"w<app_server");
2957 	if (receivePort < B_OK) {
2958 		// TODO: huh?
2959 		debugger("Could not create BWindow's receive port, used for "
2960 				 "interacting with the app_server!");
2961 		delete this;
2962 		return;
2963 	}
2964 
2965 	STRACE(("BWindow::InitData(): contacting app_server...\n"));
2966 
2967 	// let app_server know that a window has been created.
2968 	fLink = new(std::nothrow) BPrivate::PortLink(
2969 		BApplication::Private::ServerLink()->SenderPort(), receivePort);
2970 	if (fLink == NULL) {
2971 		// Zombie!
2972 		return;
2973 	}
2974 
2975 	{
2976 		BPrivate::AppServerLink lockLink;
2977 			// we're talking to the server application using our own
2978 			// communication channel (fLink) - we better make sure no one
2979 			// interferes by locking that channel (which AppServerLink does
2980 			// implicetly)
2981 
2982 		if (bitmapToken < 0) {
2983 			fLink->StartMessage(AS_CREATE_WINDOW);
2984 		} else {
2985 			fLink->StartMessage(AS_CREATE_OFFSCREEN_WINDOW);
2986 			fLink->Attach<int32>(bitmapToken);
2987 			fOffscreen = true;
2988 		}
2989 
2990 		fLink->Attach<BRect>(fFrame);
2991 		fLink->Attach<uint32>((uint32)fLook);
2992 		fLink->Attach<uint32>((uint32)fFeel);
2993 		fLink->Attach<uint32>(fFlags);
2994 		fLink->Attach<uint32>(workspace);
2995 		fLink->Attach<int32>(_get_object_token_(this));
2996 		fLink->Attach<port_id>(receivePort);
2997 		fLink->Attach<port_id>(fMsgPort);
2998 		fLink->AttachString(title);
2999 
3000 		port_id sendPort;
3001 		int32 code;
3002 		if (fLink->FlushWithReply(code) == B_OK
3003 			&& code == B_OK
3004 			&& fLink->Read<port_id>(&sendPort) == B_OK) {
3005 			// read the frame size and its limits that were really
3006 			// enforced on the server side
3007 
3008 			fLink->Read<BRect>(&fFrame);
3009 			fLink->Read<float>(&fMinWidth);
3010 			fLink->Read<float>(&fMaxWidth);
3011 			fLink->Read<float>(&fMinHeight);
3012 			fLink->Read<float>(&fMaxHeight);
3013 
3014 			fMaxZoomWidth = fMaxWidth;
3015 			fMaxZoomHeight = fMaxHeight;
3016 		} else
3017 			sendPort = -1;
3018 
3019 		// Redirect our link to the new window connection
3020 		fLink->SetSenderPort(sendPort);
3021 		STRACE(("Server says that our send port is %ld\n", sendPort));
3022 	}
3023 
3024 	STRACE(("Window locked?: %s\n", IsLocked() ? "True" : "False"));
3025 
3026 	_CreateTopView();
3027 }
3028 
3029 
3030 //! Rename the handler and its thread
3031 void
3032 BWindow::_SetName(const char* title)
3033 {
3034 	if (title == NULL)
3035 		title = "";
3036 
3037 	// we will change BWindow's thread name to "w>window title"
3038 
3039 	char threadName[B_OS_NAME_LENGTH];
3040 	strcpy(threadName, "w>");
3041 #ifdef __HAIKU__
3042 	strlcat(threadName, title, B_OS_NAME_LENGTH);
3043 #else
3044 	int32 length = strlen(title);
3045 	length = min_c(length, B_OS_NAME_LENGTH - 3);
3046 	memcpy(threadName + 2, title, length);
3047 	threadName[length + 2] = '\0';
3048 #endif
3049 
3050 	// change the handler's name
3051 	SetName(threadName);
3052 
3053 	// if the message loop has been started...
3054 	if (Thread() >= B_OK)
3055 		rename_thread(Thread(), threadName);
3056 }
3057 
3058 
3059 //!	Reads all pending messages from the window port and put them into the queue.
3060 void
3061 BWindow::_DequeueAll()
3062 {
3063 	//	Get message count from port
3064 	int32 count = port_count(fMsgPort);
3065 
3066 	for (int32 i = 0; i < count; i++) {
3067 		BMessage* message = MessageFromPort(0);
3068 		if (message != NULL)
3069 			fDirectTarget->Queue()->AddMessage(message);
3070 	}
3071 }
3072 
3073 
3074 /*!	This here is an almost complete code duplication to BLooper::task_looper()
3075 	but with some important differences:
3076 	 a)	it uses the _DetermineTarget() method to tell what the later target of
3077 		a message will be, if no explicit target is supplied.
3078 	 b)	it calls _UnpackMessage() and _SanitizeMessage() to duplicate the message
3079 		to all of its intended targets, and to add all fields the target would
3080 		expect in such a message.
3081 
3082 	This is important because the app_server sends all input events to the
3083 	preferred handler, and expects them to be correctly distributed to their
3084 	intended targets.
3085 */
3086 void
3087 BWindow::task_looper()
3088 {
3089 	STRACE(("info: BWindow::task_looper() started.\n"));
3090 
3091 	// Check that looper is locked (should be)
3092 	AssertLocked();
3093 	Unlock();
3094 
3095 	if (IsLocked())
3096 		debugger("window must not be locked!");
3097 
3098 	while (!fTerminating) {
3099 		// Did we get a message?
3100 		BMessage* msg = MessageFromPort();
3101 		if (msg)
3102 			_AddMessagePriv(msg);
3103 
3104 		//	Get message count from port
3105 		int32 msgCount = port_count(fMsgPort);
3106 		for (int32 i = 0; i < msgCount; ++i) {
3107 			// Read 'count' messages from port (so we will not block)
3108 			// We use zero as our timeout since we know there is stuff there
3109 			msg = MessageFromPort(0);
3110 			// Add messages to queue
3111 			if (msg)
3112 				_AddMessagePriv(msg);
3113 		}
3114 
3115 		bool dispatchNextMessage = true;
3116 		while (!fTerminating && dispatchNextMessage) {
3117 			// Get next message from queue (assign to fLastMessage after
3118 			// locking)
3119 			BMessage* message = fDirectTarget->Queue()->NextMessage();
3120 
3121 			// Lock the looper
3122 			if (!Lock()) {
3123 				delete message;
3124 				break;
3125 			}
3126 
3127 			fLastMessage = message;
3128 
3129 			if (fLastMessage == NULL) {
3130 				// No more messages: Unlock the looper and terminate the
3131 				// dispatch loop.
3132 				dispatchNextMessage = false;
3133 			} else {
3134 				// Get the target handler
3135 				BMessage::Private messagePrivate(fLastMessage);
3136 				bool usePreferred = messagePrivate.UsePreferredTarget();
3137 				BHandler* handler = NULL;
3138 				bool dropMessage = false;
3139 
3140 				if (usePreferred) {
3141 					handler = PreferredHandler();
3142 					if (handler == NULL)
3143 						handler = this;
3144 				} else {
3145 					gDefaultTokens.GetToken(messagePrivate.GetTarget(),
3146 						B_HANDLER_TOKEN, (void**)&handler);
3147 
3148 					// if this handler doesn't belong to us, we drop the message
3149 					if (handler != NULL && handler->Looper() != this) {
3150 						dropMessage = true;
3151 						handler = NULL;
3152 					}
3153 				}
3154 
3155 				if ((handler == NULL && !dropMessage) || usePreferred)
3156 					handler = _DetermineTarget(fLastMessage, handler);
3157 
3158 				unpack_cookie cookie;
3159 				while (_UnpackMessage(cookie, &fLastMessage, &handler, &usePreferred)) {
3160 					// if there is no target handler, the message is dropped
3161 					if (handler != NULL) {
3162 						_SanitizeMessage(fLastMessage, handler, usePreferred);
3163 
3164 						// Is this a scripting message?
3165 						if (fLastMessage->HasSpecifiers()) {
3166 							int32 index = 0;
3167 							// Make sure the current specifier is kosher
3168 							if (fLastMessage->GetCurrentSpecifier(&index) == B_OK)
3169 								handler = resolve_specifier(handler, fLastMessage);
3170 						}
3171 
3172 						if (handler != NULL)
3173 							handler = _TopLevelFilter(fLastMessage, handler);
3174 
3175 						if (handler != NULL)
3176 							DispatchMessage(fLastMessage, handler);
3177 					}
3178 
3179 					// Delete the current message
3180 					delete fLastMessage;
3181 					fLastMessage = NULL;
3182 				}
3183 			}
3184 
3185 			if (fTerminating) {
3186 				// we leave the looper locked when we quit
3187 				return;
3188 			}
3189 
3190 			Unlock();
3191 
3192 			// Are any messages on the port?
3193 			if (port_count(fMsgPort) > 0) {
3194 				// Do outer loop
3195 				dispatchNextMessage = false;
3196 			}
3197 		}
3198 	}
3199 }
3200 
3201 
3202 window_type
3203 BWindow::_ComposeType(window_look look, window_feel feel) const
3204 {
3205 	switch (feel) {
3206 		case B_NORMAL_WINDOW_FEEL:
3207 			switch (look) {
3208 				case B_TITLED_WINDOW_LOOK:
3209 					return B_TITLED_WINDOW;
3210 
3211 				case B_DOCUMENT_WINDOW_LOOK:
3212 					return B_DOCUMENT_WINDOW;
3213 
3214 				case B_BORDERED_WINDOW_LOOK:
3215 					return B_BORDERED_WINDOW;
3216 
3217 				default:
3218 					return B_UNTYPED_WINDOW;
3219 			}
3220 			break;
3221 
3222 		case B_MODAL_APP_WINDOW_FEEL:
3223 			if (look == B_MODAL_WINDOW_LOOK)
3224 				return B_MODAL_WINDOW;
3225 			break;
3226 
3227 		case B_FLOATING_APP_WINDOW_FEEL:
3228 			if (look == B_FLOATING_WINDOW_LOOK)
3229 				return B_FLOATING_WINDOW;
3230 			break;
3231 
3232 		default:
3233 			return B_UNTYPED_WINDOW;
3234 	}
3235 
3236 	return B_UNTYPED_WINDOW;
3237 }
3238 
3239 
3240 void
3241 BWindow::_DecomposeType(window_type type, window_look* _look,
3242 	window_feel* _feel) const
3243 {
3244 	switch (type) {
3245 		case B_DOCUMENT_WINDOW:
3246 			*_look = B_DOCUMENT_WINDOW_LOOK;
3247 			*_feel = B_NORMAL_WINDOW_FEEL;
3248 			break;
3249 
3250 		case B_MODAL_WINDOW:
3251 			*_look = B_MODAL_WINDOW_LOOK;
3252 			*_feel = B_MODAL_APP_WINDOW_FEEL;
3253 			break;
3254 
3255 		case B_FLOATING_WINDOW:
3256 			*_look = B_FLOATING_WINDOW_LOOK;
3257 			*_feel = B_FLOATING_APP_WINDOW_FEEL;
3258 			break;
3259 
3260 		case B_BORDERED_WINDOW:
3261 			*_look = B_BORDERED_WINDOW_LOOK;
3262 			*_feel = B_NORMAL_WINDOW_FEEL;
3263 			break;
3264 
3265 		case B_TITLED_WINDOW:
3266 		case B_UNTYPED_WINDOW:
3267 		default:
3268 			*_look = B_TITLED_WINDOW_LOOK;
3269 			*_feel = B_NORMAL_WINDOW_FEEL;
3270 			break;
3271 	}
3272 }
3273 
3274 
3275 void
3276 BWindow::_CreateTopView()
3277 {
3278 	STRACE(("_CreateTopView(): enter\n"));
3279 
3280 	BRect frame = fFrame.OffsetToCopy(B_ORIGIN);
3281 	// TODO: what to do here about std::nothrow?
3282 	fTopView = new BView(frame, "fTopView", B_FOLLOW_ALL, B_WILL_DRAW);
3283 	fTopView->fTopLevelView = true;
3284 
3285 	//inhibit check_lock()
3286 	fLastViewToken = _get_object_token_(fTopView);
3287 
3288 	// set fTopView's owner, add it to window's eligible handler list
3289 	// and also set its next handler to be this window.
3290 
3291 	STRACE(("Calling setowner fTopView = %p this = %p.\n",
3292 		fTopView, this));
3293 
3294 	fTopView->_SetOwner(this);
3295 
3296 	// we can't use AddChild() because this is the top view
3297 	fTopView->_CreateSelf();
3298 	STRACE(("BuildTopView ended\n"));
3299 }
3300 
3301 
3302 /*!
3303 	Resizes the top view to match the window size. This will also
3304 	adapt the size of all its child views as needed.
3305 	This method has to be called whenever the frame of the window
3306 	changes.
3307 */
3308 void
3309 BWindow::_AdoptResize()
3310 {
3311 	// Resize views according to their resize modes - this
3312 	// saves us some server communication, as the server
3313 	// does the same with our views on its side.
3314 
3315 	int32 deltaWidth = (int32)(fFrame.Width() - fTopView->Bounds().Width());
3316 	int32 deltaHeight = (int32)(fFrame.Height() - fTopView->Bounds().Height());
3317 	if (deltaWidth == 0 && deltaHeight == 0)
3318 		return;
3319 
3320 	fTopView->_ResizeBy(deltaWidth, deltaHeight);
3321 }
3322 
3323 
3324 void
3325 BWindow::_SetFocus(BView* focusView, bool notifyInputServer)
3326 {
3327 	if (fFocus == focusView)
3328 		return;
3329 
3330 	// we notify the input server if we are passing focus
3331 	// from a view which has the B_INPUT_METHOD_AWARE to a one
3332 	// which does not, or vice-versa
3333 	if (notifyInputServer && fActive) {
3334 		bool inputMethodAware = false;
3335 		if (focusView)
3336 			inputMethodAware = focusView->Flags() & B_INPUT_METHOD_AWARE;
3337 		BMessage msg(inputMethodAware ? IS_FOCUS_IM_AWARE_VIEW : IS_UNFOCUS_IM_AWARE_VIEW);
3338 		BMessenger messenger(focusView);
3339 		BMessage reply;
3340 		if (focusView)
3341 			msg.AddMessenger("view", messenger);
3342 		_control_input_server_(&msg, &reply);
3343 	}
3344 
3345 	fFocus = focusView;
3346 	SetPreferredHandler(focusView);
3347 }
3348 
3349 
3350 /*!
3351 	\brief Determines the target of a message received for the
3352 		focus view.
3353 */
3354 BHandler*
3355 BWindow::_DetermineTarget(BMessage* message, BHandler* target)
3356 {
3357 	if (target == NULL)
3358 		target = this;
3359 
3360 	switch (message->what) {
3361 		case B_KEY_DOWN:
3362 		case B_KEY_UP:
3363 		{
3364 			// if we have a default button, it might want to hear
3365 			// about pressing the <enter> key
3366 			const int32 kNonLockModifierKeys = B_SHIFT_KEY | B_COMMAND_KEY
3367 				| B_CONTROL_KEY | B_OPTION_KEY | B_MENU_KEY;
3368 			int32 rawChar;
3369 			if (DefaultButton() != NULL
3370 				&& message->FindInt32("raw_char", &rawChar) == B_OK
3371 				&& rawChar == B_ENTER
3372 				&& (modifiers() & kNonLockModifierKeys) == 0)
3373 				return DefaultButton();
3374 
3375 			// supposed to fall through
3376 		}
3377 		case B_UNMAPPED_KEY_DOWN:
3378 		case B_UNMAPPED_KEY_UP:
3379 		case B_MODIFIERS_CHANGED:
3380 			// these messages should be dispatched by the focus view
3381 			if (CurrentFocus() != NULL)
3382 				return CurrentFocus();
3383 			break;
3384 
3385 		case B_MOUSE_DOWN:
3386 		case B_MOUSE_UP:
3387 		case B_MOUSE_MOVED:
3388 		case B_MOUSE_WHEEL_CHANGED:
3389 		case B_MOUSE_IDLE:
3390 			// is there a token of the view that is currently under the mouse?
3391 			int32 token;
3392 			if (message->FindInt32("_view_token", &token) == B_OK) {
3393 				BView* view = _FindView(token);
3394 				if (view != NULL)
3395 					return view;
3396 			}
3397 
3398 			// if there is no valid token in the message, we try our
3399 			// luck with the last target, if available
3400 			if (fLastMouseMovedView != NULL)
3401 				return fLastMouseMovedView;
3402 			break;
3403 
3404 		case B_PULSE:
3405 		case B_QUIT_REQUESTED:
3406 			// TODO: test whether R5 will let BView dispatch these messages
3407 			return this;
3408 
3409 		case _MESSAGE_DROPPED_:
3410 			if (fLastMouseMovedView != NULL)
3411 				return fLastMouseMovedView;
3412 			break;
3413 
3414 		default:
3415 			break;
3416 	}
3417 
3418 	return target;
3419 }
3420 
3421 
3422 /*!	\brief Determines whether or not this message has targeted the focus view.
3423 
3424 	This will return \c false only if the message did not go to the preferred
3425 	handler, or if the packed message does not contain address the focus view
3426 	at all.
3427 */
3428 bool
3429 BWindow::_IsFocusMessage(BMessage* message)
3430 {
3431 	BMessage::Private messagePrivate(message);
3432 	if (!messagePrivate.UsePreferredTarget())
3433 		return false;
3434 
3435 	bool feedFocus;
3436 	if (message->HasInt32("_token")
3437 		&& (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus))
3438 		return false;
3439 
3440 	return true;
3441 }
3442 
3443 
3444 /*!	\brief Distributes the message to its intended targets. This is done for
3445 		all messages that should go to the preferred handler.
3446 
3447 	Returns \c true in case the message should still be dispatched
3448 */
3449 bool
3450 BWindow::_UnpackMessage(unpack_cookie& cookie, BMessage** _message,
3451 	BHandler** _target, bool* _usePreferred)
3452 {
3453 	if (cookie.message == NULL)
3454 		return false;
3455 
3456 	if (cookie.index == 0 && !cookie.tokens_scanned) {
3457 		// We were called the first time for this message
3458 
3459 		if (!*_usePreferred) {
3460 			// only consider messages targeted at the preferred handler
3461 			cookie.message = NULL;
3462 			return true;
3463 		}
3464 
3465 		// initialize our cookie
3466 		cookie.message = *_message;
3467 		cookie.focus = *_target;
3468 
3469 		if (cookie.focus != NULL)
3470 			cookie.focus_token = _get_object_token_(*_target);
3471 
3472 		if (fLastMouseMovedView != NULL && cookie.message->what == B_MOUSE_MOVED)
3473 			cookie.last_view_token = _get_object_token_(fLastMouseMovedView);
3474 
3475 		*_usePreferred = false;
3476 	}
3477 
3478 	_DequeueAll();
3479 
3480 	// distribute the message to all targets specified in the
3481 	// message directly (but not to the focus view)
3482 
3483 	for (int32 token; !cookie.tokens_scanned
3484 			&& cookie.message->FindInt32("_token", cookie.index, &token)
3485 				== B_OK;
3486 			cookie.index++) {
3487 		// focus view is preferred and should get its message directly
3488 		if (token == cookie.focus_token) {
3489 			cookie.found_focus = true;
3490 			continue;
3491 		}
3492 		if (token == cookie.last_view_token)
3493 			continue;
3494 
3495 		BView* target = _FindView(token);
3496 		if (target == NULL)
3497 			continue;
3498 
3499 		*_message = new BMessage(*cookie.message);
3500 		// the secondary copies of the message should not be treated as focus
3501 		// messages, otherwise there will be unintended side effects, i.e.
3502 		// keyboard shortcuts getting processed multiple times.
3503 		(*_message)->RemoveName("_feed_focus");
3504 		*_target = target;
3505 		cookie.index++;
3506 		return true;
3507 	}
3508 
3509 	cookie.tokens_scanned = true;
3510 
3511 	// if there is a last mouse moved view, and the new focus is
3512 	// different, the previous view wants to get its B_EXITED_VIEW
3513 	// message
3514 	if (cookie.last_view_token != B_NULL_TOKEN && fLastMouseMovedView != NULL
3515 		&& fLastMouseMovedView != cookie.focus) {
3516 		*_message = new BMessage(*cookie.message);
3517 		*_target = fLastMouseMovedView;
3518 		cookie.last_view_token = B_NULL_TOKEN;
3519 		return true;
3520 	}
3521 
3522 	bool dispatchToFocus = true;
3523 
3524 	// check if the focus token is still valid (could have been removed in the mean time)
3525 	BHandler* handler;
3526 	if (gDefaultTokens.GetToken(cookie.focus_token, B_HANDLER_TOKEN, (void**)&handler) != B_OK
3527 		|| handler->Looper() != this)
3528 		dispatchToFocus = false;
3529 
3530 	if (dispatchToFocus && cookie.index > 0) {
3531 		// should this message still be dispatched by the focus view?
3532 		bool feedFocus;
3533 		if (!cookie.found_focus
3534 			&& (cookie.message->FindBool("_feed_focus", &feedFocus) != B_OK
3535 				|| feedFocus == false))
3536 			dispatchToFocus = false;
3537 	}
3538 
3539 	if (!dispatchToFocus) {
3540 		delete cookie.message;
3541 		cookie.message = NULL;
3542 		return false;
3543 	}
3544 
3545 	*_message = cookie.message;
3546 	*_target = cookie.focus;
3547 	*_usePreferred = true;
3548 	cookie.message = NULL;
3549 	return true;
3550 }
3551 
3552 
3553 /*!	Some messages don't get to the window in a shape an application should see.
3554 	This method is supposed to give a message the last grinding before
3555 	it's acceptable for the receiving application.
3556 */
3557 void
3558 BWindow::_SanitizeMessage(BMessage* message, BHandler* target, bool usePreferred)
3559 {
3560 	if (target == NULL)
3561 		return;
3562 
3563 	switch (message->what) {
3564 		case B_MOUSE_MOVED:
3565 		case B_MOUSE_UP:
3566 		case B_MOUSE_DOWN:
3567 		{
3568 			BPoint where;
3569 			if (message->FindPoint("screen_where", &where) != B_OK)
3570 				break;
3571 
3572 			BView* view = dynamic_cast<BView*>(target);
3573 
3574 			if (view == NULL || message->what == B_MOUSE_MOVED) {
3575 				// add local window coordinates, only
3576 				// for regular mouse moved messages
3577 				message->AddPoint("where", ConvertFromScreen(where));
3578 			}
3579 
3580 			if (view != NULL) {
3581 				// add local view coordinates
3582 				BPoint viewWhere = view->ConvertFromScreen(where);
3583 				if (message->what != B_MOUSE_MOVED) {
3584 					// Yep, the meaning of "where" is different
3585 					// for regular mouse moved messages versus
3586 					// mouse up/down!
3587 					message->AddPoint("where", viewWhere);
3588 				}
3589 				message->AddPoint("be:view_where", viewWhere);
3590 
3591 				if (message->what == B_MOUSE_MOVED) {
3592 					// is there a token of the view that is currently under
3593 					// the mouse?
3594 					BView* viewUnderMouse = NULL;
3595 					int32 token;
3596 					if (message->FindInt32("_view_token", &token) == B_OK)
3597 						viewUnderMouse = _FindView(token);
3598 
3599 					// add transit information
3600 					uint32 transit
3601 						= _TransitForMouseMoved(view, viewUnderMouse);
3602 					message->AddInt32("be:transit", transit);
3603 
3604 					if (usePreferred)
3605 						fLastMouseMovedView = viewUnderMouse;
3606 				}
3607 			}
3608 			break;
3609 		}
3610 
3611 		case B_MOUSE_IDLE:
3612 		{
3613 			// App Server sends screen coordinates, convert the point to
3614 			// local view coordinates, then add the point in be:view_where
3615 			BPoint where;
3616 			if (message->FindPoint("screen_where", &where) != B_OK)
3617 				break;
3618 
3619 			BView* view = dynamic_cast<BView*>(target);
3620 			if (view != NULL) {
3621 				// add local view coordinates
3622 				message->AddPoint("be:view_where",
3623 					view->ConvertFromScreen(where));
3624 			}
3625 			break;
3626 		}
3627 
3628 		case _MESSAGE_DROPPED_:
3629 		{
3630 			uint32 originalWhat;
3631 			if (message->FindInt32("_original_what",
3632 					(int32*)&originalWhat) == B_OK) {
3633 				message->what = originalWhat;
3634 				message->RemoveName("_original_what");
3635 			}
3636 			break;
3637 		}
3638 	}
3639 }
3640 
3641 
3642 /*!
3643 	This is called by BView::GetMouse() when a B_MOUSE_MOVED message
3644 	is removed from the queue.
3645 	It allows the window to update the last mouse moved view, and
3646 	let it decide if this message should be kept. It will also remove
3647 	the message from the queue.
3648 	You need to hold the message queue lock when calling this method!
3649 
3650 	\return true if this message can be used to get the mouse data from,
3651 	\return false if this is not meant for the public.
3652 */
3653 bool
3654 BWindow::_StealMouseMessage(BMessage* message, bool& deleteMessage)
3655 {
3656 	BMessage::Private messagePrivate(message);
3657 	if (!messagePrivate.UsePreferredTarget()) {
3658 		// this message is targeted at a specific handler, so we should
3659 		// not steal it
3660 		return false;
3661 	}
3662 
3663 	int32 token;
3664 	if (message->FindInt32("_token", 0, &token) == B_OK) {
3665 		// This message has other targets, so we can't remove it;
3666 		// just prevent it from being sent to the preferred handler
3667 		// again (if it should have gotten it at all).
3668 		bool feedFocus;
3669 		if (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus)
3670 			return false;
3671 
3672 		message->RemoveName("_feed_focus");
3673 		deleteMessage = false;
3674 	} else {
3675 		deleteMessage = true;
3676 
3677 		if (message->what == B_MOUSE_MOVED) {
3678 			// We need to update the last mouse moved view, as this message
3679 			// won't make it to _SanitizeMessage() anymore.
3680 			BView* viewUnderMouse = NULL;
3681 			int32 token;
3682 			if (message->FindInt32("_view_token", &token) == B_OK)
3683 				viewUnderMouse = _FindView(token);
3684 
3685 			// Don't remove important transit messages!
3686 			uint32 transit = _TransitForMouseMoved(fLastMouseMovedView,
3687 				viewUnderMouse);
3688 			if (transit == B_ENTERED_VIEW || transit == B_EXITED_VIEW)
3689 				deleteMessage = false;
3690 		}
3691 
3692 		if (deleteMessage) {
3693 			// The message is only thought for the preferred handler, so we
3694 			// can just remove it.
3695 			MessageQueue()->RemoveMessage(message);
3696 		}
3697 	}
3698 
3699 	return true;
3700 }
3701 
3702 
3703 uint32
3704 BWindow::_TransitForMouseMoved(BView* view, BView* viewUnderMouse) const
3705 {
3706 	uint32 transit;
3707 	if (viewUnderMouse == view) {
3708 		// the mouse is over the target view
3709 		if (fLastMouseMovedView != view)
3710 			transit = B_ENTERED_VIEW;
3711 		else
3712 			transit = B_INSIDE_VIEW;
3713 	} else {
3714 		// the mouse is not over the target view
3715 		if (view == fLastMouseMovedView)
3716 			transit = B_EXITED_VIEW;
3717 		else
3718 			transit = B_OUTSIDE_VIEW;
3719 	}
3720 	return transit;
3721 }
3722 
3723 
3724 /*!	Forwards the key to the switcher
3725 */
3726 void
3727 BWindow::_Switcher(int32 rawKey, uint32 modifiers, bool repeat)
3728 {
3729 	// only send the first key press, no repeats
3730 	if (repeat)
3731 		return;
3732 
3733 	BMessenger deskbar(kDeskbarSignature);
3734 	if (!deskbar.IsValid()) {
3735 		// TODO: have some kind of fallback-handling in case the Deskbar is
3736 		// not available?
3737 		return;
3738 	}
3739 
3740 	BMessage message('TASK');
3741 	message.AddInt32("key", rawKey);
3742 	message.AddInt32("modifiers", modifiers);
3743 	message.AddInt64("when", system_time());
3744 	message.AddInt32("team", Team());
3745 	deskbar.SendMessage(&message);
3746 }
3747 
3748 
3749 /*!	Handles keyboard input before it gets forwarded to the target handler.
3750 	This includes shortcut evaluation, keyboard navigation, etc.
3751 
3752 	\return handled if true, the event was already handled, and will not
3753 		be forwarded to the target handler.
3754 
3755 	TODO: must also convert the incoming key to the font encoding of the target
3756 */
3757 bool
3758 BWindow::_HandleKeyDown(BMessage* event)
3759 {
3760 	// Only handle special functions when the event targeted the active focus
3761 	// view
3762 	if (!_IsFocusMessage(event))
3763 		return false;
3764 
3765 	const char* bytes = NULL;
3766 	if (event->FindString("bytes", &bytes) != B_OK)
3767 		return false;
3768 
3769 	char key = bytes[0];
3770 
3771 	uint32 modifiers;
3772 	if (event->FindInt32("modifiers", (int32*)&modifiers) != B_OK)
3773 		modifiers = 0;
3774 
3775 	// handle BMenuBar key
3776 	if (key == B_ESCAPE && (modifiers & B_COMMAND_KEY) != 0
3777 		&& fKeyMenuBar != NULL) {
3778 		fKeyMenuBar->StartMenuBar(0, true, false, NULL);
3779 		return true;
3780 	}
3781 
3782 	// Keyboard navigation through views
3783 	// (B_OPTION_KEY makes BTextViews and friends navigable, even in editing
3784 	// mode)
3785 	if (key == B_TAB && (modifiers & B_OPTION_KEY) != 0) {
3786 		_KeyboardNavigation();
3787 		return true;
3788 	}
3789 
3790 	int32 rawKey;
3791 	event->FindInt32("key", &rawKey);
3792 
3793 	// Deskbar's Switcher
3794 	if ((key == B_TAB || rawKey == 0x11) && (modifiers & B_CONTROL_KEY) != 0) {
3795 		_Switcher(rawKey, modifiers, event->HasInt32("be:key_repeat"));
3796 		return true;
3797 	}
3798 
3799 	// Optionally close window when the escape key is pressed
3800 	if (key == B_ESCAPE && (Flags() & B_CLOSE_ON_ESCAPE) != 0) {
3801 		BMessage message(B_QUIT_REQUESTED);
3802 		message.AddBool("shortcut", true);
3803 
3804 		PostMessage(&message);
3805 		return true;
3806 	}
3807 
3808 	// PrtScr key takes a screenshot
3809 	if (key == B_FUNCTION_KEY && rawKey == B_PRINT_KEY) {
3810 		// With no modifier keys the best way to get a screenshot is by
3811 		// calling the screenshot CLI
3812 		if (modifiers == 0) {
3813 			be_roster->Launch("application/x-vnd.haiku-screenshot-cli");
3814 			return true;
3815 		}
3816 
3817 		// Prepare a message based on the modifier keys pressed and launch the
3818 		// screenshot GUI
3819 		BMessage message(B_ARGV_RECEIVED);
3820 		int32 argc = 1;
3821 		message.AddString("argv", "Screenshot");
3822 		if ((modifiers & B_CONTROL_KEY) != 0) {
3823 			argc++;
3824 			message.AddString("argv", "--clipboard");
3825 		}
3826 		if ((modifiers & B_SHIFT_KEY) != 0) {
3827 			argc++;
3828 			message.AddString("argv", "--silent");
3829 		}
3830 		message.AddInt32("argc", argc);
3831 		be_roster->Launch("application/x-vnd.haiku-screenshot", &message);
3832 		return true;
3833 	}
3834 
3835 	// Handle shortcuts
3836 	if ((modifiers & B_COMMAND_KEY) != 0) {
3837 		// Command+q has been pressed, so, we will quit
3838 		// the shortcut mechanism doesn't allow handlers outside the window
3839 		if (!fNoQuitShortcut && (key == 'Q' || key == 'q')) {
3840 			BMessage message(B_QUIT_REQUESTED);
3841 			message.AddBool("shortcut", true);
3842 
3843 			be_app->PostMessage(&message);
3844 			// eat the event
3845 			return true;
3846 		}
3847 
3848 		// Send Command+Left and Command+Right to textview if it has focus
3849 		if (key == B_LEFT_ARROW || key == B_RIGHT_ARROW) {
3850 			// check key before doing expensive dynamic_cast
3851 			BTextView* textView = dynamic_cast<BTextView*>(CurrentFocus());
3852 			if (textView != NULL) {
3853 				textView->KeyDown(bytes, modifiers);
3854 				// eat the event
3855 				return true;
3856 			}
3857 		}
3858 
3859 		// Pretend that the user opened a menu, to give the subclass a
3860 		// chance to update it's menus. This may install new shortcuts,
3861 		// which is why we have to call it here, before trying to find
3862 		// a shortcut for the given key.
3863 		MenusBeginning();
3864 
3865 		Shortcut* shortcut = _FindShortcut(key, modifiers);
3866 		if (shortcut != NULL) {
3867 			// TODO: would be nice to move this functionality to
3868 			//	a Shortcut::Invoke() method - but since BMenu::InvokeItem()
3869 			//	(and BMenuItem::Invoke()) are private, I didn't want
3870 			//	to mess with them (BMenuItem::Invoke() is public in
3871 			//	Dano/Zeta, though, maybe we should just follow their
3872 			//	example)
3873 			if (shortcut->MenuItem() != NULL) {
3874 				BMenu* menu = shortcut->MenuItem()->Menu();
3875 				if (menu != NULL)
3876 					MenuPrivate(menu).InvokeItem(shortcut->MenuItem(), true);
3877 			} else {
3878 				BHandler* target = shortcut->Target();
3879 				if (target == NULL)
3880 					target = CurrentFocus();
3881 
3882 				if (shortcut->Message() != NULL) {
3883 					BMessage message(*shortcut->Message());
3884 
3885 					if (message.ReplaceInt64("when", system_time()) != B_OK)
3886 						message.AddInt64("when", system_time());
3887 					if (message.ReplaceBool("shortcut", true) != B_OK)
3888 						message.AddBool("shortcut", true);
3889 
3890 					PostMessage(&message, target);
3891 				}
3892 			}
3893 		}
3894 
3895 		MenusEnded();
3896 
3897 		// we always eat the event if the command key was pressed
3898 		return true;
3899 	}
3900 
3901 	// TODO: convert keys to the encoding of the target view
3902 
3903 	return false;
3904 }
3905 
3906 
3907 bool
3908 BWindow::_HandleUnmappedKeyDown(BMessage* event)
3909 {
3910 	// Only handle special functions when the event targeted the active focus
3911 	// view
3912 	if (!_IsFocusMessage(event))
3913 		return false;
3914 
3915 	uint32 modifiers;
3916 	int32 rawKey;
3917 	if (event->FindInt32("modifiers", (int32*)&modifiers) != B_OK
3918 		|| event->FindInt32("key", &rawKey))
3919 		return false;
3920 
3921 	// Deskbar's Switcher
3922 	if (rawKey == 0x11 && (modifiers & B_CONTROL_KEY) != 0) {
3923 		_Switcher(rawKey, modifiers, event->HasInt32("be:key_repeat"));
3924 		return true;
3925 	}
3926 
3927 	return false;
3928 }
3929 
3930 
3931 void
3932 BWindow::_KeyboardNavigation()
3933 {
3934 	BMessage* message = CurrentMessage();
3935 	if (message == NULL)
3936 		return;
3937 
3938 	const char* bytes;
3939 	uint32 modifiers;
3940 	if (message->FindString("bytes", &bytes) != B_OK || bytes[0] != B_TAB)
3941 		return;
3942 
3943 	message->FindInt32("modifiers", (int32*)&modifiers);
3944 
3945 	BView* nextFocus;
3946 	int32 jumpGroups = (modifiers & B_OPTION_KEY) != 0
3947 		? B_NAVIGABLE_JUMP : B_NAVIGABLE;
3948 	if (modifiers & B_SHIFT_KEY)
3949 		nextFocus = _FindPreviousNavigable(fFocus, jumpGroups);
3950 	else
3951 		nextFocus = _FindNextNavigable(fFocus, jumpGroups);
3952 
3953 	if (nextFocus != NULL && nextFocus != fFocus)
3954 		nextFocus->MakeFocus(true);
3955 }
3956 
3957 
3958 /*!
3959 	\brief Return the position of the window centered horizontally to the passed
3960            in \a frame and vertically 3/4 from the top of \a frame.
3961 
3962 	If the window is on the borders
3963 
3964 	\param width The width of the window.
3965 	\param height The height of the window.
3966 	\param frame The \a frame to center the window in.
3967 
3968 	\return The new window position.
3969 */
3970 BPoint
3971 BWindow::AlertPosition(const BRect& frame)
3972 {
3973 	float width = Bounds().Width();
3974 	float height = Bounds().Height();
3975 
3976 	BPoint point(frame.left + (frame.Width() / 2.0f) - (width / 2.0f),
3977 		frame.top + (frame.Height() / 4.0f) - ceil(height / 3.0f));
3978 
3979 	BRect screenFrame = BScreen(this).Frame();
3980 	if (frame == screenFrame) {
3981 		// reference frame is screen frame, skip the below adjustments
3982 		return point;
3983 	}
3984 
3985 	float borderWidth;
3986 	float tabHeight;
3987 	_GetDecoratorSize(&borderWidth, &tabHeight);
3988 
3989 	// clip the x position within the horizontal edges of the screen
3990 	if (point.x < screenFrame.left + borderWidth)
3991 		point.x = screenFrame.left + borderWidth;
3992 	else if (point.x + width > screenFrame.right - borderWidth)
3993 		point.x = screenFrame.right - borderWidth - width;
3994 
3995 	// lower the window down if it is covering the window tab
3996 	float tabPosition = frame.LeftTop().y + tabHeight + borderWidth;
3997 	if (point.y < tabPosition)
3998 		point.y = tabPosition;
3999 
4000 	// clip the y position within the vertical edges of the screen
4001 	if (point.y < screenFrame.top + borderWidth)
4002 		point.y = screenFrame.top + borderWidth;
4003 	else if (point.y + height > screenFrame.bottom - borderWidth)
4004 		point.y = screenFrame.bottom - borderWidth - height;
4005 
4006 	return point;
4007 }
4008 
4009 
4010 BMessage*
4011 BWindow::ConvertToMessage(void* raw, int32 code)
4012 {
4013 	return BLooper::ConvertToMessage(raw, code);
4014 }
4015 
4016 
4017 BWindow::Shortcut*
4018 BWindow::_FindShortcut(uint32 key, uint32 modifiers)
4019 {
4020 	int32 count = fShortcuts.CountItems();
4021 
4022 	key = Shortcut::PrepareKey(key);
4023 	modifiers = Shortcut::PrepareModifiers(modifiers);
4024 
4025 	for (int32 index = 0; index < count; index++) {
4026 		Shortcut* shortcut = (Shortcut*)fShortcuts.ItemAt(index);
4027 
4028 		if (shortcut->Matches(key, modifiers))
4029 			return shortcut;
4030 	}
4031 
4032 	return NULL;
4033 }
4034 
4035 
4036 BView*
4037 BWindow::_FindView(int32 token)
4038 {
4039 	BHandler* handler;
4040 	if (gDefaultTokens.GetToken(token, B_HANDLER_TOKEN,
4041 			(void**)&handler) != B_OK) {
4042 		return NULL;
4043 	}
4044 
4045 	// the view must belong to us in order to be found by this method
4046 	BView* view = dynamic_cast<BView*>(handler);
4047 	if (view != NULL && view->Window() == this)
4048 		return view;
4049 
4050 	return NULL;
4051 }
4052 
4053 
4054 BView*
4055 BWindow::_FindView(BView* view, BPoint point) const
4056 {
4057 	// point is assumed to be already in view's coordinates
4058 	if (!view->IsHidden(view) && view->Bounds().Contains(point)) {
4059 		if (view->fFirstChild == NULL)
4060 			return view;
4061 		else {
4062 			BView* child = view->fFirstChild;
4063 			while (child != NULL) {
4064 				BPoint childPoint = point - child->Frame().LeftTop();
4065 				BView* subView  = _FindView(child, childPoint);
4066 				if (subView != NULL)
4067 					return subView;
4068 
4069 				child = child->fNextSibling;
4070 			}
4071 		}
4072 		return view;
4073 	}
4074 	return NULL;
4075 }
4076 
4077 
4078 BView*
4079 BWindow::_FindNextNavigable(BView* focus, uint32 flags)
4080 {
4081 	if (focus == NULL)
4082 		focus = fTopView;
4083 
4084 	BView* nextFocus = focus;
4085 
4086 	// Search the tree for views that accept focus (depth search)
4087 	while (true) {
4088 		if (nextFocus->fFirstChild)
4089 			nextFocus = nextFocus->fFirstChild;
4090 		else if (nextFocus->fNextSibling)
4091 			nextFocus = nextFocus->fNextSibling;
4092 		else {
4093 			// go to the nearest parent with a next sibling
4094 			while (!nextFocus->fNextSibling && nextFocus->fParent) {
4095 				nextFocus = nextFocus->fParent;
4096 			}
4097 
4098 			if (nextFocus == fTopView) {
4099 				// if we started with the top view, we traversed the whole tree already
4100 				if (nextFocus == focus)
4101 					return NULL;
4102 
4103 				nextFocus = nextFocus->fFirstChild;
4104 			} else
4105 				nextFocus = nextFocus->fNextSibling;
4106 		}
4107 
4108 		if (nextFocus == focus || nextFocus == NULL) {
4109 			// When we get here it means that the hole tree has been
4110 			// searched and there is no view with B_NAVIGABLE(_JUMP) flag set!
4111 			return NULL;
4112 		}
4113 
4114 		if (!nextFocus->IsHidden() && (nextFocus->Flags() & flags) != 0)
4115 			return nextFocus;
4116 	}
4117 }
4118 
4119 
4120 BView*
4121 BWindow::_FindPreviousNavigable(BView* focus, uint32 flags)
4122 {
4123 	if (focus == NULL)
4124 		focus = fTopView;
4125 
4126 	BView* previousFocus = focus;
4127 
4128 	// Search the tree for the previous view that accept focus
4129 	while (true) {
4130 		if (previousFocus->fPreviousSibling) {
4131 			// find the last child in the previous sibling
4132 			previousFocus = _LastViewChild(previousFocus->fPreviousSibling);
4133 		} else {
4134 			previousFocus = previousFocus->fParent;
4135 			if (previousFocus == fTopView)
4136 				previousFocus = _LastViewChild(fTopView);
4137 		}
4138 
4139 		if (previousFocus == focus || previousFocus == NULL) {
4140 			// When we get here it means that the hole tree has been
4141 			// searched and there is no view with B_NAVIGABLE(_JUMP) flag set!
4142 			return NULL;
4143 		}
4144 
4145 		if (!previousFocus->IsHidden() && (previousFocus->Flags() & flags) != 0)
4146 			return previousFocus;
4147 	}
4148 }
4149 
4150 
4151 /*!
4152 	Returns the last child in a view hierarchy.
4153 	Needed only by _FindPreviousNavigable().
4154 */
4155 BView*
4156 BWindow::_LastViewChild(BView* parent)
4157 {
4158 	while (true) {
4159 		BView* last = parent->fFirstChild;
4160 		if (last == NULL)
4161 			return parent;
4162 
4163 		while (last->fNextSibling) {
4164 			last = last->fNextSibling;
4165 		}
4166 
4167 		parent = last;
4168 	}
4169 }
4170 
4171 
4172 void
4173 BWindow::SetIsFilePanel(bool isFilePanel)
4174 {
4175 	fIsFilePanel = isFilePanel;
4176 }
4177 
4178 
4179 bool
4180 BWindow::IsFilePanel() const
4181 {
4182 	return fIsFilePanel;
4183 }
4184 
4185 
4186 void
4187 BWindow::_GetDecoratorSize(float* _borderWidth, float* _tabHeight) const
4188 {
4189 	// fallback in case retrieving the decorator settings fails
4190 	// (highly unlikely)
4191 	float borderWidth = 5.0;
4192 	float tabHeight = 21.0;
4193 
4194 	BMessage settings;
4195 	if (GetDecoratorSettings(&settings) == B_OK) {
4196 		BRect tabRect;
4197 		if (settings.FindRect("tab frame", &tabRect) == B_OK)
4198 			tabHeight = tabRect.Height();
4199 		settings.FindFloat("border width", &borderWidth);
4200 	} else {
4201 		// probably no-border window look
4202 		if (fLook == B_NO_BORDER_WINDOW_LOOK) {
4203 			borderWidth = 0.0;
4204 			tabHeight = 0.0;
4205 		}
4206 		// else use fall-back values from above
4207 	}
4208 
4209 	if (_borderWidth != NULL)
4210 		*_borderWidth = borderWidth;
4211 	if (_tabHeight != NULL)
4212 		*_tabHeight = tabHeight;
4213 }
4214 
4215 
4216 void
4217 BWindow::_SendShowOrHideMessage()
4218 {
4219 	fLink->StartMessage(AS_SHOW_OR_HIDE_WINDOW);
4220 	fLink->Attach<int32>(fShowLevel);
4221 	fLink->Flush();
4222 }
4223 
4224 
4225 //	#pragma mark - C++ binary compatibility kludge
4226 
4227 
4228 extern "C" void
4229 _ReservedWindow1__7BWindow(BWindow* window, BLayout* layout)
4230 {
4231 	// SetLayout()
4232 	perform_data_set_layout data;
4233 	data.layout = layout;
4234 	window->Perform(PERFORM_CODE_SET_LAYOUT, &data);
4235 }
4236 
4237 
4238 void BWindow::_ReservedWindow2() {}
4239 void BWindow::_ReservedWindow3() {}
4240 void BWindow::_ReservedWindow4() {}
4241 void BWindow::_ReservedWindow5() {}
4242 void BWindow::_ReservedWindow6() {}
4243 void BWindow::_ReservedWindow7() {}
4244 void BWindow::_ReservedWindow8() {}
4245 
4246