diff options
author | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-09 21:20:52 +0000 |
---|---|---|
committer | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-09 21:20:52 +0000 |
commit | 90b6707fe7bdd8dea5d908040e3a2c1f17feb838 (patch) | |
tree | 90d3538522d78e296f8f2d15f10058054b183211 /chrome/browser/gtk | |
parent | 1d4efb6bc9f956cdbca55c7a4ba99d1bb76e42f8 (diff) | |
download | chromium_src-90b6707fe7bdd8dea5d908040e3a2c1f17feb838.zip chromium_src-90b6707fe7bdd8dea5d908040e3a2c1f17feb838.tar.gz chromium_src-90b6707fe7bdd8dea5d908040e3a2c1f17feb838.tar.bz2 |
Change the window background color to the inactive color when the
window manager says the window isn't active.
ActiveWindowWatcher listens for X events and notifies the browser
windows when the active window changes. We can't just use focus
events because popup menus cause browser windows to lose focus,
but it's still the "active" window.
Some window managers don't track active window, in which case we
don't get the x event and we just say that all windows are
active (our current behavior).
BUG=14649
Review URL: http://codereview.chromium.org/155303
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20313 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk')
-rw-r--r-- | chrome/browser/gtk/active_window_watcher.cc | 57 | ||||
-rw-r--r-- | chrome/browser/gtk/active_window_watcher.h | 35 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_window_gtk.cc | 91 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_window_gtk.h | 5 |
4 files changed, 166 insertions, 22 deletions
diff --git a/chrome/browser/gtk/active_window_watcher.cc b/chrome/browser/gtk/active_window_watcher.cc new file mode 100644 index 0000000..5028b25 --- /dev/null +++ b/chrome/browser/gtk/active_window_watcher.cc @@ -0,0 +1,57 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <X11/Xlib.h> +#include <gdk/gdk.h> +#include <gdk/gdkx.h> + +#include "chrome/browser/gtk/active_window_watcher.h" +#include "chrome/common/notification_service.h" + +ActiveWindowWatcher::ActiveWindowWatcher() { + Init(); +} + +void ActiveWindowWatcher::Init() { + // Set up X Event filter to listen for PropertyChange X events. These events + // tell us when the active window changes. + GdkWindow* root = gdk_screen_get_root_window(gdk_screen_get_default()); + gdk_window_add_filter(root, &ActiveWindowWatcher::OnWindowXEvent, this); + XSelectInput(GDK_WINDOW_XDISPLAY(root), GDK_WINDOW_XID(root), + PropertyChangeMask); +} + +void ActiveWindowWatcher::NotifyActiveWindowChanged() { + GdkWindow* active_window = gdk_screen_get_active_window( + gdk_screen_get_default()); + + // If the window manager doesn't support _NET_ACTIVE_WINDOW, we don't know + // which window is active and just give up. + if (!active_window) + return; + + NotificationService::current()->Notify( + NotificationType::ACTIVE_WINDOW_CHANGED, + Source<ActiveWindowWatcher>(this), + Details<const GdkWindow>(active_window)); +} + +GdkFilterReturn ActiveWindowWatcher::OnWindowXEvent(GdkXEvent* xevent, + GdkEvent* event, gpointer window_watcher) { + static const GdkAtom kNetActiveWindow = gdk_atom_intern( + "_NET_ACTIVE_WINDOW", FALSE); + static const Atom kNetActiveWindowAtom = gdk_x11_atom_to_xatom_for_display( + gdk_screen_get_display(gdk_screen_get_default()), kNetActiveWindow); + + ActiveWindowWatcher* watcher = reinterpret_cast<ActiveWindowWatcher*>( + window_watcher); + XEvent* xev = static_cast<XEvent*>(xevent); + + if (xev->xany.type == PropertyNotify && + xev->xproperty.atom == kNetActiveWindowAtom) { + watcher->NotifyActiveWindowChanged(); + } + + return GDK_FILTER_CONTINUE; +} diff --git a/chrome/browser/gtk/active_window_watcher.h b/chrome/browser/gtk/active_window_watcher.h new file mode 100644 index 0000000..dc115c6 --- /dev/null +++ b/chrome/browser/gtk/active_window_watcher.h @@ -0,0 +1,35 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_GTK_ACTIVE_WINDOW_WATCHER_H_ +#define CHROME_BROWSER_GTK_ACTIVE_WINDOW_WATCHER_H_ + +#include "base/basictypes.h" + +typedef void* gpointer; +typedef void GdkXEvent; +typedef union _GdkEvent GdkEvent; + +// This is a helper class that is used to keep track of which window the window +// manager thinks is active. +class ActiveWindowWatcher { + public: + ActiveWindowWatcher(); + + private: + void Init(); + + // Sends a notification out through the NotificationService that the active + // window has changed. + void NotifyActiveWindowChanged(); + + // Callback for PropertyChange XEvents. + static GdkFilterReturn OnWindowXEvent(GdkXEvent* xevent, + GdkEvent* event, + gpointer window_watcher); + + DISALLOW_COPY_AND_ASSIGN(ActiveWindowWatcher); +}; + +#endif // CHROME_BROWSER_GTK_ACTIVE_WINDOW_WATCHER_H_ diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index 2c7c39a..a7d3e01 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -12,6 +12,7 @@ #include "base/base_paths_linux.h" #include "base/command_line.h" #include "base/gfx/gtk_util.h" +#include "base/lazy_instance.h" #include "base/logging.h" #include "base/message_loop.h" #include "base/path_service.h" @@ -26,6 +27,7 @@ #include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/gtk/about_chrome_dialog.h" +#include "chrome/browser/gtk/active_window_watcher.h" #include "chrome/browser/gtk/bookmark_bar_gtk.h" #include "chrome/browser/gtk/bookmark_manager_gtk.h" #include "chrome/browser/gtk/browser_titlebar.h" @@ -80,6 +82,9 @@ const int kTopResizeAdjust = 1; // the 16 px at the end of each edge triggers diagonal resizing. const int kResizeAreaCornerSize = 16; +base::LazyInstance<ActiveWindowWatcher> + g_active_window_watcher(base::LINKER_INITIALIZED); + gboolean MainWindowConfigured(GtkWindow* window, GdkEventConfigure* event, BrowserWindowGtk* browser_win) { gfx::Rect bounds = gfx::Rect(event->x, event->y, event->width, event->height); @@ -370,7 +375,8 @@ BrowserWindowGtk::BrowserWindowGtk(Browser* browser) drag_active_(false), panel_controller_(NULL), #endif - frame_cursor_(NULL) { + frame_cursor_(NULL), + is_active_(true) { use_custom_frame_.Init(prefs::kUseCustomChromeFrame, browser_->profile()->GetPrefs(), this); window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); @@ -390,6 +396,10 @@ BrowserWindowGtk::BrowserWindowGtk(Browser* browser) registrar_.Add(this, NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED, NotificationService::AllSources()); + registrar_.Add(this, NotificationType::ACTIVE_WINDOW_CHANGED, + NotificationService::AllSources()); + // Make sure the ActiveWindowWatcher instance exists (it's a lazy instance). + g_active_window_watcher.Get(); } BrowserWindowGtk::~BrowserWindowGtk() { @@ -412,19 +422,23 @@ void BrowserWindowGtk::HandleAccelerator(guint keyval, gboolean BrowserWindowGtk::OnCustomFrameExpose(GtkWidget* widget, GdkEventExpose* event, BrowserWindowGtk* window) { - // TODO(tc): This will have to be dynamic once themes are supported. Maybe - // detect the theme install and delete the pointer? static NineBox* custom_frame_border = NULL; static NineBox* default_background = NULL; + static NineBox* default_background_inactive = NULL; static NineBox* default_background_otr = NULL; + static NineBox* default_background_otr_inactive = NULL; ThemeProvider* theme_provider = window->browser()->profile()->GetThemeProvider(); if (!default_background) { default_background = new NineBox(theme_provider, 0, IDR_THEME_FRAME, 0, 0, 0, 0, 0, 0, 0); + default_background_inactive = new NineBox(theme_provider, + 0, IDR_THEME_FRAME_INACTIVE, 0, 0, 0, 0, 0, 0, 0); default_background_otr = new NineBox(theme_provider, 0, IDR_THEME_FRAME_INCOGNITO, 0, 0, 0, 0, 0, 0, 0); + default_background_otr_inactive = new NineBox(theme_provider, + 0, IDR_THEME_FRAME_INCOGNITO_INACTIVE, 0, 0, 0, 0, 0, 0, 0); } // Draw the default background. @@ -432,8 +446,14 @@ gboolean BrowserWindowGtk::OnCustomFrameExpose(GtkWidget* widget, cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event->area.height); cairo_clip(cr); - NineBox* image = window->browser()->profile()->IsOffTheRecord() - ? default_background_otr : default_background; + NineBox* image = NULL; + if (window->IsActive()) { + image = window->browser()->profile()->IsOffTheRecord() + ? default_background_otr : default_background; + } else { + image = window->browser()->profile()->IsOffTheRecord() + ? default_background_otr_inactive : default_background_inactive; + } image->RenderTopCenterStrip(cr, 0, 0, widget->allocation.width); cairo_destroy(cr); @@ -526,8 +546,7 @@ void BrowserWindowGtk::Activate() { } bool BrowserWindowGtk::IsActive() const { - NOTIMPLEMENTED(); - return true; + return is_active_; } void BrowserWindowGtk::FlashFrame() { @@ -771,17 +790,39 @@ void BrowserWindowGtk::ConfirmBrowserCloseWithPendingDownloads() { void BrowserWindowGtk::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - if (type == NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED) { - MaybeShowBookmarkBar(browser_->GetSelectedTabContents(), true); - } else if (type == NotificationType::PREF_CHANGED) { - std::wstring* pref_name = Details<std::wstring>(details).ptr(); - if (*pref_name == prefs::kUseCustomChromeFrame) { - UpdateCustomFrame(); - } else { - NOTREACHED() << "Got a pref change notification we didn't register for!"; + switch (type.value) { + case NotificationType::BOOKMARK_BAR_VISIBILITY_PREF_CHANGED: + MaybeShowBookmarkBar(browser_->GetSelectedTabContents(), true); + break; + + case NotificationType::PREF_CHANGED: { + std::wstring* pref_name = Details<std::wstring>(details).ptr(); + if (*pref_name == prefs::kUseCustomChromeFrame) { + UpdateCustomFrame(); + } else { + NOTREACHED() << "Got pref change notification we didn't register for!"; + } + break; } - } else { - NOTREACHED() << "Got a notification we didn't register for!"; + + case NotificationType::ACTIVE_WINDOW_CHANGED: { + const GdkWindow* active_window = Details<const GdkWindow>(details).ptr(); + bool is_active = (GTK_WIDGET(window_)->window == active_window); + bool changed = (is_active != is_active_); + is_active_ = is_active; + if (changed) { + SetBackgroundColor(); + gdk_window_invalidate_rect(GTK_WIDGET(window_)->window, + >K_WIDGET(window_)->allocation, TRUE); + // For some reason, the above two calls cause the window shape to be + // lost so reset it. + UpdateWindowShape(bounds_.width(), bounds_.height()); + } + break; + } + + default: + NOTREACHED() << "Got a notification we didn't register for!"; } } @@ -1084,14 +1125,19 @@ void BrowserWindowGtk::SetBackgroundColor() { // TODO(tc): Handle active/inactive colors. Profile* profile = browser()->profile(); ThemeProvider* theme_provider = profile->GetThemeProvider(); - SkColor frame_color; - if (browser()->profile()->IsOffTheRecord()) { - frame_color = theme_provider->GetColor( - BrowserThemeProvider::COLOR_FRAME_INCOGNITO); + int frame_color_id; + if (IsActive()) { + frame_color_id = browser()->profile()->IsOffTheRecord() + ? BrowserThemeProvider::COLOR_FRAME_INCOGNITO + : BrowserThemeProvider::COLOR_FRAME; } else { - frame_color = theme_provider->GetColor(BrowserThemeProvider::COLOR_FRAME); + frame_color_id = browser()->profile()->IsOffTheRecord() + ? BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE + : BrowserThemeProvider::COLOR_FRAME_INACTIVE; } + SkColor frame_color = theme_provider->GetColor(frame_color_id); + // Paint the frame color on the left, right and bottom. GdkColor frame_color_gdk = GDK_COLOR_RGB(SkColorGetR(frame_color), SkColorGetG(frame_color), SkColorGetB(frame_color)); @@ -1118,6 +1164,7 @@ void BrowserWindowGtk::UpdateWindowShape(int width, int height) { gtk_alignment_set_padding(GTK_ALIGNMENT(window_container_), 1, kFrameBorderThickness, kFrameBorderThickness, kFrameBorderThickness); } else { + // XFCE disables the system decorations if there's an xshape set. if (use_custom_frame_.GetValue()) { // Disable rounded corners. Simply passing in a NULL region doesn't // seem to work on KWin, so manually set the shape to the whole window. diff --git a/chrome/browser/gtk/browser_window_gtk.h b/chrome/browser/gtk/browser_window_gtk.h index cf55189..42de7d7 100644 --- a/chrome/browser/gtk/browser_window_gtk.h +++ b/chrome/browser/gtk/browser_window_gtk.h @@ -310,6 +310,11 @@ class BrowserWindowGtk : public BrowserWindow, // custom frame border. We set it to NULL if we want the default cursor. GdkCursor* frame_cursor_; + // True if the window manager thinks the window is active. Not all window + // managers keep track of this state (_NET_ACTIVE_WINDOW), in which case + // this will always be true. + bool is_active_; + DISALLOW_COPY_AND_ASSIGN(BrowserWindowGtk); }; |