root/ui/base/gtk/g_object_destructor_filo.cc

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

DEFINITIONS

This source file includes following definitions.
  1. GetInstance
  2. Connect
  3. Disconnect
  4. WeakNotify

// 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/base/gtk/g_object_destructor_filo.h"

#include <glib-object.h>

#include "base/logging.h"
#include "base/memory/singleton.h"

namespace ui {

GObjectDestructorFILO::GObjectDestructorFILO() {
}

GObjectDestructorFILO::~GObjectDestructorFILO() {
  // Probably CHECK(handler_map_.empty()) would look natural here. But
  // some tests (some views_unittests) violate this assertion.
}

// static
GObjectDestructorFILO* GObjectDestructorFILO::GetInstance() {
  return Singleton<GObjectDestructorFILO>::get();
}

void GObjectDestructorFILO::Connect(
    GObject* object, DestructorHook callback, void* context) {
  const Hook hook(object, callback, context);
  HandlerMap::iterator iter = handler_map_.find(object);
  if (iter == handler_map_.end()) {
    g_object_weak_ref(object, WeakNotifyThunk, this);
    handler_map_[object].push_front(hook);
  } else {
    iter->second.push_front(hook);
  }
}

void GObjectDestructorFILO::Disconnect(
    GObject* object, DestructorHook callback, void* context) {
  HandlerMap::iterator iter = handler_map_.find(object);
  if (iter == handler_map_.end()) {
    LOG(DFATAL) << "Unable to disconnect destructor hook for object " << object
                << ": hook not found (" << callback << ", " << context << ").";
    return;
  }
  HandlerList& dtors = iter->second;
  if (dtors.empty()) {
    LOG(DFATAL) << "Destructor list is empty for specified object " << object
                << " Maybe it is being executed?";
    return;
  }
  if (!dtors.front().equal(object, callback, context)) {
    // Reenable this warning once this bug is fixed:
    // http://code.google.com/p/chromium/issues/detail?id=85603
    DVLOG(1) << "Destructors should be unregistered the reverse order they "
             << "were registered. But for object " << object << " "
             << "deleted hook is "<< context << ", the last queued hook is "
             << dtors.front().context;
  }
  for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i) {
    if (i->equal(object, callback, context)) {
      dtors.erase(i);
      break;
    }
  }
  if (dtors.empty()) {
    g_object_weak_unref(object, WeakNotifyThunk, this);
    handler_map_.erase(iter);
  }
}

void GObjectDestructorFILO::WeakNotify(GObject* where_the_object_was) {
  HandlerMap::iterator iter = handler_map_.find(where_the_object_was);
  DCHECK(iter != handler_map_.end());
  DCHECK(!iter->second.empty());

  // Save destructor list for given object into local copy to avoid reentrancy
  // problem: if callee wants to modify the caller list.
  HandlerList dtors;
  iter->second.swap(dtors);
  handler_map_.erase(iter);

  // Execute hooks in local list in FILO order.
  for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i)
    i->callback(i->context, where_the_object_was);
}

}  // napespace ui

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