Bug 1491808 - Listen on window-state-event to set titlebar active/inactive state, r=jhorak
authorMartin Stransky <stransky@redhat.com>
Mon, 03 Dec 2018 12:48:35 +0000
changeset 449242 d1fc8c77ad7fc8098a798cb0df05587d7f374b95
parent 449241 7670b6ce33a4b3ad15ff3dc1ec3bfb9349cec19b
child 449243 1a6f9251c41f32feca557aa9f9ace21070bf803e
push id74184
push usernbeleuzu@mozilla.com
push dateMon, 03 Dec 2018 16:50:58 +0000
treeherderautoland@1a6f9251c41f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhorak
bugs1491808
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1491808 - Listen on window-state-event to set titlebar active/inactive state, r=jhorak This is a workaround for https://gitlab.gnome.org/GNOME/gtk/issues/1395 Gtk+ controls window active appearance by window-state-event signal but gecko uses focus-in/out signals. So we need to set the the titlebar state when window-state-event comes *after* focus-in/out signals. Differential Revision: https://phabricator.services.mozilla.com/D13051
widget/gtk/nsNativeThemeGTK.cpp
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -438,18 +438,21 @@ bool nsNativeThemeGTK::GetGtkWidgetAndSt
       }
     }
 
     if (aAppearance == StyleAppearance::MozWindowTitlebar ||
         aAppearance == StyleAppearance::MozWindowTitlebarMaximized ||
         aAppearance == StyleAppearance::MozWindowButtonClose ||
         aAppearance == StyleAppearance::MozWindowButtonMinimize ||
         aAppearance == StyleAppearance::MozWindowButtonMaximize ||
-        aAppearance == StyleAppearance::MozWindowButtonRestore ||
-        aAppearance == StyleAppearance::ScrollbarbuttonUp ||
+        aAppearance == StyleAppearance::MozWindowButtonRestore) {
+      aState->backdrop = !nsWindow::GetTopLevelWindowActiveState(aFrame);
+    }
+
+    if (aAppearance == StyleAppearance::ScrollbarbuttonUp ||
         aAppearance == StyleAppearance::ScrollbarbuttonDown ||
         aAppearance == StyleAppearance::ScrollbarbuttonLeft ||
         aAppearance == StyleAppearance::ScrollbarbuttonRight ||
         aAppearance == StyleAppearance::ScrollbarVertical ||
         aAppearance == StyleAppearance::ScrollbarHorizontal ||
         aAppearance == StyleAppearance::ScrollbartrackHorizontal ||
         aAppearance == StyleAppearance::ScrollbartrackVertical ||
         aAppearance == StyleAppearance::ScrollbarthumbVertical ||
@@ -1983,22 +1986,16 @@ nsITheme::Transparency nsNativeThemeGTK:
     default:
       return eUnknownTransparency;
   }
 }
 
 bool nsNativeThemeGTK::WidgetAppearanceDependsOnWindowFocus(
     StyleAppearance aAppearance) {
   switch (aAppearance) {
-    case StyleAppearance::MozWindowTitlebar:
-    case StyleAppearance::MozWindowTitlebarMaximized:
-    case StyleAppearance::MozWindowButtonClose:
-    case StyleAppearance::MozWindowButtonMinimize:
-    case StyleAppearance::MozWindowButtonMaximize:
-    case StyleAppearance::MozWindowButtonRestore:
     case StyleAppearance::ScrollbarbuttonUp:
     case StyleAppearance::ScrollbarbuttonDown:
     case StyleAppearance::ScrollbarbuttonLeft:
     case StyleAppearance::ScrollbarbuttonRight:
     case StyleAppearance::ScrollbarVertical:
     case StyleAppearance::ScrollbarHorizontal:
     case StyleAppearance::ScrollbartrackHorizontal:
     case StyleAppearance::ScrollbartrackVertical:
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -429,16 +429,17 @@ nsWindow::nsWindow() {
   mTransparencyBitmapHeight = 0;
 
 #if GTK_CHECK_VERSION(3, 4, 0)
   mLastScrollEventTime = GDK_CURRENT_TIME;
 #endif
   mPendingConfigures = 0;
   mCSDSupportLevel = CSD_SUPPORT_NONE;
   mDrawInTitlebar = false;
+  mTitlebarBackdropState = false;
 
   mHasAlphaVisual = false;
 }
 
 nsWindow::~nsWindow() {
   LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
 
   delete[] mTransparencyBitmap;
@@ -3082,16 +3083,30 @@ void nsWindow::OnWindowStateEvent(GtkWid
     aEvent->changed_mask = static_cast<GdkWindowState>(
         aEvent->changed_mask & ~GDK_WINDOW_STATE_MAXIMIZED);
   } else if (aEvent->changed_mask & GDK_WINDOW_STATE_WITHDRAWN &&
              aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
     aEvent->changed_mask = static_cast<GdkWindowState>(
         aEvent->changed_mask | GDK_WINDOW_STATE_MAXIMIZED);
   }
 
+  // This is a workaround for https://gitlab.gnome.org/GNOME/gtk/issues/1395
+  // Gtk+ controls window active appearance by window-state-event signal
+  // but gecko uses focus-in/out signals. So we need to repaint the titlebar
+  // when window-state-event comes.
+  if (mDrawInTitlebar && (aEvent->changed_mask & GDK_WINDOW_STATE_FOCUSED)) {
+    // Emulate what Gtk+ does at gtk_window_state_event().
+    // We can't check GTK_STATE_FLAG_BACKDROP directly as it's set by Gtk+
+    // *after* this window-state-event handler.
+    mTitlebarBackdropState =
+        !(aEvent->new_window_state & GDK_WINDOW_STATE_FOCUSED);
+
+    return;
+  }
+
   // We don't care about anything but changes in the maximized/icon/fullscreen
   // states
   if ((aEvent->changed_mask &
        (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED |
         GDK_WINDOW_STATE_FULLSCREEN)) == 0) {
     return;
   }
 
@@ -6678,8 +6693,43 @@ already_AddRefed<nsIWidget> nsIWidget::C
   nsCOMPtr<nsIWidget> window = new nsWindow();
   return window.forget();
 }
 
 already_AddRefed<nsIWidget> nsIWidget::CreateChildWindow() {
   nsCOMPtr<nsIWidget> window = new nsWindow();
   return window.forget();
 }
+
+bool nsWindow::GetTopLevelWindowActiveState(nsIFrame *aFrame) {
+  // Used by window frame and button box rendering. We can end up in here in
+  // the content process when rendering one of these moz styles freely in a
+  // page. Fail in this case, there is no applicable window focus state.
+  if (!XRE_IsParentProcess()) {
+    return false;
+  }
+  // All headless windows are considered active so they are painted.
+  if (gfxPlatform::IsHeadless()) {
+    return true;
+  }
+  // Get the widget. nsIFrame's GetNearestWidget walks up the view chain
+  // until it finds a real window.
+  nsWindow *window = static_cast<nsWindow *>(aFrame->GetNearestWidget());
+  if (!window) {
+    return false;
+  }
+
+  // Get our toplevel nsWindow.
+  if (!window->mIsTopLevel) {
+    GtkWidget *widget = window->GetMozContainerWidget();
+    if (!widget) {
+      return false;
+    }
+
+    GtkWidget *toplevelWidget = gtk_widget_get_toplevel(widget);
+    window = get_window_for_gtk_widget(toplevelWidget);
+    if (!window) {
+      return false;
+    }
+  }
+
+  return !window->mTitlebarBackdropState;
+}
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -411,16 +411,17 @@ class nsWindow final : public nsBaseWidg
   } CSDSupportLevel;
   /**
    * Get the support of Client Side Decoration by checking
    * the XDG_CURRENT_DESKTOP environment variable.
    */
   static CSDSupportLevel GetSystemCSDSupportLevel();
 
   static bool TopLevelWindowUseARGBVisual();
+  static bool GetTopLevelWindowActiveState(nsIFrame* aFrame);
 
  protected:
   virtual ~nsWindow();
 
   // event handling code
   void DispatchActivateEvent(void);
   void DispatchDeactivateEvent(void);
   void DispatchResized();
@@ -530,16 +531,18 @@ class nsWindow final : public nsBaseWidg
   // window. See bug 1225044.
   unsigned int mPendingConfigures;
 
   // Window titlebar rendering mode, CSD_SUPPORT_NONE if it's disabled
   // for this window.
   CSDSupportLevel mCSDSupportLevel;
   // If true, draw our own window titlebar.
   bool mDrawInTitlebar;
+  // Draw titlebar with :backdrop css state (inactive/unfocused).
+  bool mTitlebarBackdropState;
   // Draggable titlebar region maintained by UpdateWindowDraggingRegion
   LayoutDeviceIntRegion mDraggableRegion;
 
 #ifdef ACCESSIBILITY
   RefPtr<mozilla::a11y::Accessible> mRootAccessible;
 
   /**
    * Request to create the accessible for this window if it is top level.