{"id":16643198,"url":"https://github.com/ebassi/glib-controller","last_synced_at":"2025-12-24T09:25:53.530Z","repository":{"id":6409068,"uuid":"7647300","full_name":"ebassi/glib-controller","owner":"ebassi","description":"Prototype MVC classes for GLib/GObject","archived":false,"fork":false,"pushed_at":"2013-01-16T17:26:16.000Z","size":196,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-18T16:22:56.240Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-2.1","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ebassi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-01-16T14:38:02.000Z","updated_at":"2021-10-22T16:59:22.000Z","dependencies_parsed_at":"2022-09-08T16:41:19.755Z","dependency_job_id":null,"html_url":"https://github.com/ebassi/glib-controller","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebassi%2Fglib-controller","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebassi%2Fglib-controller/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebassi%2Fglib-controller/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebassi%2Fglib-controller/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ebassi","download_url":"https://codeload.github.com/ebassi/glib-controller/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243165529,"owners_count":20246725,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-12T08:07:48.272Z","updated_at":"2025-12-24T09:25:53.501Z","avatar_url":"https://github.com/ebassi.png","language":"C","readme":"GController :: A Controller implementation for GLib data types\n===============================================================================\n\nThe story so far...\n-------------------------------------------------------------------------------\nGiven a model-view-controller design, the current approach in GLib-based\nlibraries is to encapsulate the data structure used for storage and add\nstorage accessors that notify the view(s) of changes - thus conflating the\nmodel and the controller sides into one data structure.\n\nEncapsulation of storage and controller has invariably led to some issues:\n\n * data replication: unless the model is an interface that resides at a\n   lower level in the dependency chain, and that can be bolted on top of\n   an existing data storage, there has to be a copy from the simple data\n   storage types provided by GLib (GArray, GList, GHashTable, etc.) into\n   the model itself.\n\n * data access replication: be the model an interface or a base class,\n   it requires the implementation of an API to access the data from the\n   storage, including iteration over the data storage.\n\n * loss of performance/generality: if a model has to be accessible from\n   higher levels of the platform stack, it has to lose every knowledge\n   of data types, or re-implement them abstractly, incurring in a loss\n   of performance; conversely, if it can be placed at higher levels of\n   the stack, it will become tied to the view structure, losing\n   generality.\n\nThese issues have been nominally approached by different libraries in\ndifferent ways - but always trying to maintain the model (data storage)\nand the controller angles together.\n\nGController: An alternative angle of attack\n-------------------------------------------------------------------------------\nInstead of collapsing both model and controller inside the same class it\nshould be possible to devise a way to use simple data structures already\nprovided by GLib for storage, access and iteration, and decouple the\ncontroller into a separate class.\n\n### Design requirements ###\n\n * must work with GLib data types:\n   + GArray/GPtrArray\n   + GSequence\n   + GList/GSList\n   + GHashTable\n * must not require changes to those data types\n   + must be able to notify actions on the data types\n * must defer data access and iteration over to the data types\n\n### GController ###\n\nGController is the base, abstract class for controllers.\n\nA specialized implementation of GController for a data type might be\nprovided - e.g. GArrayController for GArray - but it is not necessary; a\nspecialized implementation of GController for a model class might also\nbe provided, though it's not necessary.\n\nEvery time an action is performed on the GArray, the GController has to:\n\n  * create a GControllerReference\n  * emit the GController::changed signal\n\nFor instance, given a GController created for a given GArray:\n\n    GController *controller = g_array_controller_new (array);\n\nThe GArrayController code for appending a value inside the GArray would\nlook something like:\n\n    g_array_append (array, value);\n\n    GIndexSet *index =\n      g_index_set_init_with_index (g_index_set_alloc (), array-\u003elen - 1);\n\n    GControllerEvent *event =\n      g_controller_create_event (controller, G_CONTROLLER_ADD, index);\n\n    g_controller_emit_changed (controller, ref);\n    g_object_unref (ref);\n\nThis will result in the _GController::changed_ signal being emitted; the\nsignal has the following prototype:\n\n    void (* changed) (GController       *controller,\n                      GControllerAction  action,\n                      GControllerEvent  *event);\n\nImplementations of the view for a given controller should use the changed\nsignal to update themselves, for instance:\n\n    static void\n    on_changed (GController       *controller,\n                GControllerAction  action,\n                GControllerEvent  *event)\n    {\n      GArray *array =\n        g_array_controller_get_array (G_ARRAY_CONTROLLER (controller));\n      const GIndexSet *indices =\n        g_controller_event_get_indices (event);\n\n      guint i = 0;\n      while (g_index_set_next_index (indices, \u0026i))\n        {\n          /* get the value out of the array at the given index */\n          Data *data = \u0026g_array_index (array, Data, i);\n\n          /* do something with Data */\n        }\n    }\n\n### GControllerEvent ###\n\nA GControllerEvent is an object created by each GController, and it\nreferences four things:\n\n * the action that led to the creation of the reference\n * the type of the index inside the data storage controlled by\n   the GController\n * the number of indices affected by the action on the data storage\n   that caused the emission of the changed signal\n * the indices affected by the action on the data storage\n\nThe GControllerEvent does not store or replicate the data affected by\nthe action recorded by the GController: it merely references where the\nView might find the data inside the storage.\n\n### Indices and Ranges ###\n\nFIXME\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febassi%2Fglib-controller","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Febassi%2Fglib-controller","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febassi%2Fglib-controller/lists"}