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