Browse Source

fix: calling of X11 functions when running under Wayland (#33355)

* fix: don't call X11 functions in file dialog and message box

* refactor: remove unused GtkUiPlatform declaration

* fix: set gtk darktheme only when running under X11

* fix: replace X11 window state watcher with implementation using ozone

* fix: make sure global menu barr is used only when supported

* fix: don't call X11 function in native window views under wayland

* style: fix lint issues

* fix: use GtkUiPlatform::ShowGtkWindow instead of gtk_window_present directly

* refactor: extract CreateGlobalMenuBar into separate function

* refactor: move checking for WaylandWindowDecorations inside class

* fix: check if we run under X11 only in ozone build

* refactor: drop including unused ui/base/ui_base_features.h header

* fix: modify ui_gtk_public_header.patch to also export gtk_ui.h

* fix: refactor guarding of X11 calls

- Introduce patch exposing new electron_can_call_x11 property
- Replace defined(USE_OZONE) with BUILDFLAG(OZONE_PLATFORM_X11) flags

* fix: remove the last remaining usage of USE_X11

* fix: usage of BUILDFLAG(OZONE_PLATFORM_X11) not building on non ozone

* fix: call UpdateWindowState from OnBoundsChanged only under X11
Marek Rusinowski 3 years ago
parent
commit
cdf2b3f4e4

+ 0 - 1
BUILD.gn

@@ -563,7 +563,6 @@ source_set("electron_lib") {
     defines += [
       # Disable warnings for g_settings_list_schemas.
       "GLIB_DISABLE_DEPRECATION_WARNINGS",
-      "USE_X11=1",
     ]
 
     sources += [

+ 0 - 2
filenames.gni

@@ -53,8 +53,6 @@ filenames = {
     "shell/browser/ui/views/global_menu_bar_x11.h",
     "shell/browser/ui/x/event_disabler.cc",
     "shell/browser/ui/x/event_disabler.h",
-    "shell/browser/ui/x/window_state_watcher.cc",
-    "shell/browser/ui/x/window_state_watcher.h",
     "shell/browser/ui/x/x_window_utils.cc",
     "shell/browser/ui/x/x_window_utils.h",
   ]

+ 1 - 0
patches/chromium/.patches

@@ -114,3 +114,4 @@ port_autofill_colors_to_the_color_pipeline.patch
 build_disable_partition_alloc_on_mac.patch
 fix_non-client_mouse_tracking_and_message_bubbling_on_windows.patch
 build_make_libcxx_abi_unstable_false_for_electron.patch
+introduce_ozoneplatform_electron_can_call_x11_property.patch

+ 37 - 0
patches/chromium/introduce_ozoneplatform_electron_can_call_x11_property.patch

@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Marek Rusinowski <[email protected]>
+Date: Wed, 23 Mar 2022 21:09:37 +0100
+Subject: introduce OzonePlatform::electron_can_call_x11 property
+
+We expose this additonal property in the OzonePlatform to be able to easily
+determine whatever we can call X11 functions without crashing the application
+at rutime. It would be best if eventually all usages of this property were
+replaced with clean ozone native implementations.
+
+diff --git a/ui/ozone/platform/x11/ozone_platform_x11.cc b/ui/ozone/platform/x11/ozone_platform_x11.cc
+index 9008af973427d7dab8170449bc5767cebc9d2e9e..e312287e4aca61b51a69c8413088f56f9f704b5e 100644
+--- a/ui/ozone/platform/x11/ozone_platform_x11.cc
++++ b/ui/ozone/platform/x11/ozone_platform_x11.cc
+@@ -200,6 +200,7 @@ class OzonePlatformX11 : public OzonePlatform,
+       properties->supports_vulkan_swap_chain = true;
+       properties->uses_external_vulkan_image_factory = true;
+       properties->skia_can_fall_back_to_x11 = true;
++      properties->electron_can_call_x11 = true;
+       properties->platform_shows_drag_image = false;
+       properties->supports_global_application_menus = true;
+       properties->app_modal_dialogs_use_event_blocker = true;
+diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h
+index 22ba32317a74df24249d1528dcaaa28ff18bd0f4..fa57f97520a0327be2c7f5179591ca61b801c8b0 100644
+--- a/ui/ozone/public/ozone_platform.h
++++ b/ui/ozone/public/ozone_platform.h
+@@ -132,6 +132,10 @@ class COMPONENT_EXPORT(OZONE) OzonePlatform {
+     // Linux only: determines if Skia can fall back to the X11 output device.
+     bool skia_can_fall_back_to_x11 = false;
+ 
++    // Linux only: determines is Electron can call selected X11 functions while
++    // it migrates to pure ozone abstractions.
++    bool electron_can_call_x11 = false;
++
+     // Wayland only: determines whether windows which are not top level ones
+     // should be given parents explicitly.
+     bool set_parent_for_non_top_level_windows = false;

+ 15 - 5
patches/chromium/ui_gtk_public_header.patch

@@ -3,22 +3,32 @@ From: deepak1556 <[email protected]>
 Date: Fri, 10 Apr 2020 17:47:18 -0700
 Subject: ui_gtk_public_header.patch
 
-Allow electron to depend on //ui/gtk/gtk_util.h
+Allow electron to depend on gtk_util.h and gtk_ui.h from //ui/gtk/
 
 diff --git a/ui/gtk/BUILD.gn b/ui/gtk/BUILD.gn
-index 4093df78da0bbb1d8df743942f364cf728ad3414..2f31d99b207ffc3531b5334b5a01239cc1fefb35 100644
+index 4093df78da0bbb1d8df743942f364cf728ad3414..2f7c404307bfebb0e2890148cf9b0d6d9c68094f 100644
 --- a/ui/gtk/BUILD.gn
 +++ b/ui/gtk/BUILD.gn
-@@ -69,7 +69,7 @@ generate_stubs("gtk_stubs") {
+@@ -69,7 +69,11 @@ generate_stubs("gtk_stubs") {
  }
  
  component("gtk") {
 -  public = [ "gtk_ui_factory.h" ]
-+  public = [ "gtk_ui_factory.h", "gtk_util.h" ]
++  public = [
++    "gtk_ui.h",
++    "gtk_ui_factory.h",
++    "gtk_util.h",
++  ]
  
    sources = [
      "gtk_color_mixers.cc",
-@@ -85,7 +85,6 @@ component("gtk") {
+@@ -79,13 +83,11 @@ component("gtk") {
+     "gtk_key_bindings_handler.cc",
+     "gtk_key_bindings_handler.h",
+     "gtk_ui.cc",
+-    "gtk_ui.h",
+     "gtk_ui_factory.cc",
+     "gtk_ui_platform.h",
      "gtk_ui_platform_stub.cc",
      "gtk_ui_platform_stub.h",
      "gtk_util.cc",

+ 0 - 6
shell/browser/electron_browser_main_parts.h

@@ -36,12 +36,6 @@ class Screen;
 }
 #endif
 
-#if defined(USE_X11)
-namespace ui {
-class GtkUiPlatform;
-}
-#endif
-
 namespace device {
 class GeolocationManager;
 }

+ 1 - 1
shell/browser/native_window.cc

@@ -26,7 +26,7 @@
 #include "ui/display/win/screen_win.h"
 #endif
 
-#if defined(USE_OZONE) || defined(USE_X11)
+#if defined(USE_OZONE)
 #include "ui/base/ui_base_features.h"
 #include "ui/ozone/public/ozone_platform.h"
 #endif

+ 140 - 115
shell/browser/native_window_views.cc

@@ -19,7 +19,6 @@
 #include "content/public/browser/desktop_media_id.h"
 #include "shell/browser/api/electron_api_web_contents.h"
 #include "shell/browser/native_browser_view_views.h"
-#include "shell/browser/native_window_features.h"
 #include "shell/browser/ui/drag_util.h"
 #include "shell/browser/ui/inspectable_web_contents.h"
 #include "shell/browser/ui/inspectable_web_contents_view.h"
@@ -55,20 +54,16 @@
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
 #include "ui/views/window/native_frame_view.h"
 
-#if defined(USE_X11)
+#if defined(USE_OZONE)
 #include "shell/browser/ui/views/global_menu_bar_x11.h"
 #include "shell/browser/ui/x/event_disabler.h"
-#include "shell/browser/ui/x/window_state_watcher.h"
 #include "shell/browser/ui/x/x_window_utils.h"
 #include "ui/base/x/x11_util.h"
 #include "ui/gfx/x/shape.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 #include "ui/gfx/x/xproto.h"
 #include "ui/gfx/x/xproto_util.h"
-#endif
-
-#if defined(USE_OZONE) || defined(USE_X11)
-#include "ui/base/ui_base_features.h"
+#include "ui/ozone/public/ozone_platform.h"
 #endif
 
 #elif BUILDFLAG(IS_WIN)
@@ -130,6 +125,26 @@ gfx::Rect DIPToScreenRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
 
 #endif
 
+#if defined(USE_OZONE)
+
+bool CreateGlobalMenuBar() {
+  return ui::OzonePlatform::GetInstance()
+      ->GetPlatformProperties()
+      .supports_global_application_menus;
+}
+
+#endif
+
+#if defined(USE_OZONE_PLATFORM_X11)
+
+bool IsX11() {
+  return ui::OzonePlatform::GetInstance()
+      ->GetPlatformProperties()
+      .electron_can_call_x11;
+}
+
+#endif
+
 class NativeWindowClientView : public views::ClientView {
  public:
   NativeWindowClientView(views::Widget* widget,
@@ -257,12 +272,10 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
   params.wm_class_name = base::ToLowerASCII(name);
   params.wm_class_class = name;
 
-  if (base::FeatureList::IsEnabled(features::kWaylandWindowDecorations)) {
-    auto* native_widget = new views::DesktopNativeWidgetAura(widget());
-    params.native_widget = native_widget;
-    params.desktop_window_tree_host =
-        new ElectronDesktopWindowTreeHostLinux(this, native_widget);
-  }
+  auto* native_widget = new views::DesktopNativeWidgetAura(widget());
+  params.native_widget = native_widget;
+  params.desktop_window_tree_host =
+      new ElectronDesktopWindowTreeHostLinux(this, native_widget);
 #endif
 
   widget()->Init(std::move(params));
@@ -274,55 +287,52 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
   std::string window_type;
   options.Get(options::kType, &window_type);
 
-#if defined(USE_X11)
-  // Start monitoring window states.
-  window_state_watcher_ = std::make_unique<WindowStateWatcher>(this);
-
+#if BUILDFLAG(IS_LINUX)
   // Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
   bool use_dark_theme = false;
   if (options.Get(options::kDarkTheme, &use_dark_theme) && use_dark_theme) {
     SetGTKDarkThemeEnabled(use_dark_theme);
   }
-#endif
 
-#if BUILDFLAG(IS_LINUX)
   if (parent)
     SetParentWindow(parent);
 #endif
 
-#if defined(USE_X11)
-  // TODO(ckerr): remove in Electron v20.0.0
-  // Before the window is mapped the SetWMSpecState can not work, so we have
-  // to manually set the _NET_WM_STATE.
-  std::vector<x11::Atom> state_atom_list;
-  bool skip_taskbar = false;
-  if (options.Get(options::kSkipTaskbar, &skip_taskbar) && skip_taskbar) {
-    state_atom_list.push_back(x11::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
-  }
+#if defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11()) {
+    // TODO(ckerr): remove in Electron v20.0.0
+    // Before the window is mapped the SetWMSpecState can not work, so we have
+    // to manually set the _NET_WM_STATE.
+    std::vector<x11::Atom> state_atom_list;
+    bool skip_taskbar = false;
+    if (options.Get(options::kSkipTaskbar, &skip_taskbar) && skip_taskbar) {
+      state_atom_list.push_back(x11::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
+    }
 
-  // Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
-  if (fullscreen) {
-    state_atom_list.push_back(x11::GetAtom("_NET_WM_STATE_FULLSCREEN"));
-  }
+    // Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
+    if (fullscreen) {
+      state_atom_list.push_back(x11::GetAtom("_NET_WM_STATE_FULLSCREEN"));
+    }
 
-  if (parent) {
-    // Force using dialog type for child window.
-    window_type = "dialog";
+    if (parent) {
+      // Force using dialog type for child window.
+      window_type = "dialog";
 
-    // Modal window needs the _NET_WM_STATE_MODAL hint.
-    if (is_modal())
-      state_atom_list.push_back(x11::GetAtom("_NET_WM_STATE_MODAL"));
-  }
+      // Modal window needs the _NET_WM_STATE_MODAL hint.
+      if (is_modal())
+        state_atom_list.push_back(x11::GetAtom("_NET_WM_STATE_MODAL"));
+    }
 
-  if (!state_atom_list.empty())
-    SetArrayProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
-                     x11::GetAtom("_NET_WM_STATE"), x11::Atom::ATOM,
-                     state_atom_list);
+    if (!state_atom_list.empty())
+      SetArrayProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
+                       x11::GetAtom("_NET_WM_STATE"), x11::Atom::ATOM,
+                       state_atom_list);
 
-  // Set the _NET_WM_WINDOW_TYPE.
-  if (!window_type.empty())
-    SetWindowType(static_cast<x11::Window>(GetAcceleratedWidget()),
-                  window_type);
+    // Set the _NET_WM_WINDOW_TYPE.
+    if (!window_type.empty())
+      SetWindowType(static_cast<x11::Window>(GetAcceleratedWidget()),
+                    window_type);
+  }
 #endif
 
 #if BUILDFLAG(IS_WIN)
@@ -419,11 +429,13 @@ NativeWindowViews::~NativeWindowViews() {
 }
 
 void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
-#if defined(USE_X11)
-  const std::string color = use_dark_theme ? "dark" : "light";
-  x11::SetStringProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
-                         x11::GetAtom("_GTK_THEME_VARIANT"),
-                         x11::GetAtom("UTF8_STRING"), color);
+#if defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11()) {
+    const std::string color = use_dark_theme ? "dark" : "light";
+    x11::SetStringProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
+                           x11::GetAtom("_GTK_THEME_VARIANT"),
+                           x11::GetAtom("UTF8_STRING"), color);
+  }
 #endif
 }
 
@@ -478,7 +490,7 @@ void NativeWindowViews::Show() {
 
   NotifyWindowShow();
 
-#if defined(USE_X11)
+#if defined(USE_OZONE)
   if (global_menu_bar_)
     global_menu_bar_->OnWindowMapped();
 #endif
@@ -489,7 +501,7 @@ void NativeWindowViews::ShowInactive() {
 
   NotifyWindowShow();
 
-#if defined(USE_X11)
+#if defined(USE_OZONE)
   if (global_menu_bar_)
     global_menu_bar_->OnWindowMapped();
 #endif
@@ -503,7 +515,7 @@ void NativeWindowViews::Hide() {
 
   NotifyWindowHide();
 
-#if defined(USE_X11)
+#if defined(USE_OZONE)
   if (global_menu_bar_)
     global_menu_bar_->OnWindowUnmapped();
 #endif
@@ -525,8 +537,9 @@ bool NativeWindowViews::IsEnabled() {
 #if BUILDFLAG(IS_WIN)
   return ::IsWindowEnabled(GetAcceleratedWidget());
 #elif BUILDFLAG(IS_LINUX)
-#if defined(USE_X11)
-  return !event_disabler_.get();
+#if defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11())
+    return !event_disabler_.get();
 #endif
   NOTIMPLEMENTED();
   return true;
@@ -565,16 +578,18 @@ void NativeWindowViews::SetEnabledInternal(bool enable) {
 
 #if BUILDFLAG(IS_WIN)
   ::EnableWindow(GetAcceleratedWidget(), enable);
-#elif defined(USE_X11)
-  views::DesktopWindowTreeHostPlatform* tree_host =
-      views::DesktopWindowTreeHostLinux::GetHostForWidget(
-          GetAcceleratedWidget());
-  if (enable) {
-    tree_host->RemoveEventRewriter(event_disabler_.get());
-    event_disabler_.reset();
-  } else {
-    event_disabler_ = std::make_unique<EventDisabler>();
-    tree_host->AddEventRewriter(event_disabler_.get());
+#elif defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11()) {
+    views::DesktopWindowTreeHostPlatform* tree_host =
+        views::DesktopWindowTreeHostLinux::GetHostForWidget(
+            GetAcceleratedWidget());
+    if (enable) {
+      tree_host->RemoveEventRewriter(event_disabler_.get());
+      event_disabler_.reset();
+    } else {
+      event_disabler_ = std::make_unique<EventDisabler>();
+      tree_host->AddEventRewriter(event_disabler_.get());
+    }
   }
 #endif
 }
@@ -798,12 +813,14 @@ bool NativeWindowViews::MoveAbove(const std::string& sourceId) {
   ::SetWindowPos(GetAcceleratedWidget(), GetWindow(otherWindow, GW_HWNDPREV), 0,
                  0, 0, 0,
                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
-#elif defined(USE_X11)
-  if (!IsWindowValid(static_cast<x11::Window>(id.id)))
-    return false;
+#elif defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11()) {
+    if (!IsWindowValid(static_cast<x11::Window>(id.id)))
+      return false;
 
-  electron::MoveWindowAbove(static_cast<x11::Window>(GetAcceleratedWidget()),
-                            static_cast<x11::Window>(id.id));
+    electron::MoveWindowAbove(static_cast<x11::Window>(GetAcceleratedWidget()),
+                              static_cast<x11::Window>(id.id));
+  }
 #endif
 
   return true;
@@ -818,9 +835,10 @@ void NativeWindowViews::MoveTop() {
   ::SetWindowPos(GetAcceleratedWidget(), HWND_TOP, pos.x(), pos.y(),
                  size.width(), size.height(),
                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
-#elif defined(USE_X11)
-  electron::MoveWindowToForeground(
-      static_cast<x11::Window>(GetAcceleratedWidget()));
+#elif defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11())
+    electron::MoveWindowToForeground(
+        static_cast<x11::Window>(GetAcceleratedWidget()));
 #endif
 }
 
@@ -1002,9 +1020,10 @@ void NativeWindowViews::SetSkipTaskbar(bool skip) {
     taskbar->AddTab(GetAcceleratedWidget());
     taskbar_host_.RestoreThumbarButtons(GetAcceleratedWidget());
   }
-#elif defined(USE_X11)
-  SetWMSpecState(static_cast<x11::Window>(GetAcceleratedWidget()), skip,
-                 x11::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
+#elif defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11())
+    SetWMSpecState(static_cast<x11::Window>(GetAcceleratedWidget()), skip,
+                   x11::GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
 #endif
 }
 
@@ -1104,24 +1123,28 @@ void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) {
   } else {
     SetForwardMouseMessages(forward);
   }
-#elif defined(USE_X11)
-  auto* connection = x11::Connection::Get();
-  if (ignore) {
-    x11::Rectangle r{0, 0, 1, 1};
-    connection->shape().Rectangles({
-        .operation = x11::Shape::So::Set,
-        .destination_kind = x11::Shape::Sk::Input,
-        .ordering = x11::ClipOrdering::YXBanded,
-        .destination_window = static_cast<x11::Window>(GetAcceleratedWidget()),
-        .rectangles = {r},
-    });
-  } else {
-    connection->shape().Mask({
-        .operation = x11::Shape::So::Set,
-        .destination_kind = x11::Shape::Sk::Input,
-        .destination_window = static_cast<x11::Window>(GetAcceleratedWidget()),
-        .source_bitmap = x11::Pixmap::None,
-    });
+#elif defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11()) {
+    auto* connection = x11::Connection::Get();
+    if (ignore) {
+      x11::Rectangle r{0, 0, 1, 1};
+      connection->shape().Rectangles({
+          .operation = x11::Shape::So::Set,
+          .destination_kind = x11::Shape::Sk::Input,
+          .ordering = x11::ClipOrdering::YXBanded,
+          .destination_window =
+              static_cast<x11::Window>(GetAcceleratedWidget()),
+          .rectangles = {r},
+      });
+    } else {
+      connection->shape().Mask({
+          .operation = x11::Shape::So::Set,
+          .destination_kind = x11::Shape::Sk::Input,
+          .destination_window =
+              static_cast<x11::Window>(GetAcceleratedWidget()),
+          .source_bitmap = x11::Pixmap::None,
+      });
+    }
   }
 #endif
 }
@@ -1168,7 +1191,7 @@ bool NativeWindowViews::IsFocusable() {
 }
 
 void NativeWindowViews::SetMenu(ElectronMenuModel* menu_model) {
-#if defined(USE_X11)
+#if defined(USE_OZONE)
   // Remove global menu bar.
   if (global_menu_bar_ && menu_model == nullptr) {
     global_menu_bar_.reset();
@@ -1177,7 +1200,7 @@ void NativeWindowViews::SetMenu(ElectronMenuModel* menu_model) {
   }
 
   // Use global application menu bar when possible.
-  if (ShouldUseGlobalMenuBar()) {
+  if (CreateGlobalMenuBar() && ShouldUseGlobalMenuBar()) {
     if (!global_menu_bar_)
       global_menu_bar_ = std::make_unique<GlobalMenuBarX11>(this);
     if (global_menu_bar_->IsServerStarted()) {
@@ -1264,12 +1287,13 @@ void NativeWindowViews::SetTopBrowserView(NativeBrowserView* view) {
 void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
   NativeWindow::SetParentWindow(parent);
 
-#if defined(USE_X11)
-  x11::SetProperty(
-      static_cast<x11::Window>(GetAcceleratedWidget()),
-      x11::Atom::WM_TRANSIENT_FOR, x11::Atom::WINDOW,
-      parent ? static_cast<x11::Window>(parent->GetAcceleratedWidget())
-             : ui::GetX11RootWindow());
+#if defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11())
+    x11::SetProperty(
+        static_cast<x11::Window>(GetAcceleratedWidget()),
+        x11::Atom::WM_TRANSIENT_FOR, x11::Atom::WINDOW,
+        parent ? static_cast<x11::Window>(parent->GetAcceleratedWidget())
+               : ui::GetX11RootWindow());
 #elif BUILDFLAG(IS_WIN)
   // To set parentship between windows into Windows is better to play with the
   //  owner instead of the parent, as Windows natively seems to do if a parent
@@ -1347,18 +1371,19 @@ void NativeWindowViews::SetVisibleOnAllWorkspaces(
 }
 
 bool NativeWindowViews::IsVisibleOnAllWorkspaces() {
-#if defined(USE_X11)
-  // Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to
-  // determine whether the current window is visible on all workspaces.
-  x11::Atom sticky_atom = x11::GetAtom("_NET_WM_STATE_STICKY");
-  std::vector<x11::Atom> wm_states;
-  GetArrayProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
-                   x11::GetAtom("_NET_WM_STATE"), &wm_states);
-  return std::find(wm_states.begin(), wm_states.end(), sticky_atom) !=
-         wm_states.end();
-#else
-  return false;
+#if defined(USE_OZONE_PLATFORM_X11)
+  if (IsX11()) {
+    // Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to
+    // determine whether the current window is visible on all workspaces.
+    x11::Atom sticky_atom = x11::GetAtom("_NET_WM_STATE_STICKY");
+    std::vector<x11::Atom> wm_states;
+    GetArrayProperty(static_cast<x11::Window>(GetAcceleratedWidget()),
+                     x11::GetAtom("_NET_WM_STATE"), &wm_states);
+    return std::find(wm_states.begin(), wm_states.end(), sticky_atom) !=
+           wm_states.end();
+  }
 #endif
+  return false;
 }
 
 content::DesktopMediaID NativeWindowViews::GetDesktopMediaID() const {

+ 11 - 4
shell/browser/native_window_views.h

@@ -16,6 +16,13 @@
 #include "third_party/skia/include/core/SkRegion.h"
 #include "ui/views/widget/widget_observer.h"
 
+#if defined(USE_OZONE)
+#include "ui/ozone/buildflags.h"
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+#define USE_OZONE_PLATFORM_X11
+#endif
+#endif
+
 #if BUILDFLAG(IS_WIN)
 #include "base/win/scoped_gdi_object.h"
 #include "shell/browser/ui/win/taskbar_host.h"
@@ -32,7 +39,7 @@ class GlobalMenuBarX11;
 class RootView;
 class WindowStateWatcher;
 
-#if defined(USE_X11)
+#if defined(USE_OZONE_PLATFORM_X11)
 class EventDisabler;
 #endif
 
@@ -259,12 +266,12 @@ class NativeWindowViews : public NativeWindow,
   // events from resizing the window.
   extensions::SizeConstraints old_size_constraints_;
 
-#if defined(USE_X11)
+#if defined(USE_OZONE)
   std::unique_ptr<GlobalMenuBarX11> global_menu_bar_;
 
-  // Handles window state events.
-  std::unique_ptr<WindowStateWatcher> window_state_watcher_;
+#endif
 
+#if defined(USE_OZONE_PLATFORM_X11)
   // To disable the mouse events.
   std::unique_ptr<EventDisabler> event_disabler_;
 #endif

+ 67 - 6
shell/browser/ui/electron_desktop_window_tree_host_linux.cc

@@ -10,7 +10,9 @@
 
 #include <vector>
 
+#include "base/feature_list.h"
 #include "base/i18n/rtl.h"
+#include "shell/browser/native_window_features.h"
 #include "shell/browser/ui/views/client_frame_view_linux.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/skia_conversions.h"
@@ -20,6 +22,14 @@
 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
 #include "ui/views/window/non_client_view.h"
 
+#if defined(USE_OZONE)
+#include "ui/ozone/buildflags.h"
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+#define USE_OZONE_PLATFORM_X11
+#endif
+#include "ui/ozone/public/ozone_platform.h"
+#endif
+
 namespace electron {
 
 ElectronDesktopWindowTreeHostLinux::ElectronDesktopWindowTreeHostLinux(
@@ -46,6 +56,18 @@ void ElectronDesktopWindowTreeHostLinux::OnBoundsChanged(
     const BoundsChange& change) {
   views::DesktopWindowTreeHostLinux::OnBoundsChanged(change);
   UpdateFrameHints();
+
+#if defined(USE_OZONE_PLATFORM_X11)
+  if (ui::OzonePlatform::GetInstance()
+          ->GetPlatformProperties()
+          .electron_can_call_x11) {
+    // The OnWindowStateChanged should receive all updates but currently under
+    // X11 it doesn't receive changes to the fullscreen status because chromium
+    // is handling the fullscreen state changes synchronously, see
+    // X11Window::ToggleFullscreen in ui/ozone/platform/x11/x11_window.cc.
+    UpdateWindowState(platform_window()->GetPlatformWindowState());
+  }
+#endif
 }
 
 void ElectronDesktopWindowTreeHostLinux::OnWindowStateChanged(
@@ -53,6 +75,43 @@ void ElectronDesktopWindowTreeHostLinux::OnWindowStateChanged(
     ui::PlatformWindowState new_state) {
   views::DesktopWindowTreeHostLinux::OnWindowStateChanged(old_state, new_state);
   UpdateFrameHints();
+  UpdateWindowState(new_state);
+}
+
+void ElectronDesktopWindowTreeHostLinux::UpdateWindowState(
+    ui::PlatformWindowState new_state) {
+  if (window_state_ == new_state)
+    return;
+
+  switch (window_state_) {
+    case ui::PlatformWindowState::kMinimized:
+      native_window_view_->NotifyWindowRestore();
+      break;
+    case ui::PlatformWindowState::kMaximized:
+      native_window_view_->NotifyWindowUnmaximize();
+      break;
+    case ui::PlatformWindowState::kFullScreen:
+      native_window_view_->NotifyWindowLeaveFullScreen();
+      break;
+    case ui::PlatformWindowState::kUnknown:
+    case ui::PlatformWindowState::kNormal:
+      break;
+  }
+  switch (new_state) {
+    case ui::PlatformWindowState::kMinimized:
+      native_window_view_->NotifyWindowMinimize();
+      break;
+    case ui::PlatformWindowState::kMaximized:
+      native_window_view_->NotifyWindowMaximize();
+      break;
+    case ui::PlatformWindowState::kFullScreen:
+      native_window_view_->NotifyWindowEnterFullScreen();
+      break;
+    case ui::PlatformWindowState::kUnknown:
+    case ui::PlatformWindowState::kNormal:
+      break;
+  }
+  window_state_ = new_state;
 }
 
 void ElectronDesktopWindowTreeHostLinux::OnNativeThemeUpdated(
@@ -65,13 +124,15 @@ void ElectronDesktopWindowTreeHostLinux::OnDeviceScaleFactorChanged() {
 }
 
 void ElectronDesktopWindowTreeHostLinux::UpdateFrameHints() {
-  if (SupportsClientFrameShadow() && native_window_view_->has_frame() &&
-      native_window_view_->has_client_frame()) {
-    UpdateClientDecorationHints(static_cast<ClientFrameViewLinux*>(
-        native_window_view_->widget()->non_client_view()->frame_view()));
-  }
+  if (base::FeatureList::IsEnabled(features::kWaylandWindowDecorations)) {
+    if (SupportsClientFrameShadow() && native_window_view_->has_frame() &&
+        native_window_view_->has_client_frame()) {
+      UpdateClientDecorationHints(static_cast<ClientFrameViewLinux*>(
+          native_window_view_->widget()->non_client_view()->frame_view()));
+    }
 
-  SizeConstraintsChanged();
+    SizeConstraintsChanged();
+  }
 }
 
 void ElectronDesktopWindowTreeHostLinux::UpdateClientDecorationHints(

+ 3 - 0
shell/browser/ui/electron_desktop_window_tree_host_linux.h

@@ -14,6 +14,7 @@
 #include "shell/browser/ui/views/client_frame_view_linux.h"
 #include "third_party/skia/include/core/SkRRect.h"
 #include "ui/native_theme/native_theme_observer.h"
+#include "ui/platform_window/platform_window.h"
 #include "ui/views/linux_ui/device_scale_factor_observer.h"
 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
 
@@ -55,6 +56,7 @@ class ElectronDesktopWindowTreeHostLinux
  private:
   void UpdateFrameHints();
   void UpdateClientDecorationHints(ClientFrameViewLinux* view);
+  void UpdateWindowState(ui::PlatformWindowState new_state);
 
   NativeWindowViews* native_window_view_;  // weak ref
 
@@ -65,6 +67,7 @@ class ElectronDesktopWindowTreeHostLinux
                           &views::LinuxUI::AddDeviceScaleFactorObserver,
                           &views::LinuxUI::RemoveDeviceScaleFactorObserver>
       scale_observation_{this};
+  ui::PlatformWindowState window_state_ = ui::PlatformWindowState::kUnknown;
 };
 
 }  // namespace electron

+ 2 - 16
shell/browser/ui/file_dialog_gtk.cc

@@ -18,16 +18,9 @@
 #include "shell/browser/unresponsive_suppressor.h"
 #include "shell/common/gin_converters/file_path_converter.h"
 #include "ui/base/glib/glib_signal.h"
+#include "ui/gtk/gtk_ui.h"
 #include "ui/gtk/gtk_util.h"
 
-#if defined(USE_X11)
-#include "ui/events/platform/x11/x11_event_source.h"
-#endif
-
-#if defined(USE_OZONE) || defined(USE_X11)
-#include "ui/base/ui_base_features.h"
-#endif
-
 namespace file_dialog {
 
 static GModule* gtk_module;
@@ -247,14 +240,7 @@ class FileChooserDialog {
       dl_gtk_native_dialog_show(static_cast<void*>(dialog_));
     } else {
       gtk_widget_show_all(GTK_WIDGET(dialog_));
-
-#if defined(USE_X11)
-      // We need to call gtk_window_present after making the widgets visible
-      // to make sure window gets correctly raised and gets focus.
-      x11::Time time = ui::X11EventSource::GetInstance()->GetTimestamp();
-      gtk_window_present_with_time(GTK_WINDOW(dialog_),
-                                   static_cast<uint32_t>(time));
-#endif
+      gtk::GtkUi::GetPlatform()->ShowGtkWindow(GTK_WINDOW(dialog_));
     }
   }
 

+ 21 - 9
shell/browser/ui/gtk/menu_util.cc

@@ -22,8 +22,12 @@
 #include "ui/events/event_constants.h"
 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
 
-#if defined(USE_OZONE) || defined(USE_X11)
-#include "ui/base/ui_base_features.h"
+#if defined(USE_OZONE)
+#include "ui/ozone/buildflags.h"
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+#define USE_OZONE_PLATFORM_X11
+#endif
+#include "ui/ozone/public/ozone_platform.h"
 #endif
 
 namespace electron {
@@ -45,6 +49,8 @@ int EventFlagsFromGdkState(guint state) {
   return flags;
 }
 
+#if defined(USE_OZONE_PLATFORM_X11)
+
 guint GetGdkKeyCodeForAccelerator(const ui::Accelerator& accelerator) {
   // The second parameter is false because accelerator keys are expressed in
   // terms of the non-shift-modified key.
@@ -64,6 +70,8 @@ GdkModifierType GetGdkModifierForAccelerator(
   return static_cast<GdkModifierType>(modifier);
 }
 
+#endif
+
 }  // namespace
 
 GtkWidget* BuildMenuItemWithImage(const std::string& label, GtkWidget* image) {
@@ -225,13 +233,17 @@ void BuildSubmenuFromModel(ui::MenuModel* model,
       connect_to_activate = false;
     }
 
-#if defined(USE_X11)
-    ui::Accelerator accelerator;
-    if (model->GetAcceleratorAt(i, &accelerator)) {
-      gtk_widget_add_accelerator(menu_item, "activate", nullptr,
-                                 GetGdkKeyCodeForAccelerator(accelerator),
-                                 GetGdkModifierForAccelerator(accelerator),
-                                 GTK_ACCEL_VISIBLE);
+#if defined(USE_OZONE_PLATFORM_X11)
+    if (ui::OzonePlatform::GetInstance()
+            ->GetPlatformProperties()
+            .electron_can_call_x11) {
+      ui::Accelerator accelerator;
+      if (model->GetAcceleratorAt(i, &accelerator)) {
+        gtk_widget_add_accelerator(menu_item, "activate", nullptr,
+                                   GetGdkKeyCodeForAccelerator(accelerator),
+                                   GetGdkModifierForAccelerator(accelerator),
+                                   GTK_ACCEL_VISIBLE);
+      }
     }
 #endif
 

+ 3 - 13
shell/browser/ui/message_box_gtk.cc

@@ -18,13 +18,10 @@
 #include "shell/browser/unresponsive_suppressor.h"
 #include "ui/base/glib/glib_signal.h"
 #include "ui/gfx/image/image_skia.h"
+#include "ui/gtk/gtk_ui.h"
 #include "ui/gtk/gtk_util.h"
 
-#if defined(USE_X11)
-#include "ui/events/platform/x11/x11_event_source.h"
-#endif
-
-#if defined(USE_OZONE) || defined(USE_X11)
+#if defined(USE_OZONE)
 #include "ui/base/ui_base_features.h"
 #endif
 
@@ -161,14 +158,7 @@ class GtkMessageBox : public NativeWindowObserver {
 
   void Show() {
     gtk_widget_show(dialog_);
-
-#if defined(USE_X11)
-    // We need to call gtk_window_present after making the widgets visible to
-    // make sure window gets correctly raised and gets focus.
-    x11::Time time = ui::X11EventSource::GetInstance()->GetTimestamp();
-    gtk_window_present_with_time(GTK_WINDOW(dialog_),
-                                 static_cast<uint32_t>(time));
-#endif
+    gtk::GtkUi::GetPlatform()->ShowGtkWindow(GTK_WINDOW(dialog_));
   }
 
   int RunSynchronous() {

+ 0 - 82
shell/browser/ui/x/window_state_watcher.cc

@@ -1,82 +0,0 @@
-// Copyright (c) 2014 GitHub, Inc.
-// Use of this source code is governed by the MIT license that can be
-// found in the LICENSE file.
-
-#include "shell/browser/ui/x/window_state_watcher.h"
-
-#include <vector>
-
-#include "ui/base/x/x11_util.h"
-#include "ui/gfx/x/x11_atom_cache.h"
-#include "ui/gfx/x/xproto_util.h"
-
-namespace electron {
-
-WindowStateWatcher::WindowStateWatcher(NativeWindowViews* window)
-    : window_(window),
-      widget_(window->GetAcceleratedWidget()),
-      net_wm_state_atom_(x11::GetAtom("_NET_WM_STATE")),
-      net_wm_state_hidden_atom_(x11::GetAtom("_NET_WM_STATE_HIDDEN")),
-      net_wm_state_maximized_vert_atom_(
-          x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")),
-      net_wm_state_maximized_horz_atom_(
-          x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")),
-      net_wm_state_fullscreen_atom_(x11::GetAtom("_NET_WM_STATE_FULLSCREEN")),
-      was_minimized_(window_->IsMinimized()),
-      was_maximized_(window_->IsMaximized()) {
-  ui::X11EventSource::GetInstance()->connection()->AddEventObserver(this);
-}
-
-WindowStateWatcher::~WindowStateWatcher() {
-  ui::X11EventSource::GetInstance()->connection()->RemoveEventObserver(this);
-}
-
-void WindowStateWatcher::OnEvent(const x11::Event& x11_event) {
-  if (IsWindowStateEvent(x11_event)) {
-    std::vector<x11::Atom> wm_states;
-    if (GetArrayProperty(
-            static_cast<x11::Window>(window_->GetAcceleratedWidget()),
-            net_wm_state_atom_, &wm_states)) {
-      const auto props =
-          base::flat_set<x11::Atom>(std::begin(wm_states), std::end(wm_states));
-      const bool is_minimized = props.contains(net_wm_state_hidden_atom_);
-      const bool is_maximized =
-          props.contains(net_wm_state_maximized_vert_atom_) &&
-          props.contains(net_wm_state_maximized_horz_atom_);
-      const bool is_fullscreen = props.contains(net_wm_state_fullscreen_atom_);
-
-      if (is_minimized != was_minimized_) {
-        if (is_minimized)
-          window_->NotifyWindowMinimize();
-        else
-          window_->NotifyWindowRestore();
-      } else if (is_maximized != was_maximized_) {
-        if (is_maximized)
-          window_->NotifyWindowMaximize();
-        else
-          window_->NotifyWindowUnmaximize();
-      } else {
-        // If this is neither a "maximize" or "minimize" event, then we think it
-        // is a "fullscreen" event.
-        // The "IsFullscreen()" becomes true immediately before "OnEvent"
-        // is called, so we can not handle this like "maximize" and "minimize"
-        // by watching whether they have changed.
-        if (is_fullscreen)
-          window_->NotifyWindowEnterFullScreen();
-        else
-          window_->NotifyWindowLeaveFullScreen();
-      }
-
-      was_minimized_ = is_minimized;
-      was_maximized_ = is_maximized;
-    }
-  }
-}
-
-bool WindowStateWatcher::IsWindowStateEvent(const x11::Event& x11_event) const {
-  auto* property = x11_event.As<x11::PropertyNotifyEvent>();
-  return (property && property->atom == net_wm_state_atom_ &&
-          static_cast<uint32_t>(property->window) == widget_);
-}
-
-}  // namespace electron

+ 0 - 45
shell/browser/ui/x/window_state_watcher.h

@@ -1,45 +0,0 @@
-// Copyright (c) 2014 GitHub, Inc.
-// Use of this source code is governed by the MIT license that can be
-// found in the LICENSE file.
-
-#ifndef ELECTRON_SHELL_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_
-#define ELECTRON_SHELL_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_
-
-#include "ui/events/platform/x11/x11_event_source.h"
-#include "ui/gfx/x/event.h"
-
-#include "shell/browser/native_window_views.h"
-
-namespace electron {
-
-class WindowStateWatcher : public x11::EventObserver {
- public:
-  explicit WindowStateWatcher(NativeWindowViews* window);
-  ~WindowStateWatcher() override;
-
-  // disable copy
-  WindowStateWatcher(const WindowStateWatcher&) = delete;
-  WindowStateWatcher& operator=(const WindowStateWatcher&) = delete;
-
- protected:
-  // x11::EventObserver:
-  void OnEvent(const x11::Event& x11_event) override;
-
- private:
-  bool IsWindowStateEvent(const x11::Event& x11_event) const;
-
-  NativeWindowViews* window_;
-  gfx::AcceleratedWidget widget_;
-  const x11::Atom net_wm_state_atom_;
-  const x11::Atom net_wm_state_hidden_atom_;
-  const x11::Atom net_wm_state_maximized_vert_atom_;
-  const x11::Atom net_wm_state_maximized_horz_atom_;
-  const x11::Atom net_wm_state_fullscreen_atom_;
-
-  bool was_minimized_ = false;
-  bool was_maximized_ = false;
-};
-
-}  // namespace electron
-
-#endif  // ELECTRON_SHELL_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_