[gjs: 1/2] Gtk: Add overrides for Gtk.CustomSorter methods




commit 6e33365b062a4b391568f17b9e2fa3f32de160ed
Author: Philip Chimento <philip chimento gmail com>
Date:   Sat Feb 12 16:22:46 2022 -0800

    Gtk: Add overrides for Gtk.CustomSorter methods
    
    Gtk.CustomSorter.new() and Gtk.CustomSorter.prototype.set_sort_func()
    didn't work previously, because GCompareDataFunc doesn't have the right
    type annotations (and can't be changed for backwards compatibility
    reasons.)
    
    This adds overrides that wrap the functions with a callback type with the
    correct type annotations, much like in #326.
    
    Note that libgjs-private cannot link to GTK, so instead of calling the
    functions directly we look them up via gobject-introspection and call them
    with g_function_info_invoke().
    
    [skip cpplint]: work around https://github.com/cpplint/cpplint/issues/190
    
    Closes: #460

 installed-tests/js/testGtk4.js | 22 +++++++++++++
 libgjs-private/gjs-util.c      | 73 ++++++++++++++++++++++++++++++++++++++++++
 libgjs-private/gjs-util.h      | 10 ++++++
 modules/core/overrides/Gtk.js  |  7 ++++
 4 files changed, 112 insertions(+)
---
diff --git a/installed-tests/js/testGtk4.js b/installed-tests/js/testGtk4.js
index c34447154..810145422 100644
--- a/installed-tests/js/testGtk4.js
+++ b/installed-tests/js/testGtk4.js
@@ -190,6 +190,28 @@ describe('Gtk overrides', function () {
         iter.stamp = 42;
         expect(iter.stamp).toEqual(42);
     });
