diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index d3c8e79c79..b69f1342aa 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -73,6 +73,7 @@ public: static ImageDecoderClient::Client& image_decoder_client() { return *the().m_image_decoder_client; } virtual bool supports_vertical_tabs() const { return false; } + virtual bool supports_server_side_window_decorations() const { return false; } void tab_settings_changed(Badge); static BookmarkStore& bookmark_store() { return the().m_bookmark_store; } diff --git a/Libraries/LibWebView/Settings.cpp b/Libraries/LibWebView/Settings.cpp index 387bb7d18d..7e3a227b29 100644 --- a/Libraries/LibWebView/Settings.cpp +++ b/Libraries/LibWebView/Settings.cpp @@ -98,6 +98,14 @@ static Array(ConfigVariableID::Cou .default_value = true, .array_element_type = {}, }, + { + .id = ConfigVariableID::UseServerSideWindowDecorations, + .name = "ui.window.use_server_side_decorations"sv, + .title = "Use server-side window decorations"sv, + .description = "Use the system window frame instead of the custom title bar and window controls."sv, + .default_value = false, + .array_element_type = {}, + }, } }; ReadonlySpan config_variable_definitions() diff --git a/Libraries/LibWebView/Settings.h b/Libraries/LibWebView/Settings.h index 92bcdb51ef..7faef08bd6 100644 --- a/Libraries/LibWebView/Settings.h +++ b/Libraries/LibWebView/Settings.h @@ -54,6 +54,7 @@ enum class ConfigVariableID : u8 { ShowAdvancedDebugMenu, ContentBlockerListPaths, UseRoundedWindowCorners, + UseServerSideWindowDecorations, Count, }; diff --git a/Libraries/LibWebView/WebUI/SettingsUI.cpp b/Libraries/LibWebView/WebUI/SettingsUI.cpp index 85319f77dc..c046f67401 100644 --- a/Libraries/LibWebView/WebUI/SettingsUI.cpp +++ b/Libraries/LibWebView/WebUI/SettingsUI.cpp @@ -39,6 +39,8 @@ static bool should_show_config_variable([[maybe_unused]] ConfigVariableID id) if (id == ConfigVariableID::UseRoundedWindowCorners) return false; #endif + if (id == ConfigVariableID::UseServerSideWindowDecorations) + return Application::the().supports_server_side_window_decorations(); return true; } diff --git a/UI/Qt/Application.h b/UI/Qt/Application.h index d00cb53662..d2a494b857 100644 --- a/UI/Qt/Application.h +++ b/UI/Qt/Application.h @@ -60,6 +60,7 @@ private: virtual void insert_clipboard_entry(Web::Clipboard::SystemClipboardRepresentation) override; virtual bool supports_vertical_tabs() const override { return true; } + virtual bool supports_server_side_window_decorations() const override { return true; } virtual void update_tabs_display() const override; virtual void rebuild_bookmarks_menu() const override; diff --git a/UI/Qt/BrowserWindow.cpp b/UI/Qt/BrowserWindow.cpp index f3c5a8bea2..81de511a44 100644 --- a/UI/Qt/BrowserWindow.cpp +++ b/UI/Qt/BrowserWindow.cpp @@ -231,7 +231,7 @@ BrowserWindow::BrowserWindow(Vector const& initial_urls, IsPopupWindow { auto const& browser_options = WebView::Application::browser_options(); - setWindowFlag(Qt::FramelessWindowHint); + setWindowFlag(Qt::FramelessWindowHint, uses_client_side_decorations()); setAttribute(Qt::WA_OpaquePaintEvent); setWindowIcon(app_icon()); qApp->installEventFilter(this); @@ -573,6 +573,11 @@ FullscreenMode& BrowserWindow::fullscreen_mode() return *m_fullscreen_mode; } +bool BrowserWindow::uses_client_side_decorations() +{ + return !WebView::Application::settings().config_variable_as_bool(WebView::ConfigVariableID::UseServerSideWindowDecorations); +} + Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab) { auto* tab = new Tab(this); @@ -931,8 +936,8 @@ void BrowserWindow::update_menu_bar_visibility(bool show_menubar) { menuBar()->setVisible(show_menubar); if (m_menu_bar_window_controls) - m_menu_bar_window_controls->setVisible(show_menubar); - m_tabs_container->set_window_controls_visible(!show_menubar); + m_menu_bar_window_controls->setVisible(show_menubar && uses_client_side_decorations()); + m_tabs_container->set_window_controls_visible(!show_menubar && uses_client_side_decorations()); } void BrowserWindow::update_menu_bar_window_control_icons() @@ -947,6 +952,33 @@ void BrowserWindow::update_menu_bar_window_control_icons() m_menu_bar_close_window_button->setIcon(create_chrome_icon(ChromeIcon::WindowClose, palette())); } +void BrowserWindow::update_window_decoration_state() +{ + clear_resize_cursor(); + + auto should_be_frameless = uses_client_side_decorations(); + auto is_frameless = windowFlags().testFlag(Qt::FramelessWindowHint); + + if (is_frameless != should_be_frameless) { + auto was_visible = isVisible(); + auto was_fullscreen = isFullScreen(); + auto was_maximized = isMaximized(); + + setWindowFlag(Qt::FramelessWindowHint, should_be_frameless); + + if (was_visible) { + if (was_fullscreen) + showFullScreen(); + else if (was_maximized) + showMaximized(); + else + show(); + } + } + + update_menu_bar_visibility(Settings::the()->show_menubar()); +} + void BrowserWindow::toggle_window_maximized() { if (isMaximized()) @@ -1133,6 +1165,8 @@ bool BrowserWindow::eventFilter(QObject* object, QEvent* event) auto* widget = as_if(object); if (!widget || widget->window() != this) return QMainWindow::eventFilter(object, event); + if (!uses_client_side_decorations()) + return QMainWindow::eventFilter(object, event); auto const is_button = qobject_cast(object) != nullptr; @@ -1233,7 +1267,7 @@ Optional BrowserWindow::resize_cursor_for_edges(Qt::Edges edges void BrowserWindow::update_resize_cursor(QPoint const& position) { - if (isMaximized() || isFullScreen() || !rect().contains(position)) { + if (!uses_client_side_decorations() || isMaximized() || isFullScreen() || !rect().contains(position)) { clear_resize_cursor(); return; } @@ -1301,6 +1335,8 @@ void BrowserWindow::config_variable_changed(WebView::ConfigVariableID variable) { if (variable == WebView::ConfigVariableID::UseRoundedWindowCorners) update_window_corners(); + else if (variable == WebView::ConfigVariableID::UseServerSideWindowDecorations) + update_window_decoration_state(); } void BrowserWindow::update_window_corners() diff --git a/UI/Qt/BrowserWindow.h b/UI/Qt/BrowserWindow.h index d0192f2e62..c0ac489ebb 100644 --- a/UI/Qt/BrowserWindow.h +++ b/UI/Qt/BrowserWindow.h @@ -106,6 +106,7 @@ public: FullscreenMode& fullscreen_mode(); QMenu& hamburger_menu() const { return *m_hamburger_menu; } + static bool uses_client_side_decorations(); QAction& new_window_action() const { return *m_new_window_action; } QAction& find_action() const { return *m_find_in_page_action; } @@ -181,6 +182,7 @@ private: void update_menu_bar_style(); void update_menu_bar_visibility(bool); void update_menu_bar_window_control_icons(); + void update_window_decoration_state(); void toggle_window_maximized(); bool start_window_move(); bool connect_window_screen_changed_signal(); diff --git a/UI/Qt/TabBar.cpp b/UI/Qt/TabBar.cpp index 53670d9021..879aa92fc9 100644 --- a/UI/Qt/TabBar.cpp +++ b/UI/Qt/TabBar.cpp @@ -99,6 +99,12 @@ static QPointer s_active_tab_dragged_tab; static QPointer s_pending_tab_drop_target; static int s_pending_tab_drop_index { -1 }; +static bool window_uses_client_side_decorations(QWidget& widget) +{ + auto* top_level_window = qobject_cast(widget.window()); + return !top_level_window || top_level_window->uses_client_side_decorations(); +} + static QPainterPath tab_shape_path(QRectF const& rect, qreal top_radius, qreal bottom_radius) { top_radius = min(top_radius, rect.height() / 2.0); @@ -735,7 +741,7 @@ void TabBar::mouseReleaseEvent(QMouseEvent* event) void TabBar::mouseDoubleClickEvent(QMouseEvent* event) { - if (tab_index_at(event->pos()) < 0 && event->button() == Qt::LeftButton) { + if (window_uses_client_side_decorations(*this) && tab_index_at(event->pos()) < 0 && event->button() == Qt::LeftButton) { toggle_window_maximized(); event->accept(); return; @@ -1465,7 +1471,7 @@ bool TabWidget::eventFilter(QObject* watched, QEvent* event) } } - if (watched == m_tab_bar_row || watched == m_vertical_tab_bar_column) { + if ((watched == m_tab_bar_row || watched == m_vertical_tab_bar_column) && window_uses_client_side_decorations(*this)) { auto is_empty_chrome_area = [this, watched](QMouseEvent const& mouse_event) { if (watched == m_vertical_tab_bar_column) { auto* child = m_vertical_tab_bar_column->childAt(mouse_event.pos());