diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-22 19:57:00 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-22 19:57:00 +0000 |
commit | a1a4f0e7528cb7d8369017ab3e4e8e083c7ab218 (patch) | |
tree | 55e3f2c515eb9b5008b2b853b73b27c09024b96d /ash | |
parent | 0d95ce3eda2df2bb49cdb11c0493ee2f4de4a1b7 (diff) | |
download | chromium_src-a1a4f0e7528cb7d8369017ab3e4e8e083c7ab218.zip chromium_src-a1a4f0e7528cb7d8369017ab3e4e8e083c7ab218.tar.gz chromium_src-a1a4f0e7528cb7d8369017ab3e4e8e083c7ab218.tar.bz2 |
ash: Refactor transparent window headers for single windows
Fixes issue where V2 app windows cause the transparency of window headers
to be computed incorrectly.
BUG=176583
TEST=ash_unittests FramePainterTest.*
R=mukai@chromium.org
Review URL: https://codereview.chromium.org/12807003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@189887 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/wm/frame_painter.cc | 160 | ||||
-rw-r--r-- | ash/wm/frame_painter.h | 41 | ||||
-rw-r--r-- | ash/wm/frame_painter_unittest.cc | 63 | ||||
-rw-r--r-- | ash/wm/window_properties.cc | 3 | ||||
-rw-r--r-- | ash/wm/window_properties.h | 8 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_manager.cc | 12 |
6 files changed, 153 insertions, 134 deletions
diff --git a/ash/wm/frame_painter.cc b/ash/wm/frame_painter.cc index 8264620..4371a53 100644 --- a/ash/wm/frame_painter.cc +++ b/ash/wm/frame_painter.cc @@ -4,12 +4,16 @@ #include "ash/wm/frame_painter.h" +#include <vector> + #include "ash/ash_constants.h" +#include "ash/root_window_controller.h" #include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/wm/property_util.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_util.h" +#include "ash/wm/workspace_controller.h" #include "base/logging.h" // DCHECK #include "grit/ash_resources.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -35,6 +39,7 @@ using aura::RootWindow; using aura::Window; +using views::Widget; namespace { // TODO(jamescook): Border is specified to be a single pixel overlapping @@ -111,6 +116,7 @@ bool IsVisibleToRoot(Window* child) { } return true; } + // Returns true if |window| is a visible, normal window. bool IsVisibleNormalWindow(aura::Window* window) { // Test visibility up to root in case the whole workspace is hidden. @@ -120,6 +126,32 @@ bool IsVisibleNormalWindow(aura::Window* window) { window->type() == aura::client::WINDOW_TYPE_PANEL); } +// Returns a list of windows in |root_window|| that potentially could have +// a transparent solo-window header. +std::vector<Window*> GetWindowsForSoloHeaderUpdate(RootWindow* root_window) { + std::vector<Window*> windows; + // During shutdown there may not be a workspace controller. In that case + // we don't care about updating any windows. + ash::internal::WorkspaceController* workspace_controller = + ash::GetRootWindowController(root_window)->workspace_controller(); + if (workspace_controller) { + // Avoid memory allocations for typical window counts. + windows.reserve(16); + // Collect windows from the active workspace. + Window* workspace = workspace_controller->GetActiveWorkspaceWindow(); + windows.insert(windows.end(), + workspace->children().begin(), + workspace->children().end()); + // Collect "always on top" windows. + Window* top_container = + ash::Shell::GetContainer( + root_window, ash::internal::kShellWindowId_AlwaysOnTopContainer); + windows.insert(windows.end(), + top_container->children().begin(), + top_container->children().end()); + } + return windows; +} } // namespace namespace ash { @@ -128,7 +160,6 @@ namespace ash { int FramePainter::kActiveWindowOpacity = 255; // 1.0 int FramePainter::kInactiveWindowOpacity = 255; // 1.0 int FramePainter::kSoloWindowOpacity = 77; // 0.3 -std::set<FramePainter*>* FramePainter::instances_ = NULL; /////////////////////////////////////////////////////////////////////////////// // FramePainter, public: @@ -151,25 +182,16 @@ FramePainter::FramePainter() crossfade_opacity_(0), crossfade_animation_(NULL), size_button_behavior_(SIZE_BUTTON_MAXIMIZES) { - if (!instances_) - instances_ = new std::set<FramePainter*>(); - instances_->insert(this); } FramePainter::~FramePainter() { // Sometimes we are destroyed before the window closes, so ensure we clean up. if (window_) { - aura::RootWindow* root = window_->GetRootWindow(); - if (root && - root->GetProperty(internal::kSoloWindowFramePainterKey) == this) { - root->SetProperty(internal::kSoloWindowFramePainterKey, - static_cast<FramePainter*>(NULL)); - } window_->RemoveObserver(this); + aura::RootWindow* root = window_->GetRootWindow(); if (root) root->RemoveObserver(this); } - instances_->erase(this); } void FramePainter::Init(views::Widget* frame, @@ -221,9 +243,8 @@ void FramePainter::Init(views::Widget* frame, if (root) root->AddObserver(this); - // If there is already a solo window in the same root, this initialization - // should turn off its solo-mode. - UpdateSoloWindowFramePainter(NULL); + // Solo-window header updates are handled by the workspace controller when + // this window is added to the active workspace. } // static @@ -621,11 +642,11 @@ void FramePainter::OnWindowVisibilityChanged(aura::Window* window, // Window visibility change may trigger the change of window solo-ness in a // different window. - UpdateSoloWindowFramePainter(visible ? NULL : window_); + UpdateSoloWindowInRoot(window_->GetRootWindow(), visible ? NULL : window_); } void FramePainter::OnWindowDestroying(aura::Window* destroying) { - aura::Window* root = window_->GetRootWindow(); + aura::RootWindow* root = window_->GetRootWindow(); DCHECK(destroying == window_ || destroying == root); // Must be removed here and not in the destructor, as the aura::Window is @@ -634,12 +655,9 @@ void FramePainter::OnWindowDestroying(aura::Window* destroying) { if (root) root->RemoveObserver(this); - // For purposes of painting and solo window computation, we're done. - instances_->erase(this); - // If we have two or more windows open and we close this one, we might trigger // the solo window appearance for another window. - UpdateSoloWindowFramePainter(window_); + UpdateSoloWindowInRoot(root, window_); window_ = NULL; } @@ -662,21 +680,23 @@ void FramePainter::OnWindowBoundsChanged(aura::Window* window, void FramePainter::OnWindowAddedToRootWindow(aura::Window* window) { DCHECK_EQ(window_, window); - window->GetRootWindow()->AddObserver(this); + RootWindow* root = window->GetRootWindow(); + root->AddObserver(this); // Needs to trigger the window appearance change if the window moves across // root windows and a solo window is already in the new root. - UpdateSoloWindowFramePainter(NULL); + UpdateSoloWindowInRoot(root, NULL /* ignore_window */); } void FramePainter::OnWindowRemovingFromRootWindow(aura::Window* window) { DCHECK_EQ(window_, window); - window->GetRootWindow()->RemoveObserver(this); + RootWindow* root = window->GetRootWindow(); + root->RemoveObserver(this); // Needs to trigger the window appearance change if the window moves across // root windows and only one window is left in the previous root. Because // |window| is not yet moved, |window| has to be ignored. - UpdateSoloWindowFramePainter(window); + UpdateSoloWindowInRoot(root, window); } /////////////////////////////////////////////////////////////////////////////// @@ -796,70 +816,64 @@ bool FramePainter::UseSoloWindowHeader() { aura::RootWindow* root = window_->GetRootWindow(); if (!root || root->GetProperty(internal::kIgnoreSoloWindowFramePainterPolicy)) return false; - return (root->GetProperty(internal::kSoloWindowFramePainterKey) == this); + // Don't recompute every time, as it would require many window property + // lookups. + return root->GetProperty(internal::kSoloWindowHeaderKey); } // static -FramePainter* FramePainter::GetSoloPainterInRoot(RootWindow* root_window, - Window* ignorable_window) { - // Can be NULL in tests that don't use FramePainter windows. - if (!instances_) - return NULL; - - FramePainter* painter = NULL; - for (std::set<FramePainter*>::const_iterator it = instances_->begin(); - it != instances_->end(); +bool FramePainter::UseSoloWindowHeaderInRoot(RootWindow* root_window, + Window* ignore_window) { + int visible_window_count = 0; + std::vector<Window*> windows = GetWindowsForSoloHeaderUpdate(root_window); + for (std::vector<Window*>::const_iterator it = windows.begin(); + it != windows.end(); ++it) { - if (ignorable_window == (*it)->window_) + Window* window = *it; + // Various sorts of windows "don't count" for this computation. + if (ignore_window == window || + !IsVisibleNormalWindow(window) || + window->GetProperty(kConstrainedWindowKey)) continue; - - if (root_window != (*it)->window_->GetRootWindow()) - continue; - - // The window needs to be a 'normal window'. To exclude constrained windows - // the existence of a layout manager gets additionally tested. - if (IsVisibleNormalWindow((*it)->window_) && - (!(*it)->window_->GetProperty(ash::kConstrainedWindowKey))) { - if (wm::IsWindowMaximized((*it)->window_)) { - return NULL; - } - if (painter) - return NULL; - - painter = (*it); - } + if (wm::IsWindowMaximized(window)) + return false; + ++visible_window_count; + if (visible_window_count > 1) + return false; } - - return painter; + // Count must be tested because all windows might be "don't count" windows + // in the loop above. + return visible_window_count == 1; } // static void FramePainter::UpdateSoloWindowInRoot(RootWindow* root, - Window* ignorable_window) { + Window* ignore_window) { +#if defined(OS_WIN) + // Non-Ash Windows doesn't do solo-window counting for transparency effects, + // as the desktop background and window frames are managed by the OS. + if (!ash::Shell::HasInstance()) + return; +#endif if (!root) return; - - FramePainter* old_solo_painter = root->GetProperty( - internal::kSoloWindowFramePainterKey); - FramePainter* new_solo_painter = GetSoloPainterInRoot(root, ignorable_window); - if (old_solo_painter != new_solo_painter) { - if (old_solo_painter && old_solo_painter->frame_ && - old_solo_painter->frame_->non_client_view()) { - old_solo_painter->frame_->non_client_view()->SchedulePaint(); - } - root->SetProperty(internal::kSoloWindowFramePainterKey, new_solo_painter); - if (new_solo_painter && new_solo_painter->frame_ && - new_solo_painter->frame_->non_client_view()) { - new_solo_painter->frame_->non_client_view()->SchedulePaint(); - } + bool old_solo_header = root->GetProperty(internal::kSoloWindowHeaderKey); + bool new_solo_header = UseSoloWindowHeaderInRoot(root, ignore_window); + if (old_solo_header == new_solo_header) + return; + root->SetProperty(internal::kSoloWindowHeaderKey, new_solo_header); + // Invalidate all the window frames in the active workspace. There should + // only be a few. + std::vector<Window*> windows = GetWindowsForSoloHeaderUpdate(root); + for (std::vector<Window*>::const_iterator it = windows.begin(); + it != windows.end(); + ++it) { + Widget* widget = Widget::GetWidgetForNativeWindow(*it); + if (widget && widget->non_client_view()) + widget->non_client_view()->SchedulePaint(); } } -void FramePainter::UpdateSoloWindowFramePainter( - aura::Window* ignorable_window) { - UpdateSoloWindowInRoot(window_->GetRootWindow(), ignorable_window); -} - void FramePainter::SchedulePaintForHeader() { int top_left_height = top_left_corner_->height(); int top_right_height = top_right_corner_->height(); diff --git a/ash/wm/frame_painter.h b/ash/wm/frame_painter.h index 547c35d..1f67ca5 100644 --- a/ash/wm/frame_painter.h +++ b/ash/wm/frame_painter.h @@ -5,8 +5,6 @@ #ifndef ASH_WM_FRAME_PAINTER_H_ #define ASH_WM_FRAME_PAINTER_H_ -#include <set> - #include "ash/ash_export.h" #include "base/basictypes.h" #include "base/compiler_specific.h" // OVERRIDE @@ -73,7 +71,7 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver, SizeButtonBehavior behavior); // Updates the solo-window transparent header appearance for all windows - // using frame painters across all root windows. + // using frame painters in |root_window|. static void UpdateSoloWindowHeader(aura::RootWindow* root_window); // Helpers for views::NonClientFrameView implementations. @@ -140,9 +138,9 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver, virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE; private: - FRIEND_TEST_ALL_PREFIXES(FramePainterTest, Basics); FRIEND_TEST_ALL_PREFIXES(FramePainterTest, CreateAndDeleteSingleWindow); FRIEND_TEST_ALL_PREFIXES(FramePainterTest, UseSoloWindowHeader); + FRIEND_TEST_ALL_PREFIXES(FramePainterTest, UseSoloWindowHeaderWithApp); FRIEND_TEST_ALL_PREFIXES(FramePainterTest, UseSoloWindowHeaderMultiDisplay); FRIEND_TEST_ALL_PREFIXES(FramePainterTest, GetHeaderOpacity); @@ -173,28 +171,23 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver, // Returns true if the user is cycling through workspaces. bool IsCyclingThroughWorkspaces() const; - // Returns true if |window_| is exactly one visible, normal-type window in - // |window_->GetRootWindow()|, in which case we should paint a transparent - // window header. + // Returns true if |window_->GetRootWindow()| should be drawing transparent + // window headers. bool UseSoloWindowHeader(); - // Returns the frame painter for the solo window in |root_window|. Returns - // NULL in case there is no such window, for example more than two windows or - // there's a fullscreen window. It ignores |ignorable_window| to check the - // solo-ness of the window. Pass NULL for |ignorable_window| to consider - // all windows. - static FramePainter* GetSoloPainterInRoot(aura::RootWindow* root_window, - aura::Window* ignorable_window); - - // Updates the current solo window frame painter for |root_window| while - // ignoring |ignorable_window|. If the solo window frame painter changed it - // schedules paints as necessary. + // Returns true if |root_window| has exactly one visible, normal-type window. + // It ignores |ignore_window| while calculating the number of windows. + // Pass NULL for |ignore_window| to consider all windows. + static bool UseSoloWindowHeaderInRoot(aura::RootWindow* root_window, + aura::Window* ignore_window); + + // Updates the solo-window transparent header appearance for all windows in + // |root_window|. If |ignore_window| is not NULL it is ignored for when + // counting visible windows. This is useful for updates when a window is about + // to be closed or is moving to another root. If the solo window status + // changes it schedules paints as necessary. static void UpdateSoloWindowInRoot(aura::RootWindow* root_window, - aura::Window* ignorable_window); - - // Convenience method to call UpdateSoloWindowInRoot() with the current - // window's root window. - void UpdateSoloWindowFramePainter(aura::Window* ignorable_window); + aura::Window* ignore_window); // Schedules a paint for the header. Used when transitioning from no header to // a header (or other way around). @@ -205,8 +198,6 @@ class ASH_EXPORT FramePainter : public aura::WindowObserver, gfx::Rect GetTitleBounds(views::NonClientFrameView* view, const gfx::Font& title_font); - static std::set<FramePainter*>* instances_; - // Not owned views::Widget* frame_; views::View* window_icon_; // May be NULL. diff --git a/ash/wm/frame_painter_unittest.cc b/ash/wm/frame_painter_unittest.cc index 61d7b1e..66055a3 100644 --- a/ash/wm/frame_painter_unittest.cc +++ b/ash/wm/frame_painter_unittest.cc @@ -165,21 +165,6 @@ class FramePainterTest : public ash::test::AshTestBase { } }; -TEST_F(FramePainterTest, Basics) { - // Other tests might have created a FramePainter, so we cannot assert that - // FramePainter::instances_ is NULL here. - - // Creating a painter bumps the instance count. - scoped_ptr<FramePainter> painter(new FramePainter); - ASSERT_TRUE(FramePainter::instances_); - EXPECT_EQ(1u, FramePainter::instances_->size()); - - // Destroying that painter leaves a valid pointer but no instances. - painter.reset(); - ASSERT_TRUE(FramePainter::instances_); - EXPECT_EQ(0u, FramePainter::instances_->size()); -} - TEST_F(FramePainterTest, CreateAndDeleteSingleWindow) { // Ensure that creating/deleting a window works well and doesn't cause // crashes. See crbug.com/155634 @@ -195,12 +180,11 @@ TEST_F(FramePainterTest, CreateAndDeleteSingleWindow) { // We only have one window, so it should use a solo header. EXPECT_TRUE(painter->UseSoloWindowHeader()); - EXPECT_EQ(painter.get(), - root->GetProperty(internal::kSoloWindowFramePainterKey)); + EXPECT_TRUE(root->GetProperty(internal::kSoloWindowHeaderKey)); // Close the window. widget.reset(); - EXPECT_EQ(NULL, root->GetProperty(internal::kSoloWindowFramePainterKey)); + EXPECT_FALSE(root->GetProperty(internal::kSoloWindowHeaderKey)); // Recreate another window again. painter.reset(new FramePainter); @@ -210,8 +194,7 @@ TEST_F(FramePainterTest, CreateAndDeleteSingleWindow) { widget.get(), NULL, &size, &close, FramePainter::SIZE_BUTTON_MAXIMIZES); widget->Show(); EXPECT_TRUE(painter->UseSoloWindowHeader()); - EXPECT_EQ(painter.get(), - root->GetProperty(internal::kSoloWindowFramePainterKey)); + EXPECT_TRUE(root->GetProperty(internal::kSoloWindowHeaderKey)); } TEST_F(FramePainterTest, LayoutHeader) { @@ -297,9 +280,10 @@ TEST_F(FramePainterTest, UseSoloWindowHeader) { p2.Init(w2.get(), NULL, &size2, &close2, FramePainter::SIZE_BUTTON_MAXIMIZES); w2->Show(); - // Now there are two windows, so we should not use solo headers. + // Now there are two windows, so we should not use solo headers. This only + // needs to test |p1| because "solo window headers" are a per-root-window + // property. EXPECT_FALSE(p1.UseSoloWindowHeader()); - EXPECT_FALSE(p2.UseSoloWindowHeader()); // Hide one window. Solo should be enabled. w2->Hide(); @@ -308,19 +292,16 @@ TEST_F(FramePainterTest, UseSoloWindowHeader) { // Show that window. Solo should be disabled. w2->Show(); EXPECT_FALSE(p1.UseSoloWindowHeader()); - EXPECT_FALSE(p2.UseSoloWindowHeader()); // Maximize the window, then activate the first window. The second window // is in its own workspace, so solo should be active for the first one. w2->Maximize(); w1->Activate(); EXPECT_TRUE(p1.UseSoloWindowHeader()); - EXPECT_FALSE(p2.UseSoloWindowHeader()); // Switch to the second window and restore it. Solo should be disabled. w2->Activate(); w2->Restore(); - EXPECT_FALSE(p1.UseSoloWindowHeader()); EXPECT_FALSE(p2.UseSoloWindowHeader()); // Minimize the second window. Solo should be enabled. @@ -338,7 +319,6 @@ TEST_F(FramePainterTest, UseSoloWindowHeader) { ImageButton close3(NULL); p3.Init(w3.get(), NULL, &size3, &close3, FramePainter::SIZE_BUTTON_MAXIMIZES); w3->Show(); - EXPECT_FALSE(p1.UseSoloWindowHeader()); EXPECT_FALSE(p3.UseSoloWindowHeader()); // Close the always-on-top widget. @@ -346,6 +326,37 @@ TEST_F(FramePainterTest, UseSoloWindowHeader) { EXPECT_TRUE(p1.UseSoloWindowHeader()); } +// An open V2 app window should cause browser windows not to use the +// solo window header. +TEST_F(FramePainterTest, UseSoloWindowHeaderWithApp) { + // Create a widget and a painter for it. + scoped_ptr<Widget> w1(CreateTestWidget()); + FramePainter p1; + ImageButton size1(NULL); + ImageButton close1(NULL); + p1.Init(w1.get(), NULL, &size1, &close1, FramePainter::SIZE_BUTTON_MAXIMIZES); + w1->Show(); + + // We only have one window, so it should use a solo header. + EXPECT_TRUE(p1.UseSoloWindowHeader()); + + // Simulate a V2 app window, which is part of the active workspace but does + // not have a frame painter. + scoped_ptr<Widget> w2(CreateTestWidget()); + w2->Show(); + + // Now there are two windows, so we should not use solo headers. + EXPECT_FALSE(p1.UseSoloWindowHeader()); + + // Minimize the app window. The first window should go solo again. + w2->Minimize(); + EXPECT_TRUE(p1.UseSoloWindowHeader()); + + // Restoring the app window turns off solo headers. + w2->Restore(); + EXPECT_FALSE(p1.UseSoloWindowHeader()); +} + #if defined(OS_WIN) // Multiple displays are not supported on Windows Ash. http://crbug.com/165962 #define MAYBE_UseSoloWindowHeaderMultiDisplay \ diff --git a/ash/wm/window_properties.cc b/ash/wm/window_properties.cc index 792d3b6..8b0ed34 100644 --- a/ash/wm/window_properties.cc +++ b/ash/wm/window_properties.cc @@ -30,8 +30,7 @@ DEFINE_WINDOW_PROPERTY_KEY( ui::WindowShowState, kRestoreShowStateKey, ui::SHOW_STATE_DEFAULT); DEFINE_WINDOW_PROPERTY_KEY(RootWindowController*, kRootWindowControllerKey, NULL); -DEFINE_WINDOW_PROPERTY_KEY( - ash::FramePainter*, kSoloWindowFramePainterKey, NULL); +DEFINE_WINDOW_PROPERTY_KEY(bool, kSoloWindowHeaderKey, false); DEFINE_WINDOW_PROPERTY_KEY(bool, kStayInSameRootWindowKey, false); DEFINE_WINDOW_PROPERTY_KEY(bool, kUsesScreenCoordinatesKey, false); DEFINE_WINDOW_PROPERTY_KEY(bool, kUserChangedWindowPositionOrSizeKey, false); diff --git a/ash/wm/window_properties.h b/ash/wm/window_properties.h index 509e3f6..21d7ae9 100644 --- a/ash/wm/window_properties.h +++ b/ash/wm/window_properties.h @@ -61,10 +61,10 @@ extern const aura::WindowProperty<ui::WindowShowState>* const extern const aura::WindowProperty<RootWindowController*>* const kRootWindowControllerKey; -// A property key to remember the frame painter for the solo-window in the root -// window. It is only available for root windows. -ASH_EXPORT extern const aura::WindowProperty<ash::FramePainter*>* const - kSoloWindowFramePainterKey; +// RootWindow property to indicate if the window in the active workspace should +// use the transparent "solo-window" header style. +ASH_EXPORT extern const aura::WindowProperty<bool>* const + kSoloWindowHeaderKey; // If this is set to true, the window stays in the same root window // even if the bounds outside of its root window is set. diff --git a/ash/wm/workspace/workspace_manager.cc b/ash/wm/workspace/workspace_manager.cc index 32899bf..106dbff 100644 --- a/ash/wm/workspace/workspace_manager.cc +++ b/ash/wm/workspace/workspace_manager.cc @@ -666,11 +666,13 @@ void WorkspaceManager::ProcessDeletion() { void WorkspaceManager::OnWindowAddedToWorkspace(Workspace* workspace, Window* child) { child->SetProperty(kWorkspaceKey, workspace); - // Do nothing (other than updating shelf visibility) as the right parent was - // chosen by way of GetParentForNewWindow() or we explicitly moved the window + // Don't make changes to window parenting as the right parent was chosen + // by way of GetParentForNewWindow() or we explicitly moved the window // to the workspace. - if (workspace == active_workspace_) + if (workspace == active_workspace_) { UpdateShelfVisibility(); + FramePainter::UpdateSoloWindowHeader(child->GetRootWindow()); + } RearrangeVisibleWindowOnShow(child); } @@ -698,8 +700,10 @@ void WorkspaceManager::OnWorkspaceChildWindowVisibilityChanged( RearrangeVisibleWindowOnShow(child); else RearrangeVisibleWindowOnHideOrRemove(child); - if (workspace == active_workspace_) + if (workspace == active_workspace_) { UpdateShelfVisibility(); + FramePainter::UpdateSoloWindowHeader(child->GetRootWindow()); + } } } |