summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk
diff options
context:
space:
mode:
authortc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-09 21:20:52 +0000
committertc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-09 21:20:52 +0000
commit90b6707fe7bdd8dea5d908040e3a2c1f17feb838 (patch)
tree90d3538522d78e296f8f2d15f10058054b183211 /chrome/browser/gtk
parent1d4efb6bc9f956cdbca55c7a4ba99d1bb76e42f8 (diff)
downloadchromium_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.cc57
-rw-r--r--chrome/browser/gtk/active_window_watcher.h35
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc91
-rw-r--r--chrome/browser/gtk/browser_window_gtk.h5
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,
+ &GTK_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);
};