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