Home | History | Annotate | Download | only in gfx
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/gfx/gtk_native_view_id_manager.h"
      6 
      7 #include <gdk/gdkx.h>
      8 #include <gtk/gtk.h>
      9 
     10 #include "base/logging.h"
     11 #include "base/memory/singleton.h"
     12 #include "base/rand_util.h"
     13 #include "ui/base/gtk/gdk_x_compat.h"
     14 #include "ui/base/gtk/gtk_compat.h"
     15 #include "ui/gfx/gtk_preserve_window.h"
     16 
     17 // -----------------------------------------------------------------------------
     18 // Bounce functions for GTK to callback into a C++ object...
     19 
     20 void OnRealize(gfx::NativeView widget, void* arg) {
     21   GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
     22   manager->OnRealize(widget);
     23 }
     24 
     25 void OnUnrealize(gfx::NativeView widget, void *arg) {
     26   GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
     27   manager->OnUnrealize(widget);
     28 }
     29 
     30 static void OnDestroy(GtkObject* obj, void* arg) {
     31   GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
     32   manager->OnDestroy(reinterpret_cast<GtkWidget*>(obj));
     33 }
     34 
     35 // -----------------------------------------------------------------------------
     36 
     37 
     38 // -----------------------------------------------------------------------------
     39 // Public functions...
     40 
     41 GtkNativeViewManager::GtkNativeViewManager() {
     42 }
     43 
     44 GtkNativeViewManager::~GtkNativeViewManager() {
     45 }
     46 
     47 // static
     48 GtkNativeViewManager* GtkNativeViewManager::GetInstance() {
     49   return Singleton<GtkNativeViewManager>::get();
     50 }
     51 
     52 gfx::NativeViewId GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget) {
     53   // This is just for unit tests:
     54   if (!widget)
     55     return 0;
     56 
     57   base::AutoLock locked(lock_);
     58 
     59   std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i =
     60     native_view_to_id_.find(widget);
     61 
     62   if (i != native_view_to_id_.end())
     63     return i->second;
     64 
     65   gfx::NativeViewId new_id =
     66       static_cast<gfx::NativeViewId>(base::RandUint64());
     67   while (id_to_info_.find(new_id) != id_to_info_.end())
     68     new_id = static_cast<gfx::NativeViewId>(base::RandUint64());
     69 
     70   NativeViewInfo info;
     71   info.widget = widget;
     72   if (gtk_widget_get_realized(widget)) {
     73     GdkWindow *gdk_window = gtk_widget_get_window(widget);
     74     DCHECK(gdk_window);
     75     info.x_window_id = GDK_WINDOW_XID(gdk_window);
     76   }
     77 
     78   native_view_to_id_[widget] = new_id;
     79   id_to_info_[new_id] = info;
     80 
     81   g_signal_connect(widget, "realize", G_CALLBACK(::OnRealize), this);
     82   g_signal_connect(widget, "unrealize", G_CALLBACK(::OnUnrealize), this);
     83   g_signal_connect(widget, "destroy", G_CALLBACK(::OnDestroy), this);
     84 
     85   return new_id;
     86 }
     87 
     88 bool GtkNativeViewManager::GetXIDForId(XID* output, gfx::NativeViewId id) {
     89   base::AutoLock locked(lock_);
     90 
     91   std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i =
     92       id_to_info_.find(id);
     93 
     94   if (i == id_to_info_.end())
     95     return false;
     96 
     97   *output = i->second.x_window_id;
     98   return true;
     99 }
    100 
    101 bool GtkNativeViewManager::GetNativeViewForId(gfx::NativeView* output,
    102                                               gfx::NativeViewId id) {
    103   base::AutoLock locked(lock_);
    104 
    105   std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i =
    106       id_to_info_.find(id);
    107 
    108   if (i == id_to_info_.end())
    109     return false;
    110 
    111   *output = i->second.widget;
    112   return true;
    113 }
    114 
    115 bool GtkNativeViewManager::GetPermanentXIDForId(XID* output,
    116                                                 gfx::NativeViewId id) {
    117   base::AutoLock locked(lock_);
    118 
    119   std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
    120       id_to_info_.find(id);
    121 
    122   if (i == id_to_info_.end())
    123     return false;
    124 
    125   // We only return permanent XIDs for widgets that allow us to guarantee that
    126   // the XID will not change.
    127   DCHECK(GTK_IS_PRESERVE_WINDOW(i->second.widget));
    128   GtkPreserveWindow* widget =
    129       reinterpret_cast<GtkPreserveWindow*>(i->second.widget);
    130   gtk_preserve_window_set_preserve(widget, TRUE);
    131 
    132   *output = GDK_WINDOW_XID(gtk_widget_get_window(i->second.widget));
    133 
    134   // Update the reference count on the permanent XID.
    135   PermanentXIDInfo info;
    136   info.widget = widget;
    137   info.ref_count = 1;
    138   std::pair<std::map<XID, PermanentXIDInfo>::iterator, bool> ret =
    139     perm_xid_to_info_.insert(std::make_pair(*output, info));
    140 
    141   if (!ret.second) {
    142     DCHECK(ret.first->second.widget == widget);
    143     ret.first->second.ref_count++;
    144   }
    145 
    146   return true;
    147 }
    148 
    149 bool GtkNativeViewManager::AddRefPermanentXID(XID xid) {
    150   base::AutoLock locked(lock_);
    151 
    152   std::map<XID, PermanentXIDInfo>::iterator i =
    153     perm_xid_to_info_.find(xid);
    154 
    155   if (i == perm_xid_to_info_.end())
    156     return false;
    157 
    158   i->second.ref_count++;
    159 
    160   return true;
    161 }
    162 
    163 void GtkNativeViewManager::ReleasePermanentXID(XID xid) {
    164   base::AutoLock locked(lock_);
    165 
    166   std::map<XID, PermanentXIDInfo>::iterator i =
    167     perm_xid_to_info_.find(xid);
    168 
    169   if (i == perm_xid_to_info_.end())
    170     return;
    171 
    172   if (i->second.ref_count > 1) {
    173     i->second.ref_count--;
    174   } else {
    175     if (i->second.widget) {
    176       gtk_preserve_window_set_preserve(i->second.widget, FALSE);
    177     } else {
    178       GdkWindow* window = reinterpret_cast<GdkWindow*>(
    179           gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid));
    180       DCHECK(window);
    181       gdk_window_destroy(window);
    182     }
    183     perm_xid_to_info_.erase(i);
    184   }
    185 }
    186 
    187 // -----------------------------------------------------------------------------
    188 
    189 
    190 // -----------------------------------------------------------------------------
    191 // Private functions...
    192 
    193 gfx::NativeViewId GtkNativeViewManager::GetWidgetId(gfx::NativeView widget) {
    194   lock_.AssertAcquired();
    195 
    196   std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i =
    197     native_view_to_id_.find(widget);
    198 
    199   CHECK(i != native_view_to_id_.end());
    200   return i->second;
    201 }
    202 
    203 void GtkNativeViewManager::OnRealize(gfx::NativeView widget) {
    204   base::AutoLock locked(lock_);
    205 
    206   const gfx::NativeViewId id = GetWidgetId(widget);
    207   std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
    208     id_to_info_.find(id);
    209 
    210   CHECK(i != id_to_info_.end());
    211 
    212   GdkWindow* gdk_window = gtk_widget_get_window(widget);
    213   CHECK(gdk_window);
    214   i->second.x_window_id = GDK_WINDOW_XID(gdk_window);
    215 }
    216 
    217 void GtkNativeViewManager::OnUnrealize(gfx::NativeView widget) {
    218   base::AutoLock locked(lock_);
    219 
    220   const gfx::NativeViewId id = GetWidgetId(widget);
    221   std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
    222     id_to_info_.find(id);
    223 
    224   CHECK(i != id_to_info_.end());
    225 }
    226 
    227 void GtkNativeViewManager::OnDestroy(gfx::NativeView widget) {
    228   base::AutoLock locked(lock_);
    229 
    230   std::map<gfx::NativeView, gfx::NativeViewId>::iterator i =
    231     native_view_to_id_.find(widget);
    232   CHECK(i != native_view_to_id_.end());
    233 
    234   std::map<gfx::NativeViewId, NativeViewInfo>::iterator j =
    235     id_to_info_.find(i->second);
    236   CHECK(j != id_to_info_.end());
    237 
    238   // If the XID is supposed to outlive the widget, mark it
    239   // in the lookup table.
    240   if (GTK_IS_PRESERVE_WINDOW(widget) &&
    241       gtk_preserve_window_get_preserve(
    242           reinterpret_cast<GtkPreserveWindow*>(widget))) {
    243     std::map<XID, PermanentXIDInfo>::iterator k =
    244         perm_xid_to_info_.find(GDK_WINDOW_XID(gtk_widget_get_window(widget)));
    245 
    246     if (k != perm_xid_to_info_.end())
    247       k->second.widget = NULL;
    248   }
    249 
    250   native_view_to_id_.erase(i);
    251   id_to_info_.erase(j);
    252 }
    253 
    254 // -----------------------------------------------------------------------------
    255