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
This commit is contained in:
Marek Rusinowski 2022-03-28 18:48:50 +02:00 committed by GitHub
parent 1153a5ce5a
commit cdf2b3f4e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 305 additions and 309 deletions

View file

@ -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(

View file

@ -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

View file

@ -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_));
}
}

View file

@ -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

View file

@ -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() {

View file

@ -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

View file

@ -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_