diff --git a/libcef/browser/native/browser_platform_delegate_native_linux.cc b/libcef/browser/native/browser_platform_delegate_native_linux.cc index 68ca2e7b6..6570ed872 100644 --- a/libcef/browser/native/browser_platform_delegate_native_linux.cc +++ b/libcef/browser/native/browser_platform_delegate_native_linux.cc @@ -81,8 +81,8 @@ bool CefBrowserPlatformDelegateNativeLinux::CreateHostWindow() { // Add a reference that will be released in BrowserDestroyed(). browser_->AddRef(); - CefWindowDelegateView* delegate_view = - new CefWindowDelegateView(GetBackgroundColor()); + CefWindowDelegateView* delegate_view = new CefWindowDelegateView( + GetBackgroundColor(), window_x11_->TopLevelAlwaysOnTop()); delegate_view->Init(window_info_.window, browser_->web_contents(), gfx::Rect(gfx::Point(), rect.size())); diff --git a/libcef/browser/native/browser_platform_delegate_native_win.cc b/libcef/browser/native/browser_platform_delegate_native_win.cc index 57a135b2e..cc09b2916 100644 --- a/libcef/browser/native/browser_platform_delegate_native_win.cc +++ b/libcef/browser/native/browser_platform_delegate_native_win.cc @@ -194,8 +194,15 @@ bool CefBrowserPlatformDelegateNativeWin::CreateHostWindow() { point = gfx::ToFlooredPoint(gfx::ScalePoint(gfx::PointF(point), 1.0f / scale)); + // Stay on top if top-most window hosting the web view is topmost. + HWND top_level_window = GetAncestor(window_info_.window, GA_ROOT); + DWORD top_level_window_ex_styles = + GetWindowLongPtr(top_level_window, GWL_EXSTYLE); + bool always_on_top = + (top_level_window_ex_styles & WS_EX_TOPMOST) == WS_EX_TOPMOST; + CefWindowDelegateView* delegate_view = - new CefWindowDelegateView(GetBackgroundColor()); + new CefWindowDelegateView(GetBackgroundColor(), always_on_top); delegate_view->Init(window_info_.window, browser_->web_contents(), gfx::Rect(0, 0, point.x(), point.y())); diff --git a/libcef/browser/native/window_delegate_view.cc b/libcef/browser/native/window_delegate_view.cc index 30100759f..fc9de781b 100644 --- a/libcef/browser/native/window_delegate_view.cc +++ b/libcef/browser/native/window_delegate_view.cc @@ -12,8 +12,11 @@ #include "ui/views/layout/fill_layout.h" #include "ui/views/widget/widget.h" -CefWindowDelegateView::CefWindowDelegateView(SkColor background_color) - : background_color_(background_color), web_view_(NULL) {} +CefWindowDelegateView::CefWindowDelegateView(SkColor background_color, + bool always_on_top) + : background_color_(background_color), + web_view_(NULL), + always_on_top_(always_on_top) {} void CefWindowDelegateView::Init(gfx::AcceleratedWidget parent_widget, content::WebContents* web_contents, @@ -44,6 +47,8 @@ void CefWindowDelegateView::Init(gfx::AcceleratedWidget parent_widget, // CefBrowserHostImpl::PlatformSetFocus. params.activatable = views::Widget::InitParams::ACTIVATABLE_YES; + params.keep_on_top = always_on_top_; + // Results in a call to InitContent(). widget->Init(params); diff --git a/libcef/browser/native/window_delegate_view.h b/libcef/browser/native/window_delegate_view.h index 29c0fb08e..7c50d3658 100644 --- a/libcef/browser/native/window_delegate_view.h +++ b/libcef/browser/native/window_delegate_view.h @@ -20,7 +20,7 @@ class WebView; // will be deleted automatically when the associated root window is destroyed. class CefWindowDelegateView : public views::WidgetDelegateView { public: - explicit CefWindowDelegateView(SkColor background_color); + CefWindowDelegateView(SkColor background_color, bool always_on_top); // Create the Widget and associated root window. void Init(gfx::AcceleratedWidget parent_widget, @@ -43,6 +43,7 @@ class CefWindowDelegateView : public views::WidgetDelegateView { private: SkColor background_color_; views::WebView* web_view_; + bool always_on_top_; DISALLOW_COPY_AND_ASSIGN(CefWindowDelegateView); }; diff --git a/libcef/browser/native/window_x11.cc b/libcef/browser/native/window_x11.cc index 298a13c11..2300b1b67 100644 --- a/libcef/browser/native/window_x11.cc +++ b/libcef/browser/native/window_x11.cc @@ -396,3 +396,34 @@ void CefWindowX11::ContinueFocus() { browser_->SetFocus(true); focus_pending_ = false; } + +bool CefWindowX11::TopLevelAlwaysOnTop() const { + ::Window toplevel_window = FindToplevelParent(xdisplay_, xwindow_); + + Atom state_atom = gfx::GetAtom("_NET_WM_STATE"); + Atom state_keep_above = gfx::GetAtom("_NET_WM_STATE_KEEP_ABOVE"); + Atom* states; + + Atom actual_type; + int actual_format; + unsigned long num_items; + unsigned long bytes_after; + + XGetWindowProperty(xdisplay_, toplevel_window, state_atom, 0, 1024, + x11::False, XA_ATOM, &actual_type, &actual_format, + &num_items, &bytes_after, + reinterpret_cast(&states)); + + bool always_on_top = false; + + for (unsigned long i = 0; i < num_items; ++i) { + if (states[i] == state_keep_above) { + always_on_top = true; + break; + } + } + + XFree(states); + + return always_on_top; +} diff --git a/libcef/browser/native/window_x11.h b/libcef/browser/native/window_x11.h index 90d409d37..a9bca9094 100644 --- a/libcef/browser/native/window_x11.h +++ b/libcef/browser/native/window_x11.h @@ -52,6 +52,8 @@ class CefWindowX11 : public ui::PlatformEventDispatcher { ::Window xwindow() const { return xwindow_; } gfx::Rect bounds() const { return bounds_; } + bool TopLevelAlwaysOnTop() const; + private: void ContinueFocus(); diff --git a/tests/cefclient/browser/root_window.h b/tests/cefclient/browser/root_window.h index f8600a292..7d1dfff6a 100644 --- a/tests/cefclient/browser/root_window.h +++ b/tests/cefclient/browser/root_window.h @@ -23,6 +23,9 @@ namespace client { struct RootWindowConfig { RootWindowConfig(); + // If true the window will always display above other windows. + bool always_on_top; + // If true the window will show controls. bool with_controls; diff --git a/tests/cefclient/browser/root_window_gtk.cc b/tests/cefclient/browser/root_window_gtk.cc index 15821bec1..512a79c54 100644 --- a/tests/cefclient/browser/root_window_gtk.cc +++ b/tests/cefclient/browser/root_window_gtk.cc @@ -51,6 +51,7 @@ void MaximizeWindow(GtkWindow* window) { RootWindowGtk::RootWindowGtk() : with_controls_(false), + always_on_top_(false), with_osr_(false), with_extension_(false), is_popup_(false), @@ -84,6 +85,7 @@ void RootWindowGtk::Init(RootWindow::Delegate* delegate, delegate_ = delegate; with_controls_ = config.with_controls; + always_on_top_ = config.always_on_top; with_osr_ = config.with_osr; with_extension_ = config.with_extension; start_rect_ = config.bounds; @@ -275,6 +277,10 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings, window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL); CHECK(window_); + if (always_on_top_) { + gtk_window_set_keep_above(GTK_WINDOW(window_), TRUE); + } + gtk_window_set_default_size(GTK_WINDOW(window_), width, height); g_signal_connect(G_OBJECT(window_), "focus-in-event", G_CALLBACK(&RootWindowGtk::WindowFocusIn), this); diff --git a/tests/cefclient/browser/root_window_gtk.h b/tests/cefclient/browser/root_window_gtk.h index 6b2f5a17f..9982c1474 100644 --- a/tests/cefclient/browser/root_window_gtk.h +++ b/tests/cefclient/browser/root_window_gtk.h @@ -125,6 +125,7 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate { // After initialization all members are only accessed on the main thread. // Members set during initialization. bool with_controls_; + bool always_on_top_; bool with_osr_; bool with_extension_; bool is_popup_; diff --git a/tests/cefclient/browser/root_window_views.cc b/tests/cefclient/browser/root_window_views.cc index 98c5d5496..f0800ff88 100644 --- a/tests/cefclient/browser/root_window_views.cc +++ b/tests/cefclient/browser/root_window_views.cc @@ -21,6 +21,7 @@ static const char* kDefaultImageCache[] = {"menu_icon", "window_icon"}; RootWindowViews::RootWindowViews() : with_controls_(false), + always_on_top_(false), with_extension_(false), initially_hidden_(false), is_popup_(false), @@ -42,6 +43,7 @@ void RootWindowViews::Init(RootWindow::Delegate* delegate, delegate_ = delegate; with_controls_ = config.with_controls; + always_on_top_ = config.always_on_top; with_extension_ = config.with_extension; initially_hidden_ = config.initially_hidden; if (initially_hidden_ && !config.source_bounds.IsEmpty()) { @@ -239,6 +241,7 @@ void RootWindowViews::OnViewsWindowCreated(CefRefPtr window) { CEF_REQUIRE_UI_THREAD(); DCHECK(!window_); window_ = window; + window_->SetAlwaysOnTop(always_on_top_); if (!pending_extensions_.empty()) { window_->OnExtensionsChanged(pending_extensions_); diff --git a/tests/cefclient/browser/root_window_views.h b/tests/cefclient/browser/root_window_views.h index a3cc8d034..5cce3ca10 100644 --- a/tests/cefclient/browser/root_window_views.h +++ b/tests/cefclient/browser/root_window_views.h @@ -104,6 +104,7 @@ class RootWindowViews : public RootWindow, // unless otherwise indicated. // Members set during initialization. bool with_controls_; + bool always_on_top_; bool with_extension_; bool initially_hidden_; CefRefPtr parent_window_; diff --git a/tests/cefclient/browser/root_window_win.cc b/tests/cefclient/browser/root_window_win.cc index b8c0461e7..667a789ff 100644 --- a/tests/cefclient/browser/root_window_win.cc +++ b/tests/cefclient/browser/root_window_win.cc @@ -103,6 +103,7 @@ int GetURLBarHeight(HWND hwnd) { RootWindowWin::RootWindowWin() : with_controls_(false), + always_on_top_(false), with_osr_(false), with_extension_(false), is_popup_(false), @@ -152,6 +153,7 @@ void RootWindowWin::Init(RootWindow::Delegate* delegate, delegate_ = delegate; with_controls_ = config.with_controls; + always_on_top_ = config.always_on_top; with_osr_ = config.with_osr; with_extension_ = config.with_extension; @@ -333,6 +335,7 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings, CHECK(find_message_id_); const DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN; + const DWORD dwExStyle = always_on_top_ ? WS_EX_TOPMOST : 0; int x, y, width, height; if (::IsRectEmpty(&start_rect_)) { @@ -341,7 +344,7 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings, } else { // Adjust the window size to account for window frame and controls. RECT window_rect = start_rect_; - ::AdjustWindowRectEx(&window_rect, dwStyle, with_controls_, 0); + ::AdjustWindowRectEx(&window_rect, dwStyle, with_controls_, dwExStyle); x = start_rect_.left; y = start_rect_.top; @@ -352,8 +355,8 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings, browser_settings_ = settings; // Create the main window initially hidden. - CreateWindow(window_class.c_str(), window_title.c_str(), dwStyle, x, y, width, - height, NULL, NULL, hInstance, this); + CreateWindowEx(dwExStyle, window_class.c_str(), window_title.c_str(), dwStyle, + x, y, width, height, NULL, NULL, hInstance, this); CHECK(hwnd_); if (!called_enable_non_client_dpi_scaling_ && IsProcessPerMonitorDpiAware()) { diff --git a/tests/cefclient/browser/root_window_win.h b/tests/cefclient/browser/root_window_win.h index f301da6d5..153c38e3a 100644 --- a/tests/cefclient/browser/root_window_win.h +++ b/tests/cefclient/browser/root_window_win.h @@ -112,6 +112,7 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate { // After initialization all members are only accessed on the main thread. // Members set during initialization. bool with_controls_; + bool always_on_top_; bool with_osr_; bool with_extension_; bool is_popup_; diff --git a/tests/cefclient/browser/views_window.cc b/tests/cefclient/browser/views_window.cc index 7f76aa711..2da1a1a9d 100644 --- a/tests/cefclient/browser/views_window.cc +++ b/tests/cefclient/browser/views_window.cc @@ -222,6 +222,13 @@ void ViewsWindow::SetFullscreen(bool fullscreen) { } } +void ViewsWindow::SetAlwaysOnTop(bool on_top) { + CEF_REQUIRE_UI_THREAD(); + if (window_) { + window_->SetAlwaysOnTop(on_top); + } +} + void ViewsWindow::SetLoadingState(bool isLoading, bool canGoBack, bool canGoForward) { diff --git a/tests/cefclient/browser/views_window.h b/tests/cefclient/browser/views_window.h index 8d43a0ecc..62739acb5 100644 --- a/tests/cefclient/browser/views_window.h +++ b/tests/cefclient/browser/views_window.h @@ -112,6 +112,7 @@ class ViewsWindow : public CefBrowserViewDelegate, void SetTitle(const std::string& title); void SetFavicon(CefRefPtr image); void SetFullscreen(bool fullscreen); + void SetAlwaysOnTop(bool on_top); void SetLoadingState(bool isLoading, bool canGoBack, bool canGoForward); void SetDraggableRegions(const std::vector& regions); void TakeFocus(bool next); diff --git a/tests/cefclient/cefclient_gtk.cc b/tests/cefclient/cefclient_gtk.cc index c2f714e2e..ee1adb996 100644 --- a/tests/cefclient/cefclient_gtk.cc +++ b/tests/cefclient/cefclient_gtk.cc @@ -130,6 +130,7 @@ int RunMain(int argc, char* argv[]) { test_runner::RegisterSchemeHandlers(); RootWindowConfig window_config; + window_config.always_on_top = command_line->HasSwitch(switches::kAlwaysOnTop); window_config.with_controls = !command_line->HasSwitch(switches::kHideControls); window_config.with_osr = settings.windowless_rendering_enabled ? true : false; diff --git a/tests/cefclient/cefclient_win.cc b/tests/cefclient/cefclient_win.cc index de291282e..dc04f575b 100644 --- a/tests/cefclient/cefclient_win.cc +++ b/tests/cefclient/cefclient_win.cc @@ -95,6 +95,7 @@ int RunMain(HINSTANCE hInstance, int nCmdShow) { test_runner::RegisterSchemeHandlers(); RootWindowConfig window_config; + window_config.always_on_top = command_line->HasSwitch(switches::kAlwaysOnTop); window_config.with_controls = !command_line->HasSwitch(switches::kHideControls); window_config.with_osr = settings.windowless_rendering_enabled ? true : false; diff --git a/tests/shared/common/client_switches.cc b/tests/shared/common/client_switches.cc index d5cf11d64..545d046ba 100644 --- a/tests/shared/common/client_switches.cc +++ b/tests/shared/common/client_switches.cc @@ -37,6 +37,7 @@ const char kFilterURL[] = "filter-url"; const char kUseViews[] = "use-views"; const char kHideFrame[] = "hide-frame"; const char kHideControls[] = "hide-controls"; +const char kAlwaysOnTop[] = "always-on-top"; const char kHideTopMenu[] = "hide-top-menu"; const char kWidevineCdmPath[] = "widevine-cdm-path"; const char kSslClientCertificate[] = "ssl-client-certificate"; diff --git a/tests/shared/common/client_switches.h b/tests/shared/common/client_switches.h index c6f6e8b2d..d653f4445 100644 --- a/tests/shared/common/client_switches.h +++ b/tests/shared/common/client_switches.h @@ -31,6 +31,7 @@ extern const char kFilterURL[]; extern const char kUseViews[]; extern const char kHideFrame[]; extern const char kHideControls[]; +extern const char kAlwaysOnTop[]; extern const char kHideTopMenu[]; extern const char kWidevineCdmPath[]; extern const char kSslClientCertificate[];