root/ui/gfx/gtk_native_view_id_manager.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. OnRealize
  2. OnUnrealize
  3. OnDestroy
  4. GetInstance
  5. GetIdForWidget
  6. GetXIDForId
  7. GetNativeViewForId
  8. GetPermanentXIDForId
  9. AddRefPermanentXID
  10. ReleasePermanentXID
  11. GetWidgetId
  12. OnRealize
  13. OnUnrealize
  14. OnDestroy

// 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);
}

// -----------------------------------------------------------------------------

/* [<][>][^][v][top][bottom][index][help] */