Bug 1442755 - Redraw titlebar widgets when application focus changes and draw inactive titlebar with GTK_STATE_FLAG_BACKDROP state, r=jhorak
authorMartin Stransky <stransky@redhat.com>
Wed, 12 Sep 2018 11:03:56 +0000
changeset 494316 511150b11de9f0143a1152d7bfbffe89c20a22bc
parent 494315 3271f5d15d52cb6989cc0850a7aebfd3631af885
child 494317 8fca7dfccf8d1a0d70b7b8e33973edef96a33b15
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhorak
bugs1442755
milestone64.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 1442755 - Redraw titlebar widgets when application focus changes and draw inactive titlebar with GTK_STATE_FLAG_BACKDROP state, r=jhorak Differential Revision: https://phabricator.services.mozilla.com/D5582
widget/gtk/gtk3drawing.cpp
widget/gtk/gtkdrawing.h
widget/gtk/mozgtk/mozgtk.c
widget/gtk/nsNativeThemeGTK.cpp
widget/gtk/nsNativeThemeGTK.h
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -167,16 +167,18 @@ GetStateFlagsFromGtkWidgetState(GtkWidge
         stateFlags = GTK_STATE_FLAG_INSENSITIVE;
     else {
         if (state->depressed || state->active)
             stateFlags = static_cast<GtkStateFlags>(stateFlags|GTK_STATE_FLAG_ACTIVE);
         if (state->inHover)
             stateFlags = static_cast<GtkStateFlags>(stateFlags|GTK_STATE_FLAG_PRELIGHT);
         if (state->focused)
             stateFlags = static_cast<GtkStateFlags>(stateFlags|GTK_STATE_FLAG_FOCUSED);
+        if (state->backdrop)
+            stateFlags = static_cast<GtkStateFlags>(stateFlags|GTK_STATE_FLAG_BACKDROP);
     }
 
     return stateFlags;
 }
 
 static GtkStateFlags
 GetStateFlagsFromGtkTabFlags(GtkTabFlags flags)
 {
@@ -2306,25 +2308,28 @@ moz_gtk_info_bar_paint(cairo_t *cr, GdkR
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
 moz_gtk_header_bar_paint(WidgetNodeType widgetType,
                          cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state)
 {
     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
-    GtkStyleContext *style = GetStyleContext(widgetType, GTK_TEXT_DIR_LTR,
-                                             state_flags);
+    GtkStyleContext *style =
+        GetStyleContext(widgetType, GTK_TEXT_DIR_NONE, state_flags);
+
     InsetByMargin(rect, style);
 
     // Some themes (Adwaita for instance) draws bold dark line at
     // titlebar bottom. It does not fit well with Firefox tabs so
     // draw with some extent to make the titlebar bottom part invisible.
     #define TITLEBAR_EXTENT 4
 
+    // We don't need to draw window decoration for MOZ_GTK_HEADER_BAR_MAXIMIZED,
+    // i.e. when main window is maximized.
     if (widgetType == MOZ_GTK_HEADER_BAR) {
         GtkStyleContext* windowStyle = GetStyleContext(MOZ_GTK_WINDOW);
         bool solidDecorations =
             gtk_style_context_has_class(windowStyle, "solid-csd");
         GtkStyleContext *decorationStyle =
             GetStyleContext(solidDecorations ? MOZ_GTK_WINDOW_DECORATION_SOLID:
                                                MOZ_GTK_WINDOW_DECORATION,
                             GTK_TEXT_DIR_LTR,
@@ -2339,18 +2344,16 @@ moz_gtk_header_bar_paint(WidgetNodeType 
     gtk_render_background(style, cr, rect->x, rect->y,
                           rect->width, rect->height + TITLEBAR_EXTENT);
     gtk_render_frame(style, cr, rect->x, rect->y,
                      rect->width, rect->height + TITLEBAR_EXTENT);
 
     return MOZ_GTK_SUCCESS;
 }
 
-
-
 static GtkBorder
 GetMarginBorderPadding(GtkStyleContext* aStyle)
 {
     gint left = 0, top = 0, right = 0, bottom = 0;
     moz_gtk_add_margin_border_padding(aStyle, &left, &top, &right, &bottom);
     // narrowing conversions to gint16:
     GtkBorder result;
     result.left = left;
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -26,16 +26,17 @@ typedef struct {
   guint8 selected;
   guint8 inHover;
   guint8 disabled;
   guint8 isDefault;
   guint8 canDefault;
   /* The depressed state is for buttons which remain active for a longer period:
    * activated toggle buttons or buttons showing a popup menu. */
   guint8 depressed;
+  guint8 backdrop;
   gint32 curpos; /* curpos and maxpos are used for scrollbars */
   gint32 maxpos;
   gint32 scale;  /* actual widget scale */
 } GtkWidgetState;
 
 /**
  * A size in the same GTK pixel units as GtkBorder and GdkRectangle.
  */
--- a/widget/gtk/mozgtk/mozgtk.c
+++ b/widget/gtk/mozgtk/mozgtk.c
@@ -653,9 +653,8 @@ STUB(gtk_object_get_type)
 // mozgtk loads before libXext/libcairo and so this stub will take priority.
 // Our tree usage goes through xcb and remains unaffected by this.
 MOZ_EXPORT Bool
 XShmQueryExtension(Display* aDisplay)
 {
   return False;
 }
 #endif
-
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -36,16 +36,17 @@
 #include "gfxPlatformGtk.h"
 #include "gfxGdkNativeRenderer.h"
 #include "mozilla/gfx/BorrowedContext.h"
 #include "mozilla/gfx/HelpersCairo.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/StaticPrefs.h"
+#include "nsWindow.h"
 
 #ifdef MOZ_X11
 #  ifdef CAIRO_HAS_XLIB_SURFACE
 #    include "cairo-xlib.h"
 #  endif
 #  ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE
 #    include "cairo-xlib-xrender.h"
 #  endif
@@ -232,16 +233,18 @@ nsNativeThemeGTK::GetGtkWidgetAndState(S
                                        gint* aWidgetFlags)
 {
   if (aWidgetType == StyleAppearance::MenulistButton &&
       StaticPrefs::layout_css_webkit_appearance_enabled()) {
     aWidgetType = StyleAppearance::Menulist;
   }
 
   if (aState) {
+    memset(aState, 0, sizeof(GtkWidgetState));
+
     // For XUL checkboxes and radio buttons, the state of the parent
     // determines our state.
     nsIFrame *stateFrame = aFrame;
     if (aFrame && ((aWidgetFlags && (aWidgetType == StyleAppearance::Checkbox ||
                                      aWidgetType == StyleAppearance::Radio)) ||
                    aWidgetType == StyleAppearance::CheckboxLabel ||
                    aWidgetType == StyleAppearance::RadioLabel)) {
 
@@ -285,21 +288,19 @@ nsNativeThemeGTK::GetGtkWidgetAndState(S
       stateFrame = aFrame = aFrame->GetParent();
     }
 
     EventStates eventState = GetContentState(stateFrame, aWidgetType);
 
     aState->disabled = IsDisabled(aFrame, eventState) || IsReadOnly(aFrame);
     aState->active  = eventState.HasState(NS_EVENT_STATE_ACTIVE);
     aState->focused = eventState.HasState(NS_EVENT_STATE_FOCUS);
-    aState->selected = FALSE;
     aState->inHover = eventState.HasState(NS_EVENT_STATE_HOVER);
     aState->isDefault = IsDefaultButton(aFrame);
     aState->canDefault = FALSE; // XXX fix me
-    aState->depressed = FALSE;
 
     if (aWidgetType == StyleAppearance::FocusOutline) {
       aState->disabled = FALSE;
       aState->active  = FALSE;
       aState->inHover = FALSE;
       aState->isDefault = FALSE;
       aState->canDefault = FALSE;
 
@@ -439,16 +440,25 @@ nsNativeThemeGTK::GetGtkWidgetAndState(S
       // When the input field of the drop down button has focus, some themes
       // should draw focus for the drop down button as well.
       if ((aWidgetType == StyleAppearance::MenulistButton ||
            aWidgetType == StyleAppearance::MozMenulistButton) &&
           aWidgetFlags) {
         *aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused);
       }
     }
+
+    if (aWidgetType == StyleAppearance::MozWindowTitlebar ||
+        aWidgetType == StyleAppearance::MozWindowTitlebarMaximized ||
+        aWidgetType == StyleAppearance::MozWindowButtonClose ||
+        aWidgetType == StyleAppearance::MozWindowButtonMinimize ||
+        aWidgetType == StyleAppearance::MozWindowButtonMaximize ||
+        aWidgetType == StyleAppearance::MozWindowButtonRestore) {
+      aState->backdrop = !nsWindow::GetTopLevelWindowActiveState(aFrame);
+    }
   }
 
   switch (aWidgetType) {
   case StyleAppearance::Button:
     if (aWidgetFlags)
       *aWidgetFlags = GTK_RELIEF_NORMAL;
     aGtkWidgetType = MOZ_GTK_BUTTON;
     break;
@@ -1782,16 +1792,26 @@ nsNativeThemeGTK::WidgetStateChanged(nsI
       aWidgetType == StyleAppearance::Tooltip ||
       aWidgetType == StyleAppearance::Menuseparator ||
       aWidgetType == StyleAppearance::Window ||
       aWidgetType == StyleAppearance::Dialog) {
     *aShouldRepaint = false;
     return NS_OK;
   }
 
+  if (aWidgetType == StyleAppearance::MozWindowTitlebar ||
+      aWidgetType == StyleAppearance::MozWindowTitlebarMaximized ||
+      aWidgetType == StyleAppearance::MozWindowButtonClose ||
+      aWidgetType == StyleAppearance::MozWindowButtonMinimize ||
+      aWidgetType == StyleAppearance::MozWindowButtonMaximize ||
+      aWidgetType == StyleAppearance::MozWindowButtonRestore) {
+    *aShouldRepaint = true;
+    return NS_OK;
+  }
+
   if ((aWidgetType == StyleAppearance::ScrollbarthumbVertical ||
        aWidgetType == StyleAppearance::ScrollbarthumbHorizontal) &&
        aAttribute == nsGkAtoms::active) {
     *aShouldRepaint = true;
     return NS_OK;
   }
 
   if ((aWidgetType == StyleAppearance::ScrollbarbuttonUp ||
@@ -2078,8 +2098,24 @@ nsNativeThemeGTK::GetWidgetTransparency(
   // but are shaped on Gtk3
   case StyleAppearance::Tooltip:
     return eTransparent;
   default:
     return eUnknownTransparency;
   }
 
 }
+
+bool
+nsNativeThemeGTK::WidgetAppearanceDependsOnWindowFocus(StyleAppearance aWidgetType)
+{
+  switch (aWidgetType) {
+    case StyleAppearance::MozWindowTitlebar:
+    case StyleAppearance::MozWindowTitlebarMaximized:
+    case StyleAppearance::MozWindowButtonClose:
+    case StyleAppearance::MozWindowButtonMinimize:
+    case StyleAppearance::MozWindowButtonMaximize:
+    case StyleAppearance::MozWindowButtonRestore:
+      return true;
+    default:
+      return false;
+  }
+}
--- a/widget/gtk/nsNativeThemeGTK.h
+++ b/widget/gtk/nsNativeThemeGTK.h
@@ -71,16 +71,19 @@ public:
   NS_IMETHOD_(bool) WidgetIsContainer(WidgetType aWidgetType) override;
 
   NS_IMETHOD_(bool) ThemeDrawsFocusForWidget(WidgetType aWidgetType) override;
 
   virtual bool ThemeNeedsComboboxDropmarker() override;
 
   virtual Transparency GetWidgetTransparency(nsIFrame* aFrame,
                                              WidgetType aWidgetType) override;
+
+  virtual bool WidgetAppearanceDependsOnWindowFocus(WidgetType aWidgetType) override;
+
   nsNativeThemeGTK();
 
 protected:
   virtual ~nsNativeThemeGTK();
 
 private:
   GtkTextDirection GetTextDirection(nsIFrame* aFrame);
   gint GetTabMarginPixels(nsIFrame* aFrame);
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -7376,8 +7376,45 @@ nsIWidget::CreateTopLevelWindow()
 }
 
 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 (gFocusWindow == window);
+}
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -10,16 +10,17 @@
 
 #include "mozcontainer.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/UniquePtr.h"
 #include "nsIDragService.h"
 #include "nsITimer.h"
 #include "nsGkAtoms.h"
 #include "nsRefPtrHashtable.h"
+#include "nsIFrame.h"
 
 #include "nsBaseWidget.h"
 #include "CompositorWidget.h"
 #include <gdk/gdk.h>
 #include <gtk/gtk.h>
 
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
@@ -423,16 +424,18 @@ public:
                    CSD_SUPPORT_UNKNOWN
     } CSDSupportLevel;
     /**
      * Get the support of Client Side Decoration by checking
      * the XDG_CURRENT_DESKTOP environment variable.
      */
     static CSDSupportLevel GetSystemCSDSupportLevel();
 
+    static bool GetTopLevelWindowActiveState(nsIFrame *aFrame);
+
 protected:
     virtual ~nsWindow();
 
     // event handling code
     void DispatchActivateEvent(void);
     void DispatchDeactivateEvent(void);
     void DispatchResized();
     void MaybeDispatchResized();