GNOME Bugzilla – Bug 620569
add GController
Last modified: 2017-01-30 15:46:46 UTC
GController is a base, abstract class for creating "controllers" - objects that should be used to emit notification of changes in storage types like arrays, lists, hash tables, etc. the full design is available on the wiki, here: http://live.gnome.org/EmmanueleBassi/GController there is a prototype version of the implementation available on git.gnome.org: http://git.gnome.org/browse/glib-controller and I have a branch of GIO with the integrated GController that I can either push to gnome.org or attach as a sequence of patches to this bug. in order to implement GObjectController - an object oriented layer around the GObject::notify signal - the patch attached to bug 617446 should also be applied.
Created attachment 162749 [details] [review] Add GController GController is a class designed for adding controlling semantics to existing GLib storage data types, like GArray, GPtrArray and GHashTable. With GController it is possible to receive notification of "events" on a simple data type, so that views can be implemented without requiring a new storage class with signals. By default, GController provides support for bulk notification, to optimize performance in case of multiple operations on the same data type. Controllers for GArray, GPtrArray and GHashTable are provided.
Created attachment 162750 [details] [review] controller: Add GObjectController GObjectController is a GController that wraps a GObject instance, giving bulk notifications and property changes.
Created attachment 162751 [details] [review] controller: Add licensing, docs and aliasing machinery
Created attachment 162752 [details] [review] docs: Add GController to the API reference
Created attachment 162753 [details] [review] controller: Emit a REPLACE reference Sub-classes of GController that allow replacing the storage data type should also automatically emit the ::changed signal with a REPLACE action.
Emmanuele, my question on this is the intended usage. I see the utility in apps, where say we just want to make a one-off data store for a tree view or something like that. But in a library, it seems like an API that exposed a primitive container type and a GController would lose quite a bit in 1) clarity - what operations does this thing actually support? - and 2) encapsulation - ability to change implementation. While with GTK 3 the trend has been toward opaque objects, this is making things less opaque, no? Another minor issue, by wrapping the primitive containers, model objects often add type safety. It seems like at least some docs addressing these tradeoffs and when to use GController vs. an encapsulated object could be welcome.
(In reply to comment #6) first of all, thanks for the review. > Emmanuele, my question on this is the intended usage. the Controller API was mostly born in the frustration that is writing a model API with the current tools in GLib. mostly, it means encapsulating the same data structures - a list plus an hash table; or an array; or a GSequence, if I feel the need for some exotic behaviour - inside a GObject sub-class. then adding the functions for adding, retrieving and iterating data. then adding the signals for views to catch and update themselves. this is generally true even for implementing sub-classes of generic, encapsulated models, like GtkTreeModel or ClutterModel or the libmodel API that Ryan wrote in Vala. > I see the utility in > apps, where say we just want to make a one-off data store for a tree view or > something like that. which is, in and of itself, a niche that most application developers would like to be filled. > But in a library, it seems like an API that exposed a > primitive container type and a GController would lose quite a bit in 1) clarity > - what operations does this thing actually support? - and 2) encapsulation - > ability to change implementation. the 1) point should be covered by the API contract of any controlled data storage; currently, any encapsulated model has signals, and its API contract exposes when and how those signals are emitted. the 2) point would effectively be covered by a generic, encapsulated model implementation. one has been proposed many times, but it never materialized itself in GLib. hence, the controller approach. > While with GTK 3 the trend has been toward > opaque objects, this is making things less opaque, no? I think it's moving the transparency issue towards the application. > Another minor issue, by > wrapping the primitive containers, model objects often add type safety. it's still possible to create an encapsulated model object with the Controller approach; the difference is that instead of providing the notification signals directly on the model, you use the Controller::changed signal. > It seems like at least some docs addressing these tradeoffs and when to use > GController vs. an encapsulated object could be welcome. the documentation is lacking, I agree; I wrote the blurb on the wiki before writing the implementation, and I didn't want to copy and paste it. before committing the patches the documentation would definitely require work.
I happened upon this ticket after much mulling around and trying to find an easy way to implement models with glib/gtk in python. My use case is specifically I want an observable list type of model which holds GObjects and could manage refing/unrefing them along with notifications as to when they are removed, added, or modified. The list aspect would be used as the rows and the GObject properties would be used as columns for the data. When properties on one of the tracked GObjects is modified then views connected to the model would get a notification that one of the columns changed. I have done similar things purely in python by rolling my own custom gtk TreeModel (using GenericTreeModel in pygtk 2). But this does not exist in pygobject/Gtk 3 and furthermore it leaks python object reference counts due to how TreeIters must be dealt with in python. So an idealized python version of what I'm trying to do: class Spam(GObject.GObject): name = GObject.Property(type=str, default='Spam') size = GObject.Property(type=int, default=1) spamList = GObject.ObjectList(type=Spam) view = Gtk.ListView(model=spamList, columns=('name', 'size')) # Any modification to the spamList or an objects properties within spamList # would automatically update the view. spamList.append(Spam(name="LargeSpam", size=10)) If GController gets us any closer to achieving something like this or at least laying the foundation then I eagerly await it.
Some of the intended use cases for GController have been implemented and provided by GListModel and GListStore — even though these two types are meant for list-like containers. I'd still like to have a proper "collection type with notifications" in GIO that can augment the base GLib collection data types, but as it stands, I think this bug can be closed.