From 78ca6157b696f676eaa004e60d7d055f186df204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 27 Aug 2009 08:50:46 +0000 Subject: [PATCH] * Changed AS_GET_SCREEN_ID_FROM_WINDOW as well as AS_SCREEN_GET_MODE to no longer hold the window lock. There is now a lock that guards screen changes in particular. This fixes the deadlocks seen in apps using BDirectWindow. * All direct window handling now sits in the Desktop class - ServerWindow::HandleDirectConnection() is never called from anywhere else anymore. Furthermore, it's now only called when actually needed. * Resize/move actions now always send a B_CLIPPING_MODIFIED flag, too. * When the screen changed, the driver state is supposed to be B_MODE_CHANGED, not B_SCREEN_CHANGED (which is a message constant). * Direct windows are no longer suspended too late on screen changes. * Removed unused members of DirectWindowData, and cleaned it up a bit. * Made MultiLocker's default, and copy constructors private - I accidently used them, causing the ASSERT_MULTI_*LOCKED() macros to fail. * Added Unlock() to AutoWriteLocker as well. * Minor cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32742 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/Desktop.cpp | 154 ++++++++++++++++++++---- src/servers/app/Desktop.h | 9 +- src/servers/app/DirectWindowSupport.cpp | 42 ++----- src/servers/app/DirectWindowSupport.h | 38 ++---- src/servers/app/MultiLocker.h | 28 +++-- src/servers/app/ServerApp.cpp | 23 ++-- src/servers/app/ServerWindow.cpp | 63 ++++------ src/servers/app/ServerWindow.h | 33 ++--- src/servers/app/Window.cpp | 57 +++++---- src/servers/app/Window.h | 19 ++- 10 files changed, 277 insertions(+), 189 deletions(-) diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index 6488c8c0a1..c7c778ae02 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -289,13 +289,15 @@ workspace_in_workspaces(int32 index, uint32 workspaces) Desktop::Desktop(uid_t userID) - : MessageLooper("desktop"), + : + MessageLooper("desktop"), fUserID(userID), fSettings(NULL), fSharedReadOnlyArea(-1), fApplicationsLock("application list"), fShutdownSemaphore(-1), + fScreenLock("screen lock"), fCurrentWorkspace(0), fPreviousWorkspace(0), fAllWindows(kAllWindowList), @@ -492,14 +494,14 @@ 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; - AutoWriteLocker _(fWindowLock); - Screen* screen = fVirtualScreen.ScreenByID(id); if (screen == NULL) return B_NAME_NOT_FOUND; @@ -516,9 +518,17 @@ Desktop::SetScreenMode(int32 workspace, int32 id, const display_mode& mode, // Set the new one + _SuspendDirectFrameBufferAccess(); + + AutoWriteLocker locker(fScreenLock); + status_t status = screen->SetMode(mode); - if (status != B_OK) + if (status != B_OK) { + locker.Unlock(); + + _ResumeDirectFrameBufferAccess(); return status; + } } else { // retrieve from settings screen_configuration* configuration @@ -543,6 +553,9 @@ Desktop::SetScreenMode(int32 workspace, int32 id, const display_mode& mode, } _ScreenChanged(screen); + if (workspace == fCurrentWorkspace) + _ResumeDirectFrameBufferAccess(); + return B_OK; } @@ -550,14 +563,14 @@ Desktop::SetScreenMode(int32 workspace, int32 id, const display_mode& mode, 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; - AutoReadLocker _(fWindowLock); - if (workspace == fCurrentWorkspace) { // retrieve from current screen Screen* screen = fVirtualScreen.ScreenByID(id); @@ -582,14 +595,14 @@ Desktop::GetScreenMode(int32 workspace, int32 id, display_mode& mode) 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; - AutoReadLocker _(fWindowLock); - if (workspace == fCurrentWorkspace) { // retrieve from current screen Screen* screen = fVirtualScreen.ScreenByID(id); @@ -647,8 +660,11 @@ Desktop::RevertScreenModes(uint32 workspaces) fWorkspaces[workspace].CurrentScreenConfiguration() .Remove(current); - if (workspace == fCurrentWorkspace) + if (workspace == fCurrentWorkspace) { + _SuspendDirectFrameBufferAccess(); _SetCurrentWorkspaceConfiguration(); + _ResumeDirectFrameBufferAccess(); + } } else SetScreenMode(workspace, screen->ID(), stored->mode, false); } @@ -1078,8 +1094,12 @@ Desktop::MoveWindowBy(Window* window, float x, float y, int32 workspace) // the dirty region starts with the visible area of the window being moved BRegion newDirtyRegion(window->VisibleRegion()); - // no more drawing for DirectWindows - window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP); + // stop direct frame buffer access + bool direct = false; + if (window->ServerWindow()->IsDirectlyAccessing()) { + window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP); + direct = true; + } window->MoveBy((int32)x, (int32)y); @@ -1108,9 +1128,13 @@ Desktop::MoveWindowBy(Window* window, float x, float y, int32 workspace) _SetBackground(background); _WindowChanged(window); - // allow DirectWindows to draw again after the visual - // content is at the new location - window->ServerWindow()->HandleDirectConnection(B_DIRECT_START | B_BUFFER_MOVED); + // resume direct frame buffer access + if (direct) { + // TODO: the clipping actually only changes when we move our window + // off screen, or behind some other window + window->ServerWindow()->HandleDirectConnection( + B_DIRECT_START | B_BUFFER_MOVED | B_CLIPPING_MODIFIED); + } UnlockAllWindows(); } @@ -1135,7 +1159,12 @@ Desktop::ResizeWindowBy(Window* window, float x, float y) // it is shrunk in "previouslyOccupiedRegion" BRegion previouslyOccupiedRegion(window->VisibleRegion()); - window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP); + // stop direct frame buffer access + bool direct = false; + if (window->ServerWindow()->IsDirectlyAccessing()) { + window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP); + direct = true; + } window->ResizeBy((int32)x, (int32)y, &newDirtyRegion); @@ -1155,7 +1184,11 @@ Desktop::ResizeWindowBy(Window* window, float x, float y) _SetBackground(background); _WindowChanged(window); - window->ServerWindow()->HandleDirectConnection(B_DIRECT_START | B_BUFFER_RESIZED); + // resume direct frame buffer access + if (direct) { + window->ServerWindow()->HandleDirectConnection( + B_DIRECT_START | B_BUFFER_RESIZED | B_CLIPPING_MODIFIED); + } UnlockAllWindows(); } @@ -2428,8 +2461,10 @@ Desktop::_ShowWindow(Window* window, bool affectsOtherWindows) } else MarkDirty(dirty); - window->ServerWindow()->HandleDirectConnection( - B_DIRECT_START | B_BUFFER_RESET); + if (window->ServerWindow()->HasDirectFrameBufferAccess()) { + window->ServerWindow()->HandleDirectConnection( + B_DIRECT_START | B_BUFFER_RESET); + } } @@ -2439,7 +2474,8 @@ Desktop::_ShowWindow(Window* window, bool affectsOtherWindows) void Desktop::_HideWindow(Window* window) { - window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP); + if (window->ServerWindow()->IsDirectlyAccessing()) + window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP); // after rebuilding the clipping, // this window will not have a visible @@ -2540,8 +2576,9 @@ Desktop::_ChangeWindowWorkspaces(Window* window, uint32 oldWorkspaces, window->SetCurrentWorkspace(fCurrentWorkspace); if (!window->IsHidden()) { - // this only affects other windows if this windows has floating or - // modal windows that need to be shown as well + // This only affects other windows if this window has + // floating or modal windows that need to be shown as + // well // TODO: take care of this _ShowWindow(window, FrontWindow() == window); } @@ -2674,6 +2711,16 @@ Desktop::_SendFakeMouseMoved(Window* window) } +Screen* +Desktop::_DetermineScreenFor(BRect frame) +{ + AutoReadLocker _(fScreenLock); + + // TODO: choose the screen depending on where most of the area is + return fVirtualScreen.ScreenAt(0); +} + + void Desktop::_RebuildClippingForAllWindows(BRegion& stillAvailableOnScreen) { @@ -2688,6 +2735,13 @@ Desktop::_RebuildClippingForAllWindows(BRegion& stillAvailableOnScreen) 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); + } + // that windows region is not available on screen anymore stillAvailableOnScreen.Exclude(&window->VisibleRegion()); } @@ -2756,6 +2810,13 @@ Desktop::_RebuildAndRedrawAfterWindowChange(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); + } + // that windows region is not available on screen anymore stillAvailableOnScreen.Exclude(&window->VisibleRegion()); } @@ -2768,6 +2829,39 @@ Desktop::_RebuildAndRedrawAfterWindowChange(Window* changedWindow, } +//! Suspend all windows with direct access to the frame buffer +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); + } +} + + +//! Resume all windows with direct access to the frame buffer +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) { @@ -2800,10 +2894,10 @@ Desktop::_ScreenChanged(Screen* screen) fVirtualScreen.UpdateFrame(); - // TODO: currently ignores the screen argument! for (Window* window = fAllWindows.FirstWindow(); window != NULL; window = window->NextWindow(kAllWindowList)) { - window->ServerWindow()->ScreenChanged(&update); + if (window->Screen() == screen) + window->ServerWindow()->ScreenChanged(&update); } } @@ -2852,6 +2946,8 @@ Desktop::_SetCurrentWorkspaceConfiguration() { ASSERT_MULTI_WRITE_LOCKED(fWindowLock); + AutoWriteLocker _(fScreenLock); + uint32 changedScreens; fVirtualScreen.SetConfiguration(*this, fWorkspaces[fCurrentWorkspace].CurrentScreenConfiguration(), @@ -2870,6 +2966,8 @@ Desktop::_SetCurrentWorkspaceConfiguration() void Desktop::_SetWorkspace(int32 index) { + ASSERT_MULTI_WRITE_LOCKED(fWindowLock); + int32 previousIndex = fCurrentWorkspace; rgb_color previousColor = fWorkspaces[fCurrentWorkspace].Color(); bool movedMouseEventWindow = false; @@ -2914,6 +3012,10 @@ Desktop::_SetWorkspace(int32 index) // store current position in Workspace anchor 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)) @@ -2998,6 +3100,12 @@ Desktop::_SetWorkspace(int32 index) // send B_WORKSPACE_ACTIVATED message 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 == fMouseEventWindow && fMouseEventWindow->IsNormal()) || (!window->IsNormal() diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h index abeb90dace..94b6871427 100644 --- a/src/servers/app/Desktop.h +++ b/src/servers/app/Desktop.h @@ -86,7 +86,7 @@ public: void UnlockAllWindows() { fWindowLock.WriteUnlock(); } - MultiLocker WindowLocker() { return fWindowLock; } + const MultiLocker& WindowLocker() { return fWindowLock; } #else // USE_MULTI_LOCKER bool LockSingleWindow() { return fWindowLock.Lock(); } @@ -125,6 +125,8 @@ public: BRect& frame); void RevertScreenModes(uint32 workspaces); + MultiLocker& ScreenLocker() { return fScreenLock; } + const ::VirtualScreen& VirtualScreen() const { return fVirtualScreen; } DrawingEngine* GetDrawingEngine() const @@ -268,6 +270,7 @@ private: Window* _LastFocusSubsetWindow(Window* window); void _SendFakeMouseMoved(Window* window = NULL); + Screen* _DetermineScreenFor(BRect frame); void _RebuildClippingForAllWindows( BRegion& stillAvailableOnScreen); void _TriggerWindowRedrawing( @@ -278,6 +281,9 @@ private: status_t _ActivateApp(team_id team); + void _SuspendDirectFrameBufferAccess(); + void _ResumeDirectFrameBufferAccess(); + void _ScreenChanged(Screen* screen); void _SetCurrentWorkspaceConfiguration(); void _SetWorkspace(int32 index); @@ -302,6 +308,7 @@ private: int32 fShutdownCount; ::Workspace::Private fWorkspaces[kMaxWorkspaces]; + MultiLocker fScreenLock; int32 fCurrentWorkspace; int32 fPreviousWorkspace; diff --git a/src/servers/app/DirectWindowSupport.cpp b/src/servers/app/DirectWindowSupport.cpp index 63e59a0f5d..340cf24e66 100644 --- a/src/servers/app/DirectWindowSupport.cpp +++ b/src/servers/app/DirectWindowSupport.cpp @@ -7,17 +7,18 @@ * Axel Dörfler, axeld@pinc-software.de */ + #include "DirectWindowSupport.h" +#include +#include +#include + #include #include "RenderingBuffer.h" #include "clipping.h" -#include -#include -#include - DirectWindowData::DirectWindowData() : @@ -25,9 +26,7 @@ DirectWindowData::DirectWindowData() fBufferInfo(NULL), fSem(-1), fAcknowledgeSem(-1), - fBufferArea(-1), - fTransition(0), - fStarted(false) + fBufferArea(-1) { fBufferArea = create_area("direct area", (void**)&fBufferInfo, B_ANY_ADDRESS, DIRECT_BUFFER_INFO_AREA_SIZE, @@ -87,46 +86,31 @@ DirectWindowData::_SyncronizeWithClient() if (status != B_OK) return status; - //syslog(LOG_INFO, "Syncronize: released sem"); // Wait with a timeout of half a second until the client exits // from its DirectConnected() implementation do { #if 0 status = acquire_sem(fAcknowledgeSem); -#else +#else status = acquire_sem_etc(fAcknowledgeSem, 1, B_TIMEOUT, 500000); #endif } while (status == B_INTERRUPTED); - //syslog(LOG_INFO, "Syncronize: acquired sem"); return status; } status_t -DirectWindowData::SetState(const direct_buffer_state& bufferState, - const direct_driver_state& driverState, RenderingBuffer *buffer, +DirectWindowData::SetState(direct_buffer_state bufferState, + direct_driver_state driverState, RenderingBuffer* buffer, const BRect& windowFrame, const BRegion& clipRegion) -{ - if (!fStarted && (bufferState & B_DIRECT_MODE_MASK) - != B_DIRECT_START) - return B_OK; - +{ if ((fBufferInfo->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP && (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START) return B_OK; -#if 0 - if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_MODIFY) - syslog(LOG_INFO, "direct_modify"); -#endif - fStarted = true; -#if 0 - char string[256]; - snprintf(string, sizeof(string), "bufferState: 0x%x\n", (int)bufferState); - syslog(LOG_INFO, string); -#endif + fBufferInfo->buffer_state = bufferState; - + if (driverState != -1) fBufferInfo->driver_state = driverState; @@ -180,6 +164,6 @@ DirectWindowData::SetState(const direct_buffer_state& bufferState, for (uint32 i = 0; i < fBufferInfo->clip_list_count; i++) fBufferInfo->clip_list[i] = clipRegion.RectAtInt(i); } - + return _SyncronizeWithClient(); } diff --git a/src/servers/app/DirectWindowSupport.h b/src/servers/app/DirectWindowSupport.h index e39ec8aa09..1a562c7157 100644 --- a/src/servers/app/DirectWindowSupport.h +++ b/src/servers/app/DirectWindowSupport.h @@ -3,6 +3,9 @@ * Distributed under the terms of the MIT License. * */ +#ifndef DIRECT_WINDOW_SUPPORT_H +#define DIRECT_WINDOW_SUPPORT_H + #include #include @@ -11,26 +14,6 @@ class RenderingBuffer; -struct BufferState { - BufferState(const direct_buffer_state& state) - : - fState(state) - { - } - - inline direct_buffer_state Action() const - { - return (direct_buffer_state)(fState & B_DIRECT_MODE_MASK); - } - - inline direct_buffer_state Reason() const - { - return (direct_buffer_state)(fState & ~B_DIRECT_MODE_MASK); - } - - direct_buffer_state fState; -}; - class DirectWindowData { public: @@ -43,24 +26,23 @@ public: direct_window_sync_data& data) const; status_t SyncronizeWithClient(); - status_t SetState(const direct_buffer_state& bufferState, - const direct_driver_state& driverState, - RenderingBuffer *renderingBuffer, + status_t SetState(direct_buffer_state bufferState, + direct_driver_state driverState, + RenderingBuffer* renderingBuffer, const BRect& windowFrame, const BRegion& clipRegion); - + BRect old_window_frame; bool full_screen; private: status_t _SyncronizeWithClient(); - direct_buffer_info* fBufferInfo; + direct_buffer_info* fBufferInfo; sem_id fSem; sem_id fAcknowledgeSem; area_id fBufferArea; - direct_buffer_state fPreviousState; - int32 fTransition; - bool fStarted; }; + +#endif // DIRECT_WINDOW_SUPPORT_H diff --git a/src/servers/app/MultiLocker.h b/src/servers/app/MultiLocker.h index d3e588f421..11f2377f0b 100644 --- a/src/servers/app/MultiLocker.h +++ b/src/servers/app/MultiLocker.h @@ -2,7 +2,7 @@ * Copyright 2005-2009, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT license. * - * Copyright 1999, Be Incorporated. All Rights Reserved. + * Copyright 1999, Be Incorporated. All Rights Reserved. * This file may be used under the terms of the Be Sample Code License. */ #ifndef MULTI_LOCKER_H @@ -66,6 +66,11 @@ public: #endif private: + MultiLocker(); + MultiLocker(const MultiLocker& other); + MultiLocker& operator=(const MultiLocker& other); + // not implemented + #if MULTI_LOCKER_DEBUG // functions for managing the DEBUG reader array void _RegisterThread(); @@ -114,14 +119,20 @@ public: : fLock(*lock) { - fLock.WriteLock(); + fLocked = fLock.WriteLock(); } AutoWriteLocker(MultiLocker& lock) : fLock(lock) { - fLock.WriteLock(); + fLocked = fLock.WriteLock(); + } + + ~AutoWriteLocker() + { + if (fLocked) + fLock.WriteUnlock(); } bool IsLocked() const @@ -129,13 +140,17 @@ public: return fLock.IsWriteLocked(); } - ~AutoWriteLocker() + void Unlock() { - fLock.WriteUnlock(); + if (fLocked) { + fLock.WriteUnlock(); + fLocked = false; + } } private: MultiLocker& fLock; + bool fLocked; }; @@ -160,8 +175,7 @@ public: Unlock(); } - void - Unlock() + void Unlock() { if (fLocked) { fLock.ReadUnlock(); diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index 4aab2cdb77..531c298e21 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -2252,36 +2252,41 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) case AS_GET_SCREEN_ID_FROM_WINDOW: { - status_t status = B_ENTRY_NOT_FOUND; + status_t status = B_BAD_VALUE; // Attached data // 1) int32 - window client token int32 clientToken; if (link.Read(&clientToken) != B_OK) status = B_BAD_DATA; - else if (fDesktop->LockAllWindows()) { + else { BAutolock locker(fWindowListLock); for (int32 i = fWindowList.CountItems(); i-- > 0;) { - ServerWindow* window = fWindowList.ItemAt(i); + ServerWindow* serverWindow = fWindowList.ItemAt(i); + + if (serverWindow->ClientToken() == clientToken) { + AutoReadLocker _(fDesktop->ScreenLocker()); - if (window->ClientToken() == clientToken) { // found it! - if (window->Window() == NULL) { + Window* window = serverWindow->Window(); + const Screen* screen = NULL; + if (window != NULL) + screen = window->Screen(); + + if (screen == NULL) { // The window hasn't been added to the desktop yet, // or it's an offscreen window break; } fLink.StartMessage(B_OK); - fLink.Attach(window->Window()->Screen()->ID()); + fLink.Attach(screen->ID()); status = B_OK; break; } } - fDesktop->UnlockAllWindows(); - } else - status = B_ERROR; + } if (status != B_OK) fLink.StartMessage(status); diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 3023311752..83cfc2adf9 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -167,6 +167,7 @@ ServerWindow::ServerWindow(const char* title, ServerApp* app, fCurrentDrawingRegionValid(false), fDirectWindowData(NULL), + fIsDirectlyAccessing(false), fDirectWindowFeel(B_NORMAL_WINDOW_FEEL) { STRACE(("ServerWindow(%s)::ServerWindow()\n", title)); @@ -3401,8 +3402,6 @@ ServerWindow::_MessageLooper() void ServerWindow::ScreenChanged(const BMessage* message) { - // TODO: execute the stop notification earlier - HandleDirectConnection(B_DIRECT_STOP); SendMessageToClient(message); if (fDirectWindowData != NULL && fDirectWindowData->full_screen) { @@ -3411,9 +3410,6 @@ ServerWindow::ScreenChanged(const BMessage* message) screenFrame.Width() - fWindow->Frame().Width(), screenFrame.Height() - fWindow->Frame().Height()); } - - HandleDirectConnection(B_DIRECT_START | B_BUFFER_RESET, - B_SCREEN_CHANGED); } @@ -3441,15 +3437,6 @@ ServerWindow::MakeWindow(BRect frame, const char* name, } -/* static */ -bool -ServerWindow::_SupportsDirectMode() -{ - return false; - // TODO: For now, since it's broken -} - - status_t ServerWindow::_EnableDirectWindowMode() { @@ -3458,9 +3445,6 @@ ServerWindow::_EnableDirectWindowMode() return B_ERROR; } - if (!ServerWindow::_SupportsDirectMode()) - return B_ERROR; - fDirectWindowData = new (nothrow) DirectWindowData; if (fDirectWindowData == NULL) return B_NO_MEMORY; @@ -3480,34 +3464,35 @@ ServerWindow::_EnableDirectWindowMode() void ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState) { - STRACE(("HandleDirectConnection(bufferState = %ld, driverState = %ld)\n", - bufferState, driverState)); + ASSERT_MULTI_LOCKED(fDesktop->WindowLocker()); if (fDirectWindowData == NULL) return; - if (fDesktop->LockSingleWindow()) { - status_t status = fDirectWindowData->SetState( - (direct_buffer_state)bufferState, - (direct_driver_state)driverState, - fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(), - fWindow->VisibleContentRegion()); + STRACE(("HandleDirectConnection(bufferState = %ld, driverState = %ld)\n", + bufferState, driverState)); - if (status != B_OK) { - char errorString[256]; - snprintf(errorString, sizeof(errorString), - "%s killed for a problem in DirectConnected(): %s", - App()->Signature(), strerror(status)); - syslog(LOG_ERR, errorString); + status_t status = fDirectWindowData->SetState( + (direct_buffer_state)bufferState, (direct_driver_state)driverState, + fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(), + fWindow->VisibleContentRegion()); - // The client application didn't release the semaphore - // within the given timeout. Or something else went wrong. - // Deleting this member should make it crash. - delete fDirectWindowData; - fDirectWindowData = NULL; - } - fDesktop->UnlockSingleWindow(); - } + if (status != B_OK) { + char errorString[256]; + snprintf(errorString, sizeof(errorString), + "%s killed for a problem in DirectConnected(): %s", + App()->Signature(), strerror(status)); + syslog(LOG_ERR, errorString); + + // The client application didn't release the semaphore + // within the given timeout. Or something else went wrong. + // Deleting this member should make it crash. + delete fDirectWindowData; + fDirectWindowData = NULL; + } else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_START) + fIsDirectlyAccessing = true; + else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_STOP) + fIsDirectlyAccessing = false; } diff --git a/src/servers/app/ServerWindow.h b/src/servers/app/ServerWindow.h index fc400e66e0..6c4a450705 100644 --- a/src/servers/app/ServerWindow.h +++ b/src/servers/app/ServerWindow.h @@ -13,12 +13,6 @@ #define SERVER_WINDOW_H -#include "EventDispatcher.h" -#include "MessageLooper.h" - -#include -#include - #include #include #include @@ -28,6 +22,13 @@ #include #include +#include +#include + +#include "EventDispatcher.h" +#include "MessageLooper.h" + + class BString; class BMessenger; class BPoint; @@ -47,6 +48,7 @@ struct window_info; #define AS_UPDATE_COLORS 'asuc' #define AS_UPDATE_FONTS 'asuf' + class ServerWindow : public MessageLooper { public: ServerWindow(const char *title, ServerApp *app, @@ -77,8 +79,8 @@ public: const BMessenger& HandlerMessenger() const { return fHandlerMessenger; } - void ScreenChanged(const BMessage *screenChangedMessage); - status_t SendMessageToClient(const BMessage* msg, + void ScreenChanged(const BMessage* message); + status_t SendMessageToClient(const BMessage* message, int32 target = B_NULL_TOKEN) const; virtual ::Window* MakeWindow(BRect frame, const char* name, @@ -91,9 +93,6 @@ public: // related thread/team_id(s). inline team_id ClientTeam() const { return fClientTeam; } - void HandleDirectConnection(int32 bufferState, - int32 driverState = -1); - inline int32 ClientToken() const { return fClientToken; } inline int32 ServerToken() const { return fServerToken; } @@ -101,6 +100,13 @@ public: void GetInfo(window_info& info); + void HandleDirectConnection(int32 bufferState, + int32 driverState = 0); + bool HasDirectFrameBufferAccess() const + { return fDirectWindowData != NULL; } + bool IsDirectlyAccessing() const + { return fIsDirectlyAccessing; } + void ResyncDrawState(); // TODO: Change this @@ -127,8 +133,8 @@ private: virtual void _PrepareQuit(); virtual void _GetLooperName(char* name, size_t size); - static bool _SupportsDirectMode(); status_t _EnableDirectWindowMode(); + void _DirectWindowSetFullScreen(bool set); void _SetCurrentView(View* view); void _UpdateDrawState(View* view); @@ -137,8 +143,6 @@ private: bool _MessageNeedsAllWindowsLocked( uint32 code) const; - void _DirectWindowSetFullScreen(bool set); - // TODO: Move me elsewhere status_t PictureToRegion(ServerPicture *picture, BRegion& region, bool inverse, @@ -171,6 +175,7 @@ private: bool fCurrentDrawingRegionValid; DirectWindowData* fDirectWindowData; + bool fIsDirectlyAccessing; window_feel fDirectWindowFeel; }; diff --git a/src/servers/app/Window.cpp b/src/servers/app/Window.cpp index e9fb97c3a9..7ff5f9e6ce 100644 --- a/src/servers/app/Window.cpp +++ b/src/servers/app/Window.cpp @@ -77,6 +77,7 @@ Window::Window(const BRect& frame, const char *name, : fTitle(name), fFrame(frame), + fScreen(NULL), fVisibleRegion(), fVisibleContentRegion(), @@ -213,8 +214,6 @@ Window::SetClipping(BRegion* stillAvailableOnScreen) fVisibleContentRegionValid = false; fEffectiveDrawingRegionValid = false; - - fWindow->HandleDirectConnection(B_DIRECT_MODIFY | B_CLIPPING_MODIFIED); } @@ -562,13 +561,19 @@ Window::PreviousWindow(int32 index) const } -::Screen* +void +Window::SetScreen(const ::Screen* screen) +{ + ASSERT_MULTI_WRITE_LOCKED(fDesktop->ScreenLocker()); + fScreen = screen; +} + + +const ::Screen* Window::Screen() const { - ASSERT_MULTI_LOCKED(fDesktop->WindowLocker()); - - // TODO: we need to know which screen the window is on - return fDesktop->VirtualScreen().ScreenAt(0); + ASSERT_MULTI_READ_LOCKED(fDesktop->ScreenLocker()); + return fScreen; } @@ -1215,18 +1220,12 @@ Window::_AlterDeltaForSnap(BPoint& delta, bigtime_t now) void Window::WorkspaceActivated(int32 index, bool active) { - if (!active && !IsHidden()) - fWindow->HandleDirectConnection(B_DIRECT_STOP); - BMessage activatedMsg(B_WORKSPACE_ACTIVATED); activatedMsg.AddInt64("when", system_time()); activatedMsg.AddInt32("workspace", index); activatedMsg.AddBool("active", active); ServerWindow()->SendMessageToClient(&activatedMsg); - - if (active && !IsHidden()) - fWindow->HandleDirectConnection(B_DIRECT_START | B_BUFFER_RESET); } @@ -1338,8 +1337,8 @@ Window::IsVisible() const void -Window::SetSizeLimits(int32 minWidth, int32 maxWidth, - int32 minHeight, int32 maxHeight) +Window::SetSizeLimits(int32 minWidth, int32 maxWidth, int32 minHeight, + int32 maxHeight) { if (minWidth < 0) minWidth = 0; @@ -1354,8 +1353,8 @@ Window::SetSizeLimits(int32 minWidth, int32 maxWidth, // give the Decorator a say in this too if (fDecorator) { - fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, - &fMaxWidth, &fMaxHeight); + fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, &fMaxWidth, + &fMaxHeight); } _ObeySizeLimits(); @@ -1455,7 +1454,8 @@ Window::SetLook(window_look look, BRegion* updateRegion) fDecorator->SetLook(settings, look, updateRegion); // we might need to resize the window! - fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, &fMaxWidth, &fMaxHeight); + fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, &fMaxWidth, + &fMaxHeight); _ObeySizeLimits(); } @@ -1471,8 +1471,10 @@ void Window::SetFeel(window_feel feel) { // if the subset list is no longer needed, clear it - if ((fFeel == B_MODAL_SUBSET_WINDOW_FEEL || fFeel == B_FLOATING_SUBSET_WINDOW_FEEL) - && (feel != B_MODAL_SUBSET_WINDOW_FEEL && feel != B_FLOATING_SUBSET_WINDOW_FEEL)) + if ((fFeel == B_MODAL_SUBSET_WINDOW_FEEL + || fFeel == B_FLOATING_SUBSET_WINDOW_FEEL) + && feel != B_MODAL_SUBSET_WINDOW_FEEL + && feel != B_FLOATING_SUBSET_WINDOW_FEEL) fSubsets.MakeEmpty(); fFeel = feel; @@ -1793,8 +1795,7 @@ Window::InSubsetWorkspace(int32 index) const // #pragma mark - static -/*static*/ -bool +/*static*/ bool Window::IsValidLook(window_look look) { return look == B_TITLED_WINDOW_LOOK @@ -1808,8 +1809,7 @@ Window::IsValidLook(window_look look) } -/*static*/ -bool +/*static*/ bool Window::IsValidFeel(window_feel feel) { return feel == B_NORMAL_WINDOW_FEEL @@ -1826,8 +1826,7 @@ Window::IsValidFeel(window_feel feel) } -/*static*/ -bool +/*static*/ bool Window::IsModalFeel(window_feel feel) { return feel == B_MODAL_SUBSET_WINDOW_FEEL @@ -1836,8 +1835,7 @@ Window::IsModalFeel(window_feel feel) } -/*static*/ -bool +/*static*/ bool Window::IsFloatingFeel(window_feel feel) { return feel == B_FLOATING_SUBSET_WINDOW_FEEL @@ -2115,7 +2113,8 @@ Window::BeginUpdate(BPrivate::PortLink& link) // supress back to front buffer copies in the drawing engine fDrawingEngine->SetCopyToFrontEnabled(false); - if (!fCurrentUpdateSession->IsExpose() && fDrawingEngine->LockParallelAccess()) { + if (!fCurrentUpdateSession->IsExpose() + && fDrawingEngine->LockParallelAccess()) { fDrawingEngine->SuspendAutoSync(); fTopView->Draw(fDrawingEngine, dirty, &fContentRegion, true); diff --git a/src/servers/app/Window.h b/src/servers/app/Window.h index 41079c9c5e..0baec3a29d 100644 --- a/src/servers/app/Window.h +++ b/src/servers/app/Window.h @@ -67,7 +67,8 @@ public: ::EventTarget& EventTarget() const { return fWindow->EventTarget(); } - ::Screen* Screen() const; + void SetScreen(const ::Screen* screen); + const ::Screen* Screen() const; // setting and getting the "hard" clipping, you need to have // WriteLock()ed the clipping! @@ -234,18 +235,15 @@ public: void FindWorkspacesViews( BObjectList& list) const; - static bool IsValidLook(window_look look); - static bool IsValidFeel(window_feel feel); - static bool IsModalFeel(window_feel feel); - static bool IsFloatingFeel(window_feel feel); + static bool IsValidLook(window_look look); + static bool IsValidFeel(window_feel feel); + static bool IsModalFeel(window_feel feel); + static bool IsFloatingFeel(window_feel feel); - static uint32 ValidWindowFlags(); - static uint32 ValidWindowFlags(window_feel feel); + static uint32 ValidWindowFlags(); + static uint32 ValidWindowFlags(window_feel feel); protected: - friend class Desktop; - // TODO: for now (list management) - void _ShiftPartOfRegion(BRegion* region, BRegion* regionToShift, int32 xOffset, int32 yOffset); @@ -278,6 +276,7 @@ protected: BString fTitle; // TODO: no fp rects anywhere BRect fFrame; + const ::Screen* fScreen; window_anchor fAnchor[kListCount];