15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class assists you in dealing with a specific situation when managing 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ownership between a C++ object and a GTK widget. It is common to have a 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// C++ object which encapsulates a GtkWidget, and that widget is exposed from 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the object for use outside of the class. In this situation, you commonly 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// want the GtkWidget's lifetime to match its C++ object's lifetime. Using an 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OwnedWidgetGtk will take ownership over the initial reference of the 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GtkWidget, so that it is "owned" by the C++ object. Example usage: 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// class FooViewGtk() { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// public: 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FooViewGtk() { } 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ~FooViewGtk() { } 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// void Init() { vbox_.Own(gtk_vbox_new()); } 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GtkWidget* widget() { return vbox_.get() }; // Host my widget! 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// private: 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OwnedWidgetGtk vbox_; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// }; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This design will ensure that the widget stays alive from the call to Own() 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// until the call to Destroy(). 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - Details of the problem and OwnedWidgetGtk's solution: 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In order to make passing ownership more convenient for newly created 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// widgets, GTK has a concept of a "floating" reference. All GtkObjects (and 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thus GtkWidgets) inherit from GInitiallyUnowned. When they are created, the 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// object starts with a reference count of 1, but has its floating flag set. 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When it is put into a container for the first time, that container will 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "sink" the floating reference, and the count will still be 1. Now the 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// container owns the widget, and if we remove the widget from the container, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the widget is destroyed. This style of ownership often causes problems when 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// you have an object encapsulating the widget. If we just use a raw 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GtkObject* with no specific ownership management, we push the widget's 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ownership onto the user of the class. Now the C++ object can't depend on 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the widget being valid, since it doesn't manage its lifetime. If the widget 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// was removed from a container, removing its only reference, it would be 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// destroyed (from the C++ object's perspective) unexpectedly destroyed. The 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// solution is fairly simple, make sure that the C++ object owns the widget, 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and thus it is also responsible for destroying it. This boils down to: 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GtkWidget* widget = gtk_widget_new(); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// g_object_ref_sink(widget); // Claim the initial floating reference. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ... 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// gtk_destroy_widget(widget); // Ask all code to destroy their references. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// g_object_unref(widget); // Destroy the initial reference we had claimed. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef CHROME_BROWSER_UI_LIBGTK2UI_OWNED_WIDGET_GTK2_H_ 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHROME_BROWSER_UI_LIBGTK2UI_OWNED_WIDGET_GTK2_H_ 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct _GtkWidget GtkWidget; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace libgtk2ui { 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OwnedWidgetGtk { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an instance that isn't managing any ownership. 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OwnedWidgetGtk() : widget_(NULL) { } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create an instance that owns |widget|. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit OwnedWidgetGtk(GtkWidget* widget) : widget_(NULL) { Own(widget); } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~OwnedWidgetGtk(); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Return the currently owned widget, or NULL if no widget is owned. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* get() const { return widget_; } 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* operator->() const { return widget_; } 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Takes ownership of a widget, by taking the initial floating reference of 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the GtkWidget. It is expected that Own() is called right after the widget 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // has been created, and before any other references to the widget might have 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // been added. It is valid to never call Own(), in which case Destroy() will 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // do nothing. If Own() has been called, you must explicitly call Destroy(). 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Own(GtkWidget* widget); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // You may call Destroy() after you have called Own(). Calling Destroy() 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will call gtk_widget_destroy(), and drop our reference to the widget. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Destroy() is also called in this object's destructor. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // After a call to Destroy(), you may call Own() again. NOTE: It is expected 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that after gtk_widget_destroy we will be holding the only reference left 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // on the object. We assert this in debug mode to help catch any leaks. 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Destroy(); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GtkWidget* widget_; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(OwnedWidgetGtk); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace libgtk2ui 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // CHROME_BROWSER_UI_LIBGTK2UI_OWNED_WIDGET_GTK2_H_ 95