mozilla-enable-csd.patch
branchfirefox60
changeset 1062 48d794331fce
parent 1052 7a49806c8dae
child 1064 af29b3ac33ae
equal deleted inserted replaced
1052:7a49806c8dae 1062:48d794331fce
     1 This is a composition of these patches for Firefox 60:
       
     2 
       
     3 https://bugzilla.mozilla.org/show_bug.cgi?id=1441873
       
     4 https://bugzilla.mozilla.org/show_bug.cgi?id=1441665
       
     5 https://bugzilla.mozilla.org/show_bug.cgi?id=1456898
       
     6 https://bugzilla.mozilla.org/show_bug.cgi?id=1457309
       
     7 https://bugzilla.mozilla.org/show_bug.cgi?id=1457691
       
     8 
       
     9 which fix popup window placement at CSD window mode.
       
    10 
       
    11 
       
    12 diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp
       
    13 --- a/widget/gtk/nsLookAndFeel.cpp
       
    14 +++ b/widget/gtk/nsLookAndFeel.cpp
       
    15 @@ -1076,19 +1076,18 @@ nsLookAndFeel::EnsureInit()
       
    16                           nullptr);
       
    17  
       
    18      GetSystemFontInfo(gtk_widget_get_style_context(entry),
       
    19                        &mFieldFontName, &mFieldFontStyle);
       
    20  
       
    21      gtk_widget_destroy(window);
       
    22      g_object_unref(labelWidget);
       
    23  
       
    24 -    // Require GTK 3.10 for GtkHeaderBar support and compatible window manager.
       
    25 -    mCSDAvailable = (gtk_check_version(3, 10, 0) == nullptr &&
       
    26 -        nsWindow::GetCSDSupportLevel() != nsWindow::CSD_SUPPORT_NONE);
       
    27 +    mCSDAvailable =
       
    28 +        nsWindow::GetSystemCSDSupportLevel() != nsWindow::CSD_SUPPORT_NONE;
       
    29  
       
    30      mCSDCloseButton = false;
       
    31      mCSDMinimizeButton = false;
       
    32      mCSDMaximizeButton = false;
       
    33  
       
    34      // We need to initialize whole CSD config explicitly because it's queried
       
    35      // as -moz-gtk* media features.
       
    36      WidgetNodeType buttonLayout[TOOLBAR_BUTTONS];
       
    37 diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
       
    38 --- a/widget/gtk/nsWindow.h
       
    39 +++ b/widget/gtk/nsWindow.h
       
    40 @@ -395,28 +395,26 @@ public:
       
    41      // From GDK
       
    42      int GdkCoordToDevicePixels(gint coord);
       
    43      LayoutDeviceIntPoint GdkPointToDevicePixels(GdkPoint point);
       
    44      LayoutDeviceIntPoint GdkEventCoordsToDevicePixels(gdouble x, gdouble y);
       
    45      LayoutDeviceIntRect GdkRectToDevicePixels(GdkRectangle rect);
       
    46  
       
    47      virtual bool WidgetTypeSupportsAcceleration() override;
       
    48  
       
    49 -    bool DoDrawTitlebar() const;
       
    50 -
       
    51      typedef enum { CSD_SUPPORT_SYSTEM,    // CSD including shadows
       
    52                     CSD_SUPPORT_CLIENT,    // CSD without shadows
       
    53                     CSD_SUPPORT_NONE,      // WM does not support CSD at all
       
    54                     CSD_SUPPORT_UNKNOWN
       
    55      } CSDSupportLevel;
       
    56      /**
       
    57       * Get the support of Client Side Decoration by checking
       
    58       * the XDG_CURRENT_DESKTOP environment variable.
       
    59       */
       
    60 -    static CSDSupportLevel GetCSDSupportLevel();
       
    61 +    static CSDSupportLevel GetSystemCSDSupportLevel();
       
    62  
       
    63  protected:
       
    64      virtual ~nsWindow();
       
    65  
       
    66      // event handling code
       
    67      void DispatchActivateEvent(void);
       
    68      void DispatchDeactivateEvent(void);
       
    69      void DispatchResized();
       
    70 @@ -512,19 +510,21 @@ private:
       
    71      int                 mXDepth;
       
    72      mozilla::widget::WindowSurfaceProvider mSurfaceProvider;
       
    73  #endif
       
    74  
       
    75      // Upper bound on pending ConfigureNotify events to be dispatched to the
       
    76      // window. See bug 1225044.
       
    77      unsigned int mPendingConfigures;
       
    78  
       
    79 -    bool               mIsCSDAvailable;
       
    80 +    // Window titlebar rendering mode, CSD_SUPPORT_NONE if it's disabled
       
    81 +    // for this window.
       
    82 +    CSDSupportLevel    mCSDSupportLevel;
       
    83      // If true, draw our own window titlebar.
       
    84 -    bool               mIsCSDEnabled;
       
    85 +    bool               mDrawInTitlebar;
       
    86      // Draggable titlebar region maintained by UpdateWindowDraggingRegion
       
    87      LayoutDeviceIntRegion mDraggableRegion;
       
    88  
       
    89  #ifdef ACCESSIBILITY
       
    90      RefPtr<mozilla::a11y::Accessible> mRootAccessible;
       
    91  
       
    92      /**
       
    93       * Request to create the accessible for this window if it is top level.
       
    94 
       
    95 diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
       
    96 --- a/widget/gtk/nsWindow.cpp
       
    97 +++ b/widget/gtk/nsWindow.cpp
       
    98 @@ -474,18 +474,18 @@ nsWindow::nsWindow()
       
    99  
       
   100      mTransparencyBitmapWidth  = 0;
       
   101      mTransparencyBitmapHeight = 0;
       
   102  
       
   103  #if GTK_CHECK_VERSION(3,4,0)
       
   104      mLastScrollEventTime = GDK_CURRENT_TIME;
       
   105  #endif
       
   106      mPendingConfigures = 0;
       
   107 -    mIsCSDAvailable = false;
       
   108 -    mIsCSDEnabled = false;
       
   109 +    mCSDSupportLevel = CSD_SUPPORT_NONE;
       
   110 +    mDrawInTitlebar = false;
       
   111  }
       
   112  
       
   113  nsWindow::~nsWindow()
       
   114  {
       
   115      LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
       
   116  
       
   117      delete[] mTransparencyBitmap;
       
   118      mTransparencyBitmap = nullptr;
       
   119 @@ -2814,17 +2814,17 @@ nsWindow::OnButtonReleaseEvent(GdkEventB
       
   120      LayoutDeviceIntPoint pos = event.mRefPoint;
       
   121  
       
   122      nsEventStatus eventStatus = DispatchInputEvent(&event);
       
   123  
       
   124      bool defaultPrevented = (eventStatus == nsEventStatus_eConsumeNoDefault);
       
   125      // Check if mouse position in titlebar and doubleclick happened to
       
   126      // trigger restore/maximize.
       
   127      if (!defaultPrevented
       
   128 -             && mIsCSDEnabled
       
   129 +             && mDrawInTitlebar
       
   130               && event.button == WidgetMouseEvent::eLeftButton
       
   131               && event.mClickCount == 2
       
   132               && mDraggableRegion.Contains(pos.x, pos.y)) {
       
   133  
       
   134          if (mSizeState == nsSizeMode_Maximized) {
       
   135              SetSizeMode(nsSizeMode_Normal);
       
   136          } else {
       
   137              SetSizeMode(nsSizeMode_Maximized);
       
   138 @@ -3758,22 +3758,18 @@ nsWindow::Create(nsIWidget* aParent,
       
   139              gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel",
       
   140                                     gdk_get_program_class());
       
   141  
       
   142              // each toplevel window gets its own window group
       
   143              GtkWindowGroup *group = gtk_window_group_new();
       
   144              gtk_window_group_add_window(group, GTK_WINDOW(mShell));
       
   145              g_object_unref(group);
       
   146  
       
   147 -            int32_t isCSDAvailable = false;
       
   148 -            nsresult rv = LookAndFeel::GetInt(LookAndFeel::eIntID_GTKCSDAvailable,
       
   149 -                                              &isCSDAvailable);
       
   150 -            if (NS_SUCCEEDED(rv)) {
       
   151 -               mIsCSDAvailable = isCSDAvailable;
       
   152 -            }
       
   153 +            // We enable titlebar rendering for toplevel windows only.
       
   154 +            mCSDSupportLevel = GetSystemCSDSupportLevel();
       
   155          }
       
   156  
       
   157          // Create a container to hold child windows and child GtkWidgets.
       
   158          GtkWidget *container = moz_container_new();
       
   159          mContainer = MOZ_CONTAINER(container);
       
   160  
       
   161          // "csd" style is set when widget is realized so we need to call
       
   162          // it explicitly now.
       
   163 @@ -3788,17 +3784,17 @@ nsWindow::Create(nsIWidget* aParent,
       
   164           *    are drawn by Gtk+ to mShell. Content is rendered to mContainer
       
   165           *    and we listen to the Gtk+ events on mContainer.
       
   166           * 3) We're running on Wayland. All gecko content is rendered
       
   167           *    to mContainer and we listen to the Gtk+ events on mContainer.
       
   168           */
       
   169          GtkStyleContext* style = gtk_widget_get_style_context(mShell);
       
   170          drawToContainer =
       
   171              !mIsX11Display ||
       
   172 -            (mIsCSDAvailable && GetCSDSupportLevel() == CSD_SUPPORT_CLIENT) ||
       
   173 +            (mCSDSupportLevel == CSD_SUPPORT_CLIENT) ||
       
   174              gtk_style_context_has_class(style, "csd");
       
   175          eventWidget = (drawToContainer) ? container : mShell;
       
   176  
       
   177          gtk_widget_add_events(eventWidget, kEvents);
       
   178          if (drawToContainer)
       
   179              gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
       
   180  
       
   181          // Prevent GtkWindow from painting a background to avoid flickering.
       
   182 @@ -6581,90 +6577,91 @@ nsWindow::ClearCachedResources()
       
   183              window->ClearCachedResources();
       
   184          }
       
   185      }
       
   186  }
       
   187  
       
   188  nsresult
       
   189  nsWindow::SetNonClientMargins(LayoutDeviceIntMargin &aMargins)
       
   190  {
       
   191 -  SetDrawsInTitlebar(aMargins.top == 0);
       
   192 -  return NS_OK;
       
   193 +    SetDrawsInTitlebar(aMargins.top == 0);
       
   194 +    return NS_OK;
       
   195  }
       
   196  
       
   197  void
       
   198  nsWindow::SetDrawsInTitlebar(bool aState)
       
   199  {
       
   200 -  if (!mIsCSDAvailable || aState == mIsCSDEnabled)
       
   201 -      return;
       
   202 -
       
   203 -  if (mShell) {
       
   204 -      if (GetCSDSupportLevel() == CSD_SUPPORT_SYSTEM) {
       
   205 -          SetWindowDecoration(aState ? eBorderStyle_border : mBorderStyle);
       
   206 -      }
       
   207 -      else {
       
   208 -          /* Window manager does not support GDK_DECOR_BORDER,
       
   209 -           * emulate it by CSD.
       
   210 -           *
       
   211 -           * gtk_window_set_titlebar() works on unrealized widgets only,
       
   212 -           * we need to handle mShell carefully here.
       
   213 -           * When CSD is enabled mGdkWindow is owned by mContainer which is good
       
   214 -           * as we can't delete our mGdkWindow. To make mShell unrealized while
       
   215 -           * mContainer is preserved we temporary reparent mContainer to an
       
   216 -           * invisible GtkWindow.
       
   217 -           */
       
   218 -          NativeShow(false);
       
   219 -
       
   220 -          // Using GTK_WINDOW_POPUP rather than
       
   221 -          // GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
       
   222 -          // initialization and window manager interaction.
       
   223 -          GtkWidget* tmpWindow = gtk_window_new(GTK_WINDOW_POPUP);
       
   224 -          gtk_widget_realize(tmpWindow);
       
   225 -
       
   226 -          gtk_widget_reparent(GTK_WIDGET(mContainer), tmpWindow);
       
   227 -          gtk_widget_unrealize(GTK_WIDGET(mShell));
       
   228 -
       
   229 -          // Available as of GTK 3.10+
       
   230 -          static auto sGtkWindowSetTitlebar = (void (*)(GtkWindow*, GtkWidget*))
       
   231 -              dlsym(RTLD_DEFAULT, "gtk_window_set_titlebar");
       
   232 -          MOZ_ASSERT(sGtkWindowSetTitlebar,
       
   233 -              "Missing gtk_window_set_titlebar(), old Gtk+ library?");
       
   234 -
       
   235 -          if (aState) {
       
   236 -              // Add a hidden titlebar widget to trigger CSD, but disable the default
       
   237 -              // titlebar.  GtkFixed is a somewhat random choice for a simple unused
       
   238 -              // widget. gtk_window_set_titlebar() takes ownership of the titlebar
       
   239 -              // widget.
       
   240 -              sGtkWindowSetTitlebar(GTK_WINDOW(mShell), gtk_fixed_new());
       
   241 -          } else {
       
   242 -              sGtkWindowSetTitlebar(GTK_WINDOW(mShell), nullptr);
       
   243 -          }
       
   244 -
       
   245 -          /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=791081
       
   246 -           * gtk_widget_realize() throws:
       
   247 -           * "In pixman_region32_init_rect: Invalid rectangle passed"
       
   248 -           * when mShell has default 1x1 size.
       
   249 -           */
       
   250 -          GtkAllocation allocation = {0, 0, 0, 0};
       
   251 -          gtk_widget_get_preferred_width(GTK_WIDGET(mShell), nullptr,
       
   252 -                                         &allocation.width);
       
   253 -          gtk_widget_get_preferred_height(GTK_WIDGET(mShell), nullptr,
       
   254 -                                          &allocation.height);
       
   255 -          gtk_widget_size_allocate(GTK_WIDGET(mShell), &allocation);
       
   256 -
       
   257 -          gtk_widget_realize(GTK_WIDGET(mShell));
       
   258 -          gtk_widget_reparent(GTK_WIDGET(mContainer), GTK_WIDGET(mShell));
       
   259 -          mNeedsShow = true;
       
   260 -          NativeResize();
       
   261 -
       
   262 -          gtk_widget_destroy(tmpWindow);
       
   263 -      }
       
   264 -  }
       
   265 -
       
   266 -  mIsCSDEnabled = aState;
       
   267 +    if (!mShell ||
       
   268 +        mCSDSupportLevel == CSD_SUPPORT_NONE ||
       
   269 +        aState == mDrawInTitlebar) {
       
   270 +        return;
       
   271 +    }
       
   272 +
       
   273 +    if (mCSDSupportLevel == CSD_SUPPORT_SYSTEM) {
       
   274 +        SetWindowDecoration(aState ? eBorderStyle_border : mBorderStyle);
       
   275 +    }
       
   276 +    else if (mCSDSupportLevel == CSD_SUPPORT_CLIENT) {
       
   277 +        /* Window manager does not support GDK_DECOR_BORDER,
       
   278 +         * emulate it by CSD.
       
   279 +         *
       
   280 +         * gtk_window_set_titlebar() works on unrealized widgets only,
       
   281 +         * we need to handle mShell carefully here.
       
   282 +         * When CSD is enabled mGdkWindow is owned by mContainer which is good
       
   283 +         * as we can't delete our mGdkWindow. To make mShell unrealized while
       
   284 +         * mContainer is preserved we temporary reparent mContainer to an
       
   285 +         * invisible GtkWindow.
       
   286 +         */
       
   287 +        NativeShow(false);
       
   288 +
       
   289 +        // Using GTK_WINDOW_POPUP rather than
       
   290 +        // GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
       
   291 +        // initialization and window manager interaction.
       
   292 +        GtkWidget* tmpWindow = gtk_window_new(GTK_WINDOW_POPUP);
       
   293 +        gtk_widget_realize(tmpWindow);
       
   294 +
       
   295 +        gtk_widget_reparent(GTK_WIDGET(mContainer), tmpWindow);
       
   296 +        gtk_widget_unrealize(GTK_WIDGET(mShell));
       
   297 +
       
   298 +        // Available as of GTK 3.10+
       
   299 +        static auto sGtkWindowSetTitlebar = (void (*)(GtkWindow*, GtkWidget*))
       
   300 +            dlsym(RTLD_DEFAULT, "gtk_window_set_titlebar");
       
   301 +        MOZ_ASSERT(sGtkWindowSetTitlebar,
       
   302 +            "Missing gtk_window_set_titlebar(), old Gtk+ library?");
       
   303 +
       
   304 +        if (aState) {
       
   305 +            // Add a hidden titlebar widget to trigger CSD, but disable the default
       
   306 +            // titlebar.  GtkFixed is a somewhat random choice for a simple unused
       
   307 +            // widget. gtk_window_set_titlebar() takes ownership of the titlebar
       
   308 +            // widget.
       
   309 +            sGtkWindowSetTitlebar(GTK_WINDOW(mShell), gtk_fixed_new());
       
   310 +        } else {
       
   311 +            sGtkWindowSetTitlebar(GTK_WINDOW(mShell), nullptr);
       
   312 +        }
       
   313 +
       
   314 +        /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=791081
       
   315 +         * gtk_widget_realize() throws:
       
   316 +         * "In pixman_region32_init_rect: Invalid rectangle passed"
       
   317 +         * when mShell has default 1x1 size.
       
   318 +         */
       
   319 +        GtkAllocation allocation = {0, 0, 0, 0};
       
   320 +        gtk_widget_get_preferred_width(GTK_WIDGET(mShell), nullptr,
       
   321 +                                       &allocation.width);
       
   322 +        gtk_widget_get_preferred_height(GTK_WIDGET(mShell), nullptr,
       
   323 +                                        &allocation.height);
       
   324 +        gtk_widget_size_allocate(GTK_WIDGET(mShell), &allocation);
       
   325 +
       
   326 +        gtk_widget_realize(GTK_WIDGET(mShell));
       
   327 +        gtk_widget_reparent(GTK_WIDGET(mContainer), GTK_WIDGET(mShell));
       
   328 +        mNeedsShow = true;
       
   329 +        NativeResize();
       
   330 +
       
   331 +        gtk_widget_destroy(tmpWindow);
       
   332 +    }
       
   333 +
       
   334 +    mDrawInTitlebar = aState;
       
   335  }
       
   336  
       
   337  gint
       
   338  nsWindow::GdkScaleFactor()
       
   339  {
       
   340  #if (MOZ_WIDGET_GTK >= 3)
       
   341      // Available as of GTK 3.10+
       
   342      static auto sGdkWindowGetScaleFactorPtr = (gint (*)(GdkWindow*))
       
   343 @@ -6923,28 +6920,28 @@ nsWindow::SynthesizeNativeTouchPoint(uin
       
   344    event.touch.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
       
   345  
       
   346    gdk_event_put(&event);
       
   347  
       
   348    return NS_OK;
       
   349  }
       
   350  #endif
       
   351  
       
   352 -bool
       
   353 -nsWindow::DoDrawTitlebar() const
       
   354 -{
       
   355 -    return mIsCSDEnabled && mSizeState == nsSizeMode_Normal;
       
   356 -}
       
   357 -
       
   358  nsWindow::CSDSupportLevel
       
   359 -nsWindow::GetCSDSupportLevel() {
       
   360 +nsWindow::GetSystemCSDSupportLevel() {
       
   361      if (sCSDSupportLevel != CSD_SUPPORT_UNKNOWN) {
       
   362          return sCSDSupportLevel;
       
   363      }
       
   364  
       
   365 +    // Require GTK 3.10 for GtkHeaderBar support and compatible window manager.
       
   366 +    if (gtk_check_version(3, 10, 0) != nullptr) {
       
   367 +        sCSDSupportLevel = CSD_SUPPORT_NONE;
       
   368 +        return sCSDSupportLevel;
       
   369 +    }
       
   370 +
       
   371      const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP");
       
   372      if (currentDesktop) {
       
   373          // GNOME Flashback (fallback)
       
   374          if (strstr(currentDesktop, "GNOME-Flashback:GNOME") != nullptr) {
       
   375              sCSDSupportLevel = CSD_SUPPORT_CLIENT;
       
   376          // gnome-shell
       
   377          } else if (strstr(currentDesktop, "GNOME") != nullptr) {
       
   378              sCSDSupportLevel = CSD_SUPPORT_SYSTEM;
       
   379 diff -up firefox-60.0/widget/gtk/gtk3drawing.cpp.orig firefox-60.0/widget/gtk/gtk3drawing.cpp
       
   380 --- firefox-60.0/widget/gtk/gtk3drawing.cpp.orig	2018-04-26 22:07:36.000000000 +0200
       
   381 +++ firefox-60.0/widget/gtk/gtk3drawing.cpp	2018-04-30 13:38:19.083949868 +0200
       
   382 @@ -38,6 +38,16 @@ static ToolbarGTKMetrics sToolbarMetrics
       
   383  #define GTK_STATE_FLAG_CHECKED (1 << 11)
       
   384  #endif
       
   385  
       
   386 +static GtkBorder
       
   387 +operator+=(GtkBorder& first, const GtkBorder& second)
       
   388 +{
       
   389 +    first.left += second.left;
       
   390 +    first.right += second.right;
       
   391 +    first.top += second.top;
       
   392 +    first.bottom += second.bottom;
       
   393 +    return first;
       
   394 +}
       
   395 +
       
   396  static gint
       
   397  moz_gtk_get_tab_thickness(GtkStyleContext *style);
       
   398  
       
   399 @@ -3056,6 +3066,76 @@ GetScrollbarMetrics(GtkOrientation aOrie
       
   400      return metrics;
       
   401  }
       
   402  
       
   403 +/*
       
   404 + * get_shadow_width() from gtkwindow.c is not public so we need
       
   405 + * to implement it.
       
   406 + */
       
   407 +bool
       
   408 +GetCSDDecorationSize(GtkWindow *aGtkWindow, GtkBorder* aDecorationSize)
       
   409 +{
       
   410 +    GtkStyleContext* context = gtk_widget_get_style_context(GTK_WIDGET(aGtkWindow));
       
   411 +    bool solidDecorations = gtk_style_context_has_class(context, "solid-csd");
       
   412 +    context = GetStyleContext(solidDecorations ?
       
   413 +                              MOZ_GTK_WINDOW_DECORATION_SOLID :
       
   414 +                              MOZ_GTK_WINDOW_DECORATION);
       
   415 +
       
   416 +    /* Always sum border + padding */
       
   417 +    GtkBorder padding;
       
   418 +    GtkStateFlags state = gtk_style_context_get_state(context);
       
   419 +    gtk_style_context_get_border(context, state, aDecorationSize);
       
   420 +    gtk_style_context_get_padding(context, state, &padding);
       
   421 +    *aDecorationSize += padding;
       
   422 +
       
   423 +    // Available on GTK 3.20+.
       
   424 +    static auto sGtkRenderBackgroundGetClip =
       
   425 +        (void (*)(GtkStyleContext*, gdouble, gdouble, gdouble, gdouble, GdkRectangle*))
       
   426 +        dlsym(RTLD_DEFAULT, "gtk_render_background_get_clip");
       
   427 +
       
   428 +    GtkBorder margin;
       
   429 +    gtk_style_context_get_margin(context, state, &margin);
       
   430 +
       
   431 +    GtkBorder extents = {0, 0, 0, 0};
       
   432 +    if (sGtkRenderBackgroundGetClip) {
       
   433 +        /* Get shadow extents but combine with style margin; use the bigger value.
       
   434 +         */
       
   435 +        GdkRectangle clip;
       
   436 +        sGtkRenderBackgroundGetClip(context, 0, 0, 0, 0, &clip);
       
   437 +
       
   438 +        extents.top = -clip.y;
       
   439 +        extents.right = clip.width + clip.x;
       
   440 +        extents.bottom = clip.height + clip.y;
       
   441 +        extents.left = -clip.x;
       
   442 +
       
   443 +        // Margin is used for resize grip size - it's not present on
       
   444 +        // popup windows.
       
   445 +        if (gtk_window_get_window_type(aGtkWindow) != GTK_WINDOW_POPUP) {
       
   446 +            extents.top = MAX(extents.top, margin.top);
       
   447 +            extents.right = MAX(extents.right, margin.right);
       
   448 +            extents.bottom = MAX(extents.bottom, margin.bottom);
       
   449 +            extents.left = MAX(extents.left, margin.left);
       
   450 +        }
       
   451 +    } else {
       
   452 +        /* If we can't get shadow extents use decoration-resize-handle instead
       
   453 +         * as a workaround. This is inspired by update_border_windows()
       
   454 +         * from gtkwindow.c although this is not 100% accurate as we emulate
       
   455 +         * the extents here.
       
   456 +         */
       
   457 +        gint handle;
       
   458 +        gtk_widget_style_get(GetWidget(MOZ_GTK_WINDOW),
       
   459 +                             "decoration-resize-handle", &handle,
       
   460 +                             NULL);
       
   461 +
       
   462 +        extents.top = handle + margin.top;
       
   463 +        extents.right = handle + margin.right;
       
   464 +        extents.bottom = handle + margin.bottom;
       
   465 +        extents.left = handle + margin.left;
       
   466 +    }
       
   467 +
       
   468 +    *aDecorationSize += extents;
       
   469 +
       
   470 +    return (sGtkRenderBackgroundGetClip != nullptr);
       
   471 +}
       
   472 +
       
   473  /* cairo_t *cr argument has to be a system-cairo. */
       
   474  gint
       
   475  moz_gtk_widget_paint(WidgetNodeType widget, cairo_t *cr,
       
   476 diff -up firefox-60.0/widget/gtk/gtkdrawing.h.orig firefox-60.0/widget/gtk/gtkdrawing.h
       
   477 --- firefox-60.0/widget/gtk/gtkdrawing.h.orig	2018-04-26 22:07:35.000000000 +0200
       
   478 +++ firefox-60.0/widget/gtk/gtkdrawing.h	2018-04-30 13:38:19.083949868 +0200
       
   479 @@ -334,6 +334,10 @@ typedef enum {
       
   480     */
       
   481    MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE_RESTORE,
       
   482  
       
   483 +  /* Client-side window decoration node. Available on GTK 3.20+. */
       
   484 +  MOZ_GTK_WINDOW_DECORATION,
       
   485 +  MOZ_GTK_WINDOW_DECORATION_SOLID,
       
   486 +
       
   487    MOZ_GTK_WIDGET_NODE_COUNT
       
   488  } WidgetNodeType;
       
   489  
       
   490 @@ -606,4 +610,17 @@ GetToolbarButtonMetrics(WidgetNodeType a
       
   491  int
       
   492  GetGtkHeaderBarButtonLayout(WidgetNodeType* aButtonLayout, int aMaxButtonNums);
       
   493  
       
   494 +/**
       
   495 + * Get size of CSD window extents of given GtkWindow.
       
   496 + *
       
   497 + * aGtkWindow      [IN]  Decorated window.
       
   498 + * aDecorationSize [OUT] Returns calculated (or estimated) decoration
       
   499 + *                       size of given aGtkWindow.
       
   500 + *
       
   501 + * returns:    True if we have extract decoration size (for GTK 3.20+)
       
   502 + *             False if we have only an estimation (for GTK+ before  3.20+)
       
   503 + */
       
   504 +bool
       
   505 +GetCSDDecorationSize(GtkWindow *aGtkWindow, GtkBorder* aDecorationSize);
       
   506 +
       
   507  #endif
       
   508 diff -up firefox-60.0/widget/gtk/nsWindow.cpp.orig firefox-60.0/widget/gtk/nsWindow.cpp
       
   509 --- firefox-60.0/widget/gtk/nsWindow.cpp.orig	2018-04-30 13:37:32.145122854 +0200
       
   510 +++ firefox-60.0/widget/gtk/nsWindow.cpp	2018-04-30 13:39:12.593752681 +0200
       
   511 @@ -127,6 +127,7 @@ using namespace mozilla::widget;
       
   512  #endif
       
   513  
       
   514  #include "nsShmImage.h"
       
   515 +#include "gtkdrawing.h"
       
   516  
       
   517  #include "nsIDOMWheelEvent.h"
       
   518  
       
   519 @@ -3360,6 +3361,10 @@ nsWindow::OnWindowStateEvent(GtkWidget *
       
   520            aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN);
       
   521        }
       
   522      }
       
   523 +
       
   524 +    if (mDrawInTitlebar && mCSDSupportLevel == CSD_SUPPORT_CLIENT) {
       
   525 +        UpdateClientOffsetForCSDWindow();
       
   526 +    }
       
   527  }
       
   528  
       
   529  void
       
   530 @@ -6552,6 +6557,32 @@ nsWindow::ClearCachedResources()
       
   531      }
       
   532  }
       
   533  
       
   534 +/* nsWindow::UpdateClientOffsetForCSDWindow() is designed to be called from
       
   535 + * paint code to update mClientOffset any time. It also propagates
       
   536 + * the mClientOffset to child tabs.
       
   537 + *
       
   538 + * It works only for CSD decorated GtkWindow.
       
   539 + */
       
   540 +void
       
   541 +nsWindow::UpdateClientOffsetForCSDWindow()
       
   542 +{
       
   543 +    // _NET_FRAME_EXTENTS is not set on client decorated windows,
       
   544 +    // so we need to read offset between mContainer and toplevel mShell
       
   545 +    // window.
       
   546 +    if (mSizeState == nsSizeMode_Normal) {
       
   547 +        GtkBorder decorationSize;
       
   548 +        GetCSDDecorationSize(GTK_WINDOW(mShell), &decorationSize);
       
   549 +        mClientOffset = nsIntPoint(decorationSize.left, decorationSize.top);
       
   550 +    } else {
       
   551 +        mClientOffset = nsIntPoint(0, 0);
       
   552 +    }
       
   553 +
       
   554 +    // Send a WindowMoved notification. This ensures that TabParent
       
   555 +    // picks up the new client offset and sends it to the child process
       
   556 +    // if appropriate.
       
   557 +    NotifyWindowMoved(mBounds.x, mBounds.y);
       
   558 +}
       
   559 +
       
   560  nsresult
       
   561  nsWindow::SetNonClientMargins(LayoutDeviceIntMargin &aMargins)
       
   562  {
       
   563 @@ -6626,6 +6657,13 @@ nsWindow::SetDrawsInTitlebar(bool aState
       
   564          mNeedsShow = true;
       
   565          NativeResize();
       
   566  
       
   567 +        // When we use system titlebar setup managed by Gtk+ we also get
       
   568 +        // _NET_FRAME_EXTENTS property for our toplevel window so we can't
       
   569 +        // update the client offset it here.
       
   570 +        if (aState) {
       
   571 +            UpdateClientOffsetForCSDWindow();
       
   572 +        }
       
   573 +
       
   574          gtk_widget_destroy(tmpWindow);
       
   575      }
       
   576  
       
   577 diff -up firefox-60.0/widget/gtk/nsWindow.h.orig firefox-60.0/widget/gtk/nsWindow.h
       
   578 --- firefox-60.0/widget/gtk/nsWindow.h.orig	2018-04-30 13:37:32.143122861 +0200
       
   579 +++ firefox-60.0/widget/gtk/nsWindow.h	2018-04-30 13:38:19.085949861 +0200
       
   580 @@ -454,6 +454,8 @@ private:
       
   581      nsIWidgetListener* GetListener();
       
   582      bool               IsComposited() const;
       
   583  
       
   584 +    void               UpdateClientOffsetForCSDWindow();
       
   585 +
       
   586      GtkWidget          *mShell;
       
   587      MozContainer       *mContainer;
       
   588      GdkWindow          *mGdkWindow;
       
   589 diff -up firefox-60.0/widget/gtk/WidgetStyleCache.cpp.orig firefox-60.0/widget/gtk/WidgetStyleCache.cpp
       
   590 --- firefox-60.0/widget/gtk/WidgetStyleCache.cpp.orig	2018-04-26 22:07:35.000000000 +0200
       
   591 +++ firefox-60.0/widget/gtk/WidgetStyleCache.cpp	2018-04-30 13:38:19.085949861 +0200
       
   592 @@ -1285,6 +1285,22 @@ GetCssNodeStyleInternal(WidgetNodeType a
       
   593            "MOZ_GTK_HEADER_BAR_BUTTON_RESTORE is used as an icon only!");
       
   594        return nullptr;
       
   595      }
       
   596 +    case MOZ_GTK_WINDOW_DECORATION:
       
   597 +    {
       
   598 +      GtkStyleContext* parentStyle =
       
   599 +          CreateSubStyleWithClass(MOZ_GTK_WINDOW, "csd");
       
   600 +      style = CreateCSSNode("decoration", parentStyle);
       
   601 +      g_object_unref(parentStyle);
       
   602 +      break;
       
   603 +    }
       
   604 +    case MOZ_GTK_WINDOW_DECORATION_SOLID:
       
   605 +    {
       
   606 +      GtkStyleContext* parentStyle =
       
   607 +          CreateSubStyleWithClass(MOZ_GTK_WINDOW, "solid-csd");
       
   608 +      style = CreateCSSNode("decoration", parentStyle);
       
   609 +      g_object_unref(parentStyle);
       
   610 +      break;
       
   611 +    }
       
   612      default:
       
   613        return GetWidgetRootStyle(aNodeType);
       
   614    }