diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-24 01:59:32 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-24 01:59:32 +0000 |
commit | 6639f5c6328b64ea800693b343d789b32c050cab (patch) | |
tree | c91de0b9bcf09d56c1ab02baef710a6f836d1098 /base | |
parent | 380ab46417433097d6fc3a0c92236e46b4ea1d40 (diff) | |
download | chromium_src-6639f5c6328b64ea800693b343d789b32c050cab.zip chromium_src-6639f5c6328b64ea800693b343d789b32c050cab.tar.gz chromium_src-6639f5c6328b64ea800693b343d789b32c050cab.tar.bz2 |
Linux: use opaque NativeViewIds
Currently we are still passing GtkWidget* into the renderer and
trusting the value on the way out. With this patch we switch to using
opaque values.
These opaque values are handled by a GtkNativeViewIdManger, a
singleton object which maintains the list of currently valid ids and
their current X window ids.
We don't pass the X window ids directly to the renderer because they
are a) guessable and b) possibly variable for a GtkWidget. From a
patch size point of view, the X window isn't current created at the
point where we need it so significant work would be needed to reorder
operations to fix that as well.
This patch also removes the GTK accesses from the BACKGROUND_X11
thread which were a temporary hack.
http://codereview.chromium.org/92110
BUG=9014,9869,10787
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14405 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/base.gyp | 5 | ||||
-rw-r--r-- | base/gfx/gtk_native_view_id_manager.cc | 141 | ||||
-rw-r--r-- | base/gfx/gtk_native_view_id_manager.h | 91 | ||||
-rw-r--r-- | base/gfx/native_widget_types.h | 31 | ||||
-rw-r--r-- | base/gfx/native_widget_types_gtk.cc | 16 |
5 files changed, 274 insertions, 10 deletions
diff --git a/base/base.gyp b/base/base.gyp index 58601ae..9c259b6 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -480,6 +480,8 @@ 'sources': [ 'gfx/gdi_util.cc', 'gfx/gdi_util.h', + 'gfx/gtk_native_view_id_manager.cc', + 'gfx/gtk_native_view_id_manager.h', 'gfx/gtk_util.cc', 'gfx/gtk_util.h', 'gfx/jpeg_codec.cc', @@ -487,6 +489,7 @@ 'gfx/native_theme.cc', 'gfx/native_theme.h', 'gfx/native_widget_types.h', + 'gfx/native_widget_types_gtk.cc', 'gfx/platform_canvas.h', 'gfx/platform_canvas_linux.h', 'gfx/platform_canvas_mac.h', @@ -528,7 +531,9 @@ ], }], [ 'OS != "linux"', { 'sources!': [ + 'gfx/gtk_native_view_id_manager.cc', 'gfx/gtk_util.cc', + 'gfx/native_widget_types_gtk.cc', ], }], ], diff --git a/base/gfx/gtk_native_view_id_manager.cc b/base/gfx/gtk_native_view_id_manager.cc new file mode 100644 index 0000000..848e1eb --- /dev/null +++ b/base/gfx/gtk_native_view_id_manager.cc @@ -0,0 +1,141 @@ +// 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 "base/gfx/gtk_native_view_id_manager.h" + +#include "base/gfx/rect.h" +#include "base/logging.h" +#include "base/rand_util.h" + +#include <gtk/gtk.h> +#include <gdk/gdkx.h> + +// ----------------------------------------------------------------------------- +// Bounce functions for GTK to callback into a C++ object... + +static void OnRealize(gfx::NativeView widget, void* arg) { + GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg); + manager->OnRealize(widget); +} + +static void OnUnrealize(gfx::NativeView widget, void *arg) { + GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg); + manager->OnUnrealize(widget); +} + +static void OnDestroy(GtkObject* obj, void* arg) { + GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg); + manager->OnDestroy(reinterpret_cast<GtkWidget*>(obj)); +} + +// ----------------------------------------------------------------------------- + + +// ----------------------------------------------------------------------------- +// Public functions... + +GtkNativeViewManager::GtkNativeViewManager() { +} + +gfx::NativeViewId GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget) { + AutoLock locked(lock_); + + std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i = + native_view_to_id_.find(widget); + + if (i != native_view_to_id_.end()) + return i->second; + + gfx::NativeViewId new_id = + static_cast<gfx::NativeViewId>(base::RandUint64()); + while (id_to_info_.find(new_id) != id_to_info_.end()) + new_id = static_cast<gfx::NativeViewId>(base::RandUint64()); + + NativeViewInfo info; + if (GTK_WIDGET_REALIZED(widget)) { + GdkWindow *gdk_window = widget->window; + CHECK(gdk_window); + info.x_window_id = GDK_WINDOW_XID(gdk_window); + } + + native_view_to_id_[widget] = new_id; + id_to_info_[new_id] = info; + + g_signal_connect(widget, "realize", G_CALLBACK(::OnRealize), this); + g_signal_connect(widget, "unrealize", G_CALLBACK(::OnUnrealize), this); + g_signal_connect(widget, "destroy", G_CALLBACK(::OnDestroy), this); + + return new_id; +} + +bool GtkNativeViewManager::GetXIDForId(XID* output, gfx::NativeViewId id) { + AutoLock locked(lock_); + + std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i = + id_to_info_.find(id); + + if (i == id_to_info_.end()) + return false; + + *output = i->second.x_window_id; + return true; +} + +// ----------------------------------------------------------------------------- + + +// ----------------------------------------------------------------------------- +// Private functions... + +gfx::NativeViewId GtkNativeViewManager::GetWidgetId(gfx::NativeView widget) { + lock_.AssertAcquired(); + + std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i = + native_view_to_id_.find(widget); + + CHECK(i != native_view_to_id_.end()); + return i->second; +} + +void GtkNativeViewManager::OnRealize(gfx::NativeView widget) { + AutoLock locked(lock_); + + const gfx::NativeViewId id = GetWidgetId(widget); + std::map<gfx::NativeViewId, NativeViewInfo>::iterator i = + id_to_info_.find(id); + + CHECK(i != id_to_info_.end()); + CHECK(widget->window); + + i->second.x_window_id = GDK_WINDOW_XID(widget->window); +} + +void GtkNativeViewManager::OnUnrealize(gfx::NativeView widget) { + AutoLock locked(lock_); + + const gfx::NativeViewId id = GetWidgetId(widget); + std::map<gfx::NativeViewId, NativeViewInfo>::iterator i = + id_to_info_.find(id); + + CHECK(i != id_to_info_.end()); + + i->second.x_window_id = 0; +} + +void GtkNativeViewManager::OnDestroy(gfx::NativeView widget) { + AutoLock locked(lock_); + + std::map<gfx::NativeView, gfx::NativeViewId>::iterator i = + native_view_to_id_.find(widget); + CHECK(i != native_view_to_id_.end()); + + std::map<gfx::NativeViewId, NativeViewInfo>::iterator j = + id_to_info_.find(i->second); + CHECK(j != id_to_info_.end()); + + native_view_to_id_.erase(i); + id_to_info_.erase(j); +} + +// ----------------------------------------------------------------------------- diff --git a/base/gfx/gtk_native_view_id_manager.h b/base/gfx/gtk_native_view_id_manager.h new file mode 100644 index 0000000..5b34baa --- /dev/null +++ b/base/gfx/gtk_native_view_id_manager.h @@ -0,0 +1,91 @@ +// 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 BASE_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_ +#define BASE_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_ + +#include <map> + +#include "base/singleton.h" +#include "base/gfx/native_widget_types.h" + +typedef unsigned long XID; + +// NativeViewIds are the opaque values which the renderer holds as a reference +// to a window. These ids are often used in sync calls from the renderer and +// one cannot terminate sync calls on the UI thread as that can lead to +// deadlocks. +// +// Because of this, we have the BACKGROUND_X11 thread for these calls and this +// thread has a separate X connection in order to answer them. But one cannot +// use GTK on multiple threads, so the BACKGROUND_X11 thread deals only in Xlib +// calls and, thus, XIDs. +// +// So we could make NativeViewIds be the X id of the window. However, at the +// time when we need to tell the renderer about its NativeViewId, an XID isn't +// availible and it goes very much against the grain of the code to make it so. +// Also, we worry that GTK might choose to change the underlying X window id +// when, say, the widget is hidden or repacked. Finally, if we used XIDs then a +// compromised renderer could start asking questions about any X windows on the +// system. +// +// Thus, we have this object. It produces random NativeViewIds from GtkWidget +// pointers and observes the various signals from the widget for when an X +// window is created, destroyed etc. Thus it provides a thread safe mapping +// from NativeViewIds to the current XID for that widget. +// +// You get a reference to the global instance with: +// Singleton<GtkNativeViewManager>() +class GtkNativeViewManager { + public: + // Must be called from the UI thread: + // + // Return a NativeViewId for the given widget and attach to the various + // signals emitted by that widget. The NativeViewId is pseudo-randomly + // allocated so that a compromised renderer trying to guess values will fail + // with high probability. The NativeViewId will not be reused for the + // lifetime of the GtkWidget. + gfx::NativeViewId GetIdForWidget(gfx::NativeView widget); + + // May be called from any thread: + // + // xid: (output) the resulting X window ID, or 0 + // id: a value previously returned from GetIdForWidget + // returns: true if |id| is a valid id, false otherwise. + // + // If the widget referenced by |id| does not current have an X window id, + // |*xid| is set to 0. + bool GetXIDForId(XID* xid, gfx::NativeViewId id); + + // These are actually private functions, but need to be called from statics. + void OnRealize(gfx::NativeView widget); + void OnUnrealize(gfx::NativeView widget); + void OnDestroy(gfx::NativeView widget); + + private: + // This object is a singleton: + GtkNativeViewManager(); + friend struct DefaultSingletonTraits<GtkNativeViewManager>; + + struct NativeViewInfo { + NativeViewInfo() + : x_window_id(0) { + } + + XID x_window_id; + }; + + gfx::NativeViewId GetWidgetId(gfx::NativeView id); + + // protects native_view_to_id_ and id_to_info_ + Lock lock_; + // If asked for an id for the same widget twice, we want to return the same + // id. So this records the current mapping. + std::map<gfx::NativeView, gfx::NativeViewId> native_view_to_id_; + std::map<gfx::NativeViewId, NativeViewInfo> id_to_info_; + + DISALLOW_COPY_AND_ASSIGN(GtkNativeViewManager); +}; + +#endif // BASE_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_ diff --git a/base/gfx/native_widget_types.h b/base/gfx/native_widget_types.h index 32d6012..d43db5c 100644 --- a/base/gfx/native_widget_types.h +++ b/base/gfx/native_widget_types.h @@ -78,23 +78,34 @@ typedef cairo_surface_t* NativeDrawingContext; // See comment at the top of the file for usage. typedef intptr_t NativeViewId; -// Convert a NativeViewId to a NativeView. At the moment, we assume that the -// ids are the same as the NativeViews. This is correct on Windows (where -// NativeView == HWND). -// TODO(port): figure out what ids are going to be and implement this function -// This is only to be called in the browser process. +// Convert a NativeViewId to a NativeView. +// On Windows, these are both HWNDS so it's just a cast. +// On Mac, for now, we pass the NSView pointer into the renderer +// On Linux we use an opaque id +#if defined(OS_WIN) || defined(OS_MACOSX) static inline NativeView NativeViewFromId(NativeViewId id) { return reinterpret_cast<NativeView>(id); } +#elif defined(OS_LINUX) +// A NativeView on Linux is a GtkWidget*. However, we can't go directly from an +// X window ID to a GtkWidget. Thus, functions which handle NativeViewIds from +// the renderer have to use Xlib. This is fine since these functions are +// generally performed on the BACKGROUND_X thread which can't use GTK anyway. + +#define NativeViewFromId(x) NATIVE_VIEW_FROM_ID_NOT_AVAILIBLE_ON_LINUX -// Convert a NativeView to a NativeViewId. At the moment, we assume that the -// ids are the same as the NativeViews. This is correct on Windows (where -// NativeView == HWND). -// TODO(port): figure out what ids are going to be and implement this function -// This is only to be called in the browser process. +#endif // defined(OS_LINUX) + +// Convert a NativeView to a NativeViewId. See the comments above +// NativeViewFromId. +#if defined(OS_WIN) || defined(OS_MACOSX) static inline NativeViewId IdFromNativeView(NativeView view) { return reinterpret_cast<NativeViewId>(view); } +#elif defined(OS_LINUX) +// Not inlined because it involves pulling too many headers. +NativeViewId IdFromNativeView(NativeView view); +#endif // defined(OS_LINUX) } // namespace gfx diff --git a/base/gfx/native_widget_types_gtk.cc b/base/gfx/native_widget_types_gtk.cc new file mode 100644 index 0000000..2deb46c --- /dev/null +++ b/base/gfx/native_widget_types_gtk.cc @@ -0,0 +1,16 @@ +// 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 "base/gfx/native_widget_types.h" + +#include "base/gfx/gtk_native_view_id_manager.h" +#include "base/logging.h" + +namespace gfx { + +NativeViewId IdFromNativeView(NativeView view) { + return Singleton<GtkNativeViewManager>()->GetIdForWidget(view); +} + +} // namespace gfx |