+
+    it('can create a Gtk.CustomSorter with callback', function () {
+        const sortFunc = jasmine.createSpy('sortFunc').and.returnValue(1);
+        const model = Gtk.StringList.new(['hello', 'world']);
+        const sorter = Gtk.CustomSorter.new(sortFunc);
+        void Gtk.SortListModel.new(model, sorter);
+        expect(sortFunc).toHaveBeenCalledOnceWith(jasmine.any(Gtk.StringObject), 
jasmine.any(Gtk.StringObject));
+    });
+
+    it('can change the callback of a Gtk.CustomSorter', function () {
+        const model = Gtk.StringList.new(['hello', 'world']);
+        const sorter = Gtk.CustomSorter.new(null);
+        void Gtk.SortListModel.new(model, sorter);
+
+        const sortFunc = jasmine.createSpy('sortFunc').and.returnValue(1);
+        sorter.set_sort_func(sortFunc);
+        expect(sortFunc).toHaveBeenCalledOnceWith(jasmine.any(Gtk.StringObject), 
jasmine.any(Gtk.StringObject));
+
+        sortFunc.calls.reset();
+        sorter.set_sort_func(null);
+        expect(sortFunc).not.toHaveBeenCalled();
+    });
 });
 
 describe('Gtk 4 regressions', function () {
diff --git a/libgjs-private/gjs-util.c b/libgjs-private/gjs-util.c
index afae2988f..d0e52b641 100644
--- a/libgjs-private/gjs-util.c
+++ b/libgjs-private/gjs-util.c
@@ -243,6 +243,79 @@ void gjs_list_store_sort(GListStore *store, GjsCompareDataFunc compare_func,
   g_list_store_sort(store, (GCompareDataFunc)compare_func, user_data);
 }
 
+/**
+ * gjs_gtk_custom_sorter_new:
+ * @sort_func: (nullable) (scope call): function to sort items
+ * @user_data: (closure): user data for @compare_func
+ * @destroy: destroy notify for @user_data
+ *
+ * Creates a new `GtkSorter` that works by calling @sort_func to compare items.
+ *
+ * If @sort_func is %NULL, all items are considered equal.
+ *
+ * Returns: (transfer full): a new `GtkCustomSorter`
+ */
+GObject* gjs_gtk_custom_sorter_new(GjsCompareDataFunc sort_func,
+                                   void* user_data, GDestroyNotify destroy) {
+    GIObjectInfo* container_info =
+        g_irepository_find_by_name(NULL, "Gtk", "CustomSorter");
+    GIBaseInfo* custom_sorter_new_fun =
+        g_object_info_find_method(container_info, "new");
+
+    GIArgument ret;
+    GIArgument custom_sorter_new_args[3];
+    custom_sorter_new_args[0].v_pointer = sort_func;
+    custom_sorter_new_args[1].v_pointer = user_data;
+    custom_sorter_new_args[2].v_pointer = destroy;
+
+    g_function_info_invoke(custom_sorter_new_fun, custom_sorter_new_args, 3,
+                           NULL, 0, &ret, NULL);
+
+    g_clear_pointer(&container_info, g_base_info_unref);
+    g_clear_pointer(&custom_sorter_new_fun, g_base_info_unref);
+
+    return (GObject*)ret.v_pointer;
+}
+
+/**
+ * gjs_gtk_custom_sorter_set_sort_func:
+ * @sorter: a `GtkCustomSorter`
+ * @sort_func: (nullable) (scope call): function to sort items
+ * @user_data: (closure): user data to pass to @sort_func
+ * @destroy: destroy notify for @user_data
+ *
+ * Sets (or unsets) the function used for sorting items.
+ *
+ * If @sort_func is %NULL, all items are considered equal.
+ *
+ * If the sort func changes its sorting behavior, gtk_sorter_changed() needs to
+ * be called.
+ *
+ * If a previous function was set, its @user_destroy will be called now.
+ */
+void gjs_gtk_custom_sorter_set_sort_func(GObject* sorter,
+                                         GjsCompareDataFunc sort_func,
+                                         void* user_data,
+                                         GDestroyNotify destroy) {
+    GIObjectInfo* container_info =
+        g_irepository_find_by_name(NULL, "Gtk", "CustomSorter");
+    GIBaseInfo* set_sort_func_fun =
+        g_object_info_find_method(container_info, "set_sort_func");
+
+    GIArgument unused_ret;
+    GIArgument set_sort_func_args[4];
+    set_sort_func_args[0].v_pointer = sorter;
+    set_sort_func_args[1].v_pointer = sort_func;
+    set_sort_func_args[2].v_pointer = user_data;
+    set_sort_func_args[3].v_pointer = destroy;
+
+    g_function_info_invoke(set_sort_func_fun, set_sort_func_args, 4, NULL, 0,
+                           &unused_ret, NULL);
+
+    g_clear_pointer(&container_info, g_base_info_unref);
+    g_clear_pointer(&set_sort_func_fun, g_base_info_unref);
+}
+
 static void* log_writer_user_data = NULL;
 static GDestroyNotify log_writer_user_data_free = NULL;
 
diff --git a/libgjs-private/gjs-util.h b/libgjs-private/gjs-util.h
index e1213600c..171a88682 100644
--- a/libgjs-private/gjs-util.h
+++ b/libgjs-private/gjs-util.h
@@ -48,6 +48,16 @@ GJS_EXPORT
 void gjs_list_store_sort(GListStore *store, GjsCompareDataFunc compare_func,
                          void *user_data);
 
+GJS_EXPORT
+GObject* gjs_gtk_custom_sorter_new(GjsCompareDataFunc sort_func,
+                                   void* user_data, GDestroyNotify destroy);
+
+GJS_EXPORT
+void gjs_gtk_custom_sorter_set_sort_func(GObject* sorter,
+                                         GjsCompareDataFunc sort_func,
+                                         void* user_data,
+                                         GDestroyNotify destroy);
+
 /**
  * GjsGLogWriterFunc:
  * @level: the log level
diff --git a/modules/core/overrides/Gtk.js b/modules/core/overrides/Gtk.js
index 611d46066..ce63ba4e7 100644
--- a/modules/core/overrides/Gtk.js
+++ b/modules/core/overrides/Gtk.js
@@ -26,6 +26,13 @@ function _init() {
         };
     }
 
+    if (Gtk.CustomSorter) {
+        Gtk.CustomSorter.new = GjsPrivate.gtk_custom_sorter_new;
+        Gtk.CustomSorter.prototype.set_sort_func = function (sortFunc) {
+            GjsPrivate.gtk_custom_sorter_set_sort_func(this, sortFunc);
+        };
+    }
+
     Gtk.Widget.prototype._init = function (params) {
         let wrapper = this;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]