diff --git a/atom.gyp b/atom.gyp index cb480c74b967..191c0428c9ee 100644 --- a/atom.gyp +++ b/atom.gyp @@ -129,10 +129,17 @@ 'atom/browser/ui/file_dialog_gtk.cc', 'atom/browser/ui/file_dialog_mac.mm', 'atom/browser/ui/file_dialog_win.cc', + 'atom/browser/ui/gtk/active_window_watcher_x.cc', + 'atom/browser/ui/gtk/active_window_watcher_x.h', + 'atom/browser/ui/gtk/active_window_watcher_x_observer.h', 'atom/browser/ui/gtk/app_indicator_icon.cc', 'atom/browser/ui/gtk/app_indicator_icon.h', + 'atom/browser/ui/gtk/root_window_property_watcher_x.cc', + 'atom/browser/ui/gtk/root_window_property_watcher_x.h', 'atom/browser/ui/gtk/status_icon.cc', 'atom/browser/ui/gtk/status_icon.h', + 'atom/browser/ui/gtk/work_area_watcher_x.cc', + 'atom/browser/ui/gtk/work_area_watcher_x.h', 'atom/browser/ui/message_box.h', 'atom/browser/ui/message_box_gtk.cc', 'atom/browser/ui/message_box_mac.mm', diff --git a/atom/browser/native_window_gtk.cc b/atom/browser/native_window_gtk.cc index 6fb4b5fdd47b..19c61c68b18b 100644 --- a/atom/browser/native_window_gtk.cc +++ b/atom/browser/native_window_gtk.cc @@ -7,6 +7,7 @@ #include #include +#include "atom/browser/ui/gtk/active_window_watcher_x.h" #include "atom/common/draggable_region.h" #include "atom/common/options_switches.h" #include "base/environment.h" @@ -20,7 +21,6 @@ #include "native_mate/dictionary.h" #include "ui/base/accelerators/platform_accelerator_gtk.h" #include "ui/base/models/simple_menu_model.h" -#include "ui/base/x/active_window_watcher_x.h" #include "ui/base/x/x11_util.h" #include "ui/gfx/font_render_params_linux.h" #include "ui/gfx/gtk_util.h" diff --git a/atom/browser/ui/gtk/active_window_watcher_x.cc b/atom/browser/ui/gtk/active_window_watcher_x.cc new file mode 100644 index 000000000000..937f161fa3c1 --- /dev/null +++ b/atom/browser/ui/gtk/active_window_watcher_x.cc @@ -0,0 +1,99 @@ +// Copyright (c) 2012 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 "atom/browser/ui/gtk/active_window_watcher_x.h" + +#include +#include + +#include "atom/browser/ui/gtk/active_window_watcher_x_observer.h" +#include "atom/browser/ui/gtk/root_window_property_watcher_x.h" +#include "base/memory/singleton.h" +#include "ui/base/x/x11_util.h" +#include "ui/gfx/gdk_compat.h" +#include "ui/gfx/gtk_compat.h" + +namespace ui { + +static const char* const kNetActiveWindow = "_NET_ACTIVE_WINDOW"; + +// static +ActiveWindowWatcherX* ActiveWindowWatcherX::GetInstance() { + return Singleton::get(); +} + +// static +void ActiveWindowWatcherX::AddObserver(ActiveWindowWatcherXObserver* observer) { + // Ensure that RootWindowPropertyWatcherX exists. + internal::RootWindowPropertyWatcherX::GetInstance(); + GetInstance()->observers_.AddObserver(observer); +} + +// static +void ActiveWindowWatcherX::RemoveObserver( + ActiveWindowWatcherXObserver* observer) { + GetInstance()->observers_.RemoveObserver(observer); +} + +// static +Atom ActiveWindowWatcherX::GetPropertyAtom() { + return GetAtom(kNetActiveWindow); +} + +// static +void ActiveWindowWatcherX::Notify() { + GetInstance()->NotifyActiveWindowChanged(); +} + +// static +bool ActiveWindowWatcherX::WMSupportsActivation() { + return gdk_x11_screen_supports_net_wm_hint( + gdk_screen_get_default(), + gdk_atom_intern_static_string(kNetActiveWindow)); +} + +ActiveWindowWatcherX::ActiveWindowWatcherX() { +} + +ActiveWindowWatcherX::~ActiveWindowWatcherX() { +} + +void ActiveWindowWatcherX::NotifyActiveWindowChanged() { + // We don't use gdk_screen_get_active_window() because it caches + // whether or not the window manager supports _NET_ACTIVE_WINDOW. + // This causes problems at startup for chromiumos. + Atom type = None; + int format = 0; // size in bits of each item in 'property' + long unsigned int num_items = 0, remaining_bytes = 0; + unsigned char* property = NULL; + + XGetWindowProperty(gdk_x11_get_default_xdisplay(), + GDK_WINDOW_XID(gdk_get_default_root_window()), + GetAtom(kNetActiveWindow), + 0, // offset into property data to read + 1, // length to get in 32-bit quantities + False, // deleted + AnyPropertyType, + &type, + &format, + &num_items, + &remaining_bytes, + &property); + + // Check that the property was set and contained a single 32-bit item (we + // don't check that remaining_bytes is 0, though, as XFCE's window manager + // seems to actually store two values in the property for some unknown + // reason.) + if (format == 32 && num_items == 1) { + int xid = *reinterpret_cast(property); + GdkDisplay* display = gdk_display_get_default(); + GdkWindow* active_window = gdk_x11_window_lookup_for_display(display, xid); + FOR_EACH_OBSERVER(ActiveWindowWatcherXObserver, observers_, + ActiveWindowChanged(active_window)); + } + if (property) + XFree(property); +} + +} // namespace ui diff --git a/atom/browser/ui/gtk/active_window_watcher_x.h b/atom/browser/ui/gtk/active_window_watcher_x.h new file mode 100644 index 000000000000..9e10bbb298da --- /dev/null +++ b/atom/browser/ui/gtk/active_window_watcher_x.h @@ -0,0 +1,59 @@ +// Copyright (c) 2012 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 ATOM_BROWSER_UI_GTK_ACTIVE_WINDOW_WATCHER_X_H_ +#define ATOM_BROWSER_UI_GTK_ACTIVE_WINDOW_WATCHER_X_H_ + +#include "base/basictypes.h" +#include "base/observer_list.h" +#include "ui/base/x/x11_util.h" + +template struct DefaultSingletonTraits; + +namespace ui { + +class ActiveWindowWatcherXObserver; + +namespace internal { +class RootWindowPropertyWatcherX; +} + +// This is a helper class that is used to keep track of which window the X +// window manager thinks is active. Add an Observer to listen for changes to +// the active window. +class ActiveWindowWatcherX { + public: + static ActiveWindowWatcherX* GetInstance(); + static void AddObserver(ActiveWindowWatcherXObserver* observer); + static void RemoveObserver(ActiveWindowWatcherXObserver* observer); + + // Checks if the WM supports the active window property. Note that the return + // value can change, especially during system startup. + static bool WMSupportsActivation(); + + private: + friend struct DefaultSingletonTraits; + friend class ui::internal::RootWindowPropertyWatcherX; + + ActiveWindowWatcherX(); + ~ActiveWindowWatcherX(); + + // Gets the atom for the default display for the property this class is + // watching for. + static Atom GetPropertyAtom(); + + // Notify observers that the active window has changed. + static void Notify(); + + // Instance method that implements Notify(). + void NotifyActiveWindowChanged(); + + ObserverList observers_; + + DISALLOW_COPY_AND_ASSIGN(ActiveWindowWatcherX); +}; + +} // namespace ui + +#endif // ATOM_BROWSER_UI_GTK_ACTIVE_WINDOW_WATCHER_X_H_ diff --git a/atom/browser/ui/gtk/active_window_watcher_x_observer.h b/atom/browser/ui/gtk/active_window_watcher_x_observer.h new file mode 100644 index 000000000000..47c677877bbf --- /dev/null +++ b/atom/browser/ui/gtk/active_window_watcher_x_observer.h @@ -0,0 +1,23 @@ +// Copyright (c) 2011 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 UI_BASE_X_ACTIVE_WINDOW_WATCHER_X_OBSERVER_H_ +#define UI_BASE_X_ACTIVE_WINDOW_WATCHER_X_OBSERVER_H_ + +#include + +namespace ui { + +class ActiveWindowWatcherXObserver { + public: + // |active_window| will be NULL if the active window isn't one of Chrome's. + virtual void ActiveWindowChanged(GdkWindow* active_window) = 0; + + protected: + virtual ~ActiveWindowWatcherXObserver() {} +}; + +} // namespace ui + +#endif // UI_BASE_X_ACTIVE_WINDOW_WATCHER_X_OBSERVER_H_ diff --git a/atom/browser/ui/gtk/root_window_property_watcher_x.cc b/atom/browser/ui/gtk/root_window_property_watcher_x.cc new file mode 100644 index 000000000000..d0bf0876cd61 --- /dev/null +++ b/atom/browser/ui/gtk/root_window_property_watcher_x.cc @@ -0,0 +1,59 @@ +// Copyright (c) 2012 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 "atom/browser/ui/gtk/root_window_property_watcher_x.h" + +#include +#include + +#include "base/memory/singleton.h" +#include "atom/browser/ui/gtk/active_window_watcher_x.h" +#include "atom/browser/ui/gtk/work_area_watcher_x.h" + +namespace ui { + +namespace internal { + +// static +RootWindowPropertyWatcherX* RootWindowPropertyWatcherX::GetInstance() { + return Singleton::get(); +} + +RootWindowPropertyWatcherX::RootWindowPropertyWatcherX() { + GdkWindow* root = gdk_get_default_root_window(); + + // Set up X Event filter to listen for PropertyChange X events. + // Don't use XSelectInput directly here, as gdk internally seems to cache the + // mask and reapply XSelectInput after this, resetting any mask we set here. + gdk_window_set_events(root, + static_cast(gdk_window_get_events(root) | + GDK_PROPERTY_CHANGE_MASK)); + gdk_window_add_filter(root, + &RootWindowPropertyWatcherX::OnWindowXEventThunk, + this); +} + +RootWindowPropertyWatcherX::~RootWindowPropertyWatcherX() { + gdk_window_remove_filter(NULL, + &RootWindowPropertyWatcherX::OnWindowXEventThunk, + this); +} + +GdkFilterReturn RootWindowPropertyWatcherX::OnWindowXEvent( + GdkXEvent* xevent, GdkEvent* event) { + XEvent* xev = static_cast(xevent); + + if (xev->xany.type == PropertyNotify) { + if (xev->xproperty.atom == ActiveWindowWatcherX::GetPropertyAtom()) + ActiveWindowWatcherX::Notify(); + else if (xev->xproperty.atom == WorkAreaWatcherX::GetPropertyAtom()) + WorkAreaWatcherX::Notify(); + } + + return GDK_FILTER_CONTINUE; +} + +} // namespace internal + +} // namespace ui diff --git a/atom/browser/ui/gtk/root_window_property_watcher_x.h b/atom/browser/ui/gtk/root_window_property_watcher_x.h new file mode 100644 index 000000000000..3b60df49adbb --- /dev/null +++ b/atom/browser/ui/gtk/root_window_property_watcher_x.h @@ -0,0 +1,43 @@ +// Copyright (c) 2012 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 ATOM_BROWSER_UI_GTK_ROOT_WINDOW_PROPERTY_WATCHER_X_H_ +#define ATOM_BROWSER_UI_GTK_ROOT_WINDOW_PROPERTY_WATCHER_X_H_ + +#include + +#include "base/basictypes.h" +#include "ui/base/gtk/gtk_signal.h" + +template struct DefaultSingletonTraits; + +namespace ui { + +namespace internal { + +// This class keeps track of changes to properties on the root window. This is +// not to be used directly. Implement a watcher for the specific property you're +// interested in. +class RootWindowPropertyWatcherX { + public: + static RootWindowPropertyWatcherX* GetInstance(); + + private: + friend struct DefaultSingletonTraits; + + RootWindowPropertyWatcherX(); + ~RootWindowPropertyWatcherX(); + + // Callback for PropertyChange XEvents. + CHROMEG_CALLBACK_1(RootWindowPropertyWatcherX, GdkFilterReturn, + OnWindowXEvent, GdkXEvent*, GdkEvent*); + + DISALLOW_COPY_AND_ASSIGN(RootWindowPropertyWatcherX); +}; + +} // namespace internal + +} // namespace ui + +#endif // ATOM_BROWSER_UI_GTK_ROOT_WINDOW_PROPERTY_WATCHER_X_H_ diff --git a/atom/browser/ui/gtk/work_area_watcher_x.cc b/atom/browser/ui/gtk/work_area_watcher_x.cc new file mode 100644 index 000000000000..3d045270abb2 --- /dev/null +++ b/atom/browser/ui/gtk/work_area_watcher_x.cc @@ -0,0 +1,53 @@ +// Copyright (c) 2012 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 "atom/browser/ui/gtk/work_area_watcher_x.h" + +#include "base/memory/singleton.h" +#include "ui/base/work_area_watcher_observer.h" +#include "atom/browser/ui/gtk/root_window_property_watcher_x.h" +#include "ui/base/x/x11_util.h" + +namespace ui { + +static const char* const kNetWorkArea = "_NET_WORKAREA"; + +// static +WorkAreaWatcherX* WorkAreaWatcherX::GetInstance() { + return Singleton::get(); +} + +// static +void WorkAreaWatcherX::AddObserver(WorkAreaWatcherObserver* observer) { + // Ensure that RootWindowPropertyWatcherX exists. + internal::RootWindowPropertyWatcherX::GetInstance(); + GetInstance()->observers_.AddObserver(observer); +} + +// static +void WorkAreaWatcherX::RemoveObserver(WorkAreaWatcherObserver* observer) { + GetInstance()->observers_.RemoveObserver(observer); +} + +// static +void WorkAreaWatcherX::Notify() { + GetInstance()->NotifyWorkAreaChanged(); +} + +// static +Atom WorkAreaWatcherX::GetPropertyAtom() { + return GetAtom(kNetWorkArea); +} + +WorkAreaWatcherX::WorkAreaWatcherX() { +} + +WorkAreaWatcherX::~WorkAreaWatcherX() { +} + +void WorkAreaWatcherX::NotifyWorkAreaChanged() { + FOR_EACH_OBSERVER(WorkAreaWatcherObserver, observers_, WorkAreaChanged()); +} + +} // namespace ui diff --git a/atom/browser/ui/gtk/work_area_watcher_x.h b/atom/browser/ui/gtk/work_area_watcher_x.h new file mode 100644 index 000000000000..56dbf014acca --- /dev/null +++ b/atom/browser/ui/gtk/work_area_watcher_x.h @@ -0,0 +1,54 @@ +// Copyright (c) 2012 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 ATOM_BROWSER_UI_GTK_WORK_AREA_WATCHER_X_H_ +#define ATOM_BROWSER_UI_GTK_WORK_AREA_WATCHER_X_H_ + +#include "base/basictypes.h" +#include "base/observer_list.h" +#include "ui/base/x/x11_util.h" + +template struct DefaultSingletonTraits; + +namespace ui { + +class WorkAreaWatcherObserver; + +namespace internal { +class RootWindowPropertyWatcherX; +} + +// This is a helper class that is used to keep track of changes to work area. +// Add an observer to track changes. +class WorkAreaWatcherX { + public: + static WorkAreaWatcherX* GetInstance(); + static void AddObserver(WorkAreaWatcherObserver* observer); + static void RemoveObserver(WorkAreaWatcherObserver* observer); + + private: + friend struct DefaultSingletonTraits; + friend class ui::internal::RootWindowPropertyWatcherX; + + WorkAreaWatcherX(); + ~WorkAreaWatcherX(); + + // Gets the atom for the default display for the property this class is + // watching for. + static Atom GetPropertyAtom(); + + // Notify observers that the work area has changed. + static void Notify(); + + // Instance method that implements Notify(). + void NotifyWorkAreaChanged(); + + ObserverList observers_; + + DISALLOW_COPY_AND_ASSIGN(WorkAreaWatcherX); +}; + +} // namespace ui + +#endif // ATOM_BROWSER_UI_GTK_WORK_AREA_WATCHER_X_H_