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