// 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 #include #include "base/logging.h" #include "base/memory/singleton.h" #include "base/rand_util.h" #include "ui/base/gtk/gdk_x_compat.h" #include "ui/base/gtk/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(arg); manager->OnRealize(widget); } void OnUnrealize(gfx::NativeView widget, void *arg) { GtkNativeViewManager* manager = reinterpret_cast(arg); manager->OnUnrealize(widget); } static void OnDestroy(GtkObject* obj, void* arg) { GtkNativeViewManager* manager = reinterpret_cast(arg); manager->OnDestroy(reinterpret_cast(obj)); } // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Public functions... GtkNativeViewManager::GtkNativeViewManager() { } GtkNativeViewManager::~GtkNativeViewManager() { } // static GtkNativeViewManager* GtkNativeViewManager::GetInstance() { return Singleton::get(); } gfx::NativeViewId GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget) { // This is just for unit tests: if (!widget) return 0; base::AutoLock locked(lock_); std::map::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(base::RandUint64()); while (id_to_info_.find(new_id) != id_to_info_.end()) new_id = static_cast(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::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::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::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(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::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::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::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( 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::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::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::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::iterator i = native_view_to_id_.find(widget); CHECK(i != native_view_to_id_.end()); std::map::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(widget))) { std::map::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); } // -----------------------------------------------------------------------------