| // 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 "ui/gfx/gtk_native_view_id_manager.h" |
| |
| #include <gdk/gdkx.h> |
| #include <gtk/gtk.h> |
| |
| #include "base/logging.h" |
| #include "base/memory/singleton.h" |
| #include "base/rand_util.h" |
| #include "ui/gfx/gdk_compat.h" |
| #include "ui/gfx/gtk_compat.h" |
| #include "ui/gfx/gtk_preserve_window.h" |
| |
| // ----------------------------------------------------------------------------- |
| // Bounce functions for GTK to callback into a C++ object... |
| |
| void OnRealize(gfx::NativeView widget, void* arg) { |
| GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg); |
| manager->OnRealize(widget); |
| } |
| |
| 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() { |
| } |
| |
| GtkNativeViewManager::~GtkNativeViewManager() { |
| } |
| |
| // static |
| GtkNativeViewManager* GtkNativeViewManager::GetInstance() { |
| return Singleton<GtkNativeViewManager>::get(); |
| } |
| |
| gfx::NativeViewId GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget) { |
| // This is just for unit tests: |
| if (!widget) |
| return 0; |
| |
| base::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; |
| info.widget = widget; |
| if (gtk_widget_get_realized(widget)) { |
| GdkWindow *gdk_window = gtk_widget_get_window(widget); |
| DCHECK(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) { |
| base::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; |
| } |
| |
| bool GtkNativeViewManager::GetNativeViewForId(gfx::NativeView* output, |
| gfx::NativeViewId id) { |
| base::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.widget; |
| return true; |
| } |
| |
| bool GtkNativeViewManager::GetPermanentXIDForId(XID* output, |
| gfx::NativeViewId id) { |
| base::AutoLock locked(lock_); |
| |
| std::map<gfx::NativeViewId, NativeViewInfo>::iterator i = |
| id_to_info_.find(id); |
| |
| if (i == id_to_info_.end()) |
| return false; |
| |
| // We only return permanent XIDs for widgets that allow us to guarantee that |
| // the XID will not change. |
| DCHECK(GTK_IS_PRESERVE_WINDOW(i->second.widget)); |
| GtkPreserveWindow* widget = |
| reinterpret_cast<GtkPreserveWindow*>(i->second.widget); |
| gtk_preserve_window_set_preserve(widget, TRUE); |
| |
| *output = GDK_WINDOW_XID(gtk_widget_get_window(i->second.widget)); |
| |
| // Update the reference count on the permanent XID. |
| PermanentXIDInfo info; |
| info.widget = widget; |
| info.ref_count = 1; |
| std::pair<std::map<XID, PermanentXIDInfo>::iterator, bool> ret = |
| perm_xid_to_info_.insert(std::make_pair(*output, info)); |
| |
| if (!ret.second) { |
| DCHECK(ret.first->second.widget == widget); |
| ret.first->second.ref_count++; |
| } |
| |
| return true; |
| } |
| |
| bool GtkNativeViewManager::AddRefPermanentXID(XID xid) { |
| base::AutoLock locked(lock_); |
| |
| std::map<XID, PermanentXIDInfo>::iterator i = |
| perm_xid_to_info_.find(xid); |
| |
| if (i == perm_xid_to_info_.end()) |
| return false; |
| |
| i->second.ref_count++; |
| |
| return true; |
| } |
| |
| void GtkNativeViewManager::ReleasePermanentXID(XID xid) { |
| base::AutoLock locked(lock_); |
| |
| std::map<XID, PermanentXIDInfo>::iterator i = |
| perm_xid_to_info_.find(xid); |
| |
| if (i == perm_xid_to_info_.end()) |
| return; |
| |
| if (i->second.ref_count > 1) { |
| i->second.ref_count--; |
| } else { |
| if (i->second.widget) { |
| gtk_preserve_window_set_preserve(i->second.widget, FALSE); |
| } else { |
| GdkWindow* window = reinterpret_cast<GdkWindow*>( |
| gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid)); |
| DCHECK(window); |
| gdk_window_destroy(window); |
| } |
| perm_xid_to_info_.erase(i); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| |
| // ----------------------------------------------------------------------------- |
| // 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) { |
| base::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()); |
| |
| GdkWindow* gdk_window = gtk_widget_get_window(widget); |
| CHECK(gdk_window); |
| i->second.x_window_id = GDK_WINDOW_XID(gdk_window); |
| } |
| |
| void GtkNativeViewManager::OnUnrealize(gfx::NativeView widget) { |
| base::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()); |
| } |
| |
| void GtkNativeViewManager::OnDestroy(gfx::NativeView widget) { |
| base::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()); |
| |
| // If the XID is supposed to outlive the widget, mark it |
| // in the lookup table. |
| if (GTK_IS_PRESERVE_WINDOW(widget) && |
| gtk_preserve_window_get_preserve( |
| reinterpret_cast<GtkPreserveWindow*>(widget))) { |
| std::map<XID, PermanentXIDInfo>::iterator k = |
| perm_xid_to_info_.find(GDK_WINDOW_XID(gtk_widget_get_window(widget))); |
| |
| if (k != perm_xid_to_info_.end()) |
| k->second.widget = NULL; |
| } |
| |
| native_view_to_id_.erase(i); |
| id_to_info_.erase(j); |
| } |
| |
| // ----------------------------------------------------------------------------- |