#include <Window.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <Application.h>
#include <AppMisc.h>
#include <AppServerLink.h>
#include <ApplicationPrivate.h>
#include <Autolock.h>
#include <Bitmap.h>
#include <Button.h>
#include <Deskbar.h>
#include <DirectMessageTarget.h>
#include <FindDirectory.h>
#include <InputServerTypes.h>
#include <Layout.h>
#include <LayoutUtils.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <MenuPrivate.h>
#include <MessagePrivate.h>
#include <MessageQueue.h>
#include <MessageRunner.h>
#include <Path.h>
#include <PortLink.h>
#include <PropertyInfo.h>
#include <Roster.h>
#include <RosterPrivate.h>
#include <Screen.h>
#include <ServerProtocol.h>
#include <String.h>
#include <TextView.h>
#include <TokenSpace.h>
#include <ToolTipManager.h>
#include <ToolTipWindow.h>
#include <UnicodeChar.h>
#include <WindowPrivate.h>
#include <binary_compatibility/Interface.h>
#include <input_globals.h>
#include <tracker_private.h>
#ifdef DEBUG_WIN
# define STRACE(x) printf x
#else
# define STRACE(x) ;
#endif
#define B_HIDE_APPLICATION '_AHD'
#define _MINIMIZE_ '_WMZ'
#define _ZOOM_ '_WZO'
#define _SEND_BEHIND_ '_WSB'
#define _SEND_TO_FRONT_ '_WSF'
void do_minimize_team(BRect zoomRect, team_id team, bool zoom);
struct BWindow::unpack_cookie {
unpack_cookie();
BMessage* message;
int32 index;
BHandler* focus;
int32 focus_token;
int32 last_view_token;
bool found_focus;
bool tokens_scanned;
};
class BWindow::Shortcut {
public:
Shortcut(uint32 key, uint32 modifiers,
BMenuItem* item);
Shortcut(uint32 key, uint32 modifiers,
BMessage* message, BHandler* target);
~Shortcut();
bool Matches(uint32 key, uint32 preparedModifiers) const;
uint32 Key() const { return fKey; };
uint32 Modifiers() const;
uint32 PreparedModifiers() const { return fPreparedModifiers; };
BMenuItem* MenuItem() const { return fMenuItem; }
BMessage* Message() const { return fMessage; }
BHandler* Target() const { return fTarget; }
static uint32 AllowedModifiers();
static uint32 PrepareKey(uint32 key);
static uint32 PrepareModifiers(uint32 modifiers);
private:
uint32 fKey;
uint32 fPreparedModifiers;
BMenuItem* fMenuItem;
BMessage* fMessage;
BHandler* fTarget;
};
using BPrivate::gDefaultTokens;
using BPrivate::MenuPrivate;
static property_info sWindowPropInfo[] = {
{
"Active", { B_GET_PROPERTY, B_SET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE }
},
{
"Feel", { B_GET_PROPERTY, B_SET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
},
{
"Flags", { B_GET_PROPERTY, B_SET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
},
{
"Frame", { B_GET_PROPERTY, B_SET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_RECT_TYPE }
},
{
"Hidden", { B_GET_PROPERTY, B_SET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE }
},
{
"Look", { B_GET_PROPERTY, B_SET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
},
{
"Title", { B_GET_PROPERTY, B_SET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_STRING_TYPE }
},
{
"Workspaces", { B_GET_PROPERTY, B_SET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
},
{
"MenuBar", {},
{ B_DIRECT_SPECIFIER }, NULL, 0, {}
},
{
"View", { B_COUNT_PROPERTIES },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_INT32_TYPE }
},
{
"View", {}, {}, NULL, 0, {}
},
{
"Minimize", { B_GET_PROPERTY, B_SET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_BOOL_TYPE }
},
{
"TabFrame", { B_GET_PROPERTY },
{ B_DIRECT_SPECIFIER }, NULL, 0, { B_RECT_TYPE }
},
{ 0 }
};
static value_info sWindowValueInfo[] = {
{
"MoveTo", 'WDMT', B_COMMAND_KIND,
"Moves to the position in the BPoint data"
},
{
"MoveBy", 'WDMB', B_COMMAND_KIND,
"Moves by the offsets in the BPoint data"
},
{
"ResizeTo", 'WDRT', B_COMMAND_KIND,
"Resize to the size in the BPoint data"
},
{
"ResizeBy", 'WDRB', B_COMMAND_KIND,
"Resize by the offsets in the BPoint data"
},
{ 0 }
};
void
_set_menu_sem_(BWindow* window, sem_id sem)
{
if (window != NULL)
window->fMenuSem = sem;
}
BWindow::unpack_cookie::unpack_cookie()
:
message((BMessage*)~0UL),
index(0),
focus_token(B_NULL_TOKEN),
last_view_token(B_NULL_TOKEN),
found_focus(false),
tokens_scanned(false)
{
}
BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item)
:
fKey(PrepareKey(key)),
fPreparedModifiers(PrepareModifiers(modifiers)),
fMenuItem(item),
fMessage(NULL),
fTarget(NULL)
{
}
BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMessage* message,
BHandler* target)
:
fKey(PrepareKey(key)),
fPreparedModifiers(PrepareModifiers(modifiers)),
fMenuItem(NULL),
fMessage(message),
fTarget(target)
{
}
BWindow::Shortcut::~Shortcut()
{
delete fMessage;
}
bool
BWindow::Shortcut::Matches(uint32 key, uint32 preparedModifiers) const
{
return fKey == key && fPreparedModifiers == preparedModifiers;
}
uint32
BWindow::Shortcut::Modifiers() const
{
return fPreparedModifiers
| (((fPreparedModifiers & B_COMMAND_KEY) == 0) ? B_NO_COMMAND_KEY : 0);
}
uint32
BWindow::Shortcut::AllowedModifiers()
{
return B_COMMAND_KEY | B_OPTION_KEY | B_SHIFT_KEY | B_CONTROL_KEY | B_MENU_KEY;
}
uint32
BWindow::Shortcut::PrepareModifiers(uint32 modifiers)
{
if ((modifiers & B_NO_COMMAND_KEY) != 0)
return (modifiers & AllowedModifiers()) & ~B_COMMAND_KEY;
else
return (modifiers & AllowedModifiers()) | B_COMMAND_KEY;
}
uint32
BWindow::Shortcut::PrepareKey(uint32 key)
{
return BUnicodeChar::ToUpper(key);
}
BWindow::BWindow(BRect frame, const char* title, window_type type,
uint32 flags, uint32 workspace)
:
BLooper(title, B_DISPLAY_PRIORITY)
{
window_look look;
window_feel feel;
_DecomposeType(type, &look, &feel);
_InitData(frame, title, look, feel, flags, workspace);
}
BWindow::BWindow(BRect frame, const char* title, window_look look,
window_feel feel, uint32 flags, uint32 workspace)
:
BLooper(title, B_DISPLAY_PRIORITY)
{
_InitData(frame, title, look, feel, flags, workspace);
}
BWindow::BWindow(BMessage* data)
:
BLooper(data)
{
data->FindRect("_frame", &fFrame);
const char* title;
data->FindString("_title", &title);
window_look look;
data->FindInt32("_wlook", (int32*)&look);
window_feel feel;
data->FindInt32("_wfeel", (int32*)&feel);
if (data->FindInt32("_flags", (int32*)&fFlags) != B_OK)
fFlags = 0;
uint32 workspaces;
data->FindInt32("_wspace", (int32*)&workspaces);
uint32 type;
if (data->FindInt32("_type", (int32*)&type) == B_OK)
_DecomposeType((window_type)type, &fLook, &fFeel);
_InitData(fFrame, title, look, feel, fFlags, workspaces);
if (data->FindFloat("_zoom", 0, &fMaxZoomWidth) == B_OK
&& data->FindFloat("_zoom", 1, &fMaxZoomHeight) == B_OK)
SetZoomLimits(fMaxZoomWidth, fMaxZoomHeight);
if (data->FindFloat("_sizel", 0, &fMinWidth) == B_OK
&& data->FindFloat("_sizel", 1, &fMinHeight) == B_OK
&& data->FindFloat("_sizel", 2, &fMaxWidth) == B_OK
&& data->FindFloat("_sizel", 3, &fMaxHeight) == B_OK)
SetSizeLimits(fMinWidth, fMaxWidth,
fMinHeight, fMaxHeight);
if (data->FindInt64("_pulse", &fPulseRate) == B_OK)
SetPulseRate(fPulseRate);
BMessage msg;
int32 i = 0;
while (data->FindMessage("_views", i++, &msg) == B_OK) {
BArchivable* obj = instantiate_object(&msg);
if (BView* child = dynamic_cast<BView*>(obj))
AddChild(child);
}
}
BWindow::BWindow(BRect frame, int32 bitmapToken)
:
BLooper("offscreen bitmap")
{
_DecomposeType(B_UNTYPED_WINDOW, &fLook, &fFeel);
_InitData(frame, "offscreen", fLook, fFeel, 0, 0, bitmapToken);
}
BWindow::~BWindow()
{
if (BMenu* menu = dynamic_cast<BMenu*>(fFocus)) {
MenuPrivate(menu).QuitTracking();
}
UnlockFully();
if (fMenuSem > 0) {
while (acquire_sem(fMenuSem) == B_INTERRUPTED)
;
}
Lock();
fTopView->RemoveSelf();
delete fTopView;
int32 shortcutCount = fShortcuts.CountItems();
for (int32 i = 0; i < shortcutCount; i++)
delete (Shortcut*)fShortcuts.ItemAtFast(i);
free(fTitle);
SetPulseRate(0);
fLink->StartMessage(AS_DELETE_WINDOW);
int32 code;
fLink->FlushWithReply(code);
delete_port(fLink->ReceiverPort());
delete fLink;
}
BArchivable*
BWindow::Instantiate(BMessage* data)
{
if (!validate_instantiation(data, "BWindow"))
return NULL;
return new(std::nothrow) BWindow(data);
}
status_t
BWindow::Archive(BMessage* data, bool deep) const
{
status_t ret = BLooper::Archive(data, deep);
if (ret == B_OK)
ret = data->AddRect("_frame", fFrame);
if (ret == B_OK)
ret = data->AddString("_title", fTitle);
if (ret == B_OK)
ret = data->AddInt32("_wlook", fLook);
if (ret == B_OK)
ret = data->AddInt32("_wfeel", fFeel);
if (ret == B_OK && fFlags != 0)
ret = data->AddInt32("_flags", fFlags);
if (ret == B_OK)
ret = data->AddInt32("_wspace", (uint32)Workspaces());
if (ret == B_OK && !_ComposeType(fLook, fFeel))
ret = data->AddInt32("_type", (uint32)Type());
if (fMaxZoomWidth != 32768.0 || fMaxZoomHeight != 32768.0) {
if (ret == B_OK)
ret = data->AddFloat("_zoom", fMaxZoomWidth);
if (ret == B_OK)
ret = data->AddFloat("_zoom", fMaxZoomHeight);
}
if (fMinWidth != 0.0 || fMinHeight != 0.0
|| fMaxWidth != 32768.0 || fMaxHeight != 32768.0) {
if (ret == B_OK)
ret = data->AddFloat("_sizel", fMinWidth);
if (ret == B_OK)
ret = data->AddFloat("_sizel", fMinHeight);
if (ret == B_OK)
ret = data->AddFloat("_sizel", fMaxWidth);
if (ret == B_OK)
ret = data->AddFloat("_sizel", fMaxHeight);
}
if (ret == B_OK && fPulseRate != 500000)
data->AddInt64("_pulse", fPulseRate);
if (ret == B_OK && deep) {
int32 noOfViews = CountChildren();
for (int32 i = 0; i < noOfViews; i++){
BMessage childArchive;
ret = ChildAt(i)->Archive(&childArchive, true);
if (ret == B_OK)
ret = data->AddMessage("_views", &childArchive);
if (ret != B_OK)
break;
}
}
return ret;
}
void
BWindow::Quit()
{
if (!IsLocked()) {
const char* name = Name();
if (name == NULL)
name = "no-name";
printf("ERROR - you must Lock a looper before calling Quit(), "
"team=%" B_PRId32 ", looper=%s\n", Team(), name);
}
if (!Lock()){
return;
}
while (!IsHidden()) {
Hide();
}
if (fFlags & B_QUIT_ON_WINDOW_CLOSE)
be_app->PostMessage(B_QUIT_REQUESTED);
BLooper::Quit();
}
void
BWindow::AddChild(BView* child, BView* before)
{
BAutolock locker(this);
if (locker.IsLocked())
fTopView->AddChild(child, before);
}
void
BWindow::AddChild(BLayoutItem* child)
{
BAutolock locker(this);
if (locker.IsLocked())
fTopView->AddChild(child);
}
bool
BWindow::RemoveChild(BView* child)
{
BAutolock locker(this);
if (!locker.IsLocked())
return false;
return fTopView->RemoveChild(child);
}
int32
BWindow::CountChildren() const
{
BAutolock locker(const_cast<BWindow*>(this));
if (!locker.IsLocked())
return 0;
return fTopView->CountChildren();
}
BView*
BWindow::ChildAt(int32 index) const
{
BAutolock locker(const_cast<BWindow*>(this));
if (!locker.IsLocked())
return NULL;
return fTopView->ChildAt(index);
}
void
BWindow::Minimize(bool minimize)
{
if (IsModal() || IsFloating() || IsHidden() || fMinimized == minimize
|| !Lock())
return;
fMinimized = minimize;
fLink->StartMessage(AS_MINIMIZE_WINDOW);
fLink->Attach<bool>(minimize);
fLink->Flush();
Unlock();
}
status_t
BWindow::SendBehind(const BWindow* window)
{
if (!Lock())
return B_ERROR;
fLink->StartMessage(AS_SEND_BEHIND);
fLink->Attach<int32>(window != NULL ? _get_object_token_(window) : -1);
fLink->Attach<team_id>(Team());
status_t status = B_ERROR;
fLink->FlushWithReply(status);
Unlock();
return status;
}
void
BWindow::Flush() const
{
if (const_cast<BWindow*>(this)->Lock()) {
fLink->Flush();
const_cast<BWindow*>(this)->Unlock();
}
}
void
BWindow::Sync() const
{
if (!const_cast<BWindow*>(this)->Lock())
return;
fLink->StartMessage(AS_SYNC);
int32 code;
fLink->FlushWithReply(code);
const_cast<BWindow*>(this)->Unlock();
}
void
BWindow::DisableUpdates()
{
if (Lock()) {
fLink->StartMessage(AS_DISABLE_UPDATES);
fLink->Flush();
Unlock();
}
}
void
BWindow::EnableUpdates()
{
if (Lock()) {
fLink->StartMessage(AS_ENABLE_UPDATES);
fLink->Flush();
Unlock();
}
}
void
BWindow::BeginViewTransaction()
{
if (Lock()) {
fInTransaction = true;
Unlock();
}
}
void
BWindow::EndViewTransaction()
{
if (Lock()) {
if (fInTransaction)
fLink->Flush();
fInTransaction = false;
Unlock();
}
}
bool
BWindow::InViewTransaction() const
{
BAutolock locker(const_cast<BWindow*>(this));
return fInTransaction;
}
bool
BWindow::IsFront() const
{
BAutolock locker(const_cast<BWindow*>(this));
if (!locker.IsLocked())
return false;
fLink->StartMessage(AS_IS_FRONT_WINDOW);
status_t status;
if (fLink->FlushWithReply(status) == B_OK)
return status >= B_OK;
return false;
}
void
BWindow::MessageReceived(BMessage* message)
{
if (!message->HasSpecifiers()) {
if (message->what == B_KEY_DOWN)
_KeyboardNavigation();
if (message->what == kMsgAppServerStarted) {
fLink->SetSenderPort(
BApplication::Private::ServerLink()->SenderPort());
BPrivate::AppServerLink lockLink;
fLink->StartMessage(AS_CREATE_WINDOW);
fLink->Attach<BRect>(fFrame);
fLink->Attach<uint32>((uint32)fLook);
fLink->Attach<uint32>((uint32)fFeel);
fLink->Attach<uint32>(fFlags);
fLink->Attach<uint32>(0);
fLink->Attach<int32>(_get_object_token_(this));
fLink->Attach<port_id>(fLink->ReceiverPort());
fLink->Attach<port_id>(fMsgPort);
fLink->AttachString(fTitle);
port_id sendPort;
int32 code;
if (fLink->FlushWithReply(code) == B_OK
&& code == B_OK
&& fLink->Read<port_id>(&sendPort) == B_OK) {
fLink->Read<BRect>(&fFrame);
fLink->Read<float>(&fMinWidth);
fLink->Read<float>(&fMaxWidth);
fLink->Read<float>(&fMinHeight);
fLink->Read<float>(&fMaxHeight);
fMaxZoomWidth = fMaxWidth;
fMaxZoomHeight = fMaxHeight;
} else
sendPort = -1;
fLink->SetSenderPort(sendPort);
fTopView->_CreateSelf();
EnableUpdates();
_SendShowOrHideMessage();
}
return BLooper::MessageReceived(message);
}
BMessage replyMsg(B_REPLY);
bool handled = false;
BMessage specifier;
int32 what;
const char* prop;
int32 index;
if (message->GetCurrentSpecifier(&index, &specifier, &what, &prop) != B_OK)
return BLooper::MessageReceived(message);
BPropertyInfo propertyInfo(sWindowPropInfo);
switch (propertyInfo.FindMatch(message, index, &specifier, what, prop)) {
case 0:
if (message->what == B_GET_PROPERTY) {
replyMsg.AddBool("result", IsActive());
handled = true;
} else if (message->what == B_SET_PROPERTY) {
bool newActive;
if (message->FindBool("data", &newActive) == B_OK) {
Activate(newActive);
handled = true;
}
}
break;
case 1:
if (message->what == B_GET_PROPERTY) {
replyMsg.AddInt32("result", (uint32)Feel());
handled = true;
} else {
uint32 newFeel;
if (message->FindInt32("data", (int32*)&newFeel) == B_OK) {
SetFeel((window_feel)newFeel);
handled = true;
}
}
break;
case 2:
if (message->what == B_GET_PROPERTY) {
replyMsg.AddInt32("result", Flags());
handled = true;
} else {
uint32 newFlags;
if (message->FindInt32("data", (int32*)&newFlags) == B_OK) {
SetFlags(newFlags);
handled = true;
}
}
break;
case 3:
if (message->what == B_GET_PROPERTY) {
replyMsg.AddRect("result", Frame());
handled = true;
} else {
BRect newFrame;
if (message->FindRect("data", &newFrame) == B_OK) {
MoveTo(newFrame.LeftTop());
ResizeTo(newFrame.Width(), newFrame.Height());
handled = true;
}
}
break;
case 4:
if (message->what == B_GET_PROPERTY) {
replyMsg.AddBool("result", IsHidden());
handled = true;
} else {
bool hide;
if (message->FindBool("data", &hide) == B_OK) {
if (hide) {
if (!IsHidden())
Hide();
} else if (IsHidden())
Show();
handled = true;
}
}
break;
case 5:
if (message->what == B_GET_PROPERTY) {
replyMsg.AddInt32("result", (uint32)Look());
handled = true;
} else {
uint32 newLook;
if (message->FindInt32("data", (int32*)&newLook) == B_OK) {
SetLook((window_look)newLook);
handled = true;
}
}
break;
case 6:
if (message->what == B_GET_PROPERTY) {
replyMsg.AddString("result", Title());
handled = true;
} else {
const char* newTitle = NULL;
if (message->FindString("data", &newTitle) == B_OK) {
SetTitle(newTitle);
handled = true;
}
}
break;
case 7:
if (message->what == B_GET_PROPERTY) {
replyMsg.AddInt32( "result", Workspaces());
handled = true;
} else {
uint32 newWorkspaces;
if (message->FindInt32("data", (int32*)&newWorkspaces) == B_OK) {
SetWorkspaces(newWorkspaces);
handled = true;
}
}
break;
case 11:
if (message->what == B_GET_PROPERTY) {
replyMsg.AddBool("result", IsMinimized());
handled = true;
} else {
bool minimize;
if (message->FindBool("data", &minimize) == B_OK) {
Minimize(minimize);
handled = true;
}
}
break;
case 12:
if (message->what == B_GET_PROPERTY) {
BMessage settings;
if (GetDecoratorSettings(&settings) == B_OK) {
BRect frame;
if (settings.FindRect("tab frame", &frame) == B_OK) {
replyMsg.AddRect("result", frame);
handled = true;
}
}
}
break;
default:
return BLooper::MessageReceived(message);
}
if (handled) {
if (message->what == B_SET_PROPERTY)
replyMsg.AddInt32("error", B_OK);
} else {
replyMsg.what = B_MESSAGE_NOT_UNDERSTOOD;
replyMsg.AddInt32("error", B_BAD_SCRIPT_SYNTAX);
replyMsg.AddString("message", "Didn't understand the specifier(s)");
}
message->SendReply(&replyMsg);
}
void
BWindow::DispatchMessage(BMessage* message, BHandler* target)
{
if (message == NULL)
return;
switch (message->what) {
case B_ZOOM:
Zoom();
break;
case _MINIMIZE_:
if ((Flags() & B_NOT_MINIMIZABLE) == 0)
Minimize(true);
break;
case _ZOOM_:
if ((Flags() & B_NOT_ZOOMABLE) == 0)
Zoom();
break;
case _SEND_BEHIND_:
SendBehind(NULL);
break;
case _SEND_TO_FRONT_:
Activate();
break;
case B_MINIMIZE:
{
bool minimize;
if (message->FindBool("minimize", &minimize) == B_OK)
Minimize(minimize);
break;
}
case B_HIDE_APPLICATION:
{
app_info info;
be_app->GetAppInfo(&info);
BList list;
be_roster->GetAppList(info.signature, &list);
for (int32 i = 0; i < list.CountItems(); i++) {
do_minimize_team(BRect(), (team_id)(addr_t)list.ItemAt(i),
false);
}
break;
}
case B_WINDOW_RESIZED:
{
int32 width, height;
if (message->FindInt32("width", &width) == B_OK
&& message->FindInt32("height", &height) == B_OK) {
BMessage* pendingMessage;
while ((pendingMessage
= MessageQueue()->FindMessage(B_WINDOW_RESIZED, 0))) {
int32 nextWidth;
if (pendingMessage->FindInt32("width", &nextWidth) == B_OK)
width = nextWidth;
int32 nextHeight;
if (pendingMessage->FindInt32("height", &nextHeight)
== B_OK) {
height = nextHeight;
}
MessageQueue()->RemoveMessage(pendingMessage);
delete pendingMessage;
}
if (width != fFrame.Width() || height != fFrame.Height()) {
fFrame.right = fFrame.left + width;
fFrame.bottom = fFrame.top + height;
_AdoptResize();
}
FrameResized(width, height);
}
break;
}
case B_WINDOW_MOVED:
{
BPoint origin;
if (message->FindPoint("where", &origin) == B_OK) {
if (fFrame.LeftTop() != origin) {
fFrame.OffsetTo(origin);
}
FrameMoved(origin);
}
break;
}
case B_WINDOW_ACTIVATED:
if (target != this) {
target->MessageReceived(message);
break;
}
bool active;
if (message->FindBool("active", &active) != B_OK)
break;
while (true) {
BMessage* pendingMessage = MessageQueue()->FindMessage(
B_WINDOW_ACTIVATED, 0);
if (pendingMessage == NULL)
break;
bool nextActive;
if (pendingMessage->FindBool("active", &nextActive) == B_OK)
active = nextActive;
MessageQueue()->RemoveMessage(pendingMessage);
delete pendingMessage;
}
if (active != fActive) {
fActive = active;
WindowActivated(active);
fTopView->_Activate(active);
if (!active)
break;
bool inputMethodAware = false;
if (fFocus)
inputMethodAware = fFocus->Flags() & B_INPUT_METHOD_AWARE;
BMessage message(inputMethodAware ? IS_FOCUS_IM_AWARE_VIEW : IS_UNFOCUS_IM_AWARE_VIEW);
BMessenger messenger(fFocus);
BMessage reply;
if (fFocus)
message.AddMessenger("view", messenger);
_control_input_server_(&message, &reply);
}
break;
case B_SCREEN_CHANGED:
if (target == this) {
BRect frame;
uint32 mode;
if (message->FindRect("frame", &frame) == B_OK
&& message->FindInt32("mode", (int32*)&mode) == B_OK) {
_PropagateMessageToChildViews(message);
ScreenChanged(frame, (color_space)mode);
}
} else
target->MessageReceived(message);
break;
case B_WORKSPACE_ACTIVATED:
if (target == this) {
uint32 workspace;
bool active;
if (message->FindInt32("workspace", (int32*)&workspace) == B_OK
&& message->FindBool("active", &active) == B_OK) {
_PropagateMessageToChildViews(message);
WorkspaceActivated(workspace, active);
}
} else
target->MessageReceived(message);
break;
case B_WORKSPACES_CHANGED:
if (target == this) {
uint32 oldWorkspace;
uint32 newWorkspace;
if (message->FindInt32("old", (int32*)&oldWorkspace) == B_OK
&& message->FindInt32("new", (int32*)&newWorkspace) == B_OK) {
_PropagateMessageToChildViews(message);
WorkspacesChanged(oldWorkspace, newWorkspace);
}
} else
target->MessageReceived(message);
break;
case B_KEY_DOWN:
if (!_HandleKeyDown(message))
target->MessageReceived(message);
break;
case B_UNMAPPED_KEY_DOWN:
if (!_HandleUnmappedKeyDown(message))
target->MessageReceived(message);
break;
case B_PULSE:
if (target == this && fPulseRunner) {
fTopView->_Pulse();
fLink->Flush();
} else
target->MessageReceived(message);
break;
case _UPDATE_:
{
STRACE(("info:BWindow handling _UPDATE_.\n"));
fLink->StartMessage(AS_BEGIN_UPDATE);
fInTransaction = true;
int32 code;
if (fLink->FlushWithReply(code) == B_OK
&& code == B_OK) {
BPoint origin;
fLink->Read<BPoint>(&origin);
float width;
float height;
fLink->Read<float>(&width);
fLink->Read<float>(&height);
struct ViewUpdateInfo {
int32 token;
BRect updateRect;
};
BList infos(20);
while (true) {
int32 token;
status_t error = fLink->Read<int32>(&token);
if (error < B_OK || token == B_NULL_TOKEN)
break;
ViewUpdateInfo* info = new(std::nothrow) ViewUpdateInfo;
if (info == NULL || !infos.AddItem(info)) {
delete info;
break;
}
info->token = token;
error = fLink->Read<BRect>(&(info->updateRect));
if (error < B_OK)
break;
}
if (origin != fFrame.LeftTop()) {
fFrame.OffsetTo(origin);
FrameMoved(origin);
}
if (width != fFrame.Width() || height != fFrame.Height()) {
fFrame.right = fFrame.left + width;
fFrame.bottom = fFrame.top + height;
_AdoptResize();
FrameResized(width, height);
}
int32 count = infos.CountItems();
for (int32 i = 0; i < count; i++) {
ViewUpdateInfo* info
= (ViewUpdateInfo*)infos.ItemAtFast(i);
if (BView* view = _FindView(info->token))
view->_Draw(info->updateRect);
else {
printf("_UPDATE_ - didn't find view by token: %"
B_PRId32 "\n", info->token);
}
}
for (int32 i = count - 1; i >= 0; i--) {
ViewUpdateInfo* info
= (ViewUpdateInfo*)infos.ItemAtFast(i);
if (BView* view = _FindView(info->token))
view->_DrawAfterChildren(info->updateRect);
delete info;
}
}
fLink->StartMessage(AS_END_UPDATE);
fLink->Flush();
fInTransaction = false;
fUpdateRequested = false;
break;
}
case _MENUS_DONE_:
MenusEnded();
break;
case B_WINDOW_MOVE_BY:
{
BPoint offset;
if (message->FindPoint("data", &offset) == B_OK)
MoveBy(offset.x, offset.y);
else
message->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
break;
}
case B_WINDOW_MOVE_TO:
{
BPoint origin;
if (message->FindPoint("data", &origin) == B_OK)
MoveTo(origin);
else
message->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
break;
}
case B_LAYOUT_WINDOW:
{
Layout(false);
break;
}
case B_COLORS_UPDATED:
{
fTopView->_ColorsUpdated(message);
target->MessageReceived(message);
break;
}
case B_FONTS_UPDATED:
{
fTopView->_FontsUpdated(message);
target->MessageReceived(message);
break;
}
default:
BLooper::DispatchMessage(message, target);
break;
}
}
void
BWindow::FrameMoved(BPoint newPosition)
{
}
void
BWindow::FrameResized(float newWidth, float newHeight)
{
}
void
BWindow::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces)
{
}
void
BWindow::WorkspaceActivated(int32 workspace, bool state)
{
}
void
BWindow::MenusBeginning()
{
}
void
BWindow::MenusEnded()
{
}
void
BWindow::SetSizeLimits(float minWidth, float maxWidth,
float minHeight, float maxHeight)
{
if (minWidth > maxWidth || minHeight > maxHeight)
return;
if (!Lock())
return;
fLink->StartMessage(AS_SET_SIZE_LIMITS);
fLink->Attach<float>(minWidth);
fLink->Attach<float>(maxWidth);
fLink->Attach<float>(minHeight);
fLink->Attach<float>(maxHeight);
int32 code;
if (fLink->FlushWithReply(code) == B_OK
&& code == B_OK) {
fLink->Read<BRect>(&fFrame);
fLink->Read<float>(&fMinWidth);
fLink->Read<float>(&fMaxWidth);
fLink->Read<float>(&fMinHeight);
fLink->Read<float>(&fMaxHeight);
_AdoptResize();
}
Unlock();
}
void
BWindow::GetSizeLimits(float* _minWidth, float* _maxWidth, float* _minHeight,
float* _maxHeight)
{
if (_minHeight != NULL)
*_minHeight = fMinHeight;
if (_minWidth != NULL)
*_minWidth = fMinWidth;
if (_maxHeight != NULL)
*_maxHeight = fMaxHeight;
if (_maxWidth != NULL)
*_maxWidth = fMaxWidth;
}
void
BWindow::UpdateSizeLimits()
{
BAutolock locker(this);
if ((fFlags & B_AUTO_UPDATE_SIZE_LIMITS) != 0) {
BSize minSize = fTopView->MinSize();
BSize maxSize = fTopView->MaxSize();
SetSizeLimits(minSize.width, maxSize.width,
minSize.height, maxSize.height);
}
}
status_t
BWindow::SetDecoratorSettings(const BMessage& settings)
{
int32 size = settings.FlattenedSize();
char buffer[size];
status_t status = settings.Flatten(buffer, size);
if (status != B_OK)
return status;
if (!Lock())
return B_ERROR;
status = fLink->StartMessage(AS_SET_DECORATOR_SETTINGS);
if (status == B_OK)
status = fLink->Attach<int32>(size);
if (status == B_OK)
status = fLink->Attach(buffer, size);
if (status == B_OK)
status = fLink->Flush();
Unlock();
return status;
}
status_t
BWindow::GetDecoratorSettings(BMessage* settings) const
{
if (!const_cast<BWindow*>(this)->Lock())
return B_ERROR;
status_t status = fLink->StartMessage(AS_GET_DECORATOR_SETTINGS);
if (status == B_OK) {
int32 code;
status = fLink->FlushWithReply(code);
if (status == B_OK && code != B_OK)
status = code;
}
if (status == B_OK) {
int32 size;
status = fLink->Read<int32>(&size);
if (status == B_OK) {
char buffer[size];
status = fLink->Read(buffer, size);
if (status == B_OK) {
status = settings->Unflatten(buffer);
}
}
}
const_cast<BWindow*>(this)->Unlock();
return status;
}
void
BWindow::SetZoomLimits(float maxWidth, float maxHeight)
{
if (maxWidth > fMaxWidth)
maxWidth = fMaxWidth;
fMaxZoomWidth = maxWidth;
if (maxHeight > fMaxHeight)
maxHeight = fMaxHeight;
fMaxZoomHeight = maxHeight;
}
void
BWindow::Zoom(BPoint origin, float width, float height)
{
MoveTo(origin);
ResizeTo(width, height);
}
void
BWindow::Zoom()
{
float maxZoomWidth = std::min(fMaxZoomWidth, fMaxWidth);
float maxZoomHeight = std::min(fMaxZoomHeight, fMaxHeight);
BRect screenFrame = (BScreen(this)).Frame();
maxZoomWidth = std::min(maxZoomWidth, screenFrame.Width());
maxZoomHeight = std::min(maxZoomHeight, screenFrame.Height());
BRect zoomArea = screenFrame;
BDeskbar deskbar;
BRect deskbarFrame = deskbar.Frame();
bool isShiftDown = (modifiers() & B_SHIFT_KEY) != 0;
if (!isShiftDown && !deskbar.IsAutoHide()) {
switch (deskbar.Location()) {
case B_DESKBAR_TOP:
zoomArea.top = deskbarFrame.bottom + 2;
break;
case B_DESKBAR_BOTTOM:
case B_DESKBAR_LEFT_BOTTOM:
case B_DESKBAR_RIGHT_BOTTOM:
zoomArea.bottom = deskbarFrame.top - 2;
break;
case B_DESKBAR_LEFT_TOP:
if (!deskbar.IsExpanded())
zoomArea.top = deskbarFrame.bottom + 2;
else if (!deskbar.IsAlwaysOnTop() && !deskbar.IsAutoRaise())
zoomArea.left = deskbarFrame.right + 2;
break;
default:
case B_DESKBAR_RIGHT_TOP:
if (!deskbar.IsExpanded())
break;
else if (!deskbar.IsAlwaysOnTop() && !deskbar.IsAutoRaise())
zoomArea.right = deskbarFrame.left - 2;
break;
}
}
float borderWidth;
float tabHeight;
_GetDecoratorSize(&borderWidth, &tabHeight);
zoomArea.left += borderWidth;
zoomArea.top += borderWidth + tabHeight;
zoomArea.right -= borderWidth;
zoomArea.bottom -= borderWidth;
if (zoomArea.Height() > maxZoomHeight)
zoomArea.InsetBy(0, roundf((zoomArea.Height() - maxZoomHeight) / 2));
if (zoomArea.top > deskbarFrame.bottom
|| zoomArea.bottom < deskbarFrame.top) {
zoomArea.left = screenFrame.left + borderWidth;
zoomArea.right = screenFrame.right - borderWidth;
}
if (zoomArea.Width() > maxZoomWidth)
zoomArea.InsetBy(roundf((zoomArea.Width() - maxZoomWidth) / 2), 0);
if (fPreviousFrame.IsValid()
&& fFrame.Width() == zoomArea.Width()
&& fFrame.Height() == zoomArea.Height()) {
Zoom(fPreviousFrame.LeftTop(), fPreviousFrame.Width(),
fPreviousFrame.Height());
return;
}
fPreviousFrame = fFrame;
Zoom(zoomArea.LeftTop(), zoomArea.Width(), zoomArea.Height());
}
void
BWindow::ScreenChanged(BRect screenSize, color_space depth)
{
}
void
BWindow::SetPulseRate(bigtime_t rate)
{
if (rate < 0
|| (rate == fPulseRate && !((rate == 0) ^ (fPulseRunner == NULL))))
return;
fPulseRate = rate;
if (rate > 0) {
if (fPulseRunner == NULL) {
BMessage message(B_PULSE);
fPulseRunner = new(std::nothrow) BMessageRunner(BMessenger(this),
&message, rate);
} else {
fPulseRunner->SetInterval(rate);
}
} else {
delete fPulseRunner;
fPulseRunner = NULL;
}
}
bigtime_t
BWindow::PulseRate() const
{
return fPulseRate;
}
void
BWindow::_AddShortcut(uint32* _key, uint32* _modifiers, BMenuItem* item)
{
Shortcut* shortcut = new(std::nothrow) Shortcut(*_key, *_modifiers, item);
if (shortcut == NULL)
return;
RemoveShortcut(shortcut->Key(), shortcut->Modifiers());
*_key = shortcut->Key();
*_modifiers = shortcut->Modifiers();
fShortcuts.AddItem(shortcut);
}
void
BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage* message)
{
AddShortcut(key, modifiers, message, this);
}
void
BWindow::AddShortcut(uint32 key, uint32 modifiers, BMessage* message, BHandler* target)
{
if (message == NULL)
return;
Shortcut* shortcut = new(std::nothrow) Shortcut(key, modifiers, message, target);
if (shortcut == NULL)
return;
RemoveShortcut(shortcut->Key(), shortcut->Modifiers());
fShortcuts.AddItem(shortcut);
}
bool
BWindow::HasShortcut(uint32 key, uint32 modifiers)
{
return _FindShortcut(key, modifiers) != NULL;
}
void
BWindow::RemoveShortcut(uint32 key, uint32 modifiers)
{
Shortcut* shortcut = _FindShortcut(key, modifiers);
if (shortcut != NULL && fShortcuts.RemoveItem(shortcut))
delete shortcut;
else if (key == 'Q' && modifiers == B_COMMAND_KEY)
fNoQuitShortcut = true;
}
BButton*
BWindow::DefaultButton() const
{
return fDefaultButton;
}
void
BWindow::SetDefaultButton(BButton* button)
{
if (fDefaultButton == button)
return;
if (fDefaultButton != NULL) {
BButton* oldDefault = fDefaultButton;
oldDefault->MakeDefault(false);
oldDefault->Invalidate();
}
fDefaultButton = button;
if (button != NULL) {
fDefaultButton->MakeDefault(true);
fDefaultButton->Invalidate();
}
}
bool
BWindow::NeedsUpdate() const
{
if (!const_cast<BWindow*>(this)->Lock())
return false;
fLink->StartMessage(AS_NEEDS_UPDATE);
int32 code = B_ERROR;
fLink->FlushWithReply(code);
const_cast<BWindow*>(this)->Unlock();
return code == B_OK;
}
void
BWindow::UpdateIfNeeded()
{
if (find_thread(NULL) != Thread())
return;
if (((const BMessageQueue*)MessageQueue())->IsLocked())
return;
if (!Lock())
return;
Sync();
_DequeueAll();
BMessageQueue* queue = MessageQueue();
while (true) {
queue->Lock();
BMessage* message = queue->FindMessage(_UPDATE_, 0);
queue->RemoveMessage(message);
queue->Unlock();
if (message == NULL)
break;
BWindow::DispatchMessage(message, this);
delete message;
}
Unlock();
}
BView*
BWindow::FindView(const char* viewName) const
{
BAutolock locker(const_cast<BWindow*>(this));
if (!locker.IsLocked())
return NULL;
return fTopView->FindView(viewName);
}
BView*
BWindow::FindView(BPoint point) const
{
BAutolock locker(const_cast<BWindow*>(this));
if (!locker.IsLocked())
return NULL;
return _FindView(fTopView, point);
}
BView*
BWindow::CurrentFocus() const
{
return fFocus;
}
void
BWindow::Activate(bool active)
{
if (!Lock())
return;
if (!IsHidden()) {
fMinimized = false;
fLink->StartMessage(AS_ACTIVATE_WINDOW);
fLink->Attach<bool>(active);
fLink->Flush();
}
Unlock();
}
void
BWindow::WindowActivated(bool focus)
{
}
void
BWindow::ConvertToScreen(BPoint* point) const
{
point->x += fFrame.left;
point->y += fFrame.top;
}
BPoint
BWindow::ConvertToScreen(BPoint point) const
{
return point + fFrame.LeftTop();
}
void
BWindow::ConvertFromScreen(BPoint* point) const
{
point->x -= fFrame.left;
point->y -= fFrame.top;
}
BPoint
BWindow::ConvertFromScreen(BPoint point) const
{
return point - fFrame.LeftTop();
}
void
BWindow::ConvertToScreen(BRect* rect) const
{
rect->OffsetBy(fFrame.LeftTop());
}
BRect
BWindow::ConvertToScreen(BRect rect) const
{
return rect.OffsetByCopy(fFrame.LeftTop());
}
void
BWindow::ConvertFromScreen(BRect* rect) const
{
rect->OffsetBy(-fFrame.left, -fFrame.top);
}
BRect
BWindow::ConvertFromScreen(BRect rect) const
{
return rect.OffsetByCopy(-fFrame.left, -fFrame.top);
}
bool
BWindow::IsMinimized() const
{
BAutolock locker(const_cast<BWindow*>(this));
if (!locker.IsLocked())
return false;
return fMinimized;
}
BRect
BWindow::Bounds() const
{
return BRect(0, 0, fFrame.Width(), fFrame.Height());
}
BRect
BWindow::Frame() const
{
return fFrame;
}
BRect
BWindow::DecoratorFrame() const
{
BRect decoratorFrame(Frame());
BRect tabRect(0, 0, 0, 0);
float borderWidth = 5.0;
BMessage settings;
if (GetDecoratorSettings(&settings) == B_OK) {
settings.FindRect("tab frame", &tabRect);
settings.FindFloat("border width", &borderWidth);
} else {
if (fLook == B_NO_BORDER_WINDOW_LOOK)
borderWidth = 0.f;
else if (fLook == B_BORDERED_WINDOW_LOOK)
borderWidth = 1.f;
}
if (fLook == kLeftTitledWindowLook) {
decoratorFrame.top -= borderWidth;
decoratorFrame.left -= borderWidth + tabRect.Width();
decoratorFrame.right += borderWidth;
decoratorFrame.bottom += borderWidth;
} else {
decoratorFrame.top -= borderWidth + tabRect.Height();
decoratorFrame.left -= borderWidth;
decoratorFrame.right += borderWidth;
decoratorFrame.bottom += borderWidth;
}
return decoratorFrame;
}
BSize
BWindow::Size() const
{
return BSize(fFrame.Width(), fFrame.Height());
}
const char*
BWindow::Title() const
{
return fTitle;
}
void
BWindow::SetTitle(const char* title)
{
if (title == NULL)
title = "";
free(fTitle);
fTitle = strdup(title);
_SetName(title);
if (Lock()) {
fLink->StartMessage(AS_SET_WINDOW_TITLE);
fLink->AttachString(fTitle);
fLink->Flush();
Unlock();
}
}
bool
BWindow::IsActive() const
{
return fActive;
}
void
BWindow::SetKeyMenuBar(BMenuBar* bar)
{
fKeyMenuBar = bar;
}
BMenuBar*
BWindow::KeyMenuBar() const
{
return fKeyMenuBar;
}
bool
BWindow::IsModal() const
{
return fFeel == B_MODAL_SUBSET_WINDOW_FEEL
|| fFeel == B_MODAL_APP_WINDOW_FEEL
|| fFeel == B_MODAL_ALL_WINDOW_FEEL
|| fFeel == kMenuWindowFeel;
}
bool
BWindow::IsFloating() const
{
return fFeel == B_FLOATING_SUBSET_WINDOW_FEEL
|| fFeel == B_FLOATING_APP_WINDOW_FEEL
|| fFeel == B_FLOATING_ALL_WINDOW_FEEL;
}
status_t
BWindow::AddToSubset(BWindow* window)
{
if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL
|| (fFeel != B_MODAL_SUBSET_WINDOW_FEEL
&& fFeel != B_FLOATING_SUBSET_WINDOW_FEEL))
return B_BAD_VALUE;
if (!Lock())
return B_ERROR;
status_t status = B_ERROR;
fLink->StartMessage(AS_ADD_TO_SUBSET);
fLink->Attach<int32>(_get_object_token_(window));
fLink->FlushWithReply(status);
Unlock();
return status;
}
status_t
BWindow::RemoveFromSubset(BWindow* window)
{
if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL
|| (fFeel != B_MODAL_SUBSET_WINDOW_FEEL
&& fFeel != B_FLOATING_SUBSET_WINDOW_FEEL))
return B_BAD_VALUE;
if (!Lock())
return B_ERROR;
status_t status = B_ERROR;
fLink->StartMessage(AS_REMOVE_FROM_SUBSET);
fLink->Attach<int32>(_get_object_token_(window));
fLink->FlushWithReply(status);
Unlock();
return status;
}
status_t
BWindow::Perform(perform_code code, void* _data)
{
switch (code) {
case PERFORM_CODE_SET_LAYOUT:
{
perform_data_set_layout* data = (perform_data_set_layout*)_data;
BWindow::SetLayout(data->layout);
return B_OK;
}
}
return BLooper::Perform(code, _data);
}
status_t
BWindow::SetType(window_type type)
{
window_look look;
window_feel feel;
_DecomposeType(type, &look, &feel);
status_t status = SetLook(look);
if (status == B_OK)
status = SetFeel(feel);
return status;
}
window_type
BWindow::Type() const
{
return _ComposeType(fLook, fFeel);
}
status_t
BWindow::SetLook(window_look look)
{
BAutolock locker(this);
if (!locker.IsLocked())
return B_BAD_VALUE;
fLink->StartMessage(AS_SET_LOOK);
fLink->Attach<int32>((int32)look);
status_t status = B_ERROR;
if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
fLook = look;
return status;
}
window_look
BWindow::Look() const
{
return fLook;
}
status_t
BWindow::SetFeel(window_feel feel)
{
BAutolock locker(this);
if (!locker.IsLocked())
return B_BAD_VALUE;
fLink->StartMessage(AS_SET_FEEL);
fLink->Attach<int32>((int32)feel);
status_t status = B_ERROR;
if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
fFeel = feel;
return status;
}
window_feel
BWindow::Feel() const
{
return fFeel;
}
status_t
BWindow::SetFlags(uint32 flags)
{
BAutolock locker(this);
if (!locker.IsLocked())
return B_BAD_VALUE;
fLink->StartMessage(AS_SET_FLAGS);
fLink->Attach<uint32>(flags);
int32 status = B_ERROR;
if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
fFlags = flags;
return status;
}
uint32
BWindow::Flags() const
{
return fFlags;
}
status_t
BWindow::SetWindowAlignment(window_alignment mode,
int32 h, int32 hOffset, int32 width, int32 widthOffset,
int32 v, int32 vOffset, int32 height, int32 heightOffset)
{
if ((mode & (B_BYTE_ALIGNMENT | B_PIXEL_ALIGNMENT)) == 0
|| (hOffset >= 0 && hOffset <= h)
|| (vOffset >= 0 && vOffset <= v)
|| (widthOffset >= 0 && widthOffset <= width)
|| (heightOffset >= 0 && heightOffset <= height))
return B_BAD_VALUE;
if (!Lock())
return B_ERROR;
fLink->StartMessage(AS_SET_ALIGNMENT);
fLink->Attach<int32>((int32)mode);
fLink->Attach<int32>(h);
fLink->Attach<int32>(hOffset);
fLink->Attach<int32>(width);
fLink->Attach<int32>(widthOffset);
fLink->Attach<int32>(v);
fLink->Attach<int32>(vOffset);
fLink->Attach<int32>(height);
fLink->Attach<int32>(heightOffset);
status_t status = B_ERROR;
fLink->FlushWithReply(status);
Unlock();
return status;
}
status_t
BWindow::GetWindowAlignment(window_alignment* mode,
int32* h, int32* hOffset, int32* width, int32* widthOffset,
int32* v, int32* vOffset, int32* height, int32* heightOffset) const
{
if (!const_cast<BWindow*>(this)->Lock())
return B_ERROR;
fLink->StartMessage(AS_GET_ALIGNMENT);
status_t status;
if (fLink->FlushWithReply(status) == B_OK && status == B_OK) {
fLink->Read<int32>((int32*)mode);
fLink->Read<int32>(h);
fLink->Read<int32>(hOffset);
fLink->Read<int32>(width);
fLink->Read<int32>(widthOffset);
fLink->Read<int32>(v);
fLink->Read<int32>(hOffset);
fLink->Read<int32>(height);
fLink->Read<int32>(heightOffset);
}
const_cast<BWindow*>(this)->Unlock();
return status;
}
uint32
BWindow::Workspaces() const
{
if (!const_cast<BWindow*>(this)->Lock())
return 0;
uint32 workspaces = 0;
fLink->StartMessage(AS_GET_WORKSPACES);
status_t status;
if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
fLink->Read<uint32>(&workspaces);
const_cast<BWindow*>(this)->Unlock();
return workspaces;
}
void
BWindow::SetWorkspaces(uint32 workspaces)
{
if (fFeel != B_NORMAL_WINDOW_FEEL)
return;
if (Lock()) {
fLink->StartMessage(AS_SET_WORKSPACES);
fLink->Attach<uint32>(workspaces);
fLink->Flush();
Unlock();
}
}
BView*
BWindow::LastMouseMovedView() const
{
return fLastMouseMovedView;
}
void
BWindow::MoveBy(float dx, float dy)
{
if ((dx != 0.0f || dy != 0.0f) && Lock()) {
MoveTo(fFrame.left + dx, fFrame.top + dy);
Unlock();
}
}
void
BWindow::MoveTo(BPoint point)
{
MoveTo(point.x, point.y);
}
void
BWindow::MoveTo(float x, float y)
{
if (!Lock())
return;
x = roundf(x);
y = roundf(y);
if (fFrame.left != x || fFrame.top != y) {
fLink->StartMessage(AS_WINDOW_MOVE);
fLink->Attach<float>(x);
fLink->Attach<float>(y);
status_t status;
if (fLink->FlushWithReply(status) == B_OK && status == B_OK)
fFrame.OffsetTo(x, y);
}
Unlock();
}
void
BWindow::ResizeBy(float dx, float dy)
{
if (Lock()) {
ResizeTo(fFrame.Width() + dx, fFrame.Height() + dy);
Unlock();
}
}
void
BWindow::ResizeTo(float width, float height)
{
if (!Lock())
return;
width = roundf(width);
height = roundf(height);
if (width < fMinWidth)
width = fMinWidth;
else if (width > fMaxWidth)
width = fMaxWidth;
if (height < fMinHeight)
height = fMinHeight;
else if (height > fMaxHeight)
height = fMaxHeight;
if (width != fFrame.Width() || height != fFrame.Height()) {
fLink->StartMessage(AS_WINDOW_RESIZE);
fLink->Attach<float>(width);
fLink->Attach<float>(height);
status_t status;
if (fLink->FlushWithReply(status) == B_OK && status == B_OK) {
fFrame.right = fFrame.left + width;
fFrame.bottom = fFrame.top + height;
_AdoptResize();
}
}
Unlock();
}
void
BWindow::ResizeToPreferred()
{
BAutolock locker(this);
Layout(false);
float width = fTopView->PreferredSize().width;
width = std::min(width, fTopView->MaxSize().width);
width = std::max(width, fTopView->MinSize().width);
float height = fTopView->PreferredSize().height;
height = std::min(height, fTopView->MaxSize().height);
height = std::max(height, fTopView->MinSize().height);
if (GetLayout()->HasHeightForWidth())
GetLayout()->GetHeightForWidth(width, NULL, NULL, &height);
ResizeTo(width, height);
}
void
BWindow::CenterIn(const BRect& rect)
{
BAutolock locker(this);
UpdateSizeLimits();
MoveTo(BLayoutUtils::AlignInFrame(rect, Size(),
BAlignment(B_ALIGN_HORIZONTAL_CENTER,
B_ALIGN_VERTICAL_CENTER)).LeftTop());
MoveOnScreen(B_DO_NOT_RESIZE_TO_FIT | B_MOVE_IF_PARTIALLY_OFFSCREEN);
}
void
BWindow::CenterOnScreen()
{
CenterIn(BScreen(this).Frame());
}
void
BWindow::CenterOnScreen(screen_id id)
{
CenterIn(BScreen(id).Frame());
}
void
BWindow::MoveOnScreen(uint32 flags)
{
UpdateSizeLimits();
BRect screenFrame = BScreen(this).Frame();
BRect frame = Frame();
float borderWidth;
float tabHeight;
_GetDecoratorSize(&borderWidth, &tabHeight);
frame.InsetBy(-borderWidth, -borderWidth);
frame.top -= tabHeight;
if ((flags & B_DO_NOT_RESIZE_TO_FIT) == 0) {
if (frame.Width() > screenFrame.Width())
frame.right -= frame.Width() - screenFrame.Width();
if (frame.Height() > screenFrame.Height())
frame.bottom -= frame.Height() - screenFrame.Height();
BRect innerFrame = frame;
innerFrame.top += tabHeight;
innerFrame.InsetBy(borderWidth, borderWidth);
ResizeTo(innerFrame.Width(), innerFrame.Height());
}
if (((flags & B_MOVE_IF_PARTIALLY_OFFSCREEN) == 0
&& !screenFrame.Contains(frame))
|| !frame.Intersects(screenFrame)) {
CenterOnScreen();
return;
}
float left = frame.left;
if (left < screenFrame.left)
left = screenFrame.left;
else if (frame.right > screenFrame.right)
left = std::max(0.f, screenFrame.right - frame.Width());
float top = frame.top;
if (top < screenFrame.top)
top = screenFrame.top;
else if (frame.bottom > screenFrame.bottom)
top = std::max(0.f, screenFrame.bottom - frame.Height());
if (top != frame.top || left != frame.left)
MoveTo(left + borderWidth, top + tabHeight + borderWidth);
}
void
BWindow::Show()
{
bool runCalled = true;
if (Lock()) {
fShowLevel--;
_SendShowOrHideMessage();
runCalled = fRunCalled;
Unlock();
}
if (!runCalled) {
if (fLink->SenderPort() < B_OK) {
fThread = B_ERROR;
return;
} else
Run();
}
}
void
BWindow::Hide()
{
if (Lock()) {
if (IsMinimized() && fShowLevel == 0)
Minimize(false);
fShowLevel++;
_SendShowOrHideMessage();
Unlock();
}
}
bool
BWindow::IsHidden() const
{
return fShowLevel > 0;
}
bool
BWindow::QuitRequested()
{
return BLooper::QuitRequested();
}
thread_id
BWindow::Run()
{
EnableUpdates();
return BLooper::Run();
}
void
BWindow::SetLayout(BLayout* layout)
{
if (layout != NULL)
fTopView->AdoptViewColors(layout->View());
fTopView->SetLayout(layout);
}
BLayout*
BWindow::GetLayout() const
{
return fTopView->GetLayout();
}
void
BWindow::InvalidateLayout(bool descendants)
{
fTopView->InvalidateLayout(descendants);
}
void
BWindow::Layout(bool force)
{
UpdateSizeLimits();
fTopView->Layout(force);
}
bool
BWindow::IsOffscreenWindow() const
{
return fOffscreen;
}
status_t
BWindow::GetSupportedSuites(BMessage* data)
{
if (data == NULL)
return B_BAD_VALUE;
status_t status = data->AddString("suites", "suite/vnd.Be-window");
if (status == B_OK) {
BPropertyInfo propertyInfo(sWindowPropInfo, sWindowValueInfo);
status = data->AddFlat("messages", &propertyInfo);
if (status == B_OK)
status = BLooper::GetSupportedSuites(data);
}
return status;
}
BHandler*
BWindow::ResolveSpecifier(BMessage* message, int32 index, BMessage* specifier,
int32 what, const char* property)
{
if (message->what == B_WINDOW_MOVE_BY
|| message->what == B_WINDOW_MOVE_TO)
return this;
BPropertyInfo propertyInfo(sWindowPropInfo);
if (propertyInfo.FindMatch(message, index, specifier, what, property) >= 0) {
if (strcmp(property, "View") == 0) {
return fTopView;
} else if (strcmp(property, "MenuBar") == 0) {
if (fKeyMenuBar) {
message->PopSpecifier();
return fKeyMenuBar;
} else {
BMessage replyMsg(B_MESSAGE_NOT_UNDERSTOOD);
replyMsg.AddInt32("error", B_NAME_NOT_FOUND);
replyMsg.AddString("message",
"This window doesn't have a main MenuBar");
message->SendReply(&replyMsg);
return NULL;
}
} else
return this;
}
return BLooper::ResolveSpecifier(message, index, specifier, what, property);
}
void
BWindow::_InitData(BRect frame, const char* title, window_look look,
window_feel feel, uint32 flags, uint32 workspace, int32 bitmapToken)
{
STRACE(("BWindow::InitData()\n"));
if (be_app == NULL) {
debugger("You need a valid BApplication object before interacting with "
"the app_server");
return;
}
frame.left = roundf(frame.left);
frame.top = roundf(frame.top);
frame.right = roundf(frame.right);
frame.bottom = roundf(frame.bottom);
fFrame = frame;
if (title == NULL)
title = "";
fTitle = strdup(title);
_SetName(title);
fFeel = feel;
fLook = look;
fFlags = flags | B_ASYNCHRONOUS_CONTROLS;
fInTransaction = bitmapToken >= 0;
fUpdateRequested = false;
fActive = false;
fShowLevel = 1;
fTopView = NULL;
fFocus = NULL;
fLastMouseMovedView = NULL;
fKeyMenuBar = NULL;
fDefaultButton = NULL;
fNoQuitShortcut = IsModal();
if ((fFlags & B_NOT_CLOSABLE) == 0 && !IsModal()) {
AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
}
AddShortcut('X', B_COMMAND_KEY, new BMessage(B_CUT), NULL);
AddShortcut('C', B_COMMAND_KEY, new BMessage(B_COPY), NULL);
AddShortcut('V', B_COMMAND_KEY, new BMessage(B_PASTE), NULL);
AddShortcut('A', B_COMMAND_KEY, new BMessage(B_SELECT_ALL), NULL);
AddShortcut('M', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_MINIMIZE_), NULL);
AddShortcut('Z', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_ZOOM_), NULL);
AddShortcut('Z', B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_ZOOM_), NULL);
AddShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(B_HIDE_APPLICATION), NULL);
AddShortcut('F', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_SEND_TO_FRONT_), NULL);
AddShortcut('B', B_COMMAND_KEY | B_CONTROL_KEY,
new BMessage(_SEND_BEHIND_), NULL);
fPulseRate = 500000;
fPulseRunner = NULL;
fIsFilePanel = false;
fMenuSem = -1;
fMinimized = false;
fMaxZoomHeight = 32768.0;
fMaxZoomWidth = 32768.0;
fMinHeight = 0.0;
fMinWidth = 0.0;
fMaxHeight = 32768.0;
fMaxWidth = 32768.0;
fLastViewToken = B_NULL_TOKEN;
fOffscreen = false;
port_id receivePort = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY,
"w<app_server");
if (receivePort < B_OK) {
debugger("Could not create BWindow's receive port, used for "
"interacting with the app_server!");
delete this;
return;
}
STRACE(("BWindow::InitData(): contacting app_server...\n"));
fLink = new(std::nothrow) BPrivate::PortLink(
BApplication::Private::ServerLink()->SenderPort(), receivePort);
if (fLink == NULL) {
return;
}
{
BPrivate::AppServerLink lockLink;
if (bitmapToken < 0) {
fLink->StartMessage(AS_CREATE_WINDOW);
} else {
fLink->StartMessage(AS_CREATE_OFFSCREEN_WINDOW);
fLink->Attach<int32>(bitmapToken);
fOffscreen = true;
}
fLink->Attach<BRect>(fFrame);
fLink->Attach<uint32>((uint32)fLook);
fLink->Attach<uint32>((uint32)fFeel);
fLink->Attach<uint32>(fFlags);
fLink->Attach<uint32>(workspace);
fLink->Attach<int32>(_get_object_token_(this));
fLink->Attach<port_id>(receivePort);
fLink->Attach<port_id>(fMsgPort);
fLink->AttachString(title);
port_id sendPort;
int32 code;
if (fLink->FlushWithReply(code) == B_OK
&& code == B_OK
&& fLink->Read<port_id>(&sendPort) == B_OK) {
fLink->Read<BRect>(&fFrame);
fLink->Read<float>(&fMinWidth);
fLink->Read<float>(&fMaxWidth);
fLink->Read<float>(&fMinHeight);
fLink->Read<float>(&fMaxHeight);
fMaxZoomWidth = fMaxWidth;
fMaxZoomHeight = fMaxHeight;
} else
sendPort = -1;
fLink->SetSenderPort(sendPort);
STRACE(("Server says that our send port is %ld\n", sendPort));
}
STRACE(("Window locked?: %s\n", IsLocked() ? "True" : "False"));
_CreateTopView();
}
void
BWindow::_SetName(const char* title)
{
if (title == NULL)
title = "";
char threadName[B_OS_NAME_LENGTH];
strcpy(threadName, "w>");
#ifdef __HAIKU__
strlcat(threadName, title, B_OS_NAME_LENGTH);
#else
int32 length = strlen(title);
length = min_c(length, B_OS_NAME_LENGTH - 3);
memcpy(threadName + 2, title, length);
threadName[length + 2] = '\0';
#endif
SetName(threadName);
if (Thread() >= B_OK)
rename_thread(Thread(), threadName);
}
void
BWindow::_DequeueAll()
{
int32 count = port_count(fMsgPort);
for (int32 i = 0; i < count; i++) {
BMessage* message = MessageFromPort(0);
if (message != NULL)
fDirectTarget->Queue()->AddMessage(message);
}
}
void
BWindow::task_looper()
{
STRACE(("info: BWindow::task_looper() started.\n"));
AssertLocked();
Unlock();
if (IsLocked())
debugger("window must not be locked!");
while (!fTerminating) {
BMessage* msg = MessageFromPort();
if (msg)
_AddMessagePriv(msg);
int32 msgCount = port_count(fMsgPort);
for (int32 i = 0; i < msgCount; ++i) {
msg = MessageFromPort(0);
if (msg)
_AddMessagePriv(msg);
}
bool dispatchNextMessage = true;
while (!fTerminating && dispatchNextMessage) {
BMessage* message = fDirectTarget->Queue()->NextMessage();
if (!Lock()) {
delete message;
break;
}
fLastMessage = message;
if (fLastMessage == NULL) {
dispatchNextMessage = false;
} else {
BMessage::Private messagePrivate(fLastMessage);
bool usePreferred = messagePrivate.UsePreferredTarget();
BHandler* handler = NULL;
bool dropMessage = false;
if (usePreferred) {
handler = PreferredHandler();
if (handler == NULL)
handler = this;
} else {
gDefaultTokens.GetToken(messagePrivate.GetTarget(),
B_HANDLER_TOKEN, (void**)&handler);
if (handler != NULL && handler->Looper() != this) {
dropMessage = true;
handler = NULL;
}
}
if ((handler == NULL && !dropMessage) || usePreferred)
handler = _DetermineTarget(fLastMessage, handler);
unpack_cookie cookie;
while (_UnpackMessage(cookie, &fLastMessage, &handler, &usePreferred)) {
if (handler != NULL) {
_SanitizeMessage(fLastMessage, handler, usePreferred);
if (fLastMessage->HasSpecifiers()) {
int32 index = 0;
if (fLastMessage->GetCurrentSpecifier(&index) == B_OK)
handler = resolve_specifier(handler, fLastMessage);
}
if (handler != NULL)
handler = _TopLevelFilter(fLastMessage, handler);
if (handler != NULL)
DispatchMessage(fLastMessage, handler);
}
delete fLastMessage;
fLastMessage = NULL;
}
}
if (fTerminating) {
return;
}
Unlock();
if (port_count(fMsgPort) > 0) {
dispatchNextMessage = false;
}
}
}
}
window_type
BWindow::_ComposeType(window_look look, window_feel feel) const
{
switch (feel) {
case B_NORMAL_WINDOW_FEEL:
switch (look) {
case B_TITLED_WINDOW_LOOK:
return B_TITLED_WINDOW;
case B_DOCUMENT_WINDOW_LOOK:
return B_DOCUMENT_WINDOW;
case B_BORDERED_WINDOW_LOOK:
return B_BORDERED_WINDOW;
default:
return B_UNTYPED_WINDOW;
}
break;
case B_MODAL_APP_WINDOW_FEEL:
if (look == B_MODAL_WINDOW_LOOK)
return B_MODAL_WINDOW;
break;
case B_FLOATING_APP_WINDOW_FEEL:
if (look == B_FLOATING_WINDOW_LOOK)
return B_FLOATING_WINDOW;
break;
default:
return B_UNTYPED_WINDOW;
}
return B_UNTYPED_WINDOW;
}
void
BWindow::_DecomposeType(window_type type, window_look* _look,
window_feel* _feel) const
{
switch (type) {
case B_DOCUMENT_WINDOW:
*_look = B_DOCUMENT_WINDOW_LOOK;
*_feel = B_NORMAL_WINDOW_FEEL;
break;
case B_MODAL_WINDOW:
*_look = B_MODAL_WINDOW_LOOK;
*_feel = B_MODAL_APP_WINDOW_FEEL;
break;
case B_FLOATING_WINDOW:
*_look = B_FLOATING_WINDOW_LOOK;
*_feel = B_FLOATING_APP_WINDOW_FEEL;
break;
case B_BORDERED_WINDOW:
*_look = B_BORDERED_WINDOW_LOOK;
*_feel = B_NORMAL_WINDOW_FEEL;
break;
case B_TITLED_WINDOW:
case B_UNTYPED_WINDOW:
default:
*_look = B_TITLED_WINDOW_LOOK;
*_feel = B_NORMAL_WINDOW_FEEL;
break;
}
}
void
BWindow::_CreateTopView()
{
STRACE(("_CreateTopView(): enter\n"));
BRect frame = fFrame.OffsetToCopy(B_ORIGIN);
fTopView = new BView(frame, "fTopView", B_FOLLOW_ALL, B_WILL_DRAW);
fTopView->fTopLevelView = true;
fLastViewToken = _get_object_token_(fTopView);
STRACE(("Calling setowner fTopView = %p this = %p.\n",
fTopView, this));
fTopView->_SetOwner(this);
fTopView->_CreateSelf();
STRACE(("BuildTopView ended\n"));
}
void
BWindow::_AdoptResize()
{
int32 deltaWidth = (int32)(fFrame.Width() - fTopView->Bounds().Width());
int32 deltaHeight = (int32)(fFrame.Height() - fTopView->Bounds().Height());
if (deltaWidth == 0 && deltaHeight == 0)
return;
fTopView->_ResizeBy(deltaWidth, deltaHeight);
}
void
BWindow::_SetFocus(BView* focusView, bool notifyInputServer)
{
if (fFocus == focusView)
return;
if (notifyInputServer && fActive) {
bool inputMethodAware = false;
if (focusView)
inputMethodAware = focusView->Flags() & B_INPUT_METHOD_AWARE;
BMessage msg(inputMethodAware ? IS_FOCUS_IM_AWARE_VIEW : IS_UNFOCUS_IM_AWARE_VIEW);
BMessenger messenger(focusView);
BMessage reply;
if (focusView)
msg.AddMessenger("view", messenger);
_control_input_server_(&msg, &reply);
}
fFocus = focusView;
SetPreferredHandler(focusView);
}
BHandler*
BWindow::_DetermineTarget(BMessage* message, BHandler* target)
{
if (target == NULL)
target = this;
switch (message->what) {
case B_KEY_DOWN:
case B_KEY_UP:
{
BButton* defaultButton = DefaultButton();
if (defaultButton != NULL) {
int32 rawChar = message->GetInt32("raw_char", 0);
uint32 mods = modifiers();
if (rawChar == B_ENTER && (mods & Shortcut::AllowedModifiers()) == 0)
return defaultButton;
}
}
case B_UNMAPPED_KEY_DOWN:
case B_UNMAPPED_KEY_UP:
case B_MODIFIERS_CHANGED:
if (CurrentFocus() != NULL)
return CurrentFocus();
break;
case B_MOUSE_DOWN:
case B_MOUSE_UP:
case B_MOUSE_MOVED:
case B_MOUSE_WHEEL_CHANGED:
case B_MOUSE_IDLE:
{
int32 token;
if (message->FindInt32("_view_token", &token) == B_OK) {
BView* view = _FindView(token);
if (view != NULL)
return view;
}
if (fLastMouseMovedView != NULL)
return fLastMouseMovedView;
break;
}
case B_PULSE:
case B_QUIT_REQUESTED:
return this;
case _MESSAGE_DROPPED_:
if (fLastMouseMovedView != NULL)
return fLastMouseMovedView;
break;
default:
break;
}
return target;
}
bool
BWindow::_IsFocusMessage(BMessage* message)
{
BMessage::Private messagePrivate(message);
if (!messagePrivate.UsePreferredTarget())
return false;
bool feedFocus;
if (message->HasInt32("_token")
&& (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus))
return false;
return true;
}
bool
BWindow::_UnpackMessage(unpack_cookie& cookie, BMessage** _message,
BHandler** _target, bool* _usePreferred)
{
if (cookie.message == NULL)
return false;
if (cookie.index == 0 && !cookie.tokens_scanned) {
if (!*_usePreferred) {
cookie.message = NULL;
return true;
}
cookie.message = *_message;
cookie.focus = *_target;
if (cookie.focus != NULL)
cookie.focus_token = _get_object_token_(*_target);
if (fLastMouseMovedView != NULL && cookie.message->what == B_MOUSE_MOVED)
cookie.last_view_token = _get_object_token_(fLastMouseMovedView);
*_usePreferred = false;
}
_DequeueAll();
for (int32 token; !cookie.tokens_scanned
&& cookie.message->FindInt32("_token", cookie.index, &token)
== B_OK;
cookie.index++) {
if (token == cookie.focus_token) {
cookie.found_focus = true;
continue;
}
if (token == cookie.last_view_token)
continue;
BView* target = _FindView(token);
if (target == NULL)
continue;
*_message = new BMessage(*cookie.message);
(*_message)->RemoveName("_feed_focus");
*_target = target;
cookie.index++;
return true;
}
cookie.tokens_scanned = true;
if (cookie.last_view_token != B_NULL_TOKEN && fLastMouseMovedView != NULL
&& fLastMouseMovedView != cookie.focus) {
*_message = new BMessage(*cookie.message);
*_target = fLastMouseMovedView;
cookie.last_view_token = B_NULL_TOKEN;
return true;
}
bool dispatchToFocus = true;
BHandler* handler;
if (gDefaultTokens.GetToken(cookie.focus_token, B_HANDLER_TOKEN, (void**)&handler) != B_OK
|| handler->Looper() != this)
dispatchToFocus = false;
if (dispatchToFocus && cookie.index > 0) {
bool feedFocus;
if (!cookie.found_focus
&& (cookie.message->FindBool("_feed_focus", &feedFocus) != B_OK
|| feedFocus == false))
dispatchToFocus = false;
}
if (!dispatchToFocus) {
delete cookie.message;
cookie.message = NULL;
return false;
}
*_message = cookie.message;
*_target = cookie.focus;
*_usePreferred = true;
cookie.message = NULL;
return true;
}
void
BWindow::_SanitizeMessage(BMessage* message, BHandler* target, bool usePreferred)
{
if (target == NULL)
return;
switch (message->what) {
case B_MOUSE_MOVED:
case B_MOUSE_UP:
case B_MOUSE_DOWN:
{
BPoint where;
if (message->FindPoint("screen_where", &where) != B_OK)
break;
BView* view = dynamic_cast<BView*>(target);
if (view == NULL || message->what == B_MOUSE_MOVED) {
message->AddPoint("where", ConvertFromScreen(where));
}
if (view != NULL) {
BPoint viewWhere = view->ConvertFromScreen(where);
if (message->what != B_MOUSE_MOVED) {
message->AddPoint("where", viewWhere);
}
message->AddPoint("be:view_where", viewWhere);
if (message->what == B_MOUSE_MOVED) {
BView* viewUnderMouse = NULL;
int32 token;
if (message->FindInt32("_view_token", &token) == B_OK)
viewUnderMouse = _FindView(token);
uint32 transit
= _TransitForMouseMoved(view, viewUnderMouse);
message->AddInt32("be:transit", transit);
if (usePreferred)
fLastMouseMovedView = viewUnderMouse;
}
}
break;
}
case B_MOUSE_IDLE:
{
BPoint where;
if (message->FindPoint("screen_where", &where) != B_OK)
break;
BView* view = dynamic_cast<BView*>(target);
if (view != NULL) {
message->AddPoint("be:view_where",
view->ConvertFromScreen(where));
}
break;
}
case _MESSAGE_DROPPED_:
{
uint32 originalWhat;
if (message->FindInt32("_original_what",
(int32*)&originalWhat) == B_OK) {
message->what = originalWhat;
message->RemoveName("_original_what");
}
break;
}
}
}
bool
BWindow::_StealMouseMessage(BMessage* message, bool& deleteMessage)
{
BMessage::Private messagePrivate(message);
if (!messagePrivate.UsePreferredTarget()) {
return false;
}
int32 token;
if (message->FindInt32("_token", 0, &token) == B_OK) {
bool feedFocus;
if (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus)
return false;
message->RemoveName("_feed_focus");
deleteMessage = false;
} else {
deleteMessage = true;
if (message->what == B_MOUSE_MOVED) {
BView* viewUnderMouse = NULL;
int32 token;
if (message->FindInt32("_view_token", &token) == B_OK)
viewUnderMouse = _FindView(token);
uint32 transit = _TransitForMouseMoved(fLastMouseMovedView,
viewUnderMouse);
if (transit == B_ENTERED_VIEW || transit == B_EXITED_VIEW)
deleteMessage = false;
}
if (deleteMessage) {
MessageQueue()->RemoveMessage(message);
}
}
return true;
}
uint32
BWindow::_TransitForMouseMoved(BView* view, BView* viewUnderMouse) const
{
uint32 transit;
if (viewUnderMouse == view) {
if (fLastMouseMovedView != view)
transit = B_ENTERED_VIEW;
else
transit = B_INSIDE_VIEW;
} else {
if (view == fLastMouseMovedView)
transit = B_EXITED_VIEW;
else
transit = B_OUTSIDE_VIEW;
}
return transit;
}
void
BWindow::_Switcher(int32 rawKey, uint32 modifiers, bool repeat)
{
if (repeat)
return;
BMessenger deskbar(kDeskbarSignature);
if (!deskbar.IsValid()) {
return;
}
BMessage message('TASK');
message.AddInt32("key", rawKey);
message.AddInt32("modifiers", modifiers);
message.AddInt64("when", system_time());
message.AddInt32("team", Team());
deskbar.SendMessage(&message);
}
bool
BWindow::_HandleKeyDown(BMessage* event)
{
if (!_IsFocusMessage(event))
return false;
const char* bytes;
if (event->FindString("bytes", &bytes) != B_OK)
return false;
char key = Shortcut::PrepareKey(bytes[0]);
uint32 modifiers;
if (event->FindInt32("modifiers", (int32*)&modifiers) != B_OK)
modifiers = 0;
uint32 rawKey;
if (event->FindInt32("key", (int32*)&rawKey) != B_OK)
rawKey = 0;
if (key == B_ESCAPE && (modifiers & B_COMMAND_KEY) != 0 && fKeyMenuBar != NULL) {
fKeyMenuBar->StartMenuBar(0, true, false, NULL);
return true;
}
if (key == B_TAB && (modifiers & B_OPTION_KEY) != 0) {
_KeyboardNavigation();
return true;
}
if ((key == B_TAB || rawKey == 0x11) && (modifiers & B_CONTROL_KEY) != 0) {
_Switcher(rawKey, modifiers, event->HasInt32("be:key_repeat"));
return true;
}
if (key == B_ESCAPE && (Flags() & B_CLOSE_ON_ESCAPE) != 0) {
BMessage message(B_QUIT_REQUESTED);
message.AddBool("shortcut", true);
PostMessage(&message);
return true;
}
if (key == B_FUNCTION_KEY && rawKey == B_PRINT_KEY) {
if (modifiers == 0) {
be_roster->Launch("application/x-vnd.haiku-screenshot-cli");
return true;
}
if ((modifiers & B_OPTION_KEY) != 0) {
BMessage message(B_ARGV_RECEIVED);
message.AddString("argv", "screenshot");
message.AddString("argv", "--area");
message.AddInt32("argc", 2);
be_roster->Launch("application/x-vnd.haiku-screenshot-cli", &message);
return true;
}
BMessage message(B_ARGV_RECEIVED);
int32 argc = 1;
message.AddString("argv", "Screenshot");
if ((modifiers & B_CONTROL_KEY) != 0) {
argc++;
message.AddString("argv", "--clipboard");
}
if ((modifiers & B_SHIFT_KEY) != 0) {
argc++;
message.AddString("argv", "--silent");
}
message.AddInt32("argc", argc);
be_roster->Launch("application/x-vnd.haiku-screenshot", &message);
return true;
}
if ((modifiers & B_COMMAND_KEY) != 0) {
if (!fNoQuitShortcut && key == 'Q') {
BMessage message(B_QUIT_REQUESTED);
message.AddBool("shortcut", true);
be_app->PostMessage(&message);
return true;
}
if (key == B_LEFT_ARROW || key == B_RIGHT_ARROW) {
BTextView* textView = dynamic_cast<BTextView*>(CurrentFocus());
if (textView != NULL) {
textView->KeyDown(bytes, modifiers);
return true;
}
}
}
{
if ((modifiers & B_COMMAND_KEY) != 0)
MenusBeginning();
Shortcut* shortcut = _FindShortcut(key, modifiers
| (((modifiers & B_COMMAND_KEY) == 0) ? B_NO_COMMAND_KEY : 0));
if (shortcut != NULL) {
if (shortcut->MenuItem() != NULL) {
BMenu* menu = shortcut->MenuItem()->Menu();
if (menu != NULL && shortcut->MenuItem()->IsEnabled()) {
MenuPrivate(menu).InvokeItem(shortcut->MenuItem(), true);
} else {
shortcut = NULL;
}
} else {
BHandler* target = shortcut->Target();
if (target == NULL)
target = CurrentFocus();
if (shortcut->Message() != NULL) {
BMessage message(*shortcut->Message());
if (message.ReplaceInt64("when", system_time()) != B_OK)
message.AddInt64("when", system_time());
if (message.ReplaceBool("shortcut", true) != B_OK)
message.AddBool("shortcut", true);
PostMessage(&message, target);
}
}
}
if ((modifiers & B_COMMAND_KEY) != 0)
MenusEnded();
if (shortcut != NULL)
return true;
}
if ((modifiers & B_COMMAND_KEY) != 0) {
return true;
}
return false;
}
bool
BWindow::_HandleUnmappedKeyDown(BMessage* event)
{
if (!_IsFocusMessage(event))
return false;
uint32 modifiers;
int32 rawKey;
if (event->FindInt32("modifiers", (int32*)&modifiers) != B_OK
|| event->FindInt32("key", &rawKey))
return false;
if (rawKey == 0x11 && (modifiers & B_CONTROL_KEY) != 0) {
_Switcher(rawKey, modifiers, event->HasInt32("be:key_repeat"));
return true;
}
return false;
}
void
BWindow::_KeyboardNavigation()
{
BMessage* message = CurrentMessage();
if (message == NULL)
return;
const char* bytes;
if (message->FindString("bytes", &bytes) != B_OK || bytes[0] != B_TAB)
return;
uint32 modifiers;
if (message->FindInt32("modifiers", (int32*)&modifiers) != B_OK)
modifiers = 0;
BView* nextFocus;
int32 jumpGroups = (modifiers & B_OPTION_KEY) != 0 ? B_NAVIGABLE_JUMP : B_NAVIGABLE;
if ((modifiers & B_SHIFT_KEY) != 0)
nextFocus = _FindPreviousNavigable(fFocus, jumpGroups);
else
nextFocus = _FindNextNavigable(fFocus, jumpGroups);
if (nextFocus != NULL && nextFocus != fFocus)
nextFocus->MakeFocus(true);
}
BPoint
BWindow::AlertPosition(const BRect& frame)
{
float width = Bounds().Width();
float height = Bounds().Height();
BPoint point(frame.left + (frame.Width() / 2.0f) - (width / 2.0f),
frame.top + (frame.Height() / 4.0f) - ceil(height / 3.0f));
BRect screenFrame = BScreen(this).Frame();
if (frame == screenFrame) {
return point;
}
float borderWidth;
float tabHeight;
_GetDecoratorSize(&borderWidth, &tabHeight);
if (point.x < screenFrame.left + borderWidth)
point.x = screenFrame.left + borderWidth;
else if (point.x + width > screenFrame.right - borderWidth)
point.x = screenFrame.right - borderWidth - width;
float tabPosition = frame.LeftTop().y + tabHeight + borderWidth;
if (point.y < tabPosition)
point.y = tabPosition;
if (point.y < screenFrame.top + borderWidth)
point.y = screenFrame.top + borderWidth;
else if (point.y + height > screenFrame.bottom - borderWidth)
point.y = screenFrame.bottom - borderWidth - height;
return point;
}
BMessage*
BWindow::ConvertToMessage(void* raw, int32 code)
{
return BLooper::ConvertToMessage(raw, code);
}
BWindow::Shortcut*
BWindow::_FindShortcut(uint32 key, uint32 modifiers)
{
key = Shortcut::PrepareKey(key);
uint32 preparedModifiers = Shortcut::PrepareModifiers(modifiers);
int32 shortcutCount = fShortcuts.CountItems();
for (int32 index = 0; index < shortcutCount; index++) {
Shortcut* shortcut = (Shortcut*)fShortcuts.ItemAt(index);
if (shortcut != NULL && shortcut->Matches(key, preparedModifiers))
return shortcut;
}
return NULL;
}
BView*
BWindow::_FindView(int32 token)
{
BHandler* handler;
if (gDefaultTokens.GetToken(token, B_HANDLER_TOKEN,
(void**)&handler) != B_OK) {
return NULL;
}
BView* view = dynamic_cast<BView*>(handler);
if (view != NULL && view->Window() == this)
return view;
return NULL;
}
BView*
BWindow::_FindView(BView* view, BPoint point) const
{
if (!view->IsHidden(view) && view->Bounds().Contains(point)) {
if (view->fFirstChild == NULL)
return view;
else {
BView* child = view->fFirstChild;
while (child != NULL) {
BPoint childPoint = point - child->Frame().LeftTop();
BView* subView = _FindView(child, childPoint);
if (subView != NULL)
return subView;
child = child->fNextSibling;
}
}
return view;
}
return NULL;
}
BView*
BWindow::_FindNextNavigable(BView* focus, uint32 flags)
{
if (focus == NULL)
focus = fTopView;
BView* nextFocus = focus;
while (true) {
if (nextFocus->fFirstChild)
nextFocus = nextFocus->fFirstChild;
else if (nextFocus->fNextSibling)
nextFocus = nextFocus->fNextSibling;
else {
while (!nextFocus->fNextSibling && nextFocus->fParent) {
nextFocus = nextFocus->fParent;
}
if (nextFocus == fTopView) {
if (nextFocus == focus)
return NULL;
nextFocus = nextFocus->fFirstChild;
} else
nextFocus = nextFocus->fNextSibling;
}
if (nextFocus == focus || nextFocus == NULL) {
return NULL;
}
if (!nextFocus->IsHidden() && (nextFocus->Flags() & flags) != 0)
return nextFocus;
}
}
BView*
BWindow::_FindPreviousNavigable(BView* focus, uint32 flags)
{
if (focus == NULL)
focus = fTopView;
BView* previousFocus = focus;
while (true) {
if (previousFocus->fPreviousSibling) {
previousFocus = _LastViewChild(previousFocus->fPreviousSibling);
} else {
previousFocus = previousFocus->fParent;
if (previousFocus == fTopView)
previousFocus = _LastViewChild(fTopView);
}
if (previousFocus == focus || previousFocus == NULL) {
return NULL;
}
if (!previousFocus->IsHidden() && (previousFocus->Flags() & flags) != 0)
return previousFocus;
}
}
BView*
BWindow::_LastViewChild(BView* parent)
{
while (true) {
BView* last = parent->fFirstChild;
if (last == NULL)
return parent;
while (last->fNextSibling) {
last = last->fNextSibling;
}
parent = last;
}
}
void
BWindow::SetIsFilePanel(bool isFilePanel)
{
fIsFilePanel = isFilePanel;
}
bool
BWindow::IsFilePanel() const
{
return fIsFilePanel;
}
void
BWindow::_GetDecoratorSize(float* _borderWidth, float* _tabHeight) const
{
float borderWidth = 5.0;
float tabHeight = 21.0;
BMessage settings;
if (GetDecoratorSettings(&settings) == B_OK) {
BRect tabRect;
if (settings.FindRect("tab frame", &tabRect) == B_OK)
tabHeight = tabRect.Height();
settings.FindFloat("border width", &borderWidth);
} else {
if (fLook == B_NO_BORDER_WINDOW_LOOK) {
borderWidth = 0.0;
tabHeight = 0.0;
}
}
if (_borderWidth != NULL)
*_borderWidth = borderWidth;
if (_tabHeight != NULL)
*_tabHeight = tabHeight;
}
void
BWindow::_SendShowOrHideMessage()
{
fLink->StartMessage(AS_SHOW_OR_HIDE_WINDOW);
fLink->Attach<int32>(fShowLevel);
fLink->Flush();
}
void
BWindow::_PropagateMessageToChildViews(BMessage* message)
{
int32 childrenCount = CountChildren();
for (int32 index = 0; index < childrenCount; index++) {
BView* view = ChildAt(index);
if (view != NULL)
PostMessage(message, view);
}
}
extern "C" void
_ReservedWindow1__7BWindow(BWindow* window, BLayout* layout)
{
perform_data_set_layout data;
data.layout = layout;
window->Perform(PERFORM_CODE_SET_LAYOUT, &data);
}
void BWindow::_ReservedWindow2() {}
void BWindow::_ReservedWindow3() {}
void BWindow::_ReservedWindow4() {}
void BWindow::_ReservedWindow5() {}
void BWindow::_ReservedWindow6() {}
void BWindow::_ReservedWindow7() {}
void BWindow::_ReservedWindow8() {}