2 * Copyright 2001-2014 Haiku, Inc. All rights reserved
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus, superstippi@gmx.de
7 * Axel Dörfler, axeld@pinc-software.de
8 * Adrian Oanca, adioanca@cotty.iren.ro
9 * John Scipione, jscipione@gmail.com
20 #include <Application.h>
24 #include <FindDirectory.h>
26 #include <LayoutUtils.h>
29 #include <MessageQueue.h>
30 #include <MessageRunner.h>
32 #include <PropertyInfo.h>
36 #include <UnicodeChar.h>
39 #include <AppServerLink.h>
40 #include <ApplicationPrivate.h>
41 #include <binary_compatibility/Interface.h>
42 #include <DirectMessageTarget.h>
43 #include <input_globals.h>
44 #include <InputServerTypes.h>
45 #include <MenuPrivate.h>
46 #include <MessagePrivate.h>
48 #include <RosterPrivate.h>
49 #include <ServerProtocol.h>
50 #include <TokenSpace.h>
51 #include <ToolTipManager.h>
52 #include <ToolTipWindow.h>
53 #include <tracker_private.h>
54 #include <WindowPrivate.h>
59 # define STRACE(x) printf x
64 #define B_HIDE_APPLICATION '_AHD'
65 // if we ever move this to a public namespace, we should also move the
66 // handling of this message into BApplication
68 #define _MINIMIZE_ '_WMZ'
70 #define _SEND_BEHIND_ '_WSB'
71 #define _SEND_TO_FRONT_ '_WSF'
74 void do_minimize_team(BRect zoomRect
, team_id team
, bool zoom
);
77 struct BWindow::unpack_cookie
{
84 int32 last_view_token
;
90 class BWindow::Shortcut
{
92 Shortcut(uint32 key
, uint32 modifiers
,
94 Shortcut(uint32 key
, uint32 modifiers
,
95 BMessage
* message
, BHandler
* target
);
98 bool Matches(uint32 key
, uint32 modifiers
) const;
100 BMenuItem
* MenuItem() const { return fMenuItem
; }
101 BMessage
* Message() const { return fMessage
; }
102 BHandler
* Target() const { return fTarget
; }
104 static uint32
AllowedModifiers();
105 static uint32
PrepareKey(uint32 key
);
106 static uint32
PrepareModifiers(uint32 modifiers
);
111 BMenuItem
* fMenuItem
;
117 using BPrivate::gDefaultTokens
;
118 using BPrivate::MenuPrivate
;
120 static property_info sWindowPropInfo
[] = {
122 "Active", { B_GET_PROPERTY
, B_SET_PROPERTY
},
123 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_BOOL_TYPE
}
127 "Feel", { B_GET_PROPERTY
, B_SET_PROPERTY
},
128 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_INT32_TYPE
}
132 "Flags", { B_GET_PROPERTY
, B_SET_PROPERTY
},
133 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_INT32_TYPE
}
137 "Frame", { B_GET_PROPERTY
, B_SET_PROPERTY
},
138 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_RECT_TYPE
}
142 "Hidden", { B_GET_PROPERTY
, B_SET_PROPERTY
},
143 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_BOOL_TYPE
}
147 "Look", { B_GET_PROPERTY
, B_SET_PROPERTY
},
148 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_INT32_TYPE
}
152 "Title", { B_GET_PROPERTY
, B_SET_PROPERTY
},
153 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_STRING_TYPE
}
157 "Workspaces", { B_GET_PROPERTY
, B_SET_PROPERTY
},
158 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_INT32_TYPE
}
163 { B_DIRECT_SPECIFIER
}, NULL
, 0, {}
167 "View", { B_COUNT_PROPERTIES
},
168 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_INT32_TYPE
}
172 "View", {}, {}, NULL
, 0, {}
176 "Minimize", { B_GET_PROPERTY
, B_SET_PROPERTY
},
177 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_BOOL_TYPE
}
181 "TabFrame", { B_GET_PROPERTY
},
182 { B_DIRECT_SPECIFIER
}, NULL
, 0, { B_RECT_TYPE
}
188 static value_info sWindowValueInfo
[] = {
190 "MoveTo", 'WDMT', B_COMMAND_KIND
,
191 "Moves to the position in the BPoint data"
195 "MoveBy", 'WDMB', B_COMMAND_KIND
,
196 "Moves by the offsets in the BPoint data"
200 "ResizeTo", 'WDRT', B_COMMAND_KIND
,
201 "Resize to the size in the BPoint data"
205 "ResizeBy", 'WDRB', B_COMMAND_KIND
,
206 "Resize by the offsets in the BPoint data"
214 _set_menu_sem_(BWindow
* window
, sem_id sem
)
217 window
->fMenuSem
= sem
;
224 BWindow::unpack_cookie::unpack_cookie()
226 message((BMessage
*)~0UL),
227 // message == NULL is our exit condition
229 focus_token(B_NULL_TOKEN
),
230 last_view_token(B_NULL_TOKEN
),
232 tokens_scanned(false)
237 // #pragma mark - BWindow::Shortcut
240 BWindow::Shortcut::Shortcut(uint32 key
, uint32 modifiers
, BMenuItem
* item
)
242 fKey(PrepareKey(key
)),
243 fModifiers(PrepareModifiers(modifiers
)),
251 BWindow::Shortcut::Shortcut(uint32 key
, uint32 modifiers
, BMessage
* message
,
254 fKey(PrepareKey(key
)),
255 fModifiers(PrepareModifiers(modifiers
)),
263 BWindow::Shortcut::~Shortcut()
265 // we own the message, if any
271 BWindow::Shortcut::Matches(uint32 key
, uint32 modifiers
) const
273 return fKey
== key
&& fModifiers
== modifiers
;
279 BWindow::Shortcut::AllowedModifiers()
281 return B_COMMAND_KEY
| B_OPTION_KEY
| B_SHIFT_KEY
| B_CONTROL_KEY
288 BWindow::Shortcut::PrepareModifiers(uint32 modifiers
)
290 return (modifiers
& AllowedModifiers()) | B_COMMAND_KEY
;
296 BWindow::Shortcut::PrepareKey(uint32 key
)
298 return BUnicodeChar::ToLower(key
);
302 // #pragma mark - BWindow
305 BWindow::BWindow(BRect frame
, const char* title
, window_type type
,
306 uint32 flags
, uint32 workspace
)
308 BLooper(title
, B_DISPLAY_PRIORITY
)
312 _DecomposeType(type
, &look
, &feel
);
314 _InitData(frame
, title
, look
, feel
, flags
, workspace
);
318 BWindow::BWindow(BRect frame
, const char* title
, window_look look
,
319 window_feel feel
, uint32 flags
, uint32 workspace
)
321 BLooper(title
, B_DISPLAY_PRIORITY
)
323 _InitData(frame
, title
, look
, feel
, flags
, workspace
);
327 BWindow::BWindow(BMessage
* data
)
331 data
->FindRect("_frame", &fFrame
);
334 data
->FindString("_title", &title
);
337 data
->FindInt32("_wlook", (int32
*)&look
);
340 data
->FindInt32("_wfeel", (int32
*)&feel
);
342 if (data
->FindInt32("_flags", (int32
*)&fFlags
) != B_OK
)
346 data
->FindInt32("_wspace", (int32
*)&workspaces
);
349 if (data
->FindInt32("_type", (int32
*)&type
) == B_OK
)
350 _DecomposeType((window_type
)type
, &fLook
, &fFeel
);
352 // connect to app_server and initialize data
353 _InitData(fFrame
, title
, look
, feel
, fFlags
, workspaces
);
355 if (data
->FindFloat("_zoom", 0, &fMaxZoomWidth
) == B_OK
356 && data
->FindFloat("_zoom", 1, &fMaxZoomHeight
) == B_OK
)
357 SetZoomLimits(fMaxZoomWidth
, fMaxZoomHeight
);
359 if (data
->FindFloat("_sizel", 0, &fMinWidth
) == B_OK
360 && data
->FindFloat("_sizel", 1, &fMinHeight
) == B_OK
361 && data
->FindFloat("_sizel", 2, &fMaxWidth
) == B_OK
362 && data
->FindFloat("_sizel", 3, &fMaxHeight
) == B_OK
)
363 SetSizeLimits(fMinWidth
, fMaxWidth
,
364 fMinHeight
, fMaxHeight
);
366 if (data
->FindInt64("_pulse", &fPulseRate
) == B_OK
)
367 SetPulseRate(fPulseRate
);
371 while (data
->FindMessage("_views", i
++, &msg
) == B_OK
) {
372 BArchivable
* obj
= instantiate_object(&msg
);
373 if (BView
* child
= dynamic_cast<BView
*>(obj
))
379 BWindow::BWindow(BRect frame
, int32 bitmapToken
)
381 BLooper("offscreen bitmap")
383 _DecomposeType(B_UNTYPED_WINDOW
, &fLook
, &fFeel
);
384 _InitData(frame
, "offscreen", fLook
, fFeel
, 0, 0, bitmapToken
);
390 if (BMenu
* menu
= dynamic_cast<BMenu
*>(fFocus
)) {
391 MenuPrivate(menu
).QuitTracking();
394 // The BWindow is locked when the destructor is called,
395 // we need to unlock because the menubar thread tries
396 // to post a message, which will deadlock otherwise.
397 // TODO: I replaced Unlock() with UnlockFully() because the window
398 // was kept locked after that in case it was closed using ALT-W.
399 // There might be an extra Lock() somewhere in the quitting path...
402 // Wait if a menu is still tracking
404 while (acquire_sem(fMenuSem
) == B_INTERRUPTED
)
410 fTopView
->RemoveSelf();
413 // remove all remaining shortcuts
414 int32 shortCutCount
= fShortcuts
.CountItems();
415 for (int32 i
= 0; i
< shortCutCount
; i
++) {
416 delete (Shortcut
*)fShortcuts
.ItemAtFast(i
);
419 // TODO: release other dynamically-allocated objects
425 // tell app_server about our demise
426 fLink
->StartMessage(AS_DELETE_WINDOW
);
427 // sync with the server so that for example
428 // a BBitmap can be sure that there are no
429 // more pending messages that are executed
430 // after the bitmap is deleted (which uses
431 // a different link and server side thread)
433 fLink
->FlushWithReply(code
);
435 // the sender port belongs to the app_server
436 delete_port(fLink
->ReceiverPort());
442 BWindow::Instantiate(BMessage
* data
)
444 if (!validate_instantiation(data
, "BWindow"))
447 return new(std::nothrow
) BWindow(data
);
452 BWindow::Archive(BMessage
* data
, bool deep
) const
454 status_t ret
= BLooper::Archive(data
, deep
);
457 ret
= data
->AddRect("_frame", fFrame
);
459 ret
= data
->AddString("_title", fTitle
);
461 ret
= data
->AddInt32("_wlook", fLook
);
463 ret
= data
->AddInt32("_wfeel", fFeel
);
464 if (ret
== B_OK
&& fFlags
!= 0)
465 ret
= data
->AddInt32("_flags", fFlags
);
467 ret
= data
->AddInt32("_wspace", (uint32
)Workspaces());
469 if (ret
== B_OK
&& !_ComposeType(fLook
, fFeel
))
470 ret
= data
->AddInt32("_type", (uint32
)Type());
472 if (fMaxZoomWidth
!= 32768.0 || fMaxZoomHeight
!= 32768.0) {
474 ret
= data
->AddFloat("_zoom", fMaxZoomWidth
);
476 ret
= data
->AddFloat("_zoom", fMaxZoomHeight
);
479 if (fMinWidth
!= 0.0 || fMinHeight
!= 0.0
480 || fMaxWidth
!= 32768.0 || fMaxHeight
!= 32768.0) {
482 ret
= data
->AddFloat("_sizel", fMinWidth
);
484 ret
= data
->AddFloat("_sizel", fMinHeight
);
486 ret
= data
->AddFloat("_sizel", fMaxWidth
);
488 ret
= data
->AddFloat("_sizel", fMaxHeight
);
491 if (ret
== B_OK
&& fPulseRate
!= 500000)
492 data
->AddInt64("_pulse", fPulseRate
);
494 if (ret
== B_OK
&& deep
) {
495 int32 noOfViews
= CountChildren();
496 for (int32 i
= 0; i
< noOfViews
; i
++){
497 BMessage childArchive
;
498 ret
= ChildAt(i
)->Archive(&childArchive
, true);
500 ret
= data
->AddMessage("_views", &childArchive
);
514 const char* name
= Name();
518 printf("ERROR - you must Lock a looper before calling Quit(), "
519 "team=%" B_PRId32
", looper=%s\n", Team(), name
);
524 // We're toast already
528 while (!IsHidden()) {
532 if (fFlags
& B_QUIT_ON_WINDOW_CLOSE
)
533 be_app
->PostMessage(B_QUIT_REQUESTED
);
540 BWindow::AddChild(BView
* child
, BView
* before
)
542 BAutolock
locker(this);
543 if (locker
.IsLocked())
544 fTopView
->AddChild(child
, before
);
549 BWindow::AddChild(BLayoutItem
* child
)
551 BAutolock
locker(this);
552 if (locker
.IsLocked())
553 fTopView
->AddChild(child
);
558 BWindow::RemoveChild(BView
* child
)
560 BAutolock
locker(this);
561 if (!locker
.IsLocked())
564 return fTopView
->RemoveChild(child
);
569 BWindow::CountChildren() const
571 BAutolock
locker(const_cast<BWindow
*>(this));
572 if (!locker
.IsLocked())
575 return fTopView
->CountChildren();
580 BWindow::ChildAt(int32 index
) const
582 BAutolock
locker(const_cast<BWindow
*>(this));
583 if (!locker
.IsLocked())
586 return fTopView
->ChildAt(index
);
591 BWindow::Minimize(bool minimize
)
593 if (IsModal() || IsFloating() || IsHidden() || fMinimized
== minimize
597 fMinimized
= minimize
;
599 fLink
->StartMessage(AS_MINIMIZE_WINDOW
);
600 fLink
->Attach
<bool>(minimize
);
608 BWindow::SendBehind(const BWindow
* window
)
613 fLink
->StartMessage(AS_SEND_BEHIND
);
614 fLink
->Attach
<int32
>(window
!= NULL
? _get_object_token_(window
) : -1);
615 fLink
->Attach
<team_id
>(Team());
617 status_t status
= B_ERROR
;
618 fLink
->FlushWithReply(status
);
627 BWindow::Flush() const
629 if (const_cast<BWindow
*>(this)->Lock()) {
631 const_cast<BWindow
*>(this)->Unlock();
637 BWindow::Sync() const
639 if (!const_cast<BWindow
*>(this)->Lock())
642 fLink
->StartMessage(AS_SYNC
);
644 // waiting for the reply is the actual syncing
646 fLink
->FlushWithReply(code
);
648 const_cast<BWindow
*>(this)->Unlock();
653 BWindow::DisableUpdates()
656 fLink
->StartMessage(AS_DISABLE_UPDATES
);
664 BWindow::EnableUpdates()
667 fLink
->StartMessage(AS_ENABLE_UPDATES
);
675 BWindow::BeginViewTransaction()
678 fInTransaction
= true;
685 BWindow::EndViewTransaction()
690 fInTransaction
= false;
697 BWindow::InViewTransaction() const
699 BAutolock
locker(const_cast<BWindow
*>(this));
700 return fInTransaction
;
705 BWindow::IsFront() const
707 BAutolock
locker(const_cast<BWindow
*>(this));
708 if (!locker
.IsLocked())
711 fLink
->StartMessage(AS_IS_FRONT_WINDOW
);
714 if (fLink
->FlushWithReply(status
) == B_OK
)
715 return status
>= B_OK
;
722 BWindow::MessageReceived(BMessage
* message
)
724 if (!message
->HasSpecifiers()) {
725 if (message
->what
== B_KEY_DOWN
)
726 _KeyboardNavigation();
728 if (message
->what
== (int32
)kMsgAppServerRestarted
) {
729 fLink
->SetSenderPort(
730 BApplication::Private::ServerLink()->SenderPort());
732 BPrivate::AppServerLink lockLink
;
733 // we're talking to the server application using our own
734 // communication channel (fLink) - we better make sure no one
735 // interferes by locking that channel (which AppServerLink does
738 fLink
->StartMessage(AS_CREATE_WINDOW
);
740 fLink
->Attach
<BRect
>(fFrame
);
741 fLink
->Attach
<uint32
>((uint32
)fLook
);
742 fLink
->Attach
<uint32
>((uint32
)fFeel
);
743 fLink
->Attach
<uint32
>(fFlags
);
744 fLink
->Attach
<uint32
>(0);
745 fLink
->Attach
<int32
>(_get_object_token_(this));
746 fLink
->Attach
<port_id
>(fLink
->ReceiverPort());
747 fLink
->Attach
<port_id
>(fMsgPort
);
748 fLink
->AttachString(fTitle
);
752 if (fLink
->FlushWithReply(code
) == B_OK
754 && fLink
->Read
<port_id
>(&sendPort
) == B_OK
) {
755 // read the frame size and its limits that were really
756 // enforced on the server side
758 fLink
->Read
<BRect
>(&fFrame
);
759 fLink
->Read
<float>(&fMinWidth
);
760 fLink
->Read
<float>(&fMaxWidth
);
761 fLink
->Read
<float>(&fMinHeight
);
762 fLink
->Read
<float>(&fMaxHeight
);
764 fMaxZoomWidth
= fMaxWidth
;
765 fMaxZoomHeight
= fMaxHeight
;
769 // Redirect our link to the new window connection
770 fLink
->SetSenderPort(sendPort
);
772 // connect all views to the server again
773 fTopView
->_CreateSelf();
775 _SendShowOrHideMessage();
778 return BLooper::MessageReceived(message
);
781 BMessage
replyMsg(B_REPLY
);
782 bool handled
= false;
789 if (message
->GetCurrentSpecifier(&index
, &specifier
, &what
, &prop
) != B_OK
)
790 return BLooper::MessageReceived(message
);
792 BPropertyInfo
propertyInfo(sWindowPropInfo
);
793 switch (propertyInfo
.FindMatch(message
, index
, &specifier
, what
, prop
)) {
795 if (message
->what
== B_GET_PROPERTY
) {
796 replyMsg
.AddBool("result", IsActive());
798 } else if (message
->what
== B_SET_PROPERTY
) {
800 if (message
->FindBool("data", &newActive
) == B_OK
) {
807 if (message
->what
== B_GET_PROPERTY
) {
808 replyMsg
.AddInt32("result", (uint32
)Feel());
812 if (message
->FindInt32("data", (int32
*)&newFeel
) == B_OK
) {
813 SetFeel((window_feel
)newFeel
);
819 if (message
->what
== B_GET_PROPERTY
) {
820 replyMsg
.AddInt32("result", Flags());
824 if (message
->FindInt32("data", (int32
*)&newFlags
) == B_OK
) {
831 if (message
->what
== B_GET_PROPERTY
) {
832 replyMsg
.AddRect("result", Frame());
836 if (message
->FindRect("data", &newFrame
) == B_OK
) {
837 MoveTo(newFrame
.LeftTop());
838 ResizeTo(newFrame
.Width(), newFrame
.Height());
844 if (message
->what
== B_GET_PROPERTY
) {
845 replyMsg
.AddBool("result", IsHidden());
849 if (message
->FindBool("data", &hide
) == B_OK
) {
853 } else if (IsHidden())
860 if (message
->what
== B_GET_PROPERTY
) {
861 replyMsg
.AddInt32("result", (uint32
)Look());
865 if (message
->FindInt32("data", (int32
*)&newLook
) == B_OK
) {
866 SetLook((window_look
)newLook
);
872 if (message
->what
== B_GET_PROPERTY
) {
873 replyMsg
.AddString("result", Title());
876 const char* newTitle
= NULL
;
877 if (message
->FindString("data", &newTitle
) == B_OK
) {
884 if (message
->what
== B_GET_PROPERTY
) {
885 replyMsg
.AddInt32( "result", Workspaces());
888 uint32 newWorkspaces
;
889 if (message
->FindInt32("data", (int32
*)&newWorkspaces
) == B_OK
) {
890 SetWorkspaces(newWorkspaces
);
896 if (message
->what
== B_GET_PROPERTY
) {
897 replyMsg
.AddBool("result", IsMinimized());
901 if (message
->FindBool("data", &minimize
) == B_OK
) {
908 if (message
->what
== B_GET_PROPERTY
) {
910 if (GetDecoratorSettings(&settings
) == B_OK
) {
912 if (settings
.FindRect("tab frame", &frame
) == B_OK
) {
913 replyMsg
.AddRect("result", frame
);
920 return BLooper::MessageReceived(message
);
924 if (message
->what
== B_SET_PROPERTY
)
925 replyMsg
.AddInt32("error", B_OK
);
927 replyMsg
.what
= B_MESSAGE_NOT_UNDERSTOOD
;
928 replyMsg
.AddInt32("error", B_BAD_SCRIPT_SYNTAX
);
929 replyMsg
.AddString("message", "Didn't understand the specifier(s)");
931 message
->SendReply(&replyMsg
);
936 BWindow::DispatchMessage(BMessage
* message
, BHandler
* target
)
941 switch (message
->what
) {
947 // Used by the minimize shortcut
948 if ((Flags() & B_NOT_MINIMIZABLE
) == 0)
953 // Used by the zoom shortcut
954 if ((Flags() & B_NOT_ZOOMABLE
) == 0)
962 case _SEND_TO_FRONT_
:
969 if (message
->FindBool("minimize", &minimize
) == B_OK
)
974 case B_HIDE_APPLICATION
:
976 // Hide all applications with the same signature
977 // (ie. those that are part of the same group to be consistent
978 // to what the Deskbar shows you).
980 be_app
->GetAppInfo(&info
);
983 be_roster
->GetAppList(info
.signature
, &list
);
985 for (int32 i
= 0; i
< list
.CountItems(); i
++) {
986 do_minimize_team(BRect(), (team_id
)(addr_t
)list
.ItemAt(i
),
992 case B_WINDOW_RESIZED
:
995 if (message
->FindInt32("width", &width
) == B_OK
996 && message
->FindInt32("height", &height
) == B_OK
) {
997 // combine with pending resize notifications
998 BMessage
* pendingMessage
;
999 while ((pendingMessage
1000 = MessageQueue()->FindMessage(B_WINDOW_RESIZED
, 0))) {
1002 if (pendingMessage
->FindInt32("width", &nextWidth
) == B_OK
)
1006 if (pendingMessage
->FindInt32("height", &nextHeight
)
1008 height
= nextHeight
;
1011 MessageQueue()->RemoveMessage(pendingMessage
);
1012 delete pendingMessage
;
1013 // this deletes the first *additional* message
1014 // fCurrentMessage is safe
1016 if (width
!= fFrame
.Width() || height
!= fFrame
.Height()) {
1017 // NOTE: we might have already handled the resize
1018 // in an _UPDATE_ message
1019 fFrame
.right
= fFrame
.left
+ width
;
1020 fFrame
.bottom
= fFrame
.top
+ height
;
1023 // FrameResized(width, height);
1025 // call hook function anyways
1026 // TODO: When a window is resized programmatically,
1027 // it receives this message, and maybe it is wise to
1028 // keep the asynchronous nature of this process to
1029 // not risk breaking any apps.
1030 FrameResized(width
, height
);
1035 case B_WINDOW_MOVED
:
1038 if (message
->FindPoint("where", &origin
) == B_OK
) {
1039 if (fFrame
.LeftTop() != origin
) {
1040 // NOTE: we might have already handled the move
1041 // in an _UPDATE_ message
1042 fFrame
.OffsetTo(origin
);
1044 // FrameMoved(origin);
1046 // call hook function anyways
1047 // TODO: When a window is moved programmatically,
1048 // it receives this message, and maybe it is wise to
1049 // keep the asynchronous nature of this process to
1050 // not risk breaking any apps.
1056 case B_WINDOW_ACTIVATED
:
1057 if (target
!= this) {
1058 target
->MessageReceived(message
);
1063 if (message
->FindBool("active", &active
) != B_OK
)
1066 // find latest activation message
1069 BMessage
* pendingMessage
= MessageQueue()->FindMessage(
1070 B_WINDOW_ACTIVATED
, 0);
1071 if (pendingMessage
== NULL
)
1075 if (pendingMessage
->FindBool("active", &nextActive
) == B_OK
)
1076 active
= nextActive
;
1078 MessageQueue()->RemoveMessage(pendingMessage
);
1079 delete pendingMessage
;
1082 if (active
!= fActive
) {
1085 WindowActivated(active
);
1087 // call hook function 'WindowActivated(bool)' for all
1088 // views attached to this window.
1089 fTopView
->_Activate(active
);
1091 // we notify the input server if we are gaining or losing focus
1092 // from a view which has the B_INPUT_METHOD_AWARE on a window
1096 bool inputMethodAware
= false;
1098 inputMethodAware
= fFocus
->Flags() & B_INPUT_METHOD_AWARE
;
1099 BMessage
message(inputMethodAware
? IS_FOCUS_IM_AWARE_VIEW
: IS_UNFOCUS_IM_AWARE_VIEW
);
1100 BMessenger
messenger(fFocus
);
1103 message
.AddMessenger("view", messenger
);
1104 _control_input_server_(&message
, &reply
);
1108 case B_SCREEN_CHANGED
:
1109 if (target
== this) {
1112 if (message
->FindRect("frame", &frame
) == B_OK
1113 && message
->FindInt32("mode", (int32
*)&mode
) == B_OK
)
1114 ScreenChanged(frame
, (color_space
)mode
);
1116 target
->MessageReceived(message
);
1119 case B_WORKSPACE_ACTIVATED
:
1120 if (target
== this) {
1123 if (message
->FindInt32("workspace", (int32
*)&workspace
) == B_OK
1124 && message
->FindBool("active", &active
) == B_OK
)
1125 WorkspaceActivated(workspace
, active
);
1127 target
->MessageReceived(message
);
1130 case B_WORKSPACES_CHANGED
:
1131 if (target
== this) {
1132 uint32 oldWorkspace
, newWorkspace
;
1133 if (message
->FindInt32("old", (int32
*)&oldWorkspace
) == B_OK
1134 && message
->FindInt32("new", (int32
*)&newWorkspace
) == B_OK
)
1135 WorkspacesChanged(oldWorkspace
, newWorkspace
);
1137 target
->MessageReceived(message
);
1142 if (BView
* view
= dynamic_cast<BView
*>(target
)) {
1144 if (message
->FindRect("be:area", &rect
) == B_OK
)
1145 view
->Invalidate(rect
);
1149 target
->MessageReceived(message
);
1155 if (!_HandleKeyDown(message
)) {
1156 if (BView
* view
= dynamic_cast<BView
*>(target
)) {
1157 // TODO: cannot use "string" here if we support having
1158 // different font encoding per view (it's supposed to be
1159 // converted by _HandleKeyDown() one day)
1162 if (message
->FindData("bytes", B_STRING_TYPE
,
1163 (const void**)&string
, &bytes
) == B_OK
) {
1164 view
->KeyDown(string
, bytes
- 1);
1167 target
->MessageReceived(message
);
1174 // TODO: same as above
1175 if (BView
* view
= dynamic_cast<BView
*>(target
)) {
1178 if (message
->FindData("bytes", B_STRING_TYPE
,
1179 (const void**)&string
, &bytes
) == B_OK
) {
1180 view
->KeyUp(string
, bytes
- 1);
1183 target
->MessageReceived(message
);
1187 case B_UNMAPPED_KEY_DOWN
:
1189 if (!_HandleUnmappedKeyDown(message
))
1190 target
->MessageReceived(message
);
1196 BView
* view
= dynamic_cast<BView
*>(target
);
1200 message
->FindPoint("be:view_where", &where
);
1201 view
->MouseDown(where
);
1203 target
->MessageReceived(message
);
1210 if (BView
* view
= dynamic_cast<BView
*>(target
)) {
1212 message
->FindPoint("be:view_where", &where
);
1213 view
->fMouseEventOptions
= 0;
1214 view
->MouseUp(where
);
1216 target
->MessageReceived(message
);
1223 if (BView
* view
= dynamic_cast<BView
*>(target
)) {
1224 uint32 eventOptions
= view
->fEventOptions
1225 | view
->fMouseEventOptions
;
1226 bool noHistory
= eventOptions
& B_NO_POINTER_HISTORY
;
1227 bool dropIfLate
= !(eventOptions
& B_FULL_POINTER_HISTORY
);
1229 bigtime_t eventTime
;
1230 if (message
->FindInt64("when", (int64
*)&eventTime
) < B_OK
)
1231 eventTime
= system_time();
1234 message
->FindInt32("be:transit", (int32
*)&transit
);
1235 // don't drop late messages with these important transit values
1236 if (transit
== B_ENTERED_VIEW
|| transit
== B_EXITED_VIEW
)
1239 // TODO: The dropping code may have the following problem:
1240 // On slower computers, 20ms may just be to abitious a delay.
1241 // There, we might constantly check the message queue for a
1242 // newer message, not find any, and still use the only but
1243 // later than 20ms message, which of course makes the whole
1244 // thing later than need be. An adaptive delay would be
1245 // kind of neat, but would probably use additional BWindow
1246 // members to count the successful versus fruitless queue
1247 // searches and the delay value itself or something similar.
1250 || (dropIfLate
&& (system_time() - eventTime
> 20000))) {
1251 // filter out older mouse moved messages in the queue
1253 BMessageQueue
* queue
= MessageQueue();
1257 for (int32 i
= 0; (moved
= queue
->FindMessage(i
)) != NULL
;
1259 if (moved
!= message
&& moved
->what
== B_MOUSE_MOVED
) {
1260 // there is a newer mouse moved message in the
1261 // queue, just ignore the current one, the newer one
1262 // will be handled here eventually
1272 message
->FindPoint("be:view_where", &where
);
1273 message
->FindInt32("buttons", (int32
*)&buttons
);
1275 if (transit
== B_EXITED_VIEW
|| transit
== B_OUTSIDE_VIEW
) {
1276 if (dynamic_cast<BPrivate::ToolTipWindow
*>(this) == NULL
)
1277 BToolTipManager::Manager()->HideTip();
1280 BMessage
* dragMessage
= NULL
;
1281 if (message
->HasMessage("be:drag_message")) {
1282 dragMessage
= new BMessage();
1283 if (message
->FindMessage("be:drag_message", dragMessage
)
1290 view
->MouseMoved(where
, transit
, dragMessage
);
1293 target
->MessageReceived(message
);
1299 if (target
== this && fPulseRunner
) {
1303 target
->MessageReceived(message
);
1308 //bigtime_t now = system_time();
1309 //bigtime_t drawTime = 0;
1310 STRACE(("info:BWindow handling _UPDATE_.\n"));
1312 fLink
->StartMessage(AS_BEGIN_UPDATE
);
1313 fInTransaction
= true;
1316 if (fLink
->FlushWithReply(code
) == B_OK
1318 // read current window position and size first,
1319 // the update rect is in screen coordinates...
1320 // so we need to be up to date
1322 fLink
->Read
<BPoint
>(&origin
);
1325 fLink
->Read
<float>(&width
);
1326 fLink
->Read
<float>(&height
);
1327 if (origin
!= fFrame
.LeftTop()) {
1328 // TODO: remove code duplicatation with
1329 // B_WINDOW_MOVED case...
1330 //printf("window position was not up to date\n");
1331 fFrame
.OffsetTo(origin
);
1334 if (width
!= fFrame
.Width() || height
!= fFrame
.Height()) {
1335 // TODO: remove code duplicatation with
1336 // B_WINDOW_RESIZED case...
1337 //printf("window size was not up to date\n");
1338 fFrame
.right
= fFrame
.left
+ width
;
1339 fFrame
.bottom
= fFrame
.top
+ height
;
1342 FrameResized(width
, height
);
1345 // read tokens for views that need to be drawn
1346 // NOTE: we need to read the tokens completely
1347 // first, we cannot draw views in between reading
1348 // the tokens, since other communication would likely
1349 // mess up the data in the link.
1350 struct ViewUpdateInfo
{
1356 // read next token and create/add ViewUpdateInfo
1358 status_t error
= fLink
->Read
<int32
>(&token
);
1359 if (error
< B_OK
|| token
== B_NULL_TOKEN
)
1361 ViewUpdateInfo
* info
= new(std::nothrow
) ViewUpdateInfo
;
1362 if (info
== NULL
|| !infos
.AddItem(info
)) {
1366 info
->token
= token
;
1367 // read culmulated update rect (is in screen coords)
1368 error
= fLink
->Read
<BRect
>(&(info
->updateRect
));
1373 int32 count
= infos
.CountItems();
1374 for (int32 i
= 0; i
< count
; i
++) {
1375 //bigtime_t drawStart = system_time();
1376 ViewUpdateInfo
* info
1377 = (ViewUpdateInfo
*)infos
.ItemAtFast(i
);
1378 if (BView
* view
= _FindView(info
->token
))
1379 view
->_Draw(info
->updateRect
);
1381 printf("_UPDATE_ - didn't find view by token: %"
1382 B_PRId32
"\n", info
->token
);
1384 //drawTime += system_time() - drawStart;
1386 // NOTE: The tokens are actually hirachically sorted,
1387 // so traversing the list in revers and calling
1388 // child->_DrawAfterChildren() actually works like intended.
1389 for (int32 i
= count
- 1; i
>= 0; i
--) {
1390 ViewUpdateInfo
* info
1391 = (ViewUpdateInfo
*)infos
.ItemAtFast(i
);
1392 if (BView
* view
= _FindView(info
->token
))
1393 view
->_DrawAfterChildren(info
->updateRect
);
1397 //printf(" %ld views drawn, total Draw() time: %lld\n", count, drawTime);
1400 fLink
->StartMessage(AS_END_UPDATE
);
1402 fInTransaction
= false;
1403 fUpdateRequested
= false;
1405 //printf("BWindow(%s) - UPDATE took %lld usecs\n", Title(), system_time() - now);
1413 // These two are obviously some kind of old scripting messages
1414 // this is NOT an app_server message and we have to be cautious
1415 case B_WINDOW_MOVE_BY
:
1418 if (message
->FindPoint("data", &offset
) == B_OK
)
1419 MoveBy(offset
.x
, offset
.y
);
1421 message
->SendReply(B_MESSAGE_NOT_UNDERSTOOD
);
1425 // this is NOT an app_server message and we have to be cautious
1426 case B_WINDOW_MOVE_TO
:
1429 if (message
->FindPoint("data", &origin
) == B_OK
)
1432 message
->SendReply(B_MESSAGE_NOT_UNDERSTOOD
);
1436 case B_LAYOUT_WINDOW
:
1443 BLooper::DispatchMessage(message
, target
);
1450 BWindow::FrameMoved(BPoint newPosition
)
1458 BWindow::FrameResized(float newWidth
, float newHeight
)
1466 BWindow::WorkspacesChanged(uint32 oldWorkspaces
, uint32 newWorkspaces
)
1474 BWindow::WorkspaceActivated(int32 workspace
, bool state
)
1482 BWindow::MenusBeginning()
1490 BWindow::MenusEnded()
1498 BWindow::SetSizeLimits(float minWidth
, float maxWidth
,
1499 float minHeight
, float maxHeight
)
1501 if (minWidth
> maxWidth
|| minHeight
> maxHeight
)
1507 fLink
->StartMessage(AS_SET_SIZE_LIMITS
);
1508 fLink
->Attach
<float>(minWidth
);
1509 fLink
->Attach
<float>(maxWidth
);
1510 fLink
->Attach
<float>(minHeight
);
1511 fLink
->Attach
<float>(maxHeight
);
1514 if (fLink
->FlushWithReply(code
) == B_OK
1516 // read the values that were really enforced on
1517 // the server side (the window frame could have
1518 // been changed, too)
1519 fLink
->Read
<BRect
>(&fFrame
);
1520 fLink
->Read
<float>(&fMinWidth
);
1521 fLink
->Read
<float>(&fMaxWidth
);
1522 fLink
->Read
<float>(&fMinHeight
);
1523 fLink
->Read
<float>(&fMaxHeight
);
1526 // TODO: the same has to be done for SetLook() (that can alter
1527 // the size limits, and hence, the size of the window
1534 BWindow::GetSizeLimits(float* _minWidth
, float* _maxWidth
, float* _minHeight
,
1537 // TODO: What about locking?!?
1538 if (_minHeight
!= NULL
)
1539 *_minHeight
= fMinHeight
;
1540 if (_minWidth
!= NULL
)
1541 *_minWidth
= fMinWidth
;
1542 if (_maxHeight
!= NULL
)
1543 *_maxHeight
= fMaxHeight
;
1544 if (_maxWidth
!= NULL
)
1545 *_maxWidth
= fMaxWidth
;
1550 BWindow::UpdateSizeLimits()
1552 if ((fFlags
& B_AUTO_UPDATE_SIZE_LIMITS
) != 0) {
1553 // Get min/max constraints of the top view and enforce window
1554 // size limits respectively.
1555 BSize minSize
= fTopView
->MinSize();
1556 BSize maxSize
= fTopView
->MaxSize();
1557 SetSizeLimits(minSize
.width
, maxSize
.width
,
1558 minSize
.height
, maxSize
.height
);
1564 BWindow::SetDecoratorSettings(const BMessage
& settings
)
1566 // flatten the given settings into a buffer and send
1567 // it to the app_server to apply the settings to the
1570 int32 size
= settings
.FlattenedSize();
1572 status_t status
= settings
.Flatten(buffer
, size
);
1579 status
= fLink
->StartMessage(AS_SET_DECORATOR_SETTINGS
);
1582 status
= fLink
->Attach
<int32
>(size
);
1585 status
= fLink
->Attach(buffer
, size
);
1588 status
= fLink
->Flush();
1597 BWindow::GetDecoratorSettings(BMessage
* settings
) const
1599 // read a flattened settings message from the app_server
1600 // and put it into settings
1602 if (!const_cast<BWindow
*>(this)->Lock())
1605 status_t status
= fLink
->StartMessage(AS_GET_DECORATOR_SETTINGS
);
1607 if (status
== B_OK
) {
1609 status
= fLink
->FlushWithReply(code
);
1610 if (status
== B_OK
&& code
!= B_OK
)
1614 if (status
== B_OK
) {
1616 status
= fLink
->Read
<int32
>(&size
);
1617 if (status
== B_OK
) {
1619 status
= fLink
->Read(buffer
, size
);
1620 if (status
== B_OK
) {
1621 status
= settings
->Unflatten(buffer
);
1626 const_cast<BWindow
*>(this)->Unlock();
1633 BWindow::SetZoomLimits(float maxWidth
, float maxHeight
)
1635 // TODO: What about locking?!?
1636 if (maxWidth
> fMaxWidth
)
1637 maxWidth
= fMaxWidth
;
1639 fMaxZoomWidth
= maxWidth
;
1641 if (maxHeight
> fMaxHeight
)
1642 maxHeight
= fMaxHeight
;
1644 fMaxZoomHeight
= maxHeight
;
1649 BWindow::Zoom(BPoint origin
, float width
, float height
)
1651 // the default implementation of this hook function
1652 // just does the obvious:
1654 ResizeTo(width
, height
);
1661 // TODO: What about locking?!?
1664 // The dimensions that non-virtual Zoom() passes to hook Zoom() are deduced
1665 // from the smallest of three rectangles:
1669 _GetDecoratorSize(&borderWidth
, &tabHeight
);
1671 // 1) the rectangle defined by SetZoomLimits(),
1672 float zoomedWidth
= fMaxZoomWidth
;
1673 float zoomedHeight
= fMaxZoomHeight
;
1675 // 2) the rectangle defined by SetSizeLimits()
1676 if (fMaxWidth
< zoomedWidth
)
1677 zoomedWidth
= fMaxWidth
;
1678 if (fMaxHeight
< zoomedHeight
)
1679 zoomedHeight
= fMaxHeight
;
1681 // 3) the screen rectangle
1682 BScreen
screen(this);
1683 // TODO: Broken for tab on left side windows...
1684 float screenWidth
= screen
.Frame().Width() - 2 * borderWidth
;
1685 float screenHeight
= screen
.Frame().Height() - (2 * borderWidth
+ tabHeight
);
1686 if (screenWidth
< zoomedWidth
)
1687 zoomedWidth
= screenWidth
;
1688 if (screenHeight
< zoomedHeight
)
1689 zoomedHeight
= screenHeight
;
1691 BPoint zoomedLeftTop
= screen
.Frame().LeftTop() + BPoint(borderWidth
,
1692 tabHeight
+ borderWidth
);
1693 // Center if window cannot be made full screen
1694 if (screenWidth
> zoomedWidth
)
1695 zoomedLeftTop
.x
+= (screenWidth
- zoomedWidth
) / 2;
1696 if (screenHeight
> zoomedHeight
)
1697 zoomedLeftTop
.y
+= (screenHeight
- zoomedHeight
) / 2;
1701 if (fPreviousFrame
.IsValid()
1702 // NOTE: don't check for fFrame.LeftTop() == zoomedLeftTop
1703 // -> makes it easier on the user to get a window back into place
1704 && fFrame
.Width() == zoomedWidth
&& fFrame
.Height() == zoomedHeight
) {
1706 Zoom(fPreviousFrame
.LeftTop(), fPreviousFrame
.Width(),
1707 fPreviousFrame
.Height());
1713 // remember fFrame for later "unzooming"
1714 fPreviousFrame
= fFrame
;
1716 Zoom(zoomedLeftTop
, zoomedWidth
, zoomedHeight
);
1721 BWindow::ScreenChanged(BRect screenSize
, color_space depth
)
1728 BWindow::SetPulseRate(bigtime_t rate
)
1730 // TODO: What about locking?!?
1732 || (rate
== fPulseRate
&& !((rate
== 0) ^ (fPulseRunner
== NULL
))))
1738 if (fPulseRunner
== NULL
) {
1739 BMessage
message(B_PULSE
);
1740 fPulseRunner
= new(std::nothrow
) BMessageRunner(BMessenger(this),
1743 fPulseRunner
->SetInterval(rate
);
1747 delete fPulseRunner
;
1748 fPulseRunner
= NULL
;
1754 BWindow::PulseRate() const
1761 BWindow::AddShortcut(uint32 key
, uint32 modifiers
, BMenuItem
* item
)
1763 Shortcut
* shortcut
= new(std::nothrow
) Shortcut(key
, modifiers
, item
);
1764 if (shortcut
== NULL
)
1767 // removes the shortcut if it already exists!
1768 RemoveShortcut(key
, modifiers
);
1770 fShortcuts
.AddItem(shortcut
);
1775 BWindow::AddShortcut(uint32 key
, uint32 modifiers
, BMessage
* message
)
1777 AddShortcut(key
, modifiers
, message
, this);
1782 BWindow::AddShortcut(uint32 key
, uint32 modifiers
, BMessage
* message
,
1785 if (message
== NULL
)
1788 Shortcut
* shortcut
= new(std::nothrow
) Shortcut(key
, modifiers
, message
,
1790 if (shortcut
== NULL
)
1793 // removes the shortcut if it already exists!
1794 RemoveShortcut(key
, modifiers
);
1796 fShortcuts
.AddItem(shortcut
);
1801 BWindow::HasShortcut(uint32 key
, uint32 modifiers
)
1803 return _FindShortcut(key
, modifiers
) != NULL
;
1808 BWindow::RemoveShortcut(uint32 key
, uint32 modifiers
)
1810 Shortcut
* shortcut
= _FindShortcut(key
, modifiers
);
1811 if (shortcut
!= NULL
) {
1812 fShortcuts
.RemoveItem(shortcut
);
1814 } else if ((key
== 'q' || key
== 'Q') && modifiers
== B_COMMAND_KEY
) {
1815 // the quit shortcut is a fake shortcut
1816 fNoQuitShortcut
= true;
1822 BWindow::DefaultButton() const
1824 // TODO: What about locking?!?
1825 return fDefaultButton
;
1830 BWindow::SetDefaultButton(BButton
* button
)
1832 // TODO: What about locking?!?
1833 if (fDefaultButton
== button
)
1836 if (fDefaultButton
!= NULL
) {
1837 // tell old button it's no longer the default one
1838 BButton
* oldDefault
= fDefaultButton
;
1839 oldDefault
->MakeDefault(false);
1840 oldDefault
->Invalidate();
1843 fDefaultButton
= button
;
1845 if (button
!= NULL
) {
1846 // notify new default button
1847 fDefaultButton
->MakeDefault(true);
1848 fDefaultButton
->Invalidate();
1854 BWindow::NeedsUpdate() const
1856 if (!const_cast<BWindow
*>(this)->Lock())
1859 fLink
->StartMessage(AS_NEEDS_UPDATE
);
1861 int32 code
= B_ERROR
;
1862 fLink
->FlushWithReply(code
);
1864 const_cast<BWindow
*>(this)->Unlock();
1866 return code
== B_OK
;
1871 BWindow::UpdateIfNeeded()
1873 // works only from the window thread
1874 if (find_thread(NULL
) != Thread())
1877 // if the queue is already locked we are called recursivly
1878 // from our own dispatched update message
1879 if (((const BMessageQueue
*)MessageQueue())->IsLocked())
1885 // make sure all requests that would cause an update have
1886 // arrived at the server
1889 // Since we're blocking the event loop, we need to retrieve
1890 // all messages that are pending on the port.
1893 BMessageQueue
* queue
= MessageQueue();
1895 // First process and remove any _UPDATE_ message in the queue
1896 // With the current design, there can only be one at a time
1901 BMessage
* message
= queue
->FindMessage(_UPDATE_
, 0);
1902 queue
->RemoveMessage(message
);
1906 if (message
== NULL
)
1909 BWindow::DispatchMessage(message
, this);
1918 BWindow::FindView(const char* viewName
) const
1920 BAutolock
locker(const_cast<BWindow
*>(this));
1921 if (!locker
.IsLocked())
1924 return fTopView
->FindView(viewName
);
1929 BWindow::FindView(BPoint point
) const
1931 BAutolock
locker(const_cast<BWindow
*>(this));
1932 if (!locker
.IsLocked())
1935 // point is assumed to be in window coordinates,
1936 // fTopView has same bounds as window
1937 return _FindView(fTopView
, point
);
1942 BWindow::CurrentFocus() const
1949 BWindow::Activate(bool active
)
1956 // activating a window will also unminimize it
1958 fLink
->StartMessage(AS_ACTIVATE_WINDOW
);
1959 fLink
->Attach
<bool>(active
);
1968 BWindow::WindowActivated(bool focus
)
1976 BWindow::ConvertToScreen(BPoint
* point
) const
1978 point
->x
+= fFrame
.left
;
1979 point
->y
+= fFrame
.top
;
1984 BWindow::ConvertToScreen(BPoint point
) const
1986 return point
+ fFrame
.LeftTop();
1991 BWindow::ConvertFromScreen(BPoint
* point
) const
1993 point
->x
-= fFrame
.left
;
1994 point
->y
-= fFrame
.top
;
1999 BWindow::ConvertFromScreen(BPoint point
) const
2001 return point
- fFrame
.LeftTop();
2006 BWindow::ConvertToScreen(BRect
* rect
) const
2008 rect
->OffsetBy(fFrame
.LeftTop());
2013 BWindow::ConvertToScreen(BRect rect
) const
2015 return rect
.OffsetByCopy(fFrame
.LeftTop());
2020 BWindow::ConvertFromScreen(BRect
* rect
) const
2022 rect
->OffsetBy(-fFrame
.left
, -fFrame
.top
);
2027 BWindow::ConvertFromScreen(BRect rect
) const
2029 return rect
.OffsetByCopy(-fFrame
.left
, -fFrame
.top
);
2034 BWindow::IsMinimized() const
2036 BAutolock
locker(const_cast<BWindow
*>(this));
2037 if (!locker
.IsLocked())
2045 BWindow::Bounds() const
2047 return BRect(0, 0, fFrame
.Width(), fFrame
.Height());
2052 BWindow::Frame() const
2059 BWindow::DecoratorFrame() const
2061 BRect
decoratorFrame(Frame());
2062 BRect
tabRect(0, 0, 0, 0);
2064 float borderWidth
= 5.0;
2067 if (GetDecoratorSettings(&settings
) == B_OK
) {
2068 settings
.FindRect("tab frame", &tabRect
);
2069 settings
.FindFloat("border width", &borderWidth
);
2071 // probably no-border window look
2072 if (fLook
== B_NO_BORDER_WINDOW_LOOK
)
2074 else if (fLook
== B_BORDERED_WINDOW_LOOK
)
2076 // else use fall-back values from above
2079 if (fLook
== kLeftTitledWindowLook
) {
2080 decoratorFrame
.top
-= borderWidth
;
2081 decoratorFrame
.left
-= borderWidth
+ tabRect
.Width();
2082 decoratorFrame
.right
+= borderWidth
;
2083 decoratorFrame
.bottom
+= borderWidth
;
2085 decoratorFrame
.top
-= borderWidth
+ tabRect
.Height();
2086 decoratorFrame
.left
-= borderWidth
;
2087 decoratorFrame
.right
+= borderWidth
;
2088 decoratorFrame
.bottom
+= borderWidth
;
2091 return decoratorFrame
;
2096 BWindow::Size() const
2098 return BSize(fFrame
.Width(), fFrame
.Height());
2103 BWindow::Title() const
2110 BWindow::SetTitle(const char* title
)
2116 fTitle
= strdup(title
);
2120 // we notify the app_server so we can actually see the change
2122 fLink
->StartMessage(AS_SET_WINDOW_TITLE
);
2123 fLink
->AttachString(fTitle
);
2131 BWindow::IsActive() const
2138 BWindow::SetKeyMenuBar(BMenuBar
* bar
)
2145 BWindow::KeyMenuBar() const
2152 BWindow::IsModal() const
2154 return fFeel
== B_MODAL_SUBSET_WINDOW_FEEL
2155 || fFeel
== B_MODAL_APP_WINDOW_FEEL
2156 || fFeel
== B_MODAL_ALL_WINDOW_FEEL
2157 || fFeel
== kMenuWindowFeel
;
2162 BWindow::IsFloating() const
2164 return fFeel
== B_FLOATING_SUBSET_WINDOW_FEEL
2165 || fFeel
== B_FLOATING_APP_WINDOW_FEEL
2166 || fFeel
== B_FLOATING_ALL_WINDOW_FEEL
;
2171 BWindow::AddToSubset(BWindow
* window
)
2173 if (window
== NULL
|| window
->Feel() != B_NORMAL_WINDOW_FEEL
2174 || (fFeel
!= B_MODAL_SUBSET_WINDOW_FEEL
2175 && fFeel
!= B_FLOATING_SUBSET_WINDOW_FEEL
))
2181 status_t status
= B_ERROR
;
2182 fLink
->StartMessage(AS_ADD_TO_SUBSET
);
2183 fLink
->Attach
<int32
>(_get_object_token_(window
));
2184 fLink
->FlushWithReply(status
);
2193 BWindow::RemoveFromSubset(BWindow
* window
)
2195 if (window
== NULL
|| window
->Feel() != B_NORMAL_WINDOW_FEEL
2196 || (fFeel
!= B_MODAL_SUBSET_WINDOW_FEEL
2197 && fFeel
!= B_FLOATING_SUBSET_WINDOW_FEEL
))
2203 status_t status
= B_ERROR
;
2204 fLink
->StartMessage(AS_REMOVE_FROM_SUBSET
);
2205 fLink
->Attach
<int32
>(_get_object_token_(window
));
2206 fLink
->FlushWithReply(status
);
2215 BWindow::Perform(perform_code code
, void* _data
)
2218 case PERFORM_CODE_SET_LAYOUT
:
2220 perform_data_set_layout
* data
= (perform_data_set_layout
*)_data
;
2221 BWindow::SetLayout(data
->layout
);
2226 return BLooper::Perform(code
, _data
);
2231 BWindow::SetType(window_type type
)
2235 _DecomposeType(type
, &look
, &feel
);
2237 status_t status
= SetLook(look
);
2239 status
= SetFeel(feel
);
2246 BWindow::Type() const
2248 return _ComposeType(fLook
, fFeel
);
2253 BWindow::SetLook(window_look look
)
2255 BAutolock
locker(this);
2256 if (!locker
.IsLocked())
2259 fLink
->StartMessage(AS_SET_LOOK
);
2260 fLink
->Attach
<int32
>((int32
)look
);
2262 status_t status
= B_ERROR
;
2263 if (fLink
->FlushWithReply(status
) == B_OK
&& status
== B_OK
)
2266 // TODO: this could have changed the window size, and thus, we
2267 // need to get it from the server (and call _AdoptResize()).
2274 BWindow::Look() const
2281 BWindow::SetFeel(window_feel feel
)
2283 BAutolock
locker(this);
2284 if (!locker
.IsLocked())
2287 fLink
->StartMessage(AS_SET_FEEL
);
2288 fLink
->Attach
<int32
>((int32
)feel
);
2290 status_t status
= B_ERROR
;
2291 if (fLink
->FlushWithReply(status
) == B_OK
&& status
== B_OK
)
2299 BWindow::Feel() const
2306 BWindow::SetFlags(uint32 flags
)
2308 BAutolock
locker(this);
2309 if (!locker
.IsLocked())
2312 fLink
->StartMessage(AS_SET_FLAGS
);
2313 fLink
->Attach
<uint32
>(flags
);
2315 int32 status
= B_ERROR
;
2316 if (fLink
->FlushWithReply(status
) == B_OK
&& status
== B_OK
)
2324 BWindow::Flags() const
2331 BWindow::SetWindowAlignment(window_alignment mode
,
2332 int32 h
, int32 hOffset
, int32 width
, int32 widthOffset
,
2333 int32 v
, int32 vOffset
, int32 height
, int32 heightOffset
)
2335 if ((mode
& (B_BYTE_ALIGNMENT
| B_PIXEL_ALIGNMENT
)) == 0
2336 || (hOffset
>= 0 && hOffset
<= h
)
2337 || (vOffset
>= 0 && vOffset
<= v
)
2338 || (widthOffset
>= 0 && widthOffset
<= width
)
2339 || (heightOffset
>= 0 && heightOffset
<= height
))
2342 // TODO: test if hOffset = 0 and set it to 1 if true.
2347 fLink
->StartMessage(AS_SET_ALIGNMENT
);
2348 fLink
->Attach
<int32
>((int32
)mode
);
2349 fLink
->Attach
<int32
>(h
);
2350 fLink
->Attach
<int32
>(hOffset
);
2351 fLink
->Attach
<int32
>(width
);
2352 fLink
->Attach
<int32
>(widthOffset
);
2353 fLink
->Attach
<int32
>(v
);
2354 fLink
->Attach
<int32
>(vOffset
);
2355 fLink
->Attach
<int32
>(height
);
2356 fLink
->Attach
<int32
>(heightOffset
);
2358 status_t status
= B_ERROR
;
2359 fLink
->FlushWithReply(status
);
2368 BWindow::GetWindowAlignment(window_alignment
* mode
,
2369 int32
* h
, int32
* hOffset
, int32
* width
, int32
* widthOffset
,
2370 int32
* v
, int32
* vOffset
, int32
* height
, int32
* heightOffset
) const
2372 if (!const_cast<BWindow
*>(this)->Lock())
2375 fLink
->StartMessage(AS_GET_ALIGNMENT
);
2378 if (fLink
->FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
2379 fLink
->Read
<int32
>((int32
*)mode
);
2380 fLink
->Read
<int32
>(h
);
2381 fLink
->Read
<int32
>(hOffset
);
2382 fLink
->Read
<int32
>(width
);
2383 fLink
->Read
<int32
>(widthOffset
);
2384 fLink
->Read
<int32
>(v
);
2385 fLink
->Read
<int32
>(hOffset
);
2386 fLink
->Read
<int32
>(height
);
2387 fLink
->Read
<int32
>(heightOffset
);
2390 const_cast<BWindow
*>(this)->Unlock();
2396 BWindow::Workspaces() const
2398 if (!const_cast<BWindow
*>(this)->Lock())
2401 uint32 workspaces
= 0;
2403 fLink
->StartMessage(AS_GET_WORKSPACES
);
2406 if (fLink
->FlushWithReply(status
) == B_OK
&& status
== B_OK
)
2407 fLink
->Read
<uint32
>(&workspaces
);
2409 const_cast<BWindow
*>(this)->Unlock();
2415 BWindow::SetWorkspaces(uint32 workspaces
)
2417 // TODO: don't forget about Tracker's background window.
2418 if (fFeel
!= B_NORMAL_WINDOW_FEEL
)
2422 fLink
->StartMessage(AS_SET_WORKSPACES
);
2423 fLink
->Attach
<uint32
>(workspaces
);
2431 BWindow::LastMouseMovedView() const
2433 return fLastMouseMovedView
;
2438 BWindow::MoveBy(float dx
, float dy
)
2440 if ((dx
!= 0.0f
|| dy
!= 0.0f
) && Lock()) {
2441 MoveTo(fFrame
.left
+ dx
, fFrame
.top
+ dy
);
2448 BWindow::MoveTo(BPoint point
)
2450 MoveTo(point
.x
, point
.y
);
2455 BWindow::MoveTo(float x
, float y
)
2463 if (fFrame
.left
!= x
|| fFrame
.top
!= y
) {
2464 fLink
->StartMessage(AS_WINDOW_MOVE
);
2465 fLink
->Attach
<float>(x
);
2466 fLink
->Attach
<float>(y
);
2469 if (fLink
->FlushWithReply(status
) == B_OK
&& status
== B_OK
)
2470 fFrame
.OffsetTo(x
, y
);
2478 BWindow::ResizeBy(float dx
, float dy
)
2481 ResizeTo(fFrame
.Width() + dx
, fFrame
.Height() + dy
);
2488 BWindow::ResizeTo(float width
, float height
)
2493 width
= roundf(width
);
2494 height
= roundf(height
);
2496 // stay in minimum & maximum frame limits
2497 if (width
< fMinWidth
)
2499 else if (width
> fMaxWidth
)
2502 if (height
< fMinHeight
)
2503 height
= fMinHeight
;
2504 else if (height
> fMaxHeight
)
2505 height
= fMaxHeight
;
2507 if (width
!= fFrame
.Width() || height
!= fFrame
.Height()) {
2508 fLink
->StartMessage(AS_WINDOW_RESIZE
);
2509 fLink
->Attach
<float>(width
);
2510 fLink
->Attach
<float>(height
);
2513 if (fLink
->FlushWithReply(status
) == B_OK
&& status
== B_OK
) {
2514 fFrame
.right
= fFrame
.left
+ width
;
2515 fFrame
.bottom
= fFrame
.top
+ height
;
2525 BWindow::ResizeToPreferred()
2529 float width
= fTopView
->PreferredSize().width
;
2530 width
= std::min(width
, fTopView
->MaxSize().width
);
2531 width
= std::max(width
, fTopView
->MinSize().width
);
2533 float height
= fTopView
->PreferredSize().height
;
2534 height
= std::min(width
, fTopView
->MaxSize().height
);
2535 height
= std::max(width
, fTopView
->MinSize().height
);
2537 if (GetLayout()->HasHeightForWidth())
2538 GetLayout()->GetHeightForWidth(width
, NULL
, NULL
, &height
);
2540 ResizeTo(width
, height
);
2545 BWindow::CenterIn(const BRect
& rect
)
2547 // Set size limits now if needed
2550 MoveTo(BLayoutUtils::AlignInFrame(rect
, Size(),
2551 BAlignment(B_ALIGN_HORIZONTAL_CENTER
,
2552 B_ALIGN_VERTICAL_CENTER
)).LeftTop());
2557 BWindow::CenterOnScreen()
2559 CenterIn(BScreen(this).Frame());
2563 // Centers the window on the screen with the passed in id.
2565 BWindow::CenterOnScreen(screen_id id
)
2567 CenterIn(BScreen(id
).Frame());
2574 bool runCalled
= true;
2578 _SendShowOrHideMessage();
2580 runCalled
= fRunCalled
;
2586 // This is the fist time Show() is called, which implicitly runs the
2587 // looper. NOTE: The window is still locked if it has not been
2588 // run yet, so accessing members is safe.
2589 if (fLink
->SenderPort() < B_OK
) {
2590 // We don't have valid app_server connection; there is no point
2591 // in starting our looper
2604 // If we are minimized and are about to be hidden, unminimize
2605 if (IsMinimized() && fShowLevel
== 0)
2610 _SendShowOrHideMessage();
2618 BWindow::IsHidden() const
2620 return fShowLevel
> 0;
2625 BWindow::QuitRequested()
2627 return BLooper::QuitRequested();
2634 return BLooper::Run();
2639 BWindow::SetLayout(BLayout
* layout
)
2641 fTopView
->SetLayout(layout
);
2646 BWindow::GetLayout() const
2648 return fTopView
->GetLayout();
2653 BWindow::InvalidateLayout(bool descendants
)
2655 fTopView
->InvalidateLayout(descendants
);
2660 BWindow::Layout(bool force
)
2664 // Do the actual layout
2665 fTopView
->Layout(force
);
2670 BWindow::GetSupportedSuites(BMessage
* data
)
2675 status_t status
= data
->AddString("suites", "suite/vnd.Be-window");
2676 if (status
== B_OK
) {
2677 BPropertyInfo
propertyInfo(sWindowPropInfo
, sWindowValueInfo
);
2679 status
= data
->AddFlat("messages", &propertyInfo
);
2681 status
= BLooper::GetSupportedSuites(data
);
2689 BWindow::ResolveSpecifier(BMessage
* message
, int32 index
, BMessage
* specifier
,
2690 int32 what
, const char* property
)
2692 if (message
->what
== B_WINDOW_MOVE_BY
2693 || message
->what
== B_WINDOW_MOVE_TO
)
2696 BPropertyInfo
propertyInfo(sWindowPropInfo
);
2697 if (propertyInfo
.FindMatch(message
, index
, specifier
, what
, property
) >= 0) {
2698 if (strcmp(property
, "View") == 0) {
2699 // we will NOT pop the current specifier
2701 } else if (strcmp(property
, "MenuBar") == 0) {
2703 message
->PopSpecifier();
2706 BMessage
replyMsg(B_MESSAGE_NOT_UNDERSTOOD
);
2707 replyMsg
.AddInt32("error", B_NAME_NOT_FOUND
);
2708 replyMsg
.AddString("message",
2709 "This window doesn't have a main MenuBar");
2710 message
->SendReply(&replyMsg
);
2717 return BLooper::ResolveSpecifier(message
, index
, specifier
, what
, property
);
2721 // #pragma mark - Private Methods
2725 BWindow::_InitData(BRect frame
, const char* title
, window_look look
,
2726 window_feel feel
, uint32 flags
, uint32 workspace
, int32 bitmapToken
)
2728 STRACE(("BWindow::InitData()\n"));
2730 if (be_app
== NULL
) {
2731 debugger("You need a valid BApplication object before interacting with "
2736 frame
.left
= roundf(frame
.left
);
2737 frame
.top
= roundf(frame
.top
);
2738 frame
.right
= roundf(frame
.right
);
2739 frame
.bottom
= roundf(frame
.bottom
);
2746 fTitle
= strdup(title
);
2752 fFlags
= flags
| B_ASYNCHRONOUS_CONTROLS
;
2754 fInTransaction
= bitmapToken
>= 0;
2755 fUpdateRequested
= false;
2761 fLastMouseMovedView
= NULL
;
2763 fDefaultButton
= NULL
;
2765 // Shortcut 'Q' is handled in _HandleKeyDown() directly, as its message
2766 // get sent to the application, and not one of our handlers.
2767 // It is only installed for non-modal windows, though.
2768 fNoQuitShortcut
= IsModal();
2770 if ((fFlags
& B_NOT_CLOSABLE
) == 0 && !IsModal()) {
2771 // Modal windows default to non-closable, but you can add the
2772 // shortcut manually, if a different behaviour is wanted
2773 AddShortcut('W', B_COMMAND_KEY
, new BMessage(B_QUIT_REQUESTED
));
2776 // Edit modifier keys
2778 AddShortcut('X', B_COMMAND_KEY
, new BMessage(B_CUT
), NULL
);
2779 AddShortcut('C', B_COMMAND_KEY
, new BMessage(B_COPY
), NULL
);
2780 AddShortcut('V', B_COMMAND_KEY
, new BMessage(B_PASTE
), NULL
);
2781 AddShortcut('A', B_COMMAND_KEY
, new BMessage(B_SELECT_ALL
), NULL
);
2783 // Window modifier keys
2785 AddShortcut('M', B_COMMAND_KEY
| B_CONTROL_KEY
,
2786 new BMessage(_MINIMIZE_
), NULL
);
2787 AddShortcut('Z', B_COMMAND_KEY
| B_CONTROL_KEY
,
2788 new BMessage(_ZOOM_
), NULL
);
2789 AddShortcut('H', B_COMMAND_KEY
| B_CONTROL_KEY
,
2790 new BMessage(B_HIDE_APPLICATION
), NULL
);
2791 AddShortcut('F', B_COMMAND_KEY
| B_CONTROL_KEY
,
2792 new BMessage(_SEND_TO_FRONT_
), NULL
);
2793 AddShortcut('B', B_COMMAND_KEY
| B_CONTROL_KEY
,
2794 new BMessage(_SEND_BEHIND_
), NULL
);
2796 // We set the default pulse rate, but we don't start the pulse
2797 fPulseRate
= 500000;
2798 fPulseRunner
= NULL
;
2800 fIsFilePanel
= false;
2806 fMaxZoomHeight
= 32768.0;
2807 fMaxZoomWidth
= 32768.0;
2810 fMaxHeight
= 32768.0;
2811 fMaxWidth
= 32768.0;
2813 fLastViewToken
= B_NULL_TOKEN
;
2815 // TODO: other initializations!
2818 // Create the server-side window
2820 port_id receivePort
= create_port(B_LOOPER_PORT_DEFAULT_CAPACITY
,
2822 if (receivePort
< B_OK
) {
2824 debugger("Could not create BWindow's receive port, used for "
2825 "interacting with the app_server!");
2830 STRACE(("BWindow::InitData(): contacting app_server...\n"));
2832 // let app_server know that a window has been created.
2833 fLink
= new(std::nothrow
) BPrivate::PortLink(
2834 BApplication::Private::ServerLink()->SenderPort(), receivePort
);
2835 if (fLink
== NULL
) {
2841 BPrivate::AppServerLink lockLink
;
2842 // we're talking to the server application using our own
2843 // communication channel (fLink) - we better make sure no one
2844 // interferes by locking that channel (which AppServerLink does
2847 if (bitmapToken
< 0) {
2848 fLink
->StartMessage(AS_CREATE_WINDOW
);
2850 fLink
->StartMessage(AS_CREATE_OFFSCREEN_WINDOW
);
2851 fLink
->Attach
<int32
>(bitmapToken
);
2855 fLink
->Attach
<BRect
>(fFrame
);
2856 fLink
->Attach
<uint32
>((uint32
)fLook
);
2857 fLink
->Attach
<uint32
>((uint32
)fFeel
);
2858 fLink
->Attach
<uint32
>(fFlags
);
2859 fLink
->Attach
<uint32
>(workspace
);
2860 fLink
->Attach
<int32
>(_get_object_token_(this));
2861 fLink
->Attach
<port_id
>(receivePort
);
2862 fLink
->Attach
<port_id
>(fMsgPort
);
2863 fLink
->AttachString(title
);
2867 if (fLink
->FlushWithReply(code
) == B_OK
2869 && fLink
->Read
<port_id
>(&sendPort
) == B_OK
) {
2870 // read the frame size and its limits that were really
2871 // enforced on the server side
2873 fLink
->Read
<BRect
>(&fFrame
);
2874 fLink
->Read
<float>(&fMinWidth
);
2875 fLink
->Read
<float>(&fMaxWidth
);
2876 fLink
->Read
<float>(&fMinHeight
);
2877 fLink
->Read
<float>(&fMaxHeight
);
2879 fMaxZoomWidth
= fMaxWidth
;
2880 fMaxZoomHeight
= fMaxHeight
;
2884 // Redirect our link to the new window connection
2885 fLink
->SetSenderPort(sendPort
);
2888 STRACE(("Server says that our send port is %ld\n", sendPort
));
2889 STRACE(("Window locked?: %s\n", IsLocked() ? "True" : "False"));
2895 //! Rename the handler and its thread
2897 BWindow::_SetName(const char* title
)
2902 // we will change BWindow's thread name to "w>window title"
2904 char threadName
[B_OS_NAME_LENGTH
];
2905 strcpy(threadName
, "w>");
2907 strlcat(threadName
, title
, B_OS_NAME_LENGTH
);
2909 int32 length
= strlen(title
);
2910 length
= min_c(length
, B_OS_NAME_LENGTH
- 3);
2911 memcpy(threadName
+ 2, title
, length
);
2912 threadName
[length
+ 2] = '\0';
2915 // change the handler's name
2916 SetName(threadName
);
2918 // if the message loop has been started...
2919 if (Thread() >= B_OK
)
2920 rename_thread(Thread(), threadName
);
2924 //! Reads all pending messages from the window port and put them into the queue.
2926 BWindow::_DequeueAll()
2928 // Get message count from port
2929 int32 count
= port_count(fMsgPort
);
2931 for (int32 i
= 0; i
< count
; i
++) {
2932 BMessage
* message
= MessageFromPort(0);
2933 if (message
!= NULL
)
2934 fDirectTarget
->Queue()->AddMessage(message
);
2939 /*! This here is an almost complete code duplication to BLooper::task_looper()
2940 but with some important differences:
2941 a) it uses the _DetermineTarget() method to tell what the later target of
2942 a message will be, if no explicit target is supplied.
2943 b) it calls _UnpackMessage() and _SanitizeMessage() to duplicate the message
2944 to all of its intended targets, and to add all fields the target would
2945 expect in such a message.
2947 This is important because the app_server sends all input events to the
2948 preferred handler, and expects them to be correctly distributed to their
2952 BWindow::task_looper()
2954 STRACE(("info: BWindow::task_looper() started.\n"));
2956 // Check that looper is locked (should be)
2961 debugger("window must not be locked!");
2963 while (!fTerminating
) {
2964 // Did we get a message?
2965 BMessage
* msg
= MessageFromPort();
2967 _AddMessagePriv(msg
);
2969 // Get message count from port
2970 int32 msgCount
= port_count(fMsgPort
);
2971 for (int32 i
= 0; i
< msgCount
; ++i
) {
2972 // Read 'count' messages from port (so we will not block)
2973 // We use zero as our timeout since we know there is stuff there
2974 msg
= MessageFromPort(0);
2975 // Add messages to queue
2977 _AddMessagePriv(msg
);
2980 bool dispatchNextMessage
= true;
2981 while (!fTerminating
&& dispatchNextMessage
) {
2982 // Get next message from queue (assign to fLastMessage after
2984 BMessage
* message
= fDirectTarget
->Queue()->NextMessage();
2992 fLastMessage
= message
;
2994 if (fLastMessage
== NULL
) {
2995 // No more messages: Unlock the looper and terminate the
2997 dispatchNextMessage
= false;
2999 // Get the target handler
3000 BMessage::Private
messagePrivate(fLastMessage
);
3001 bool usePreferred
= messagePrivate
.UsePreferredTarget();
3002 BHandler
* handler
= NULL
;
3003 bool dropMessage
= false;
3006 handler
= PreferredHandler();
3007 if (handler
== NULL
)
3010 gDefaultTokens
.GetToken(messagePrivate
.GetTarget(),
3011 B_HANDLER_TOKEN
, (void**)&handler
);
3013 // if this handler doesn't belong to us, we drop the message
3014 if (handler
!= NULL
&& handler
->Looper() != this) {
3020 if ((handler
== NULL
&& !dropMessage
) || usePreferred
)
3021 handler
= _DetermineTarget(fLastMessage
, handler
);
3023 unpack_cookie cookie
;
3024 while (_UnpackMessage(cookie
, &fLastMessage
, &handler
, &usePreferred
)) {
3025 // if there is no target handler, the message is dropped
3026 if (handler
!= NULL
) {
3027 _SanitizeMessage(fLastMessage
, handler
, usePreferred
);
3029 // Is this a scripting message?
3030 if (fLastMessage
->HasSpecifiers()) {
3032 // Make sure the current specifier is kosher
3033 if (fLastMessage
->GetCurrentSpecifier(&index
) == B_OK
)
3034 handler
= resolve_specifier(handler
, fLastMessage
);
3037 if (handler
!= NULL
)
3038 handler
= _TopLevelFilter(fLastMessage
, handler
);
3040 if (handler
!= NULL
)
3041 DispatchMessage(fLastMessage
, handler
);
3044 // Delete the current message
3045 delete fLastMessage
;
3046 fLastMessage
= NULL
;
3051 // we leave the looper locked when we quit
3057 // Are any messages on the port?
3058 if (port_count(fMsgPort
) > 0) {
3060 dispatchNextMessage
= false;
3068 BWindow::_ComposeType(window_look look
, window_feel feel
) const
3071 case B_NORMAL_WINDOW_FEEL
:
3073 case B_TITLED_WINDOW_LOOK
:
3074 return B_TITLED_WINDOW
;
3076 case B_DOCUMENT_WINDOW_LOOK
:
3077 return B_DOCUMENT_WINDOW
;
3079 case B_BORDERED_WINDOW_LOOK
:
3080 return B_BORDERED_WINDOW
;
3083 return B_UNTYPED_WINDOW
;
3087 case B_MODAL_APP_WINDOW_FEEL
:
3088 if (look
== B_MODAL_WINDOW_LOOK
)
3089 return B_MODAL_WINDOW
;
3092 case B_FLOATING_APP_WINDOW_FEEL
:
3093 if (look
== B_FLOATING_WINDOW_LOOK
)
3094 return B_FLOATING_WINDOW
;
3098 return B_UNTYPED_WINDOW
;
3101 return B_UNTYPED_WINDOW
;
3106 BWindow::_DecomposeType(window_type type
, window_look
* _look
,
3107 window_feel
* _feel
) const
3110 case B_DOCUMENT_WINDOW
:
3111 *_look
= B_DOCUMENT_WINDOW_LOOK
;
3112 *_feel
= B_NORMAL_WINDOW_FEEL
;
3115 case B_MODAL_WINDOW
:
3116 *_look
= B_MODAL_WINDOW_LOOK
;
3117 *_feel
= B_MODAL_APP_WINDOW_FEEL
;
3120 case B_FLOATING_WINDOW
:
3121 *_look
= B_FLOATING_WINDOW_LOOK
;
3122 *_feel
= B_FLOATING_APP_WINDOW_FEEL
;
3125 case B_BORDERED_WINDOW
:
3126 *_look
= B_BORDERED_WINDOW_LOOK
;
3127 *_feel
= B_NORMAL_WINDOW_FEEL
;
3130 case B_TITLED_WINDOW
:
3131 case B_UNTYPED_WINDOW
:
3133 *_look
= B_TITLED_WINDOW_LOOK
;
3134 *_feel
= B_NORMAL_WINDOW_FEEL
;
3141 BWindow::_CreateTopView()
3143 STRACE(("_CreateTopView(): enter\n"));
3145 BRect frame
= fFrame
.OffsetToCopy(B_ORIGIN
);
3146 // TODO: what to do here about std::nothrow?
3147 fTopView
= new BView(frame
, "fTopView",
3148 B_FOLLOW_ALL
, B_WILL_DRAW
);
3149 fTopView
->fTopLevelView
= true;
3151 //inhibit check_lock()
3152 fLastViewToken
= _get_object_token_(fTopView
);
3154 // set fTopView's owner, add it to window's eligible handler list
3155 // and also set its next handler to be this window.
3157 STRACE(("Calling setowner fTopView = %p this = %p.\n",
3160 fTopView
->_SetOwner(this);
3162 // we can't use AddChild() because this is the top view
3163 fTopView
->_CreateSelf();
3165 STRACE(("BuildTopView ended\n"));
3170 Resizes the top view to match the window size. This will also
3171 adapt the size of all its child views as needed.
3172 This method has to be called whenever the frame of the window
3176 BWindow::_AdoptResize()
3178 // Resize views according to their resize modes - this
3179 // saves us some server communication, as the server
3180 // does the same with our views on its side.
3182 int32 deltaWidth
= (int32
)(fFrame
.Width() - fTopView
->Bounds().Width());
3183 int32 deltaHeight
= (int32
)(fFrame
.Height() - fTopView
->Bounds().Height());
3184 if (deltaWidth
== 0 && deltaHeight
== 0)
3187 fTopView
->_ResizeBy(deltaWidth
, deltaHeight
);
3192 BWindow::_SetFocus(BView
* focusView
, bool notifyInputServer
)
3194 if (fFocus
== focusView
)
3197 // we notify the input server if we are passing focus
3198 // from a view which has the B_INPUT_METHOD_AWARE to a one
3199 // which does not, or vice-versa
3200 if (notifyInputServer
&& fActive
) {
3201 bool inputMethodAware
= false;
3203 inputMethodAware
= focusView
->Flags() & B_INPUT_METHOD_AWARE
;
3204 BMessage
msg(inputMethodAware
? IS_FOCUS_IM_AWARE_VIEW
: IS_UNFOCUS_IM_AWARE_VIEW
);
3205 BMessenger
messenger(focusView
);
3208 msg
.AddMessenger("view", messenger
);
3209 _control_input_server_(&msg
, &reply
);
3213 SetPreferredHandler(focusView
);
3218 \brief Determines the target of a message received for the
3222 BWindow::_DetermineTarget(BMessage
* message
, BHandler
* target
)
3227 switch (message
->what
) {
3231 // if we have a default button, it might want to hear
3232 // about pressing the <enter> key
3234 if (DefaultButton() != NULL
3235 && message
->FindInt32("raw_char", &rawChar
) == B_OK
3236 && rawChar
== B_ENTER
)
3237 return DefaultButton();
3239 // supposed to fall through
3241 case B_UNMAPPED_KEY_DOWN
:
3242 case B_UNMAPPED_KEY_UP
:
3243 case B_MODIFIERS_CHANGED
:
3244 // these messages should be dispatched by the focus view
3245 if (CurrentFocus() != NULL
)
3246 return CurrentFocus();
3252 case B_MOUSE_WHEEL_CHANGED
:
3254 // is there a token of the view that is currently under the mouse?
3256 if (message
->FindInt32("_view_token", &token
) == B_OK
) {
3257 BView
* view
= _FindView(token
);
3262 // if there is no valid token in the message, we try our
3263 // luck with the last target, if available
3264 if (fLastMouseMovedView
!= NULL
)
3265 return fLastMouseMovedView
;
3269 case B_QUIT_REQUESTED
:
3270 // TODO: test whether R5 will let BView dispatch these messages
3273 case _MESSAGE_DROPPED_
:
3274 if (fLastMouseMovedView
!= NULL
)
3275 return fLastMouseMovedView
;
3286 /*! \brief Determines whether or not this message has targeted the focus view.
3288 This will return \c false only if the message did not go to the preferred
3289 handler, or if the packed message does not contain address the focus view
3293 BWindow::_IsFocusMessage(BMessage
* message
)
3295 BMessage::Private
messagePrivate(message
);
3296 if (!messagePrivate
.UsePreferredTarget())
3300 if (message
->HasInt32("_token")
3301 && (message
->FindBool("_feed_focus", &feedFocus
) != B_OK
|| !feedFocus
))
3308 /*! \brief Distributes the message to its intended targets. This is done for
3309 all messages that should go to the preferred handler.
3311 Returns \c true in case the message should still be dispatched
3314 BWindow::_UnpackMessage(unpack_cookie
& cookie
, BMessage
** _message
,
3315 BHandler
** _target
, bool* _usePreferred
)
3317 if (cookie
.message
== NULL
)
3320 if (cookie
.index
== 0 && !cookie
.tokens_scanned
) {
3321 // We were called the first time for this message
3323 if (!*_usePreferred
) {
3324 // only consider messages targeted at the preferred handler
3325 cookie
.message
= NULL
;
3329 // initialize our cookie
3330 cookie
.message
= *_message
;
3331 cookie
.focus
= *_target
;
3333 if (cookie
.focus
!= NULL
)
3334 cookie
.focus_token
= _get_object_token_(*_target
);
3336 if (fLastMouseMovedView
!= NULL
&& cookie
.message
->what
== B_MOUSE_MOVED
)
3337 cookie
.last_view_token
= _get_object_token_(fLastMouseMovedView
);
3339 *_usePreferred
= false;
3344 // distribute the message to all targets specified in the
3345 // message directly (but not to the focus view)
3347 for (int32 token
; !cookie
.tokens_scanned
3348 && cookie
.message
->FindInt32("_token", cookie
.index
, &token
)
3351 // focus view is preferred and should get its message directly
3352 if (token
== cookie
.focus_token
) {
3353 cookie
.found_focus
= true;
3356 if (token
== cookie
.last_view_token
)
3359 BView
* target
= _FindView(token
);
3363 *_message
= new BMessage(*cookie
.message
);
3369 cookie
.tokens_scanned
= true;
3371 // if there is a last mouse moved view, and the new focus is
3372 // different, the previous view wants to get its B_EXITED_VIEW
3374 if (cookie
.last_view_token
!= B_NULL_TOKEN
&& fLastMouseMovedView
!= NULL
3375 && fLastMouseMovedView
!= cookie
.focus
) {
3376 *_message
= new BMessage(*cookie
.message
);
3377 *_target
= fLastMouseMovedView
;
3378 cookie
.last_view_token
= B_NULL_TOKEN
;
3382 bool dispatchToFocus
= true;
3384 // check if the focus token is still valid (could have been removed in the mean time)
3386 if (gDefaultTokens
.GetToken(cookie
.focus_token
, B_HANDLER_TOKEN
, (void**)&handler
) != B_OK
3387 || handler
->Looper() != this)
3388 dispatchToFocus
= false;
3390 if (dispatchToFocus
&& cookie
.index
> 0) {
3391 // should this message still be dispatched by the focus view?
3393 if (!cookie
.found_focus
3394 && (cookie
.message
->FindBool("_feed_focus", &feedFocus
) != B_OK
3395 || feedFocus
== false))
3396 dispatchToFocus
= false;
3399 if (!dispatchToFocus
) {
3400 delete cookie
.message
;
3401 cookie
.message
= NULL
;
3405 *_message
= cookie
.message
;
3406 *_target
= cookie
.focus
;
3407 *_usePreferred
= true;
3408 cookie
.message
= NULL
;
3413 /*! Some messages don't get to the window in a shape an application should see.
3414 This method is supposed to give a message the last grinding before
3415 it's acceptable for the receiving application.
3418 BWindow::_SanitizeMessage(BMessage
* message
, BHandler
* target
, bool usePreferred
)
3423 switch (message
->what
) {
3429 if (message
->FindPoint("screen_where", &where
) != B_OK
)
3432 BView
* view
= dynamic_cast<BView
*>(target
);
3434 if (view
== NULL
|| message
->what
== B_MOUSE_MOVED
) {
3435 // add local window coordinates, only
3436 // for regular mouse moved messages
3437 message
->AddPoint("where", ConvertFromScreen(where
));
3441 // add local view coordinates
3442 BPoint viewWhere
= view
->ConvertFromScreen(where
);
3443 if (message
->what
!= B_MOUSE_MOVED
) {
3444 // Yep, the meaning of "where" is different
3445 // for regular mouse moved messages versus
3447 message
->AddPoint("where", viewWhere
);
3449 message
->AddPoint("be:view_where", viewWhere
);
3451 if (message
->what
== B_MOUSE_MOVED
) {
3452 // is there a token of the view that is currently under
3454 BView
* viewUnderMouse
= NULL
;
3456 if (message
->FindInt32("_view_token", &token
) == B_OK
)
3457 viewUnderMouse
= _FindView(token
);
3459 // add transit information
3461 = _TransitForMouseMoved(view
, viewUnderMouse
);
3462 message
->AddInt32("be:transit", transit
);
3465 fLastMouseMovedView
= viewUnderMouse
;
3473 // App Server sends screen coordinates, convert the point to
3474 // local view coordinates, then add the point in be:view_where
3476 if (message
->FindPoint("screen_where", &where
) != B_OK
)
3479 BView
* view
= dynamic_cast<BView
*>(target
);
3481 // add local view coordinates
3482 message
->AddPoint("be:view_where",
3483 view
->ConvertFromScreen(where
));
3488 case _MESSAGE_DROPPED_
:
3490 uint32 originalWhat
;
3491 if (message
->FindInt32("_original_what",
3492 (int32
*)&originalWhat
) == B_OK
) {
3493 message
->what
= originalWhat
;
3494 message
->RemoveName("_original_what");
3503 This is called by BView::GetMouse() when a B_MOUSE_MOVED message
3504 is removed from the queue.
3505 It allows the window to update the last mouse moved view, and
3506 let it decide if this message should be kept. It will also remove
3507 the message from the queue.
3508 You need to hold the message queue lock when calling this method!
3510 \return true if this message can be used to get the mouse data from,
3511 \return false if this is not meant for the public.
3514 BWindow::_StealMouseMessage(BMessage
* message
, bool& deleteMessage
)
3516 BMessage::Private
messagePrivate(message
);
3517 if (!messagePrivate
.UsePreferredTarget()) {
3518 // this message is targeted at a specific handler, so we should
3524 if (message
->FindInt32("_token", 0, &token
) == B_OK
) {
3525 // This message has other targets, so we can't remove it;
3526 // just prevent it from being sent to the preferred handler
3527 // again (if it should have gotten it at all).
3529 if (message
->FindBool("_feed_focus", &feedFocus
) != B_OK
|| !feedFocus
)
3532 message
->RemoveName("_feed_focus");
3533 deleteMessage
= false;
3535 deleteMessage
= true;
3537 if (message
->what
== B_MOUSE_MOVED
) {
3538 // We need to update the last mouse moved view, as this message
3539 // won't make it to _SanitizeMessage() anymore.
3540 BView
* viewUnderMouse
= NULL
;
3542 if (message
->FindInt32("_view_token", &token
) == B_OK
)
3543 viewUnderMouse
= _FindView(token
);
3545 // Don't remove important transit messages!
3546 uint32 transit
= _TransitForMouseMoved(fLastMouseMovedView
,
3548 if (transit
== B_ENTERED_VIEW
|| transit
== B_EXITED_VIEW
)
3549 deleteMessage
= false;
3552 if (deleteMessage
) {
3553 // The message is only thought for the preferred handler, so we
3554 // can just remove it.
3555 MessageQueue()->RemoveMessage(message
);
3564 BWindow::_TransitForMouseMoved(BView
* view
, BView
* viewUnderMouse
) const
3567 if (viewUnderMouse
== view
) {
3568 // the mouse is over the target view
3569 if (fLastMouseMovedView
!= view
)
3570 transit
= B_ENTERED_VIEW
;
3572 transit
= B_INSIDE_VIEW
;
3574 // the mouse is not over the target view
3575 if (view
== fLastMouseMovedView
)
3576 transit
= B_EXITED_VIEW
;
3578 transit
= B_OUTSIDE_VIEW
;
3584 /*! Forwards the key to the switcher
3587 BWindow::_Switcher(int32 rawKey
, uint32 modifiers
, bool repeat
)
3589 // only send the first key press, no repeats
3593 BMessenger
deskbar(kDeskbarSignature
);
3594 if (!deskbar
.IsValid()) {
3595 // TODO: have some kind of fallback-handling in case the Deskbar is
3600 BMessage
message('TASK');
3601 message
.AddInt32("key", rawKey
);
3602 message
.AddInt32("modifiers", modifiers
);
3603 message
.AddInt64("when", system_time());
3604 message
.AddInt32("team", Team());
3605 deskbar
.SendMessage(&message
);
3609 /*! Handles keyboard input before it gets forwarded to the target handler.
3610 This includes shortcut evaluation, keyboard navigation, etc.
3612 \return handled if true, the event was already handled, and will not
3613 be forwarded to the target handler.
3615 TODO: must also convert the incoming key to the font encoding of the target
3618 BWindow::_HandleKeyDown(BMessage
* event
)
3620 // Only handle special functions when the event targeted the active focus
3622 if (!_IsFocusMessage(event
))
3625 const char* string
= NULL
;
3626 if (event
->FindString("bytes", &string
) != B_OK
)
3629 char key
= string
[0];
3632 if (event
->FindInt32("modifiers", (int32
*)&modifiers
) != B_OK
)
3635 // handle BMenuBar key
3636 if (key
== B_ESCAPE
&& (modifiers
& B_COMMAND_KEY
) != 0 && fKeyMenuBar
) {
3637 fKeyMenuBar
->StartMenuBar(0, true, false, NULL
);
3641 // Keyboard navigation through views
3642 // (B_OPTION_KEY makes BTextViews and friends navigable, even in editing
3644 if (key
== B_TAB
&& (modifiers
& B_OPTION_KEY
) != 0) {
3645 _KeyboardNavigation();
3650 event
->FindInt32("key", &rawKey
);
3652 // Deskbar's Switcher
3653 if ((key
== B_TAB
|| rawKey
== 0x11) && (modifiers
& B_CONTROL_KEY
) != 0) {
3654 _Switcher(rawKey
, modifiers
, event
->HasInt32("be:key_repeat"));
3658 // Optionally close window when the escape key is pressed
3659 if (key
== B_ESCAPE
&& (Flags() & B_CLOSE_ON_ESCAPE
) != 0) {
3660 BMessage
message(B_QUIT_REQUESTED
);
3661 message
.AddBool("shortcut", true);
3663 PostMessage(&message
);
3667 // PrtScr key takes a screenshot
3668 if (key
== B_FUNCTION_KEY
&& rawKey
== B_PRINT_KEY
) {
3669 // With no modifier keys the best way to get a screenshot is by
3670 // calling the screenshot CLI
3671 if (modifiers
== 0) {
3672 be_roster
->Launch("application/x-vnd.haiku-screenshot-cli");
3676 // Prepare a message based on the modifier keys pressed and launch the
3678 BMessage
message(B_ARGV_RECEIVED
);
3680 message
.AddString("argv", "Screenshot");
3681 if ((modifiers
& B_CONTROL_KEY
) != 0) {
3683 message
.AddString("argv", "--clipboard");
3685 if ((modifiers
& B_SHIFT_KEY
) != 0) {
3687 message
.AddString("argv", "--silent");
3689 message
.AddInt32("argc", argc
);
3690 be_roster
->Launch("application/x-vnd.haiku-screenshot", &message
);
3695 if ((modifiers
& B_COMMAND_KEY
) != 0) {
3696 // Command+q has been pressed, so, we will quit
3697 // the shortcut mechanism doesn't allow handlers outside the window
3698 if (!fNoQuitShortcut
&& (key
== 'Q' || key
== 'q')) {
3699 BMessage
message(B_QUIT_REQUESTED
);
3700 message
.AddBool("shortcut", true);
3702 be_app
->PostMessage(&message
);
3707 // Pretend that the user opened a menu, to give the subclass a
3708 // chance to update it's menus. This may install new shortcuts,
3709 // which is why we have to call it here, before trying to find
3710 // a shortcut for the given key.
3713 Shortcut
* shortcut
= _FindShortcut(key
, modifiers
);
3714 if (shortcut
!= NULL
) {
3715 // TODO: would be nice to move this functionality to
3716 // a Shortcut::Invoke() method - but since BMenu::InvokeItem()
3717 // (and BMenuItem::Invoke()) are private, I didn't want
3718 // to mess with them (BMenuItem::Invoke() is public in
3719 // Dano/Zeta, though, maybe we should just follow their
3721 if (shortcut
->MenuItem() != NULL
) {
3722 BMenu
* menu
= shortcut
->MenuItem()->Menu();
3724 MenuPrivate(menu
).InvokeItem(shortcut
->MenuItem(), true);
3726 BHandler
* target
= shortcut
->Target();
3728 target
= CurrentFocus();
3730 if (shortcut
->Message() != NULL
) {
3731 BMessage
message(*shortcut
->Message());
3733 if (message
.ReplaceInt64("when", system_time()) != B_OK
)
3734 message
.AddInt64("when", system_time());
3735 if (message
.ReplaceBool("shortcut", true) != B_OK
)
3736 message
.AddBool("shortcut", true);
3738 PostMessage(&message
, target
);
3745 // we always eat the event if the command key was pressed
3749 // TODO: convert keys to the encoding of the target view
3756 BWindow::_HandleUnmappedKeyDown(BMessage
* event
)
3758 // Only handle special functions when the event targeted the active focus
3760 if (!_IsFocusMessage(event
))
3765 if (event
->FindInt32("modifiers", (int32
*)&modifiers
) != B_OK
3766 || event
->FindInt32("key", &rawKey
))
3769 // Deskbar's Switcher
3770 if (rawKey
== 0x11 && (modifiers
& B_CONTROL_KEY
) != 0) {
3771 _Switcher(rawKey
, modifiers
, event
->HasInt32("be:key_repeat"));
3780 BWindow::_KeyboardNavigation()
3782 BMessage
* message
= CurrentMessage();
3783 if (message
== NULL
)
3788 if (message
->FindString("bytes", &bytes
) != B_OK
3789 || bytes
[0] != B_TAB
)
3792 message
->FindInt32("modifiers", (int32
*)&modifiers
);
3795 int32 jumpGroups
= (modifiers
& B_OPTION_KEY
) != 0
3796 ? B_NAVIGABLE_JUMP
: B_NAVIGABLE
;
3797 if (modifiers
& B_SHIFT_KEY
)
3798 nextFocus
= _FindPreviousNavigable(fFocus
, jumpGroups
);
3800 nextFocus
= _FindNextNavigable(fFocus
, jumpGroups
);
3802 if (nextFocus
&& nextFocus
!= fFocus
) {
3803 nextFocus
->MakeFocus(true);
3809 \brief Return the position of the window centered horizontally to the passed
3810 in \a frame and vertically 3/4 from the top of \a frame.
3812 If the window is on the borders
3814 \param width The width of the window.
3815 \param height The height of the window.
3816 \param frame The \a frame to center the window in.
3818 \return The new window position.
3821 BWindow::AlertPosition(const BRect
& frame
)
3823 float width
= Bounds().Width();
3824 float height
= Bounds().Height();
3826 BPoint
point(frame
.left
+ (frame
.Width() / 2.0f
) - (width
/ 2.0f
),
3827 frame
.top
+ (frame
.Height() / 4.0f
) - ceil(height
/ 3.0f
));
3829 BRect screenFrame
= BScreen(this).Frame();
3830 if (frame
== screenFrame
) {
3831 // reference frame is screen frame, skip the below adjustments
3837 _GetDecoratorSize(&borderWidth
, &tabHeight
);
3839 // clip the x position within the horizontal edges of the screen
3840 if (point
.x
< screenFrame
.left
+ borderWidth
)
3841 point
.x
= screenFrame
.left
+ borderWidth
;
3842 else if (point
.x
+ width
> screenFrame
.right
- borderWidth
)
3843 point
.x
= screenFrame
.right
- borderWidth
- width
;
3845 // lower the window down if it is covering the window tab
3846 float tabPosition
= frame
.LeftTop().y
+ tabHeight
+ borderWidth
;
3847 if (point
.y
< tabPosition
)
3848 point
.y
= tabPosition
;
3850 // clip the y position within the vertical edges of the screen
3851 if (point
.y
< screenFrame
.top
+ borderWidth
)
3852 point
.y
= screenFrame
.top
+ borderWidth
;
3853 else if (point
.y
+ height
> screenFrame
.bottom
- borderWidth
)
3854 point
.y
= screenFrame
.bottom
- borderWidth
- height
;
3861 BWindow::ConvertToMessage(void* raw
, int32 code
)
3863 return BLooper::ConvertToMessage(raw
, code
);
3868 BWindow::_FindShortcut(uint32 key
, uint32 modifiers
)
3870 int32 count
= fShortcuts
.CountItems();
3872 key
= Shortcut::PrepareKey(key
);
3873 modifiers
= Shortcut::PrepareModifiers(modifiers
);
3875 for (int32 index
= 0; index
< count
; index
++) {
3876 Shortcut
* shortcut
= (Shortcut
*)fShortcuts
.ItemAt(index
);
3878 if (shortcut
->Matches(key
, modifiers
))
3887 BWindow::_FindView(int32 token
)
3890 if (gDefaultTokens
.GetToken(token
, B_HANDLER_TOKEN
,
3891 (void**)&handler
) != B_OK
) {
3895 // the view must belong to us in order to be found by this method
3896 BView
* view
= dynamic_cast<BView
*>(handler
);
3897 if (view
!= NULL
&& view
->Window() == this)
3905 BWindow::_FindView(BView
* view
, BPoint point
) const
3907 // point is assumed to be already in view's coordinates
3908 if (!view
->IsHidden() && view
->Bounds().Contains(point
)) {
3909 if (view
->fFirstChild
== NULL
)
3912 BView
* child
= view
->fFirstChild
;
3913 while (child
!= NULL
) {
3914 BPoint childPoint
= point
- child
->Frame().LeftTop();
3915 BView
* subView
= _FindView(child
, childPoint
);
3916 if (subView
!= NULL
)
3919 child
= child
->fNextSibling
;
3929 BWindow::_FindNextNavigable(BView
* focus
, uint32 flags
)
3934 BView
* nextFocus
= focus
;
3936 // Search the tree for views that accept focus (depth search)
3938 if (nextFocus
->fFirstChild
)
3939 nextFocus
= nextFocus
->fFirstChild
;
3940 else if (nextFocus
->fNextSibling
)
3941 nextFocus
= nextFocus
->fNextSibling
;
3943 // go to the nearest parent with a next sibling
3944 while (!nextFocus
->fNextSibling
&& nextFocus
->fParent
) {
3945 nextFocus
= nextFocus
->fParent
;
3948 if (nextFocus
== fTopView
) {
3949 // if we started with the top view, we traversed the whole tree already
3950 if (nextFocus
== focus
)
3953 nextFocus
= nextFocus
->fFirstChild
;
3955 nextFocus
= nextFocus
->fNextSibling
;
3958 if (nextFocus
== focus
|| nextFocus
== NULL
) {
3959 // When we get here it means that the hole tree has been
3960 // searched and there is no view with B_NAVIGABLE(_JUMP) flag set!
3964 if (!nextFocus
->IsHidden() && (nextFocus
->Flags() & flags
) != 0)
3971 BWindow::_FindPreviousNavigable(BView
* focus
, uint32 flags
)
3976 BView
* previousFocus
= focus
;
3978 // Search the tree for the previous view that accept focus
3980 if (previousFocus
->fPreviousSibling
) {
3981 // find the last child in the previous sibling
3982 previousFocus
= _LastViewChild(previousFocus
->fPreviousSibling
);
3984 previousFocus
= previousFocus
->fParent
;
3985 if (previousFocus
== fTopView
)
3986 previousFocus
= _LastViewChild(fTopView
);
3989 if (previousFocus
== focus
|| previousFocus
== NULL
) {
3990 // When we get here it means that the hole tree has been
3991 // searched and there is no view with B_NAVIGABLE(_JUMP) flag set!
3995 if (!previousFocus
->IsHidden() && (previousFocus
->Flags() & flags
) != 0)
3996 return previousFocus
;
4002 Returns the last child in a view hierarchy.
4003 Needed only by _FindPreviousNavigable().
4006 BWindow::_LastViewChild(BView
* parent
)
4009 BView
* last
= parent
->fFirstChild
;
4013 while (last
->fNextSibling
) {
4014 last
= last
->fNextSibling
;
4023 BWindow::SetIsFilePanel(bool isFilePanel
)
4025 fIsFilePanel
= isFilePanel
;
4030 BWindow::IsFilePanel() const
4032 return fIsFilePanel
;
4037 BWindow::_GetDecoratorSize(float* _borderWidth
, float* _tabHeight
) const
4039 // fallback in case retrieving the decorator settings fails
4040 // (highly unlikely)
4041 float borderWidth
= 5.0;
4042 float tabHeight
= 21.0;
4045 if (GetDecoratorSettings(&settings
) == B_OK
) {
4047 if (settings
.FindRect("tab frame", &tabRect
) == B_OK
)
4048 tabHeight
= tabRect
.Height();
4049 settings
.FindFloat("border width", &borderWidth
);
4051 // probably no-border window look
4052 if (fLook
== B_NO_BORDER_WINDOW_LOOK
) {
4056 // else use fall-back values from above
4059 if (_borderWidth
!= NULL
)
4060 *_borderWidth
= borderWidth
;
4061 if (_tabHeight
!= NULL
)
4062 *_tabHeight
= tabHeight
;
4067 BWindow::_SendShowOrHideMessage()
4069 fLink
->StartMessage(AS_SHOW_OR_HIDE_WINDOW
);
4070 fLink
->Attach
<int32
>(fShowLevel
);
4075 // #pragma mark - C++ binary compatibility kludge
4079 _ReservedWindow1__7BWindow(BWindow
* window
, BLayout
* layout
)
4082 perform_data_set_layout data
;
4083 data
.layout
= layout
;
4084 window
->Perform(PERFORM_CODE_SET_LAYOUT
, &data
);
4088 void BWindow::_ReservedWindow2() {}
4089 void BWindow::_ReservedWindow3() {}
4090 void BWindow::_ReservedWindow4() {}
4091 void BWindow::_ReservedWindow5() {}
4092 void BWindow::_ReservedWindow6() {}
4093 void BWindow::_ReservedWindow7() {}
4094 void BWindow::_ReservedWindow8() {}