blob: 0844b190dd92cb378e5c1500465b56176f4c222b [file] [log] [blame]
// 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);
}
// -----------------------------------------------------------------------------