* Copyright 2001-2020, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Adrian Oanca, adioanca@cotty.iren.ro
* Stephan Aßmus, superstippi@gmx.de
* Axel Dörfler, axeld@pinc-software.de
* Andrej Spielmann, andrej.spielmann@seh.ox.ac.uk
* Brecht Machiels, brecht@mos6581.org
* Clemens Zeidler, haiku@clemens-zeidler.de
* Ingo Weinhold, ingo_weinhold@gmx.de
* Joseph Groover, looncraz@looncraz.net
* Tri-Edge AI
* Jacob Secunda, secundja@gmail.com
*/
#include "Desktop.h"
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <Debug.h>
#include <debugger.h>
#include <DirectWindow.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <Message.h>
#include <MessageFilter.h>
#include <Path.h>
#include <Region.h>
#include <Roster.h>
#include <PrivateScreen.h>
#include <ServerProtocol.h>
#include <ServerReadOnlyMemory.h>
#include <ViewPrivate.h>
#include <WindowInfo.h>
#include "AppServer.h"
#include "ClickTarget.h"
#include "DecorManager.h"
#include "DesktopSettingsPrivate.h"
#include "DrawingEngine.h"
#include "GlobalFontManager.h"
#include "HWInterface.h"
#include "InputManager.h"
#include "Screen.h"
#include "ScreenManager.h"
#include "ServerApp.h"
#include "ServerConfig.h"
#include "ServerCursor.h"
#include "ServerWindow.h"
#include "SystemPalette.h"
#include "WindowPrivate.h"
#include "Window.h"
#include "Workspace.h"
#include "WorkspacesView.h"
#if TEST_MODE
# include "EventStream.h"
#endif
#ifdef DEBUG_DESKTOP
# define STRACE(a) printf a
#else
# define STRACE(a) ;
#endif
static inline float
square_vector_length(float x, float y)
{
return x * x + y * y;
}
static inline float
square_distance(const BPoint& a, const BPoint& b)
{
return square_vector_length(a.x - b.x, a.y - b.y);
}
class KeyboardFilter : public EventFilter {
public:
KeyboardFilter(Desktop* desktop);
virtual filter_result Filter(BMessage* message, EventTarget** _target,
int32* _viewToken, BMessage* latestMouseMoved);
virtual void RemoveTarget(EventTarget* target);
private:
void _UpdateFocus(int32 key, uint32 modifiers, EventTarget** _target);
Desktop* fDesktop;
EventTarget* fLastFocus;
bigtime_t fTimestamp;
};
class MouseFilter : public EventFilter {
public:
MouseFilter(Desktop* desktop);
virtual filter_result Filter(BMessage* message, EventTarget** _target,
int32* _viewToken, BMessage* latestMouseMoved);
private:
Desktop* fDesktop;
int32 fLastClickButtons;
int32 fLastClickModifiers;
int32 fResetClickCount;
BPoint fLastClickPoint;
ClickTarget fLastClickTarget;
};
KeyboardFilter::KeyboardFilter(Desktop* desktop)
:
fDesktop(desktop),
fLastFocus(NULL),
fTimestamp(0)
{
}
void
KeyboardFilter::_UpdateFocus(int32 key, uint32 modifiers, EventTarget** _target)
{
if (!fDesktop->LockSingleWindow())
return;
EventTarget* focus = fDesktop->KeyboardEventTarget();
#if 0
bigtime_t now = system_time();
if (fLastFocus == NULL
|| (focus != fLastFocus && now - fTimestamp > 100000)) {
*_target = focus;
fLastFocus = focus;
}
#endif
*_target = focus;
fLastFocus = focus;
fDesktop->UnlockSingleWindow();
#if 0
if (key == B_ENTER || modifiers == B_COMMAND_KEY
|| modifiers == B_CONTROL_KEY || modifiers == B_OPTION_KEY)
fTimestamp = 0;
else
fTimestamp = now;
#endif
}
filter_result
KeyboardFilter::Filter(BMessage* message, EventTarget** _target,
int32* , BMessage* )
{
int32 key = 0;
int32 modifiers = 0;
message->FindInt32("key", &key);
message->FindInt32("modifiers", &modifiers);
if ((message->what == B_KEY_DOWN || message->what == B_UNMAPPED_KEY_DOWN)) {
if (key == 0x01 && (modifiers & B_COMMAND_KEY) != 0
&& (modifiers & B_CONTROL_KEY) != 0
&& (modifiers & B_SHIFT_KEY) != 0) {
system("screenmode --fall-back &");
return B_SKIP_MESSAGE;
}
bool takeWindow = (modifiers & B_SHIFT_KEY) != 0
|| fDesktop->MouseEventWindow() != NULL;
if (key >= B_F1_KEY && key <= B_F12_KEY) {
#if !TEST_MODE
if ((modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY))
== B_COMMAND_KEY)
#else
if ((modifiers & B_CONTROL_KEY) != 0)
#endif
{
STRACE(("Set Workspace %" B_PRId32 "\n", key - 1));
fDesktop->SetWorkspaceAsync(key - B_F1_KEY, takeWindow);
return B_SKIP_MESSAGE;
}
} else if (key == 0x11
&& (modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY))
== B_COMMAND_KEY) {
fDesktop->SetWorkspaceAsync(-1, takeWindow);
return B_SKIP_MESSAGE;
}
}
if (message->what == B_KEY_DOWN
|| message->what == B_MODIFIERS_CHANGED
|| message->what == B_UNMAPPED_KEY_DOWN
|| message->what == B_INPUT_METHOD_EVENT)
_UpdateFocus(key, modifiers, _target);
return fDesktop->KeyEvent(message->what, key, modifiers);
}
void
KeyboardFilter::RemoveTarget(EventTarget* target)
{
if (target == fLastFocus)
fLastFocus = NULL;
}
MouseFilter::MouseFilter(Desktop* desktop)
:
fDesktop(desktop),
fLastClickButtons(0),
fLastClickModifiers(0),
fResetClickCount(0),
fLastClickPoint(),
fLastClickTarget()
{
}
filter_result
MouseFilter::Filter(BMessage* message, EventTarget** _target, int32* _viewToken,
BMessage* latestMouseMoved)
{
BPoint where;
if (message->FindPoint("where", &where) != B_OK)
return B_DISPATCH_MESSAGE;
int32 buttons;
if (message->FindInt32("buttons", &buttons) != B_OK)
buttons = 0;
if (!fDesktop->LockAllWindows())
return B_DISPATCH_MESSAGE;
int32 viewToken = B_NULL_TOKEN;
Window* window = fDesktop->MouseEventWindow();
if (window == NULL)
window = fDesktop->WindowAt(where);
if (window != NULL) {
switch (message->what) {
case B_MOUSE_DOWN:
{
int32 windowToken = window->ServerWindow()->ServerToken();
int32 modifiers = message->FindInt32("modifiers");
int32 originalClickCount = message->FindInt32("clicks");
if (originalClickCount <= 0)
originalClickCount = 1;
int32 clickCount = originalClickCount;
if (clickCount > 1) {
if (modifiers != fLastClickModifiers
|| buttons != fLastClickButtons
|| !fLastClickTarget.IsValid()
|| fLastClickTarget.WindowToken() != windowToken
|| square_distance(where, fLastClickPoint) >= 16
|| clickCount - fResetClickCount < 1) {
clickCount = 1;
} else
clickCount -= fResetClickCount;
}
ClickTarget clickTarget;
window->MouseDown(message, where, fLastClickTarget, clickCount,
clickTarget);
if (clickCount != 1 && clickTarget != fLastClickTarget)
clickCount = 1;
fResetClickCount = originalClickCount - clickCount;
fLastClickTarget = clickTarget;
fLastClickButtons = buttons;
fLastClickModifiers = modifiers;
fLastClickPoint = where;
if (clickTarget.GetType() == ClickTarget::TYPE_WINDOW_CONTENTS)
viewToken = clickTarget.WindowElement();
if (clickCount != originalClickCount) {
if (message->HasInt32("clicks"))
message->ReplaceInt32("clicks", clickCount);
else
message->AddInt32("clicks", clickCount);
}
fDesktop->NotifyMouseDown(window, message, where);
break;
}
case B_MOUSE_UP:
window->MouseUp(message, where, &viewToken);
if (buttons == 0)
fDesktop->SetMouseEventWindow(NULL);
fDesktop->NotifyMouseUp(window, message, where);
break;
case B_MOUSE_MOVED:
window->MouseMoved(message, where, &viewToken,
latestMouseMoved == NULL || latestMouseMoved == message,
false);
fDesktop->NotifyMouseMoved(window, message, where);
break;
}
if (viewToken != B_NULL_TOKEN) {
fDesktop->SetViewUnderMouse(window, viewToken);
*_viewToken = viewToken;
*_target = &window->EventTarget();
}
} else if (message->what == B_MOUSE_DOWN) {
fResetClickCount = 0;
fLastClickTarget = ClickTarget();
fLastClickButtons = message->FindInt32("buttons");
fLastClickModifiers = message->FindInt32("modifiers");
fLastClickPoint = where;
}
if (window == NULL || viewToken == B_NULL_TOKEN) {
fDesktop->SetViewUnderMouse(window, B_NULL_TOKEN);
fDesktop->SetCursor(NULL);
*_target = NULL;
}
fDesktop->SetLastMouseState(where, buttons, window);
fDesktop->NotifyMouseEvent(message);
fDesktop->UnlockAllWindows();
return B_DISPATCH_MESSAGE;
}
static inline uint32
workspace_to_workspaces(int32 index)
{
return 1UL << index;
}
static inline bool
workspace_in_workspaces(int32 index, uint32 workspaces)
{
return (workspaces & (1UL << index)) != 0;
}
Desktop::Desktop(uid_t userID, const char* targetScreen)
:
MessageLooper("desktop"),
fUserID(userID),
fTargetScreen(strdup(targetScreen)),
fSettings(NULL),
fSharedReadOnlyArea(-1),
fApplicationsLock("application list"),
fShutdownSemaphore(-1),
fShutdownCount(0),
fScreenLock("screen lock"),
fDirectScreenLock("direct screen lock"),
fDirectScreenTeam(-1),
fCurrentWorkspace(0),
fPreviousWorkspace(0),
fAllWindows(kAllWindowList),
fSubsetWindows(kSubsetList),
fFocusList(kFocusList),
fWorkspacesViews(false),
fWorkspacesLock("workspaces list"),
fWindowLock("window lock"),
fMouseEventWindow(NULL),
fWindowUnderMouse(NULL),
fLockedFocusWindow(NULL),
fViewUnderMouse(B_NULL_TOKEN),
fLastMousePosition(B_ORIGIN),
fLastMouseButtons(0),
fFocus(NULL),
fFront(NULL),
fBack(NULL)
{
memset(fLastWorkspaceFocus, 0, sizeof(fLastWorkspaceFocus));
char name[B_OS_NAME_LENGTH];
Desktop::_GetLooperName(name, sizeof(name));
fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name);
if (fMessagePort < B_OK)
return;
fLink.SetReceiverPort(fMessagePort);
RegisterListener(&fStackAndTile);
const DesktopListenerList& newListeners
= gDecorManager.GetDesktopListeners();
for (int i = 0; i < newListeners.CountItems(); i++)
RegisterListener(newListeners.ItemAt(i));
}
Desktop::~Desktop()
{
delete_area(fSharedReadOnlyArea);
delete_port(fMessagePort);
free(fTargetScreen);
}
void
Desktop::RegisterListener(DesktopListener* listener)
{
DesktopObservable::RegisterListener(listener, this);
}
*/
status_t
Desktop::Init()
{
if (fMessagePort < B_OK)
return fMessagePort;
InitializeColorMap();
const size_t areaSize = sizeof(server_read_only_memory);
char name[B_OS_NAME_LENGTH];
snprintf(name, sizeof(name), "d:%d:shared read only", fUserID);
fSharedReadOnlyArea = create_area(name, (void **)&fServerReadOnlyMemory,
B_ANY_ADDRESS, areaSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA);
if (fSharedReadOnlyArea < B_OK)
return fSharedReadOnlyArea;
fSettings.SetTo(new DesktopSettingsPrivate(fServerReadOnlyMemory));
for (int32 i = 0; i < kMaxWorkspaces; i++) {
_Windows(i).SetIndex(i);
fWorkspaces[i].RestoreConfiguration(*fSettings->WorkspacesMessage(i));
}
status_t status = fVirtualScreen.SetConfiguration(*this,
fWorkspaces[0].CurrentScreenConfiguration());
if (status != B_OK) {
debug_printf("app_server: Failed to initialize virtual screen configuration: %s\n",
strerror(status));
return status;
}
if (fVirtualScreen.HWInterface() == NULL) {
debug_printf("Could not initialize graphics output. Exiting.\n");
return B_ERROR;
}
if (fSettings->DefaultPlainFont() == *gFontManager->DefaultPlainFont()
&& !fSettings->DidLoadFontSettings()) {
float fontSize = fSettings->DefaultPlainFont().Size();
gScreenManager->Lock();
Screen* screen = gScreenManager->ScreenAt(0);
if (screen != NULL) {
display_mode mode;
screen->GetMode(mode);
if (mode.virtual_width > 3840 && mode.virtual_height > 2160)
fontSize *= 2.0f;
else if (mode.virtual_width > 1920 && mode.virtual_height > 1080)
fontSize *= 1.5f;
}
gScreenManager->Unlock();
const_cast<ServerFont&>(fSettings->DefaultPlainFont()).SetSize(fontSize);
const_cast<ServerFont&>(fSettings->DefaultBoldFont()).SetSize(fontSize);
const_cast<ServerFont&>(fSettings->DefaultFixedFont()).SetSize(fontSize);
const_cast<menu_info&>(fSettings->MenuInfo()).font_size = fontSize;
}
#if 1
if (fSettings->UIColor(B_CONTROL_BACKGROUND_COLOR) == make_color(245, 245, 245)
&& fSettings->ControlLook().IsEmpty()) {
rgb_color newControlBackground = make_color(222, 222, 222);
fSettings->SetUIColor(B_CONTROL_BACKGROUND_COLOR, newControlBackground);
fSettings->SetUIColor(B_SCROLL_BAR_THUMB_COLOR, newControlBackground);
}
#endif
fCursorManager.InitializeCursors(fSettings->DefaultBoldFont().Size() / 12.0f);
HWInterface()->SetDPMSMode(B_DPMS_ON);
float brightness = fWorkspaces[0].StoredScreenConfiguration().Brightness(0);
if (brightness > 0)
HWInterface()->SetBrightness(brightness);
fVirtualScreen.HWInterface()->MoveCursorTo(
fVirtualScreen.Frame().Width() / 2,
fVirtualScreen.Frame().Height() / 2);
#if TEST_MODE
gInputManager->AddStream(new InputServerStream);
#endif
EventStream* stream = fVirtualScreen.HWInterface()->CreateEventStream();
if (stream == NULL)
stream = gInputManager->GetStream();
fEventDispatcher.SetDesktop(this);
fEventDispatcher.SetTo(stream);
if (fEventDispatcher.InitCheck() != B_OK)
_LaunchInputServer();
fEventDispatcher.SetHWInterface(fVirtualScreen.HWInterface());
fEventDispatcher.SetMouseFilter(new MouseFilter(this));
fEventDispatcher.SetKeyboardFilter(new KeyboardFilter(this));
fScreenRegion = fVirtualScreen.Frame();
BRegion stillAvailableOnScreen;
_RebuildClippingForAllWindows(stillAvailableOnScreen);
_SetBackground(stillAvailableOnScreen);
SetCursor(NULL);
fVirtualScreen.HWInterface()->SetCursorVisible(true);
return B_OK;
}
Quite useful for notification for things like server shutdown, system
color changes, etc.
*/
void
Desktop::BroadcastToAllApps(int32 code)
{
BAutolock locker(fApplicationsLock);
for (int32 i = fApplications.CountItems(); i-- > 0;) {
fApplications.ItemAt(i)->PostMessage(code);
}
}
*/
void
Desktop::BroadcastToAllWindows(int32 code)
{
AutoReadLocker _(fWindowLock);
for (Window* window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
window->ServerWindow()->PostMessage(code);
}
}
int32
Desktop::GetAllWindowTargets(DelayedMessage& message)
{
AutoReadLocker _(fWindowLock);
int32 count = 0;
for (Window* window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
message.AddTarget(window->ServerWindow()->MessagePort());
++count;
}
return count;
}
int32
Desktop::GetAllAppTargets(DelayedMessage& message)
{
BAutolock _(fApplicationsLock);
for (int32 index = 0; index < fApplications.CountItems(); ++index)
message.AddTarget(fApplications.ItemAt(index)->MessagePort());
return fApplications.CountItems();
}
filter_result
Desktop::KeyEvent(uint32 what, int32 key, int32 modifiers)
{
filter_result result = B_DISPATCH_MESSAGE;
if (LockAllWindows()) {
Window* window = MouseEventWindow();
if (window == NULL)
window = WindowAt(fLastMousePosition);
if (window != NULL) {
if (what == B_MODIFIERS_CHANGED)
window->ModifiersChanged(modifiers);
}
if (NotifyKeyPressed(what, key, modifiers))
result = B_SKIP_MESSAGE;
UnlockAllWindows();
}
return result;
}
void
Desktop::SetCursor(ServerCursor* newCursor)
{
if (newCursor == NULL)
newCursor = fCursorManager.GetCursor(B_CURSOR_ID_SYSTEM_DEFAULT);
if (newCursor == fCursor)
return;
fCursor.SetTo(newCursor, false);
if (!fManagementCursor.IsSet())
HWInterface()->SetCursor(newCursor);
}
ServerCursorReference
Desktop::Cursor() const
{
return fCursor;
}
void
Desktop::SetManagementCursor(ServerCursor* newCursor)
{
if (newCursor == fManagementCursor)
return;
fManagementCursor.SetTo(newCursor, false);
HWInterface()->SetCursor(newCursor != NULL ? newCursor : fCursor.Get());
}
void
Desktop::SetLastMouseState(const BPoint& position, int32 buttons,
Window* windowUnderMouse)
{
fLastMousePosition = position;
fLastMouseButtons = buttons;
if (fLastMouseButtons == 0 && fLockedFocusWindow) {
fLockedFocusWindow = NULL;
if (fSettings->FocusFollowsMouse())
SetFocusWindow(windowUnderMouse);
}
}
void
Desktop::GetLastMouseState(BPoint* position, int32* buttons) const
{
*position = fLastMousePosition;
*buttons = fLastMouseButtons;
}
status_t
Desktop::SetScreenMode(int32 workspace, int32 id, const display_mode& mode,
bool makeDefault)
{
AutoWriteLocker _(fWindowLock);
if (workspace == B_CURRENT_WORKSPACE_INDEX)
workspace = fCurrentWorkspace;
if (workspace < 0 || workspace >= kMaxWorkspaces)
return B_BAD_VALUE;
Screen* screen = fVirtualScreen.ScreenByID(id);
if (screen == NULL)
return B_NAME_NOT_FOUND;
if (workspace == fCurrentWorkspace) {
display_mode oldMode;
screen->GetMode(oldMode);
if (!memcmp(&oldMode, &mode, sizeof(display_mode)))
return B_OK;
_SuspendDirectFrameBufferAccess();
AutoWriteLocker locker(fScreenLock);
status_t status = screen->SetMode(mode);
if (status != B_OK) {
locker.Unlock();
_ResumeDirectFrameBufferAccess();
return status;
}
} else {
screen_configuration* configuration
= fWorkspaces[workspace].CurrentScreenConfiguration().CurrentByID(
screen->ID());
if (configuration != NULL
&& !memcmp(&configuration->mode, &mode, sizeof(display_mode)))
return B_OK;
}
monitor_info info;
bool hasInfo = screen->GetMonitorInfo(info) == B_OK;
fWorkspaces[workspace].CurrentScreenConfiguration().Set(id,
hasInfo ? &info : NULL, screen->Frame(), mode);
if (makeDefault) {
fWorkspaces[workspace].StoredScreenConfiguration().Set(id,
hasInfo ? &info : NULL, screen->Frame(), mode);
StoreWorkspaceConfiguration(workspace);
}
_ScreenChanged(screen);
if (workspace == fCurrentWorkspace)
_ResumeDirectFrameBufferAccess();
return B_OK;
}
status_t
Desktop::GetScreenMode(int32 workspace, int32 id, display_mode& mode)
{
AutoReadLocker _(fScreenLock);
if (workspace == B_CURRENT_WORKSPACE_INDEX)
workspace = fCurrentWorkspace;
if (workspace < 0 || workspace >= kMaxWorkspaces)
return B_BAD_VALUE;
if (workspace == fCurrentWorkspace) {
Screen* screen = fVirtualScreen.ScreenByID(id);
if (screen == NULL)
return B_NAME_NOT_FOUND;
screen->GetMode(mode);
return B_OK;
}
screen_configuration* configuration
= fWorkspaces[workspace].CurrentScreenConfiguration().CurrentByID(id);
if (configuration == NULL)
return B_NAME_NOT_FOUND;
mode = configuration->mode;
return B_OK;
}
status_t
Desktop::GetScreenFrame(int32 workspace, int32 id, BRect& frame)
{
AutoReadLocker _(fScreenLock);
if (workspace == B_CURRENT_WORKSPACE_INDEX)
workspace = fCurrentWorkspace;
if (workspace < 0 || workspace >= kMaxWorkspaces)
return B_BAD_VALUE;
if (workspace == fCurrentWorkspace) {
Screen* screen = fVirtualScreen.ScreenByID(id);
if (screen == NULL)
return B_NAME_NOT_FOUND;
frame = screen->Frame();
return B_OK;
}
screen_configuration* configuration
= fWorkspaces[workspace].CurrentScreenConfiguration().CurrentByID(id);
if (configuration == NULL)
return B_NAME_NOT_FOUND;
frame = configuration->frame;
return B_OK;
}
void
Desktop::RevertScreenModes(uint32 workspaces)
{
if (workspaces == 0)
return;
AutoWriteLocker _(fWindowLock);
for (int32 workspace = 0; workspace < kMaxWorkspaces; workspace++) {
if ((workspaces & (1U << workspace)) == 0)
continue;
for (int32 index = 0; index < fVirtualScreen.CountScreens(); index++) {
Screen* screen = fVirtualScreen.ScreenAt(index);
screen_configuration* stored = fWorkspaces[workspace]
.StoredScreenConfiguration().CurrentByID(screen->ID());
screen_configuration* current = fWorkspaces[workspace]
.CurrentScreenConfiguration().CurrentByID(screen->ID());
if ((stored != NULL && current != NULL
&& !memcmp(&stored->mode, ¤t->mode,
sizeof(display_mode)))
|| (stored == NULL && current == NULL))
continue;
if (stored == NULL) {
fWorkspaces[workspace].CurrentScreenConfiguration()
.Remove(current);
if (workspace == fCurrentWorkspace) {
_SuspendDirectFrameBufferAccess();
_SetCurrentWorkspaceConfiguration();
_ResumeDirectFrameBufferAccess();
}
} else
SetScreenMode(workspace, screen->ID(), stored->mode, false);
}
}
}
status_t
Desktop::SetBrightness(int32 id, float brightness)
{
status_t result = HWInterface()->SetBrightness(brightness);
if (result == B_OK) {
if (fWorkspaces[0].StoredScreenConfiguration().CurrentByID(id) == NULL) {
screen_configuration* current
= fWorkspaces[0].CurrentScreenConfiguration().CurrentByID(id);
fWorkspaces[0].StoredScreenConfiguration().Set(id,
current->has_info ? ¤t->info : NULL, current->frame, current->mode);
}
fWorkspaces[0].StoredScreenConfiguration().SetBrightness(id,
brightness);
StoreWorkspaceConfiguration(0);
}
return result;
}
status_t
Desktop::LockDirectScreen(team_id team)
{
status_t status = fDirectScreenLock.LockWithTimeout(1000000L);
if (status == B_OK)
fDirectScreenTeam = team;
return status;
}
status_t
Desktop::UnlockDirectScreen(team_id team)
{
if (fDirectScreenTeam == team) {
fDirectScreenLock.Unlock();
fDirectScreenTeam = -1;
return B_OK;
}
return B_PERMISSION_DENIED;
}
*/
void
Desktop::SetWorkspaceAsync(int32 index, bool moveFocusWindow)
{
BPrivate::LinkSender link(MessagePort());
link.StartMessage(AS_ACTIVATE_WORKSPACE);
link.Attach<int32>(index);
link.Attach<bool>(moveFocusWindow);
link.Flush();
}
You must not hold any window lock when calling this method.
*/
void
Desktop::SetWorkspace(int32 index, bool moveFocusWindow)
{
LockAllWindows();
DesktopSettings settings(this);
if (index < 0 || index >= settings.WorkspacesCount()
|| index == fCurrentWorkspace) {
UnlockAllWindows();
return;
}
_SetWorkspace(index, moveFocusWindow);
UnlockAllWindows();
_SendFakeMouseMoved();
}
status_t
Desktop::SetWorkspacesLayout(int32 newColumns, int32 newRows)
{
int32 newCount = newColumns * newRows;
if (newCount < 1 || newCount > kMaxWorkspaces)
return B_BAD_VALUE;
if (!LockAllWindows())
return B_ERROR;
fSettings->SetWorkspacesLayout(newColumns, newRows);
bool workspaceChanged = CurrentWorkspace() >= newCount;
if (workspaceChanged)
_SetWorkspace(newCount - 1);
else
_WindowChanged(NULL);
UnlockAllWindows();
if (workspaceChanged)
_SendFakeMouseMoved();
return B_OK;
}
*/
BRect
Desktop::WorkspaceFrame(int32 index) const
{
BRect frame;
if (index == fCurrentWorkspace)
frame = fVirtualScreen.Frame();
else if (index >= 0 && index < fSettings->WorkspacesCount()) {
BMessage screenData;
if (fSettings->WorkspacesMessage(index)->FindMessage("screen",
&screenData) != B_OK
|| screenData.FindRect("frame", &frame) != B_OK) {
frame = fVirtualScreen.Frame();
}
}
return frame;
}
You must hold the window lock when calling this method.
*/
void
Desktop::StoreWorkspaceConfiguration(int32 index)
{
BMessage settings;
fWorkspaces[index].StoreConfiguration(settings);
fSettings->SetWorkspacesMessage(index, settings);
fSettings->Save(kWorkspacesSettings);
}
void
Desktop::AddWorkspacesView(WorkspacesView* view)
{
if (view->Window() == NULL || view->Window()->IsHidden())
return;
BAutolock _(fWorkspacesLock);
if (!fWorkspacesViews.HasItem(view))
fWorkspacesViews.AddItem(view);
}
void
Desktop::RemoveWorkspacesView(WorkspacesView* view)
{
BAutolock _(fWorkspacesLock);
fWorkspacesViews.RemoveItem(view);
}
*/
void
Desktop::SelectWindow(Window* window)
{
if (fSettings->ClickToFocusMouse()) {
if (window != fWindowUnderMouse
|| (window == fWindowUnderMouse && window != FocusWindow()))
ActivateWindow(window);
else
SetFocusWindow(window);
} else
ActivateWindow(window);
}
and make it the focus window.
If there are any modal windows on this screen, it might not actually
become the frontmost window, though, as modal windows stay in front
of their subset.
*/
void
Desktop::ActivateWindow(Window* window)
{
STRACE(("ActivateWindow(%p, %s)\n", window, window
? window->Title() : "<none>"));
if (window == NULL) {
fBack = NULL;
fFront = NULL;
return;
}
if (window->Workspaces() == 0 && window->IsNormal())
return;
AutoWriteLocker allWindowLocker(fWindowLock);
NotifyWindowActivated(window);
bool windowOnOtherWorkspace = !window->InWorkspace(fCurrentWorkspace);
if (windowOnOtherWorkspace
&& (window->Flags() & B_NOT_ANCHORED_ON_ACTIVATE) == 0) {
if ((window->Flags() & B_NO_WORKSPACE_ACTIVATION) == 0) {
uint32 workspaces = window->Workspaces();
for (int32 i = 0; i < fSettings->WorkspacesCount(); i++) {
uint32 workspace = workspace_to_workspaces(i);
if (workspaces & workspace) {
SetWorkspace(i);
windowOnOtherWorkspace = false;
break;
}
}
} else
return;
}
if (windowOnOtherWorkspace) {
if (!window->IsNormal()) {
Window* front = _LastFocusSubsetWindow(window);
if (front == NULL) {
return;
}
ActivateWindow(front);
if (!window->InWorkspace(fCurrentWorkspace)) {
return;
}
} else {
uint32 workspaces = workspace_to_workspaces(fCurrentWorkspace);
SetWindowWorkspaces(window, workspaces);
}
}
if (window->IsMinimized()) {
window->SetMinimized(false);
ShowWindow(window);
}
if (window == FrontWindow()) {
Window* avoidsFront = window->NextWindow(fCurrentWorkspace);
while (avoidsFront && avoidsFront->IsNormal()
&& (avoidsFront->Flags() & B_AVOID_FRONT) == 0) {
avoidsFront = avoidsFront->NextWindow(fCurrentWorkspace);
}
if (avoidsFront == NULL) {
if ((window->Flags() & B_AVOID_FOCUS) == 0)
SetFocusWindow(window);
return;
}
}
WindowList windows(kWorkingList);
Window* frontmost = window->Frontmost();
const Window* lastWindowUnderMouse = fWindowUnderMouse;
CurrentWindows().RemoveWindow(window);
windows.AddWindow(window);
window->MoveToTopStackLayer();
if (frontmost != NULL && frontmost->IsModal()) {
Window* nextModal;
for (Window* modal = frontmost; modal != NULL; modal = nextModal) {
nextModal = modal->NextWindow(fCurrentWorkspace);
while (nextModal != NULL && !nextModal->IsModal()) {
nextModal = nextModal->NextWindow(fCurrentWorkspace);
}
if (nextModal != NULL && !nextModal->HasInSubset(window))
nextModal = NULL;
CurrentWindows().RemoveWindow(modal);
windows.AddWindow(modal);
}
}
_BringWindowsToFront(windows, kWorkingList, true);
if ((window->Flags() & B_AVOID_FOCUS) == 0)
SetFocusWindow(window);
bool sendFakeMouseMoved = _CheckSendFakeMouseMoved(lastWindowUnderMouse);
allWindowLocker.Unlock();
if (sendFakeMouseMoved)
_SendFakeMouseMoved();
}
void
Desktop::SendWindowBehind(Window* window, Window* behindOf, bool sendStack)
{
if (!LockAllWindows())
return;
Window* orgWindow = window;
WindowStack* stack = window->GetWindowStack();
if (sendStack && stack != NULL)
window = stack->TopLayerWindow();
if (window == BackWindow()
|| !window->InWorkspace(fCurrentWorkspace)
|| (behindOf != NULL && !behindOf->InWorkspace(fCurrentWorkspace))) {
UnlockAllWindows();
return;
}
if (behindOf != NULL && window->HasInSubset(behindOf))
behindOf = NULL;
BRegion dirty(window->VisibleRegion());
Window* backmost = window->Backmost(behindOf);
const Window* lastWindowUnderMouse = fWindowUnderMouse;
CurrentWindows().RemoveWindow(window);
CurrentWindows().AddWindow(window, backmost
? backmost->NextWindow(fCurrentWorkspace) : BackWindow());
BRegion dummy;
_RebuildClippingForAllWindows(dummy);
if (sendStack) {
BRegion clean(window->VisibleRegion());
dirty.Exclude(&clean);
MarkDirty(dirty);
}
_UpdateFronts();
if (fSettings->FocusFollowsMouse())
SetFocusWindow(WindowAt(fLastMousePosition));
else if (fSettings->NormalMouse())
SetFocusWindow(NULL);
_WindowChanged(window);
if (sendStack && stack != NULL) {
for (int32 i = 0; i < stack->CountWindows(); i++) {
Window* stackWindow = stack->LayerOrder().ItemAt(i);
if (stackWindow == window)
continue;
SendWindowBehind(stackWindow, behindOf, false);
}
}
bool sendFakeMouseMoved = _CheckSendFakeMouseMoved(lastWindowUnderMouse);
NotifyWindowSentBehind(orgWindow, behindOf);
UnlockAllWindows();
if (sendFakeMouseMoved)
_SendFakeMouseMoved();
}
void
Desktop::ShowWindow(Window* window)
{
if (!window->IsHidden())
return;
AutoWriteLocker locker(fWindowLock);
window->SetHidden(false);
fFocusList.AddWindow(window);
if (window->InWorkspace(fCurrentWorkspace)
|| (window->IsFloating() && _LastFocusSubsetWindow(window) != NULL)) {
_ShowWindow(window, true);
_UpdateSubsetWorkspaces(window);
ActivateWindow(window);
} else {
_WindowChanged(window);
return;
}
if (window->HasWorkspacesViews()) {
BAutolock _(fWorkspacesLock);
window->FindWorkspacesViews(fWorkspacesViews);
}
_SendFakeMouseMoved(window);
}
void
Desktop::HideWindow(Window* window, bool fromMinimize)
{
if (window->IsHidden())
return;
if (!LockAllWindows())
return;
window->SetHidden(true);
fFocusList.RemoveWindow(window);
if (fMouseEventWindow == window) {
BMessage message;
int32 viewToken;
window->MouseUp(&message, fLastMousePosition, &viewToken);
fMouseEventWindow = NULL;
}
if (fLockedFocusWindow == window) {
fLockedFocusWindow = NULL;
}
if (window->InWorkspace(fCurrentWorkspace)) {
_UpdateSubsetWorkspaces(window);
_HideWindow(window);
_UpdateFronts();
} else
_WindowChanged(window);
if (FocusWindow() == window)
SetFocusWindow();
_WindowRemoved(window);
if (window->HasWorkspacesViews()) {
BObjectList<WorkspacesView> list(false);
window->FindWorkspacesViews(list);
BAutolock _(fWorkspacesLock);
while (WorkspacesView* view = list.RemoveItemAt(0)) {
fWorkspacesViews.RemoveItem(view);
}
}
NotifyWindowHidden(window, fromMinimize);
UnlockAllWindows();
if (window == fWindowUnderMouse)
_SendFakeMouseMoved();
}
void
Desktop::MinimizeWindow(Window* window, bool minimize)
{
if (!LockAllWindows())
return;
if (minimize && !window->IsHidden()) {
HideWindow(window, true);
window->SetMinimized(minimize);
NotifyWindowMinimized(window, minimize);
} else if (!minimize && window->IsHidden()) {
ActivateWindow(window);
NotifyWindowMinimized(window, minimize);
}
UnlockAllWindows();
}
void
Desktop::MoveWindowBy(Window* window, float x, float y, int32 workspace)
{
if (x == 0 && y == 0)
return;
AutoWriteLocker _(fWindowLock);
Window* topWindow = window->TopLayerStackWindow();
if (topWindow != NULL)
window = topWindow;
if (workspace == -1)
workspace = fCurrentWorkspace;
if (!window->IsVisible() || workspace != fCurrentWorkspace) {
if (workspace != fCurrentWorkspace) {
WindowStack* stack = window->GetWindowStack();
if (stack != NULL) {
for (int32 s = 0; s < stack->CountWindows(); s++) {
Window* stackWindow = stack->WindowAt(s);
if (stackWindow->Anchor(workspace).position
== kInvalidWindowPosition) {
stackWindow->Anchor(workspace).position
= stackWindow->Frame().LeftTop();
}
stackWindow->Anchor(workspace).position += BPoint(x, y);
stackWindow->SetPriorWorkspace(workspace);
_WindowChanged(stackWindow);
}
}
} else
window->MoveBy((int32)x, (int32)y);
NotifyWindowMoved(window);
return;
}
BRegion newDirtyRegion(window->VisibleRegion());
bool direct = false;
if (window->ServerWindow()->IsDirectlyAccessing()) {
window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
direct = true;
}
window->MoveBy((int32)x, (int32)y);
BRegion background;
_RebuildClippingForAllWindows(background);
BRegion copyRegion(window->VisibleRegion());
copyRegion.OffsetBy((int32)-x, (int32)-y);
copyRegion.IntersectWith(&newDirtyRegion);
newDirtyRegion.Include(&window->VisibleRegion());
if (GetDrawingEngine()->LockParallelAccess()) {
GetDrawingEngine()->CopyRegion(©Region, (int32)x, (int32)y);
GetDrawingEngine()->UnlockParallelAccess();
}
copyRegion.OffsetBy((int32)x, (int32)y);
newDirtyRegion.Exclude(©Region);
MarkDirty(newDirtyRegion);
_SetBackground(background);
_WindowChanged(window);
if (direct) {
window->ServerWindow()->HandleDirectConnection(
B_DIRECT_START | B_BUFFER_MOVED | B_CLIPPING_MODIFIED);
}
NotifyWindowMoved(window);
}
void
Desktop::ResizeWindowBy(Window* window, float x, float y)
{
if (x == 0 && y == 0)
return;
AutoWriteLocker _(fWindowLock);
Window* topWindow = window->TopLayerStackWindow();
if (topWindow)
window = topWindow;
if (!window->IsVisible()) {
window->ResizeBy((int32)x, (int32)y, NULL);
NotifyWindowResized(window);
return;
}
BRegion newDirtyRegion;
BRegion previouslyOccupiedRegion(window->VisibleRegion());
BRegion previousVisibleContentRegion(window->VisibleContentRegion());
bool direct = false;
if (window->ServerWindow()->IsDirectlyAccessing()) {
window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
direct = true;
}
window->ResizeBy((int32)x, (int32)y, &newDirtyRegion);
BRegion background;
_RebuildClippingForAllWindows(background);
previouslyOccupiedRegion.Exclude(&window->VisibleRegion());
newDirtyRegion.IntersectWith(&window->VisibleRegion());
newDirtyRegion.Include(&previouslyOccupiedRegion);
BRegion exposeRegion(previouslyOccupiedRegion);
exposeRegion.Exclude(&window->VisibleRegion());
BRegion tmp(window->VisibleContentRegion());
tmp.Exclude(&previousVisibleContentRegion);
exposeRegion.Include(&tmp);
MarkDirty(newDirtyRegion, exposeRegion);
_SetBackground(background);
_WindowChanged(window);
if (direct) {
window->ServerWindow()->HandleDirectConnection(
B_DIRECT_START | B_BUFFER_RESIZED | B_CLIPPING_MODIFIED);
}
NotifyWindowResized(window);
}
void
Desktop::SetWindowOutlinesDelta(Window* window, BPoint delta)
{
AutoWriteLocker _(fWindowLock);
if (!window->IsVisible())
return;
BRegion newDirtyRegion;
window->SetOutlinesDelta(delta, &newDirtyRegion);
BRegion background;
_RebuildClippingForAllWindows(background);
MarkDirty(newDirtyRegion);
_SetBackground(background);
}
bool
Desktop::SetWindowTabLocation(Window* window, float location, bool isShifting)
{
AutoWriteLocker _(fWindowLock);
BRegion dirty;
bool changed = window->SetTabLocation(location, isShifting, dirty);
if (changed)
RebuildAndRedrawAfterWindowChange(window, dirty);
NotifyWindowTabLocationChanged(window, location, isShifting);
return changed;
}
bool
Desktop::SetWindowDecoratorSettings(Window* window, const BMessage& settings)
{
AutoWriteLocker _(fWindowLock);
BRegion dirty;
bool changed = window->SetDecoratorSettings(settings, dirty);
bool listenerChanged = SetDecoratorSettings(window, settings);
if (changed || listenerChanged)
RebuildAndRedrawAfterWindowChange(window, dirty);
return changed;
}
void
Desktop::SetWindowWorkspaces(Window* window, uint32 workspaces)
{
LockAllWindows();
if (window->IsNormal() && workspaces == B_CURRENT_WORKSPACE)
workspaces = workspace_to_workspaces(CurrentWorkspace());
WindowStack* stack = window->GetWindowStack();
if (stack != NULL) {
for (int32 s = 0; s < stack->CountWindows(); s++) {
window = stack->LayerOrder().ItemAt(s);
uint32 oldWorkspaces = window->Workspaces();
window->WorkspacesChanged(oldWorkspaces, workspaces);
_ChangeWindowWorkspaces(window, oldWorkspaces, workspaces);
}
}
UnlockAllWindows();
}
At this point, the window is still hidden and must be shown explicitly
via ShowWindow().
*/
void
Desktop::AddWindow(Window *window)
{
LockAllWindows();
fAllWindows.AddWindow(window);
if (!window->IsNormal())
fSubsetWindows.AddWindow(window);
if (window->IsNormal()) {
if (window->Workspaces() == B_CURRENT_WORKSPACE)
window->SetWorkspaces(workspace_to_workspaces(CurrentWorkspace()));
} else {
window->SetWorkspaces(window->SubsetWorkspaces());
}
_ChangeWindowWorkspaces(window, 0, window->Workspaces());
NotifyWindowAdded(window);
UnlockAllWindows();
}
void
Desktop::RemoveWindow(Window *window)
{
LockAllWindows();
if (!window->IsHidden())
HideWindow(window);
fAllWindows.RemoveWindow(window);
if (!window->IsNormal())
fSubsetWindows.RemoveWindow(window);
_ChangeWindowWorkspaces(window, window->Workspaces(), 0);
NotifyWindowRemoved(window);
UnlockAllWindows();
EventDispatcher().RemoveTarget(window->EventTarget());
}
bool
Desktop::AddWindowToSubset(Window* subset, Window* window)
{
if (!subset->AddToSubset(window))
return false;
_ChangeWindowWorkspaces(subset, subset->Workspaces(),
subset->SubsetWorkspaces());
return true;
}
void
Desktop::RemoveWindowFromSubset(Window* subset, Window* window)
{
subset->RemoveFromSubset(window);
_ChangeWindowWorkspaces(subset, subset->Workspaces(),
subset->SubsetWorkspaces());
}
void
Desktop::FontsChanged(Window* window)
{
AutoWriteLocker _(fWindowLock);
BRegion dirty;
window->FontsChanged(&dirty);
RebuildAndRedrawAfterWindowChange(window, dirty);
fCursorManager.InitializeCursors(fSettings->DefaultBoldFont().Size() / 12.0f);
}
void
Desktop::ColorUpdated(Window* window, color_which which, rgb_color color)
{
AutoWriteLocker _(fWindowLock);
window->TopView()->ColorUpdated(which, color);
switch (which) {
case B_WINDOW_TAB_COLOR:
case B_WINDOW_TEXT_COLOR:
case B_WINDOW_INACTIVE_TAB_COLOR:
case B_WINDOW_INACTIVE_TEXT_COLOR:
case B_WINDOW_BORDER_COLOR:
case B_WINDOW_INACTIVE_BORDER_COLOR:
break;
default:
return;
}
BRegion dirty;
window->ColorsChanged(&dirty);
RebuildAndRedrawAfterWindowChange(window, dirty);
}
void
Desktop::SetWindowLook(Window* window, window_look newLook)
{
if (window->Look() == newLook)
return;
AutoWriteLocker _(fWindowLock);
BRegion dirty;
window->SetLook(newLook, &dirty);
RebuildAndRedrawAfterWindowChange(window, dirty);
NotifyWindowLookChanged(window, newLook);
}
void
Desktop::SetWindowFeel(Window* window, window_feel newFeel)
{
if (window->Feel() == newFeel)
return;
LockAllWindows();
bool wasNormal = window->IsNormal();
window->SetFeel(newFeel);
if (window->IsNormal() && !wasNormal)
fSubsetWindows.RemoveWindow(window);
else if (!window->IsNormal() && wasNormal)
fSubsetWindows.AddWindow(window);
if (!window->IsNormal()) {
_ChangeWindowWorkspaces(window, window->Workspaces(),
window->SubsetWorkspaces());
}
for (int32 i = 0; i < kMaxWorkspaces; i++) {
if (!workspace_in_workspaces(i, window->Workspaces()))
continue;
bool changed = false;
BRegion visibleBefore;
if (i == fCurrentWorkspace && window->IsVisible())
visibleBefore = window->VisibleRegion();
Window* backmost = window->Backmost(_Windows(i).LastWindow(), i);
if (backmost != NULL) {
Window* previous = window->PreviousWindow(i);
while (previous != NULL) {
if (previous == backmost)
break;
previous = previous->PreviousWindow(i);
}
if (previous == NULL) {
_Windows(i).RemoveWindow(window);
_Windows(i).AddWindow(window, backmost->NextWindow(i));
changed = true;
}
}
Window* frontmost = window->Frontmost(_Windows(i).FirstWindow(), i);
if (frontmost != NULL) {
Window* next = window->NextWindow(i);
while (next != NULL) {
if (next == frontmost)
break;
next = next->NextWindow(i);
}
if (next == NULL) {
_Windows(i).RemoveWindow(window);
_Windows(i).AddWindow(window, frontmost);
changed = true;
}
}
if (i == fCurrentWorkspace && changed) {
BRegion dummy;
_RebuildClippingForAllWindows(dummy);
BRegion visibleAfter(window->VisibleRegion());
BRegion dirty(visibleAfter);
dirty.Exclude(&visibleBefore);
visibleBefore.Exclude(&visibleAfter);
dirty.Include(&visibleBefore);
MarkDirty(dirty);
}
}
_UpdateFronts();
if (window == FocusWindow() && !window->IsVisible())
SetFocusWindow();
NotifyWindowFeelChanged(window, newFeel);
UnlockAllWindows();
}
void
Desktop::SetWindowFlags(Window *window, uint32 newFlags)
{
if (window->Flags() == newFlags)
return;
AutoWriteLocker _(fWindowLock);
BRegion dirty;
window->SetFlags(newFlags, &dirty);
RebuildAndRedrawAfterWindowChange(window, dirty);
}
void
Desktop::SetWindowTitle(Window *window, const char* title)
{
AutoWriteLocker _(fWindowLock);
BRegion dirty;
window->SetTitle(title, dirty);
RebuildAndRedrawAfterWindowChange(window, dirty);
}
You need to have acquired the All Windows lock when calling this method.
*/
Window*
Desktop::WindowAt(BPoint where)
{
for (Window* window = CurrentWindows().LastWindow(); window;
window = window->PreviousWindow(fCurrentWorkspace)) {
if (window->IsVisible() && window->VisibleRegion().Contains(where))
return window->StackedWindowAt(where);
}
return NULL;
}
void
Desktop::SetMouseEventWindow(Window* window)
{
fMouseEventWindow = window;
}
void
Desktop::SetViewUnderMouse(const Window* window, int32 viewToken)
{
fWindowUnderMouse = window;
fViewUnderMouse = viewToken;
}
int32
Desktop::ViewUnderMouse(const Window* window)
{
if (window != NULL && fWindowUnderMouse == window)
return fViewUnderMouse;
return B_NULL_TOKEN;
}
top-most window (in case it has the kAcceptKeyboardFocusFlag flag set), or
the one having focus.
The window lock must be held when calling this function.
*/
EventTarget*
Desktop::KeyboardEventTarget()
{
Window* window = CurrentWindows().LastWindow();
while (window != NULL && window->IsHidden()) {
window = window->PreviousWindow(fCurrentWorkspace);
}
if (window != NULL && (window->Flags() & kAcceptKeyboardFocusFlag) != 0)
return &window->EventTarget();
if (FocusWindow() != NULL)
return &FocusWindow()->EventTarget();
return NULL;
}
however, that the window actually can have focus. You are allowed to pass
in a NULL pointer for \a focus.
Besides the B_AVOID_FOCUS flag, a modal window, or a BWindowScreen can both
prevent it from getting focus.
In any case, this method makes sure that there is a focus window, if there
is any window at all, that is.
*/
void
Desktop::SetFocusWindow(Window* nextFocus)
{
if (!LockAllWindows())
return;
if (fLockedFocusWindow && nextFocus != fLockedFocusWindow) {
UnlockAllWindows();
return;
}
bool hasModal = _WindowHasModal(nextFocus);
bool hasWindowScreen = false;
if (!hasModal && nextFocus != NULL) {
Window* window = nextFocus;
while (true) {
window = window->NextWindow(fCurrentWorkspace);
if (window == NULL || window->Feel() == kWindowScreenFeel)
break;
}
if (window != NULL)
hasWindowScreen = true;
}
if (nextFocus == fFocus && nextFocus != NULL && !nextFocus->IsHidden()
&& (nextFocus->Flags() & B_AVOID_FOCUS) == 0
&& !hasModal && !hasWindowScreen) {
UnlockAllWindows();
return;
}
uint32 listIndex = fCurrentWorkspace;
WindowList* list = &_Windows(fCurrentWorkspace);
if (!fSettings->NormalMouse()) {
listIndex = kFocusList;
list = &fFocusList;
}
if (nextFocus == NULL || hasModal || hasWindowScreen) {
nextFocus = list->LastWindow();
if (fSettings->NormalMouse()) {
Window* lastFocus = fFocusList.LastWindow();
if (lastFocus != NULL && !lastFocus->SupportsFront()
&& _WindowCanHaveFocus(lastFocus)) {
nextFocus = lastFocus;
}
}
}
while (nextFocus != NULL && !_WindowCanHaveFocus(nextFocus)) {
nextFocus = nextFocus->PreviousWindow(listIndex);
}
if (fFocus == nextFocus) {
UnlockAllWindows();
return;
}
team_id oldActiveApp = -1;
team_id newActiveApp = -1;
if (fFocus != NULL) {
fFocus->SetFocus(false);
oldActiveApp = fFocus->ServerWindow()->App()->ClientTeam();
}
fFocus = nextFocus;
if (fFocus != NULL) {
fFocus->SetFocus(true);
newActiveApp = fFocus->ServerWindow()->App()->ClientTeam();
fFocusList.RemoveWindow(fFocus);
fFocusList.AddWindow(fFocus);
}
if (newActiveApp == -1) {
HWInterface()->SetCursorVisible(true);
}
UnlockAllWindows();
if (oldActiveApp == newActiveApp)
return;
BAutolock locker(fApplicationsLock);
for (int32 i = 0; i < fApplications.CountItems(); i++) {
ServerApp* app = fApplications.ItemAt(i);
if (oldActiveApp != -1 && app->ClientTeam() == oldActiveApp)
app->Activate(false);
else if (newActiveApp != -1 && app->ClientTeam() == newActiveApp)
app->Activate(true);
}
}
void
Desktop::SetFocusLocked(const Window* window)
{
AutoWriteLocker _(fWindowLock);
if (window != NULL) {
if (fLastMouseButtons == 0)
return;
}
fLockedFocusWindow = window;
}
Window*
Desktop::FindWindowByClientToken(int32 token, team_id teamID)
{
for (Window *window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (window->ServerWindow()->ClientToken() == token
&& window->ServerWindow()->ClientTeam() == teamID) {
return window;
}
}
return NULL;
}
::EventTarget*
Desktop::FindTarget(BMessenger& messenger)
{
for (Window *window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (window->EventTarget().Messenger() == messenger)
return &window->EventTarget();
}
return NULL;
}
void
Desktop::MarkDirty(BRegion& dirtyRegion, BRegion& exposeRegion)
{
if (dirtyRegion.CountRects() == 0)
return;
if (LockAllWindows()) {
_TriggerWindowRedrawing(dirtyRegion, exposeRegion);
UnlockAllWindows();
}
}
void
Desktop::Redraw()
{
BRegion dirty(fVirtualScreen.Frame());
MarkDirty(dirty);
}
*/
void
Desktop::RedrawBackground()
{
LockAllWindows();
BRegion redraw;
Window* window = CurrentWindows().FirstWindow();
if (window != NULL && window->Feel() == kDesktopWindowFeel) {
redraw = window->VisibleContentRegion();
View* view = window->TopView();
if (view != NULL)
view = view->FirstChild();
while (view != NULL) {
if (view->IsDesktopBackground()) {
view->SetViewColor(fWorkspaces[fCurrentWorkspace].Color());
break;
}
view = view->NextSibling();
}
window->ProcessDirtyRegion(redraw);
} else {
redraw = BackgroundRegion();
fBackgroundRegion.MakeEmpty();
_SetBackground(redraw);
}
_WindowChanged(NULL);
UnlockAllWindows();
}
bool
Desktop::ReloadDecor(DecorAddOn* oldDecor)
{
AutoWriteLocker _(fWindowLock);
bool returnValue = true;
if (oldDecor != NULL) {
const DesktopListenerList* oldListeners
= &oldDecor->GetDesktopListeners();
for (int i = 0; i < oldListeners->CountItems(); i++)
UnregisterListener(oldListeners->ItemAt(i));
}
for (Window* window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
BRegion oldBorder;
window->GetBorderRegion(&oldBorder);
if (!window->ReloadDecor()) {
returnValue = false;
}
BRegion border;
window->GetBorderRegion(&border);
border.Include(&oldBorder);
RebuildAndRedrawAfterWindowChange(window, border);
}
const DesktopListenerList& newListeners
= gDecorManager.GetDesktopListeners();
for (int i = 0; i < newListeners.CountItems(); i++)
RegisterListener(newListeners.ItemAt(i));
return returnValue;
}
void
Desktop::MinimizeApplication(team_id team)
{
AutoWriteLocker locker(fWindowLock);
for (Window *window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (window->ServerWindow()->ClientTeam() != team)
continue;
window->ServerWindow()->NotifyMinimize(true);
}
}
void
Desktop::BringApplicationToFront(team_id team)
{
AutoWriteLocker locker(fWindowLock);
for (Window *window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (window->ServerWindow()->ClientTeam() != team)
continue;
window->ServerWindow()->NotifyMinimize(false);
}
}
void
Desktop::WindowAction(int32 windowToken, int32 action)
{
if (action != B_MINIMIZE_WINDOW && action != B_BRING_TO_FRONT)
return;
LockAllWindows();
::ServerWindow* serverWindow;
Window* window;
if (BPrivate::gDefaultTokens.GetToken(windowToken,
B_SERVER_TOKEN, (void**)&serverWindow) != B_OK
|| (window = serverWindow->Window()) == NULL) {
UnlockAllWindows();
return;
}
if (action == B_BRING_TO_FRONT && !window->IsMinimized()) {
ActivateWindow(window);
} else {
serverWindow->NotifyMinimize(action == B_MINIMIZE_WINDOW);
}
UnlockAllWindows();
}
void
Desktop::WriteWindowList(team_id team, BPrivate::LinkSender& sender)
{
AutoWriteLocker locker(fWindowLock);
int32 count = 0;
for (Window *window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (team < B_OK || window->ServerWindow()->ClientTeam() == team)
count++;
}
sender.StartMessage(B_OK);
sender.Attach<int32>(count);
for (Window *window = CurrentWindows().LastWindow(); window != NULL;
window = window->PreviousWindow(fCurrentWorkspace)) {
if (team >= B_OK && window->ServerWindow()->ClientTeam() != team)
continue;
sender.Attach<int32>(window->ServerWindow()->ServerToken());
}
for (Window *window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if ((team >= B_OK && window->ServerWindow()->ClientTeam() != team)
|| window->InWorkspace(fCurrentWorkspace))
continue;
sender.Attach<int32>(window->ServerWindow()->ServerToken());
}
sender.Flush();
}
void
Desktop::WriteWindowInfo(int32 serverToken, BPrivate::LinkSender& sender)
{
AutoWriteLocker locker(fWindowLock);
BAutolock tokenLocker(BPrivate::gDefaultTokens);
::ServerWindow* window;
if (BPrivate::gDefaultTokens.GetToken(serverToken,
B_SERVER_TOKEN, (void**)&window) != B_OK) {
sender.StartMessage(B_ENTRY_NOT_FOUND);
sender.Flush();
return;
}
window_info info;
window->GetInfo(info);
float tabSize = 0.0;
float borderSize = 0.0;
::Window* tmp = window->Window();
if (tmp) {
BMessage message;
if (tmp->GetDecoratorSettings(&message)) {
BRect tabFrame;
message.FindRect("tab frame", &tabFrame);
tabSize = tabFrame.bottom - tabFrame.top;
message.FindFloat("border width", &borderSize);
}
}
int32 length = window->Title() ? strlen(window->Title()) : 0;
sender.StartMessage(B_OK);
sender.Attach<int32>(sizeof(client_window_info) + length + 1);
sender.Attach(&info, sizeof(window_info));
sender.Attach<float>(tabSize);
sender.Attach<float>(borderSize);
if (length > 0)
sender.Attach(window->Title(), length + 1);
else
sender.Attach<char>('\0');
sender.Flush();
}
void
Desktop::WriteWindowOrder(int32 workspace, BPrivate::LinkSender& sender)
{
LockSingleWindow();
if (workspace < 0)
workspace = fCurrentWorkspace;
else if (workspace >= kMaxWorkspaces) {
sender.StartMessage(B_BAD_VALUE);
sender.Flush();
UnlockSingleWindow();
return;
}
int32 count = _Windows(workspace).Count();
sender.StartMessage(B_OK);
sender.Attach<int32>(count);
for (Window *window = _Windows(workspace).LastWindow(); window != NULL;
window = window->PreviousWindow(workspace)) {
sender.Attach<int32>(window->ServerWindow()->ServerToken());
}
sender.Flush();
UnlockSingleWindow();
}
void
Desktop::WriteApplicationOrder(int32 workspace, BPrivate::LinkSender& sender)
{
fApplicationsLock.Lock();
LockSingleWindow();
int32 maxCount = fApplications.CountItems();
fApplicationsLock.Unlock();
if (workspace < 0)
workspace = fCurrentWorkspace;
else if (workspace >= kMaxWorkspaces) {
sender.StartMessage(B_BAD_VALUE);
sender.Flush();
UnlockSingleWindow();
return;
}
team_id* teams = (team_id*)malloc(maxCount * sizeof(team_id));
if (teams == NULL) {
sender.StartMessage(B_NO_MEMORY);
sender.Flush();
UnlockSingleWindow();
return;
}
int32 count = 0;
for (Window *window = _Windows(workspace).LastWindow(); window != NULL;
window = window->PreviousWindow(workspace)) {
team_id team = window->ServerWindow()->ClientTeam();
if (count > 1) {
bool found = false;
for (int32 i = 0; i < count; i++) {
if (teams[i] == team) {
found = true;
break;
}
}
if (found)
continue;
}
ASSERT(count < maxCount);
teams[count++] = team;
}
UnlockSingleWindow();
sender.StartMessage(B_OK);
sender.Attach<int32>(count);
for (int32 i = 0; i < count; i++) {
sender.Attach<int32>(teams[i]);
}
sender.Flush();
free(teams);
}
void
Desktop::_LaunchInputServer()
{
BRoster roster;
status_t status = roster.Launch("application/x-vnd.Be-input_server");
if (status == B_OK || status == B_ALREADY_RUNNING)
return;
BEntry entry;
BPath inputServerPath;
if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, &inputServerPath) == B_OK
&& inputServerPath.Append("input_server") == B_OK) {
entry.SetTo(inputServerPath.Path());
} else
entry.SetTo("/system/servers/input_server");
entry_ref ref;
status_t entryStatus = entry.GetRef(&ref);
if (entryStatus == B_OK)
entryStatus = roster.Launch(&ref);
if (entryStatus == B_OK || entryStatus == B_ALREADY_RUNNING) {
syslog(LOG_ERR, "Failed to launch the input server by signature: %s!\n",
strerror(status));
return;
}
syslog(LOG_ERR, "Failed to launch the input server: %s!\n",
strerror(entryStatus));
}
void
Desktop::_GetLooperName(char* name, size_t length)
{
snprintf(name, length, "d:%d:%s", fUserID,
fTargetScreen == NULL ? "baron" : fTargetScreen);
}
void
Desktop::_PrepareQuit()
{
fApplicationsLock.Lock();
int32 count = fApplications.CountItems();
for (int32 i = 0; i < count; i++) {
ServerApp *app = fApplications.ItemAt(i);
team_id clientTeam = app->ClientTeam();
app->Quit();
kill_team(clientTeam);
}
if (count > 0) {
acquire_sem_etc(fShutdownSemaphore, fShutdownCount, B_RELATIVE_TIMEOUT,
250000);
}
fApplicationsLock.Unlock();
}
void
Desktop::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
{
switch (code) {
case AS_CREATE_APP:
{
team_id clientTeamID = -1;
port_id clientLooperPort = -1;
port_id clientReplyPort = -1;
int32 htoken = B_NULL_TOKEN;
char* appSignature = NULL;
link.Read<port_id>(&clientReplyPort);
link.Read<port_id>(&clientLooperPort);
link.Read<team_id>(&clientTeamID);
link.Read<int32>(&htoken);
if (link.ReadString(&appSignature) != B_OK)
break;
ObjectDeleter<ServerApp> app(new (std::nothrow) ServerApp(this, clientReplyPort,
clientLooperPort, clientTeamID, htoken, appSignature));
status_t status = B_OK;
if (!app.IsSet())
status = B_NO_MEMORY;
if (status == B_OK)
status = app->InitCheck();
if (status == B_OK)
status = app->Run();
if (status == B_OK) {
fApplicationsLock.Lock();
fApplications.AddItem(app.Detach());
fApplicationsLock.Unlock();
} else {
BPrivate::LinkSender reply(clientReplyPort);
reply.StartMessage(status);
reply.Flush();
}
free(appSignature);
break;
}
case AS_DELETE_APP:
{
thread_id thread = -1;
if (link.Read<thread_id>(&thread) < B_OK)
break;
fApplicationsLock.Lock();
int32 count = fApplications.CountItems();
ServerApp* removeApp = NULL;
for (int32 i = 0; i < count; i++) {
ServerApp* app = fApplications.ItemAt(i);
if (app->Thread() == thread) {
fApplications.RemoveItemAt(i);
removeApp = app;
break;
}
}
fApplicationsLock.Unlock();
if (removeApp != NULL)
removeApp->Quit(fShutdownSemaphore);
if (fQuitting && count <= 1) {
acquire_sem_etc(fShutdownSemaphore, fShutdownCount,
B_RELATIVE_TIMEOUT, 500000);
PostMessage(kMsgQuitLooper);
}
break;
}
case AS_ACTIVATE_APP:
{
status_t status;
port_id replyPort;
team_id team;
if (link.Read(&replyPort) == B_OK
&& link.Read(&team) == B_OK)
status = _ActivateApp(team);
else
status = B_ERROR;
BPrivate::PortLink replyLink(replyPort);
replyLink.StartMessage(status);
replyLink.Flush();
break;
}
case AS_APP_CRASHED:
case AS_DUMP_ALLOCATOR:
case AS_DUMP_BITMAPS:
{
BAutolock locker(fApplicationsLock);
team_id team;
if (link.Read(&team) != B_OK)
break;
for (int32 i = 0; i < fApplications.CountItems(); i++) {
ServerApp* app = fApplications.ItemAt(i);
if (app->ClientTeam() == team)
app->PostMessage(code);
}
break;
}
case AS_EVENT_STREAM_CLOSED:
_LaunchInputServer();
break;
case B_QUIT_REQUESTED:
fApplicationsLock.Lock();
fShutdownSemaphore = create_sem(0, "desktop shutdown");
fShutdownCount = fApplications.CountItems();
fApplicationsLock.Unlock();
fQuitting = true;
BroadcastToAllApps(AS_QUIT_APP);
if (fShutdownCount == 0)
PostMessage(kMsgQuitLooper);
break;
case AS_ACTIVATE_WORKSPACE:
{
int32 index;
link.Read<int32>(&index);
if (index == -1)
index = fPreviousWorkspace;
bool moveFocusWindow;
link.Read<bool>(&moveFocusWindow);
SetWorkspace(index, moveFocusWindow);
break;
}
case AS_TALK_TO_DESKTOP_LISTENER:
{
port_id clientReplyPort;
if (link.Read<port_id>(&clientReplyPort) != B_OK)
break;
BPrivate::LinkSender reply(clientReplyPort);
AutoWriteLocker locker(fWindowLock);
if (MessageForListener(NULL, link, reply) != true) {
if (link.NeedsReply()) {
reply.StartMessage(B_ERROR);
reply.Flush();
}
}
break;
}
case AS_SET_UI_COLOR:
{
color_which which;
rgb_color color;
if (link.Read<color_which>(&which) == B_OK
&& link.Read<rgb_color>(&color) == B_OK) {
const char* colorName = ui_color_name(which);
fPendingColors.SetColor(colorName, color);
DelayedMessage delayed(AS_SET_UI_COLORS, DM_60HZ_DELAY);
delayed.AddTarget(MessagePort());
delayed.SetMerge(DM_MERGE_CANCEL);
delayed.Attach<bool>(true);
delayed.Flush();
}
break;
}
case AS_SET_UI_COLORS:
{
bool flushPendingOnly = false;
if (link.Read<bool>(&flushPendingOnly) != B_OK
|| (flushPendingOnly &&
fPendingColors.CountNames(B_RGB_32_BIT_TYPE) == 0)) {
break;
}
if (!flushPendingOnly) {
color_which which = B_NO_COLOR;
rgb_color color;
do {
if (link.Read<color_which>(&which) != B_OK
|| link.Read<rgb_color>(&color) != B_OK)
break;
fPendingColors.SetColor(ui_color_name(which), color);
} while (which != B_NO_COLOR);
}
_FlushPendingColors();
break;
}
case 'KDLE':
{
BRegion dirty;
dirty.Include(fVirtualScreen.Frame());
MarkDirty(dirty);
break;
}
default:
printf("Desktop %d:%s received unexpected code %" B_PRId32 "\n", 0,
"baron", code);
if (link.NeedsReply()) {
fLink.StartMessage(B_ERROR);
fLink.Flush();
}
break;
}
}
WindowList&
Desktop::CurrentWindows()
{
return fWorkspaces[fCurrentWorkspace].Windows();
}
WindowList&
Desktop::AllWindows()
{
return fAllWindows;
}
Window*
Desktop::WindowForClientLooperPort(port_id port)
{
ASSERT_MULTI_LOCKED(fWindowLock);
for (Window* window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (window->ServerWindow()->ClientLooperPort() == port)
return window;
}
return NULL;
}
WindowList&
Desktop::_Windows(int32 index)
{
ASSERT(index >= 0 && index < kMaxWorkspaces);
return fWorkspaces[index].Windows();
}
void
Desktop::_FlushPendingColors()
{
int32 count = fPendingColors.CountNames(B_RGB_32_BIT_TYPE);
if (count == 0)
return;
bool changed[count];
LockedDesktopSettings settings(this);
settings.SetUIColors(fPendingColors, &changed[0]);
int32 index = 0;
char* name = NULL;
type_code type = B_RGB_32_BIT_TYPE;
rgb_color color;
color_which which = B_NO_COLOR;
BMessage clientMessage(B_COLORS_UPDATED);
while (fPendingColors.GetInfo(type, index, &name, &type) == B_OK) {
which = which_ui_color(name);
if (which == B_NO_COLOR || fPendingColors.FindColor(name,
&color) != B_OK || !changed[index]) {
++index;
continue;
}
for (Window* window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
ColorUpdated(window, which, color);
}
clientMessage.AddColor(name, color);
++index;
}
BAutolock appListLock(fApplicationsLock);
for (int32 index = 0; index < fApplications.CountItems(); ++index) {
fApplications.ItemAt(index)->SendMessageToClient(&clientMessage);
}
fPendingColors.MakeEmpty();
}
void
Desktop::_UpdateFloating(int32 previousWorkspace, int32 nextWorkspace,
Window* mouseEventWindow)
{
if (previousWorkspace == -1)
previousWorkspace = fCurrentWorkspace;
if (nextWorkspace == -1)
nextWorkspace = previousWorkspace;
for (Window* floating = fSubsetWindows.FirstWindow(); floating != NULL;
floating = floating->NextWindow(kSubsetList)) {
if (floating->Feel() != B_FLOATING_SUBSET_WINDOW_FEEL
&& floating->Feel() != B_FLOATING_APP_WINDOW_FEEL)
continue;
if (fFront != NULL && fFront->IsNormal()
&& floating->HasInSubset(fFront)) {
if (_Windows(previousWorkspace).HasWindow(floating)
&& previousWorkspace != nextWorkspace
&& !floating->InSubsetWorkspace(previousWorkspace)) {
_Windows(previousWorkspace).RemoveWindow(floating);
floating->SetCurrentWorkspace(-1);
}
if (!_Windows(nextWorkspace).HasWindow(floating)) {
_Windows(nextWorkspace).AddWindow(floating,
floating->Frontmost(_Windows(nextWorkspace).FirstWindow(),
nextWorkspace));
floating->SetCurrentWorkspace(nextWorkspace);
if (mouseEventWindow != fFront)
_ShowWindow(floating);
}
} else if (_Windows(previousWorkspace).HasWindow(floating)
&& !floating->InSubsetWorkspace(previousWorkspace)) {
_Windows(previousWorkspace).RemoveWindow(floating);
floating->SetCurrentWorkspace(-1);
_HideWindow(floating);
if (FocusWindow() == floating)
SetFocusWindow();
}
}
}
(only desktop windows can't be back windows)
*/
void
Desktop::_UpdateBack()
{
fBack = NULL;
for (Window* window = CurrentWindows().FirstWindow(); window != NULL;
window = window->NextWindow(fCurrentWorkspace)) {
if (window->IsHidden() || window->Feel() == kDesktopWindowFeel)
continue;
fBack = window;
break;
}
}
(only normal and modal windows can be front windows)
The only place where you don't want to update floating windows is
during a workspace change - because then you'll call _UpdateFloating()
yourself.
*/
void
Desktop::_UpdateFront(bool updateFloating)
{
fFront = NULL;
for (Window* window = CurrentWindows().LastWindow(); window != NULL;
window = window->PreviousWindow(fCurrentWorkspace)) {
if (window->IsHidden() || window->IsFloating()
|| !window->SupportsFront())
continue;
fFront = window;
break;
}
if (updateFloating)
_UpdateFloating();
}
void
Desktop::_UpdateFronts(bool updateFloating)
{
_UpdateBack();
_UpdateFront(updateFloating);
}
bool
Desktop::_WindowHasModal(Window* window) const
{
if (window == NULL)
return false;
for (Window* modal = fSubsetWindows.FirstWindow(); modal != NULL;
modal = modal->NextWindow(kSubsetList)) {
if (!modal->IsModal() || modal->IsHidden())
continue;
if (modal->HasInSubset(window))
return true;
}
return false;
}
*/
bool
Desktop::_WindowCanHaveFocus(Window* window) const
{
return window != NULL
&& window->InWorkspace(fCurrentWorkspace)
&& (window->Flags() & B_AVOID_FOCUS) == 0
&& !_WindowHasModal(window)
&& !window->IsHidden();
}
*/
void
Desktop::_WindowChanged(Window* window)
{
ASSERT_MULTI_LOCKED(fWindowLock);
BAutolock _(fWorkspacesLock);
for (uint32 i = fWorkspacesViews.CountItems(); i-- > 0;) {
WorkspacesView* view = fWorkspacesViews.ItemAt(i);
view->WindowChanged(window);
}
}
*/
void
Desktop::_WindowRemoved(Window* window)
{
ASSERT_MULTI_LOCKED(fWindowLock);
BAutolock _(fWorkspacesLock);
for (uint32 i = fWorkspacesViews.CountItems(); i-- > 0;) {
WorkspacesView* view = fWorkspacesViews.ItemAt(i);
view->WindowRemoved(window);
}
}
Window::IsHidden() state.
*/
void
Desktop::_ShowWindow(Window* window, bool affectsOtherWindows)
{
BRegion background;
_RebuildClippingForAllWindows(background);
_SetBackground(background);
_WindowChanged(window);
BRegion dirty(window->VisibleRegion());
if (!affectsOtherWindows) {
window->ProcessDirtyRegion(dirty);
} else
MarkDirty(dirty);
if (window->ServerWindow()->HasDirectFrameBufferAccess()) {
window->ServerWindow()->HandleDirectConnection(
B_DIRECT_START | B_BUFFER_RESET);
}
}
Window::IsHidden() state.
*/
void
Desktop::_HideWindow(Window* window)
{
if (window->ServerWindow()->IsDirectlyAccessing())
window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
BRegion dirty(window->VisibleRegion());
BRegion background;
_RebuildClippingForAllWindows(background);
_SetBackground(background);
_WindowChanged(window);
MarkDirty(dirty);
}
specifed window.
If newIndex is not -1, it will move all subset windows that belong to
the specifed window to the new workspace; this form is only called by
SetWorkspace().
*/
void
Desktop::_UpdateSubsetWorkspaces(Window* window, int32 previousIndex,
int32 newIndex)
{
STRACE(("_UpdateSubsetWorkspaces(window %p, %s)\n", window,
window->Title()));
if (!window->IsNormal() || window->IsHidden())
return;
for (Window* subset = fSubsetWindows.FirstWindow(); subset != NULL;
subset = subset->NextWindow(kSubsetList)) {
if (subset->Feel() == B_MODAL_ALL_WINDOW_FEEL
|| subset->Feel() == B_FLOATING_ALL_WINDOW_FEEL) {
continue;
}
if (subset->IsFloating()) {
continue;
}
if (subset->HasInSubset(window)) {
SetWindowWorkspaces(subset, subset->SubsetWorkspaces());
}
}
}
*/
void
Desktop::_ChangeWindowWorkspaces(Window* window, uint32 oldWorkspaces,
uint32 newWorkspaces)
{
if (oldWorkspaces == newWorkspaces)
return;
LockAllWindows();
for (int32 i = 0; i < kMaxWorkspaces; i++) {
if (workspace_in_workspaces(i, oldWorkspaces)) {
if (!workspace_in_workspaces(i, newWorkspaces)) {
_Windows(i).RemoveWindow(window);
if (fLastWorkspaceFocus[i] == window)
fLastWorkspaceFocus[i] = NULL;
if (i == CurrentWorkspace()) {
window->SetCurrentWorkspace(-1);
if (!window->IsHidden())
_HideWindow(window);
}
}
} else {
if (workspace_in_workspaces(i, newWorkspaces)) {
_Windows(i).AddWindow(window,
window->Frontmost(_Windows(i).FirstWindow(), i));
if (i == CurrentWorkspace()) {
window->SetCurrentWorkspace(fCurrentWorkspace);
if (!window->IsHidden()) {
_ShowWindow(window, FrontWindow() == window);
}
}
}
}
}
int32 firstWorkspace = -1;
for (int32 i = 0; i < kMaxWorkspaces; i++) {
if ((newWorkspaces & (1L << i)) != 0) {
if (firstWorkspace != -1) {
firstWorkspace = -1;
break;
}
firstWorkspace = i;
}
}
if (firstWorkspace >= 0)
window->Anchor(firstWorkspace).position = window->Frame().LeftTop();
_UpdateSubsetWorkspaces(window);
NotifyWindowWorkspacesChanged(window, newWorkspaces);
UnlockAllWindows();
}
void
Desktop::_BringWindowsToFront(WindowList& windows, int32 list, bool wereVisible)
{
BRegion clean;
for (Window* window = windows.FirstWindow(); window != NULL;
window = window->NextWindow(list)) {
if (wereVisible)
clean.Include(&window->VisibleRegion());
CurrentWindows().AddWindow(window,
window->Frontmost(CurrentWindows().FirstWindow(),
fCurrentWorkspace));
_WindowChanged(window);
}
BRegion dummy;
_RebuildClippingForAllWindows(dummy);
BRegion dirty;
for (Window* window = windows.FirstWindow(); window != NULL;
window = window->NextWindow(list)) {
dirty.Include(&window->VisibleRegion());
}
dirty.Exclude(&clean);
MarkDirty(dirty);
_UpdateFront();
if (windows.FirstWindow() == fBack || fBack == NULL)
_UpdateBack();
}
specified \a window.
*/
Window*
Desktop::_LastFocusSubsetWindow(Window* window)
{
if (window == NULL)
return NULL;
for (Window* front = fFocusList.LastWindow(); front != NULL;
front = front->PreviousWindow(kFocusList)) {
if (front != window && !front->IsHidden()
&& window->HasInSubset(front))
return front;
}
return NULL;
}
to the previous mouse window.
You need to have the all window lock held when calling this method.
*/
bool
Desktop::_CheckSendFakeMouseMoved(const Window* lastWindowUnderMouse)
{
Window* window = WindowAt(fLastMousePosition);
return window != lastWindowUnderMouse;
}
and also updates the current view under the mouse.
This has only to be done in case the view changed without mouse movement,
ie. because of a workspace change, a closing window, or programmatic window
movement.
You must not have locked any windows when calling this method.
*/
void
Desktop::_SendFakeMouseMoved(Window* window)
{
int32 viewToken = B_NULL_TOKEN;
EventTarget* target = NULL;
LockAllWindows();
if (window == NULL)
window = WindowAt(fLastMousePosition);
if (window != NULL) {
BMessage message;
window->MouseMoved(&message, fLastMousePosition, &viewToken, true,
true);
if (viewToken != B_NULL_TOKEN)
target = &window->EventTarget();
}
if (viewToken != B_NULL_TOKEN)
SetViewUnderMouse(window, viewToken);
else {
SetViewUnderMouse(NULL, B_NULL_TOKEN);
SetCursor(NULL);
}
UnlockAllWindows();
if (target != NULL)
EventDispatcher().SendFakeMouseMoved(*target, viewToken);
}
Screen*
Desktop::_DetermineScreenFor(BRect frame)
{
AutoReadLocker _(fScreenLock);
return fVirtualScreen.ScreenAt(0);
}
void
Desktop::_RebuildClippingForAllWindows(BRegion& stillAvailableOnScreen)
{
stillAvailableOnScreen = fScreenRegion;
for (Window* window = CurrentWindows().LastWindow(); window != NULL;
window = window->PreviousWindow(fCurrentWorkspace)) {
if (!window->IsHidden()) {
window->SetClipping(&stillAvailableOnScreen);
window->SetScreen(_DetermineScreenFor(window->Frame()));
if (window->ServerWindow()->IsDirectlyAccessing()) {
window->ServerWindow()->HandleDirectConnection(
B_DIRECT_MODIFY | B_CLIPPING_MODIFIED);
}
stillAvailableOnScreen.Exclude(&window->VisibleRegion());
}
}
}
void
Desktop::_TriggerWindowRedrawing(BRegion& dirtyRegion, BRegion& exposeRegion)
{
for (Window* window = CurrentWindows().LastWindow(); window != NULL;
window = window->PreviousWindow(fCurrentWorkspace)) {
if (!window->IsHidden()
&& dirtyRegion.Intersects(window->VisibleRegion().Frame()))
window->ProcessDirtyRegion(dirtyRegion, exposeRegion);
}
}
void
Desktop::_SetBackground(BRegion& background)
{
BRegion dirtyBackground(background);
dirtyBackground.Exclude(&fBackgroundRegion);
dirtyBackground.IntersectWith(&background);
fBackgroundRegion = background;
if (dirtyBackground.Frame().IsValid()) {
if (GetDrawingEngine()->LockParallelAccess()) {
GetDrawingEngine()->FillRegion(dirtyBackground,
fWorkspaces[fCurrentWorkspace].Color());
GetDrawingEngine()->UnlockParallelAccess();
}
}
}
void
Desktop::RebuildAndRedrawAfterWindowChange(Window* changedWindow,
BRegion& dirty)
{
ASSERT_MULTI_WRITE_LOCKED(fWindowLock);
if (!changedWindow->IsVisible() || dirty.CountRects() == 0)
return;
BRegion stillAvailableOnScreen(fScreenRegion);
for (Window* window = CurrentWindows().LastWindow(); window != NULL;
window = window->PreviousWindow(fCurrentWorkspace)) {
if (!window->IsHidden()) {
if (window == changedWindow)
dirty.IntersectWith(&stillAvailableOnScreen);
window->SetClipping(&stillAvailableOnScreen);
window->SetScreen(_DetermineScreenFor(window->Frame()));
if (window->ServerWindow()->IsDirectlyAccessing()) {
window->ServerWindow()->HandleDirectConnection(
B_DIRECT_MODIFY | B_CLIPPING_MODIFIED);
}
stillAvailableOnScreen.Exclude(&window->VisibleRegion());
}
}
_SetBackground(stillAvailableOnScreen);
_WindowChanged(changedWindow);
_TriggerWindowRedrawing(dirty, dirty);
}
void
Desktop::_SuspendDirectFrameBufferAccess()
{
ASSERT_MULTI_LOCKED(fWindowLock);
for (Window* window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (window->ServerWindow()->IsDirectlyAccessing())
window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
}
}
void
Desktop::_ResumeDirectFrameBufferAccess()
{
ASSERT_MULTI_LOCKED(fWindowLock);
for (Window* window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (window->IsHidden() || !window->InWorkspace(fCurrentWorkspace))
continue;
if (window->ServerWindow()->HasDirectFrameBufferAccess()) {
window->ServerWindow()->HandleDirectConnection(
B_DIRECT_START | B_BUFFER_RESET, B_MODE_CHANGED);
}
}
}
void
Desktop::ScreenChanged(Screen* screen)
{
AutoWriteLocker windowLocker(fWindowLock);
AutoWriteLocker screenLocker(fScreenLock);
screen->SetPreferredMode();
screenLocker.Unlock();
_ScreenChanged(screen);
}
void
Desktop::_ScreenChanged(Screen* screen)
{
ASSERT_MULTI_WRITE_LOCKED(fWindowLock);
BRegion dirty(screen->Frame());
fScreenRegion.Set(screen->Frame());
gInputManager->UpdateScreenBounds(screen->Frame());
BRegion background;
_RebuildClippingForAllWindows(background);
fBackgroundRegion.MakeEmpty();
_SetBackground(background);
dirty.Exclude(&background);
_TriggerWindowRedrawing(dirty, dirty);
BMessage update(B_SCREEN_CHANGED);
update.AddInt64("when", real_time_clock_usecs());
update.AddRect("frame", screen->Frame());
update.AddInt32("mode", screen->ColorSpace());
fVirtualScreen.UpdateFrame();
for (Window* window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (window->Screen() == screen)
window->ServerWindow()->ScreenChanged(&update);
}
}
*/
status_t
Desktop::_ActivateApp(team_id team)
{
AutoWriteLocker locker(fWindowLock);
for (Window* window = CurrentWindows().LastWindow(); window != NULL;
window = window->PreviousWindow(fCurrentWorkspace)) {
if (!window->IsHidden() && window->IsNormal()
&& window->ServerWindow()->ClientTeam() == team) {
ActivateWindow(window);
return B_OK;
}
}
for (Window* window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) {
if (!window->IsHidden() && window->IsNormal()
&& window->ServerWindow()->ClientTeam() == team) {
ActivateWindow(window);
return B_OK;
}
}
return B_BAD_VALUE;
}
void
Desktop::_SetCurrentWorkspaceConfiguration()
{
ASSERT_MULTI_WRITE_LOCKED(fWindowLock);
status_t status = fDirectScreenLock.LockWithTimeout(1000000L);
if (status != B_OK) {
syslog(LOG_ERR, "Team %" B_PRId32 " did not give up its direct screen "
"lock.\n", fDirectScreenTeam);
debug_thread(fDirectScreenTeam);
fDirectScreenTeam = -1;
} else
fDirectScreenLock.Unlock();
AutoWriteLocker _(fScreenLock);
uint32 changedScreens;
fVirtualScreen.SetConfiguration(*this,
fWorkspaces[fCurrentWorkspace].CurrentScreenConfiguration(),
&changedScreens);
for (int32 i = 0; changedScreens != 0; i++, changedScreens /= 2) {
if ((changedScreens & (1 << i)) != 0)
_ScreenChanged(fVirtualScreen.ScreenAt(i));
}
}
You must hold the all window lock when calling this method.
*/
void
Desktop::_SetWorkspace(int32 index, bool moveFocusWindow)
{
ASSERT_MULTI_WRITE_LOCKED(fWindowLock);
int32 previousIndex = fCurrentWorkspace;
rgb_color previousColor = fWorkspaces[fCurrentWorkspace].Color();
bool movedMouseEventWindow = false;
Window* movedWindow = NULL;
if (moveFocusWindow) {
if (fMouseEventWindow != NULL)
movedWindow = fMouseEventWindow;
else
movedWindow = FocusWindow();
}
if (movedWindow != NULL) {
if (movedWindow->IsNormal()) {
if (!movedWindow->InWorkspace(index)) {
uint32 oldWorkspaces = movedWindow->Workspaces();
WindowStack* stack = movedWindow->GetWindowStack();
if (stack != NULL) {
for (int32 s = 0; s < stack->CountWindows(); s++) {
Window* stackWindow = stack->LayerOrder().ItemAt(s);
_Windows(previousIndex).RemoveWindow(stackWindow);
_Windows(index).AddWindow(stackWindow,
stackWindow->Frontmost(
_Windows(index).FirstWindow(), index));
stackWindow->WorkspacesChanged(oldWorkspaces,
stackWindow->Workspaces());
}
}
movedMouseEventWindow = true;
NotifyWindowWorkspacesChanged(movedWindow,
movedWindow->Workspaces());
} else {
_Windows(index).RemoveWindow(movedWindow);
_Windows(index).AddWindow(movedWindow,
movedWindow->Frontmost(_Windows(index).FirstWindow(),
index));
}
}
movedWindow->Anchor(index).position = movedWindow->Frame().LeftTop();
}
if (movedWindow == NULL || movedWindow->InWorkspace(previousIndex))
fLastWorkspaceFocus[previousIndex] = FocusWindow();
else
fLastWorkspaceFocus[previousIndex] = NULL;
BRegion dirty;
for (Window* window = CurrentWindows().FirstWindow();
window != NULL; window = window->NextWindow(previousIndex)) {
window->Anchor(previousIndex).position = window->Frame().LeftTop();
if (!window->IsHidden()
&& window->ServerWindow()->IsDirectlyAccessing())
window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
window->WorkspaceActivated(previousIndex, false);
if (window->InWorkspace(index))
continue;
if (!window->IsHidden()) {
dirty.Include(&window->VisibleRegion());
}
window->SetCurrentWorkspace(-1);
}
fPreviousWorkspace = fCurrentWorkspace;
fCurrentWorkspace = index;
_SetCurrentWorkspaceConfiguration();
WindowList windows(kWorkingList);
BList previousRegions;
for (Window* window = _Windows(index).FirstWindow();
window != NULL; window = window->NextWindow(index)) {
BPoint position = window->Anchor(index).position;
window->SetCurrentWorkspace(index);
if (window->IsHidden())
continue;
if (position == kInvalidWindowPosition) {
position = window->Frame().LeftTop();
}
if (!window->InWorkspace(previousIndex)) {
if (window->Frame().LeftTop() != position) {
BPoint offset = position - window->Frame().LeftTop();
window->MoveBy((int32)offset.x, (int32)offset.y);
}
continue;
}
if (window->Frame().LeftTop() != position) {
BPoint offset = position - window->Frame().LeftTop();
MoveWindowBy(window, offset.x, offset.y);
} else {
ObjectDeleter<BRegion> region(new (std::nothrow)
BRegion(window->VisibleRegion()));
if (region.IsSet()) {
if (previousRegions.AddItem(region.Detach()))
windows.AddWindow(window);
}
}
}
_UpdateFronts(false);
_UpdateFloating(previousIndex, index,
movedMouseEventWindow ? movedWindow : NULL);
BRegion stillAvailableOnScreen;
_RebuildClippingForAllWindows(stillAvailableOnScreen);
_SetBackground(stillAvailableOnScreen);
for (Window* window = _Windows(index).FirstWindow(); window != NULL;
window = window->NextWindow(index)) {
window->WorkspaceActivated(index, true);
if (!window->IsHidden()
&& window->ServerWindow()->HasDirectFrameBufferAccess()) {
window->ServerWindow()->HandleDirectConnection(
B_DIRECT_START | B_BUFFER_RESET, B_MODE_CHANGED);
}
if (window->InWorkspace(previousIndex) || window->IsHidden()
|| (window == movedWindow && movedWindow->IsNormal())
|| (!window->IsNormal()
&& window->HasInSubset(movedWindow))) {
continue;
}
dirty.Include(&window->VisibleRegion());
}
int32 i = 0;
for (Window* window = windows.FirstWindow(); window != NULL;
window = window->NextWindow(kWorkingList), i++) {
BRegion* region = (BRegion*)previousRegions.ItemAt(i);
region->ExclusiveInclude(&window->VisibleRegion());
dirty.Include(region);
delete region;
}
if (movedWindow != NULL)
SetFocusWindow(movedWindow);
else if (!_Windows(index).HasWindow(FocusWindow())
|| (FocusWindow() != NULL && !FocusWindow()->IsFloating()))
SetFocusWindow(fLastWorkspaceFocus[index]);
_WindowChanged(NULL);
MarkDirty(dirty);
#if 0
if (GetDrawingEngine()->LockParallelAccess()) {
GetDrawingEngine()->FillRegion(dirty, (rgb_color){255, 0, 0});
GetDrawingEngine()->UnlockParallelAccess();
snooze(100000);
}
#endif
if (previousColor != fWorkspaces[fCurrentWorkspace].Color())
RedrawBackground();
}