Home | History | Annotate | Download | only in libgtk2ui
      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 #ifndef CHROME_BROWSER_UI_LIBGTK2UI_G_OBJECT_DESTRUCTOR_FILO_H_
      6 #define CHROME_BROWSER_UI_LIBGTK2UI_G_OBJECT_DESTRUCTOR_FILO_H_
      7 
      8 #include <glib.h>
      9 #include <list>
     10 #include <map>
     11 
     12 #include "base/basictypes.h"
     13 
     14 template <typename T> struct DefaultSingletonTraits;
     15 
     16 typedef struct _GObject GObject;
     17 
     18 namespace libgtk2ui {
     19 
     20 // This class hooks calls to g_object_weak_ref()/unref() and executes them in
     21 // FILO order. This is important if there are several hooks to the single object
     22 // (set up at different levels of class hierarchy) and the lowest hook (set up
     23 // first) is deleting self - it must be called last (among hooks for the given
     24 // object). Unfortunately Glib does not provide this guarantee.
     25 //
     26 // Use it as follows:
     27 //
     28 // static void OnDestroyedThunk(gpointer data, GObject *where_the_object_was) {
     29 //   reinterpret_cast<MyClass*>(data)->OnDestroyed(where_the_object_was);
     30 // }
     31 // void MyClass::OnDestroyed(GObject *where_the_object_was) {
     32 //   destroyed_ = true;
     33 //   delete this;
     34 // }
     35 // MyClass::Init() {
     36 //   ...
     37 //   ui::GObjectDestructorFILO::GetInstance()->Connect(
     38 //       G_OBJECT(my_widget), &OnDestroyedThunk, this);
     39 // }
     40 // MyClass::~MyClass() {
     41 //   if (!destroyed_) {
     42 //     ui::GObjectDestructorFILO::GetInstance()->Disconnect(
     43 //         G_OBJECT(my_widget), &OnDestroyedThunk, this);
     44 //   }
     45 // }
     46 //
     47 // TODO(glotov): Probably worth adding ScopedGObjectDtor<T>.
     48 //
     49 // This class is a singleton. Not thread safe. Must be called within UI thread.
     50 class GObjectDestructorFILO {
     51  public:
     52   typedef void (*DestructorHook)(void* context, GObject* where_the_object_was);
     53 
     54   static GObjectDestructorFILO* GetInstance();
     55   void Connect(GObject* object, DestructorHook callback, void* context);
     56   void Disconnect(GObject* object, DestructorHook callback, void* context);
     57 
     58  private:
     59   struct Hook {
     60     Hook(GObject* o, DestructorHook cb, void* ctx)
     61         : object(o), callback(cb), context(ctx) {
     62     }
     63     bool equal(GObject* o, DestructorHook cb, void* ctx) const {
     64       return object == o && callback == cb && context == ctx;
     65     }
     66     GObject* object;
     67     DestructorHook callback;
     68     void* context;
     69   };
     70   typedef std::list<Hook> HandlerList;
     71   typedef std::map<GObject*, HandlerList> HandlerMap;
     72 
     73   GObjectDestructorFILO();
     74   ~GObjectDestructorFILO();
     75   friend struct DefaultSingletonTraits<GObjectDestructorFILO>;
     76 
     77   void WeakNotify(GObject* where_the_object_was);
     78   static void WeakNotifyThunk(gpointer data, GObject* where_the_object_was) {
     79     reinterpret_cast<GObjectDestructorFILO*>(data)->WeakNotify(
     80         where_the_object_was);
     81   }
     82 
     83   HandlerMap handler_map_;
     84 
     85   DISALLOW_COPY_AND_ASSIGN(GObjectDestructorFILO);
     86 };
     87 
     88 }  // namespace libgtk2ui
     89 
     90 #endif  // CHROME_BROWSER_UI_LIBGTK2UI_G_OBJECT_DESTRUCTOR_FILO_H_
     91