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