From 6dbaadeeea8d38c0d00718ae5cd14ebecd95ce67 Mon Sep 17 00:00:00 2001 From: Rory Fewell Date: Mon, 3 Nov 2025 23:51:36 +0000 Subject: [PATCH] Enhancement: Fixes #541, shell / shellext - API for sorting view items --- shared/comgtk/CMakeLists.txt | 2 + shared/comgtk/public/libapi.h.in | 1 + shared/comgtk/public/treemodel.h | 19 +++ shared/comgtk/src/treemodel.c | 137 +++++++++++++++ shared/shell/src/icnvwbeh.c | 22 ++- shared/shell/src/trevwbeh.c | 270 +++++++++++++++++++----------- shared/shell/src/vwcpl.c | 49 +++++- shared/shell/src/vwdesk.c | 16 ++ shared/shell/src/vwdrives.c | 16 ++ shared/shell/src/vwfs.c | 53 ++++-- shared/shellext/CMakeLists.txt | 1 + shared/shellext/public/if_view.h | 14 ++ shared/shellext/public/viewitem.h | 12 ++ shared/shellext/src/if_view.c | 46 +++++ shared/shellext/src/viewitem.c | 27 +++ shell/cpl/printers/src/vwprntrs.c | 16 ++ shell/shext/zip/src/vwzip.c | 44 ++++- 17 files changed, 622 insertions(+), 123 deletions(-) create mode 100644 shared/comgtk/public/treemodel.h create mode 100644 shared/comgtk/src/treemodel.c create mode 100644 shared/shellext/src/viewitem.c diff --git a/shared/comgtk/CMakeLists.txt b/shared/comgtk/CMakeLists.txt index 0a918a2..1617aa6 100644 --- a/shared/comgtk/CMakeLists.txt +++ b/shared/comgtk/CMakeLists.txt @@ -78,6 +78,8 @@ add_library( public/strings.h src/styles.c public/styles.h + src/treemodel.c + public/treemodel.h src/version.c public/version.h src/window.c diff --git a/shared/comgtk/public/libapi.h.in b/shared/comgtk/public/libapi.h.in index 58081a9..e1512c6 100644 --- a/shared/comgtk/public/libapi.h.in +++ b/shared/comgtk/public/libapi.h.in @@ -25,6 +25,7 @@ #include "@LIB_HEADER_DIR@/signals.h" #include "@LIB_HEADER_DIR@/strings.h" #include "@LIB_HEADER_DIR@/styles.h" +#include "@LIB_HEADER_DIR@/treemodel.h" #include "@LIB_HEADER_DIR@/version.h" #include "@LIB_HEADER_DIR@/window.h" diff --git a/shared/comgtk/public/treemodel.h b/shared/comgtk/public/treemodel.h new file mode 100644 index 0000000..cef1e6a --- /dev/null +++ b/shared/comgtk/public/treemodel.h @@ -0,0 +1,19 @@ +#ifndef __COMGTK_TREEMODEL_H__ +#define __COMGTK_TREEMODEL_H__ + +#include +#include + +// +// PUBLIC FUNCTIONS +// +gint wintc_tree_model_get_insertion_sort_pos( + GtkTreeModel* tree_model, + GtkTreeIter* node, + gint column, + gint data_type, + GCompareFunc compare_func, + gconstpointer item +); + +#endif diff --git a/shared/comgtk/src/treemodel.c b/shared/comgtk/src/treemodel.c new file mode 100644 index 0000000..40e6c83 --- /dev/null +++ b/shared/comgtk/src/treemodel.c @@ -0,0 +1,137 @@ +#include +#include + +#include "../public/treemodel.h" + +// +// PUBLIC FUNCTIONS +// +gint wintc_tree_model_get_insertion_sort_pos( + GtkTreeModel* tree_model, + GtkTreeIter* node, + gint column, + gint data_type, + GCompareFunc compare_func, + gconstpointer item +) +{ + gint n_children = gtk_tree_model_iter_n_children(tree_model, node); + + if (!n_children) + { + return 0; + } + + // Set ourselves up, if we're sorting top level children or children of a + // node + // + GtkTreeIter child; + + gint start = 0; + gint middle = n_children / 2; + gint end = n_children; + + gint diff = end - start; + + while (TRUE) + { + gtk_tree_model_iter_nth_child( + tree_model, + &child, + node, + middle + ); + + // Compare item at this node + // + gpointer item_ptr; + gint item_int; + guint item_uint; + + gint result; + + switch (data_type) + { + case G_TYPE_INT: + gtk_tree_model_get( + tree_model, + &child, + column, &item_int, + -1 + ); + + result = + compare_func( + item, + GINT_TO_POINTER(item_int) + ); + + break; + + case G_TYPE_UINT: + gtk_tree_model_get( + tree_model, + &child, + column, &item_uint, + -1 + ); + + result = + compare_func( + item, + GUINT_TO_POINTER(item_uint) + ); + + break; + + default: + gtk_tree_model_get( + tree_model, + &child, + column, &item_ptr, + -1 + ); + + result = + compare_func( + item, + item_ptr + ); + + break; + } + + // If this is the last iteration, deal with it + // + if (diff == 1) + { + if (result > 0) + { + return middle + 1; + } + else + { + return middle; + } + } + + // Otherwise, iterate + // + if (result < 0) + { + end = middle; + } + else if (result > 0) + { + start = middle; + } + else + { + start = middle; + end = middle; + } + + diff = end - start; + middle = start + (diff / 2); + } +} diff --git a/shared/shell/src/icnvwbeh.c b/shared/shell/src/icnvwbeh.c index 71defe7..c518fdf 100644 --- a/shared/shell/src/icnvwbeh.c +++ b/shared/shell/src/icnvwbeh.c @@ -814,7 +814,7 @@ static void on_browser_load_changed( } static void on_current_view_items_added( - WINTC_UNUSED(WinTCIShextView* view), + WinTCIShextView* view, WinTCShextViewItemsUpdate* update, gpointer user_data ) @@ -838,11 +838,29 @@ static void on_current_view_items_added( NULL // FIXME: Error handling ); + // Sort into model + // + GCompareFunc sort_func = wintc_ishext_view_get_sort_func(view); + + gint item_pos = + wintc_tree_model_get_insertion_sort_pos( + GTK_TREE_MODEL(behaviour->list_model), + NULL, + COLUMN_VIEW_HASH, + G_TYPE_UINT, + sort_func, + GUINT_TO_POINTER(item->hash) + ); + // Push to model // GtkTreeIter iter; - gtk_list_store_append(behaviour->list_model, &iter); + gtk_list_store_insert( + behaviour->list_model, + &iter, + item_pos + ); gtk_list_store_set( behaviour->list_model, &iter, diff --git a/shared/shell/src/trevwbeh.c b/shared/shell/src/trevwbeh.c index 5a3c2ce..6a1a305 100644 --- a/shared/shell/src/trevwbeh.c +++ b/shared/shell/src/trevwbeh.c @@ -19,6 +19,7 @@ enum COLUMN_ICON_NAME = 0, COLUMN_ENTRY_NAME, COLUMN_VIEW_HASH, + COLUMN_MAPPED_VIEW, N_COLUMNS }; @@ -43,8 +44,8 @@ static void wintc_sh_tree_view_behaviour_update_view( WinTCShBrowser* browser ); -static void clear_object_safe( - GObject* object +static void clear_tree_row_reference( + GtkTreeRowReference* row_ref ); static void on_browser_load_changed( @@ -80,8 +81,7 @@ struct _WinTCShTreeViewBehaviour WinTCShextHost* shext_host; GtkTreeStore* tree_model; - GHashTable* map_iter_to_view; - GHashTable* map_hash_to_iter; + GHashTable* map_hash_to_row; GtkWidget* tree_view; }; @@ -133,7 +133,7 @@ static void wintc_sh_tree_view_behaviour_init( WinTCShTreeViewBehaviour* self ) { - // Set up maps hash->iter->view + // Set up map for hash->row // // The intention of this is to be able to map view/viewitems to a node in // the tree, and then those nodes to a concrete view object @@ -142,18 +142,13 @@ static void wintc_sh_tree_view_behaviour_init( // that are enumerated from a view are akin to placeholders, and a view is // created only when those nodes are expanded/enumerated themselves // - self->map_iter_to_view = g_hash_table_new_full( - g_str_hash, - g_str_equal, - g_free, - (GDestroyNotify) clear_object_safe - ); - self->map_hash_to_iter = g_hash_table_new_full( - g_direct_hash, - g_direct_equal, - NULL, - g_free - ); + self->map_hash_to_row = + g_hash_table_new_full( + g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) clear_tree_row_reference + ); } // @@ -198,10 +193,11 @@ static void wintc_sh_tree_view_behaviour_constructed( behaviour->tree_model = gtk_tree_store_new( - 3, + 4, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_UINT + G_TYPE_UINT, + G_TYPE_OBJECT ); gtk_tree_view_set_headers_visible( @@ -266,8 +262,7 @@ static void wintc_sh_tree_view_behaviour_dispose( g_clear_object(&(behaviour->shext_host)); g_clear_object(&(behaviour->tree_view)); - g_hash_table_unref(g_steal_pointer(&(behaviour->map_iter_to_view))); - g_hash_table_unref(g_steal_pointer(&(behaviour->map_hash_to_iter))); + g_hash_table_unref(g_steal_pointer(&(behaviour->map_hash_to_row))); (G_OBJECT_CLASS(wintc_sh_tree_view_behaviour_parent_class)) ->dispose(object); @@ -336,11 +331,11 @@ static void wintc_sh_tree_view_behaviour_update_view( // Collect up the views back up the tree, until we hit a view we already // have // - GError* error = NULL; - const gchar* iter_path = NULL; - GSList* list_views = NULL; - WinTCShextPathInfo path_info = { 0 }; - WinTCIShextView* view = current_view; + GError* error = NULL; + GSList* list_views = NULL; + WinTCShextPathInfo path_info = { 0 }; + GtkTreeRowReference* row_ref = NULL; + WinTCIShextView* view = current_view; while (view) { @@ -350,13 +345,13 @@ static void wintc_sh_tree_view_behaviour_update_view( // If there is a node in the tree for the view hash, stop here // - iter_path = + row_ref = g_hash_table_lookup( - behaviour->map_hash_to_iter, + behaviour->map_hash_to_row, GUINT_TO_POINTER(wintc_ishext_view_get_unique_hash(view)) ); - if (iter_path) + if (row_ref) { break; } @@ -431,20 +426,30 @@ static void wintc_sh_tree_view_behaviour_update_view( // if (iter == list_views) { - if (iter_path) + if (row_ref) { - gtk_tree_model_get_iter_from_string( + WinTCIShextView* node_view = NULL; + GtkTreePath* tree_path; + + tree_path = + gtk_tree_row_reference_get_path(row_ref); + + gtk_tree_model_get_iter( GTK_TREE_MODEL(behaviour->tree_model), &next, - iter_path + tree_path ); - if ( - g_hash_table_contains( - behaviour->map_iter_to_view, - iter_path - ) - ) + gtk_tree_model_get( + GTK_TREE_MODEL(behaviour->tree_model), + &next, + COLUMN_MAPPED_VIEW, &node_view, + -1 + ); + + gtk_tree_path_free(tree_path); + + if (node_view) { WINTC_LOG_DEBUG( "shell: tree - first iter is a mapped view." @@ -475,10 +480,11 @@ static void wintc_sh_tree_view_behaviour_update_view( g_object_ref(view); } - g_hash_table_insert( - behaviour->map_iter_to_view, - g_strdup(iter_path), - view + gtk_tree_store_set( + behaviour->tree_model, + &next, + COLUMN_MAPPED_VIEW, view, + -1 ); } } @@ -498,35 +504,36 @@ static void wintc_sh_tree_view_behaviour_update_view( gtk_tree_store_set( behaviour->tree_model, &next, - COLUMN_ICON_NAME, wintc_ishext_view_get_icon_name(view), - COLUMN_ENTRY_NAME, wintc_ishext_view_get_display_name(view), - COLUMN_VIEW_HASH, hash, + COLUMN_ICON_NAME, wintc_ishext_view_get_icon_name(view), + COLUMN_ENTRY_NAME, wintc_ishext_view_get_display_name(view), + COLUMN_VIEW_HASH, hash, + COLUMN_MAPPED_VIEW, view, -1 ); - // Map the hash<->iter + // Map the hash->row // + GtkTreePath* tree_path = + gtk_tree_model_get_path( + GTK_TREE_MODEL(behaviour->tree_model), + &next + ); + if (view == current_view) { g_object_ref(view); } g_hash_table_insert( - behaviour->map_hash_to_iter, + behaviour->map_hash_to_row, GUINT_TO_POINTER(hash), - gtk_tree_model_get_string_from_iter( + gtk_tree_row_reference_new( GTK_TREE_MODEL(behaviour->tree_model), - &next + tree_path ) ); - g_hash_table_insert( - behaviour->map_iter_to_view, - gtk_tree_model_get_string_from_iter( - GTK_TREE_MODEL(behaviour->tree_model), - &next - ), - view - ); + + gtk_tree_path_free(tree_path); } last = next; // Copy node iter over @@ -554,28 +561,31 @@ static void wintc_sh_tree_view_behaviour_update_view( gtk_tree_store_set( behaviour->tree_model, &next, - COLUMN_ICON_NAME, wintc_ishext_view_get_icon_name(next_view), - COLUMN_ENTRY_NAME, wintc_ishext_view_get_display_name(next_view), - COLUMN_VIEW_HASH, hash, + COLUMN_ICON_NAME, wintc_ishext_view_get_icon_name(next_view), + COLUMN_ENTRY_NAME, wintc_ishext_view_get_display_name(next_view), + COLUMN_VIEW_HASH, hash, + COLUMN_MAPPED_VIEW, next_view, -1 ); - g_hash_table_insert( - behaviour->map_hash_to_iter, - GUINT_TO_POINTER(hash), - gtk_tree_model_get_string_from_iter( + // Map the hash->row + // + GtkTreePath* tree_path = + gtk_tree_model_get_path( GTK_TREE_MODEL(behaviour->tree_model), &next + ); + + g_hash_table_insert( + behaviour->map_hash_to_row, + GUINT_TO_POINTER(hash), + gtk_tree_row_reference_new( + GTK_TREE_MODEL(behaviour->tree_model), + tree_path ) ); - g_hash_table_insert( - behaviour->map_iter_to_view, - gtk_tree_model_get_string_from_iter( - GTK_TREE_MODEL(behaviour->tree_model), - &next - ), - next_view - ); + + gtk_tree_path_free(tree_path); } // Watch for items and refresh if this is a new view @@ -618,14 +628,33 @@ static void wintc_sh_tree_view_behaviour_update_view( // // CALLBACKS // -static void clear_object_safe( - GObject* object +static void clear_tree_row_reference( + GtkTreeRowReference* row_ref ) { - if (object) - { - g_object_unref(object); - } + WinTCIShextView* view = NULL; + + GtkTreeModel* tree_model = gtk_tree_row_reference_get_model(row_ref); + GtkTreePath* tree_path = gtk_tree_row_reference_get_path(row_ref); + + GtkTreeIter row; + + gtk_tree_model_get_iter( + tree_model, + &row, + tree_path + ); + + gtk_tree_model_get( + tree_model, + &row, + COLUMN_MAPPED_VIEW, &view, + -1 + ); + + g_clear_object(&view); + gtk_tree_path_free(tree_path); + gtk_tree_row_reference_free(row_ref); } static void on_browser_load_changed( @@ -664,17 +693,22 @@ static void on_view_items_added( // Locate the parent node // - const gchar* iter_path = + GtkTreeRowReference* row_ref; + GtkTreePath* tree_path; + + row_ref = g_hash_table_lookup( - behaviour->map_hash_to_iter, + behaviour->map_hash_to_row, GUINT_TO_POINTER(wintc_ishext_view_get_unique_hash(view)) ); + tree_path = gtk_tree_row_reference_get_path(row_ref); + if ( - !gtk_tree_model_get_iter_from_string( + !gtk_tree_model_get_iter( GTK_TREE_MODEL(behaviour->tree_model), &parent, - iter_path + tree_path ) ) { @@ -682,6 +716,8 @@ static void on_view_items_added( return; } + gtk_tree_path_free(tree_path); + // Iterate over the items to append to the tree // WinTCShextViewItem* view_item; @@ -695,7 +731,7 @@ static void on_view_items_added( if ( view_item->is_leaf || g_hash_table_contains( - behaviour->map_hash_to_iter, + behaviour->map_hash_to_row, GUINT_TO_POINTER(view_item->hash) ) ) @@ -708,10 +744,27 @@ static void on_view_items_added( GUINT_TO_POINTER(view_item->hash) ); - gtk_tree_store_append( + // Sort into model + // + GCompareFunc sort_func = wintc_ishext_view_get_sort_func(view); + + gint item_pos = + wintc_tree_model_get_insertion_sort_pos( + GTK_TREE_MODEL(behaviour->tree_model), + &parent, + COLUMN_VIEW_HASH, + G_TYPE_UINT, + sort_func, + GUINT_TO_POINTER(view_item->hash) + ); + + // Push to model + // + gtk_tree_store_insert( behaviour->tree_model, &child, - &parent + &parent, + item_pos ); gtk_tree_store_set( behaviour->tree_model, @@ -722,14 +775,24 @@ static void on_view_items_added( -1 ); - g_hash_table_insert( - behaviour->map_hash_to_iter, - GUINT_TO_POINTER(view_item->hash), - gtk_tree_model_get_string_from_iter( + // Map hash-->row + // + GtkTreePath* tree_path = + gtk_tree_model_get_path( GTK_TREE_MODEL(behaviour->tree_model), &child + ); + + g_hash_table_insert( + behaviour->map_hash_to_row, + GUINT_TO_POINTER(view_item->hash), + gtk_tree_row_reference_new( + GTK_TREE_MODEL(behaviour->tree_model), + tree_path ) ); + + gtk_tree_path_free(tree_path); } } @@ -750,34 +813,43 @@ static void on_view_items_removed( { guint item_hash = GPOINTER_TO_UINT(upd_iter->data); - const gchar* iter_path = + // Nav to iter + // + GtkTreeRowReference* row_ref; + GtkTreePath* tree_path; + + row_ref = g_hash_table_lookup( - behaviour->map_hash_to_iter, + behaviour->map_hash_to_row, GUINT_TO_POINTER(item_hash) ); - if (!iter_path) + if (!row_ref) { continue; } - gtk_tree_model_get_iter_from_string( + tree_path = + gtk_tree_row_reference_get_path(row_ref); + + gtk_tree_model_get_iter( GTK_TREE_MODEL(behaviour->tree_model), &iter, - iter_path + tree_path ); + gtk_tree_path_free(tree_path); + + // Delete node and mapping (row ref and view collected up via + // clear_tree_row_reference()) + // gtk_tree_store_remove( behaviour->tree_model, &iter ); g_hash_table_remove( - behaviour->map_iter_to_view, - iter_path - ); - g_hash_table_remove( - behaviour->map_hash_to_iter, + behaviour->map_hash_to_row, GUINT_TO_POINTER(item_hash) ); } diff --git a/shared/shell/src/vwcpl.c b/shared/shell/src/vwcpl.c index a6ce25e..fb6e397 100644 --- a/shared/shell/src/vwcpl.c +++ b/shared/shell/src/vwcpl.c @@ -38,6 +38,11 @@ static gboolean wintc_sh_view_cpl_activate_item( WinTCShextPathInfo* path_info, GError** error ); +static gint wintc_sh_view_cpl_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +); static const gchar* wintc_sh_view_cpl_get_display_name( WinTCIShextView* view ); @@ -75,6 +80,11 @@ static WinTCShextOperation* wintc_sh_view_cpl_spawn_operation( GError** error ); +static WinTCShextViewItem* wintc_sh_view_cpl_get_view_item( + WinTCShViewCpl* view_cpl, + guint item_hash +); + // // GLIB OOP/CLASS INSTANCE DEFINITIONS // @@ -131,6 +141,7 @@ static void wintc_sh_view_cpl_ishext_view_interface_init( ) { iface->activate_item = wintc_sh_view_cpl_activate_item; + iface->compare_items = wintc_sh_view_cpl_compare_items; iface->get_display_name = wintc_sh_view_cpl_get_display_name; iface->get_icon_name = wintc_sh_view_cpl_get_icon_name; iface->get_operations_for_item = wintc_sh_view_cpl_get_operations_for_item; @@ -206,11 +217,7 @@ static gboolean wintc_sh_view_cpl_activate_item( WinTCShCplApplet* applet; WinTCShextViewItem* item; - item = (WinTCShextViewItem*) - g_hash_table_lookup( - view_cpl->map_items, - GUINT_TO_POINTER(item_hash) - ); + item = wintc_sh_view_cpl_get_view_item(view_cpl, item_hash); applet = (WinTCShCplApplet*) item->priv; if (wintc_sh_cpl_applet_is_executable(applet)) @@ -223,6 +230,22 @@ static gboolean wintc_sh_view_cpl_activate_item( return TRUE; } +static gint wintc_sh_view_cpl_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +) +{ + WinTCShViewCpl* view_cpl = WINTC_SH_VIEW_CPL(view); + + WinTCShextViewItem* item1 = + wintc_sh_view_cpl_get_view_item(view_cpl, item_hash1); + WinTCShextViewItem* item2 = + wintc_sh_view_cpl_get_view_item(view_cpl, item_hash2); + + return wintc_shext_view_item_compare_by_name(item1, item2); +} + static const gchar* wintc_sh_view_cpl_get_display_name( WINTC_UNUSED(WinTCIShextView* view) ) @@ -379,3 +402,19 @@ WinTCIShextView* wintc_sh_view_cpl_new(void) ) ); } + +// +// PRIVATE FUNCTIONS +// +static WinTCShextViewItem* wintc_sh_view_cpl_get_view_item( + WinTCShViewCpl* view_cpl, + guint item_hash +) +{ + return + (WinTCShextViewItem*) + g_hash_table_lookup( + view_cpl->map_items, + GUINT_TO_POINTER(item_hash) + ); +} diff --git a/shared/shell/src/vwdesk.c b/shared/shell/src/vwdesk.c index aa52e94..f7d7bc4 100644 --- a/shared/shell/src/vwdesk.c +++ b/shared/shell/src/vwdesk.c @@ -79,6 +79,11 @@ static gboolean wintc_sh_view_desktop_activate_item( WinTCShextPathInfo* path_info, GError** error ); +static gint wintc_sh_view_desktop_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +); static const gchar* wintc_sh_view_desktop_get_display_name( WinTCIShextView* view ); @@ -201,6 +206,7 @@ static void wintc_sh_view_desktop_ishext_view_interface_init( ) { iface->activate_item = wintc_sh_view_desktop_activate_item; + iface->compare_items = wintc_sh_view_desktop_compare_items; iface->get_display_name = wintc_sh_view_desktop_get_display_name; iface->get_icon_name = wintc_sh_view_desktop_get_icon_name; iface->get_operations_for_item = @@ -272,6 +278,16 @@ static gboolean wintc_sh_view_desktop_activate_item( return TRUE; } +static gint wintc_sh_view_desktop_compare_items( + WINTC_UNUSED(WinTCIShextView* view), + WINTC_UNUSED(guint item_hash1), + WINTC_UNUSED(guint item_hash2) +) +{ + // FIXME: Proper implementation + return -1; +} + static const gchar* wintc_sh_view_desktop_get_display_name( WINTC_UNUSED(WinTCIShextView* view) ) diff --git a/shared/shell/src/vwdrives.c b/shared/shell/src/vwdrives.c index 401073f..c15bd83 100644 --- a/shared/shell/src/vwdrives.c +++ b/shared/shell/src/vwdrives.c @@ -62,6 +62,11 @@ static gboolean wintc_sh_view_drives_activate_item( WinTCShextPathInfo* path_info, GError** error ); +static gint wintc_sh_view_drives_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +); static const gchar* wintc_sh_view_drives_get_display_name( WinTCIShextView* view ); @@ -175,6 +180,7 @@ static void wintc_sh_view_drives_ishext_view_interface_init( ) { iface->activate_item = wintc_sh_view_drives_activate_item; + iface->compare_items = wintc_sh_view_drives_compare_items; iface->get_display_name = wintc_sh_view_drives_get_display_name; iface->get_icon_name = wintc_sh_view_drives_get_icon_name; iface->get_operations_for_item = @@ -242,6 +248,16 @@ static gboolean wintc_sh_view_drives_activate_item( return TRUE; } +static gint wintc_sh_view_drives_compare_items( + WINTC_UNUSED(WinTCIShextView* view), + WINTC_UNUSED(guint item_hash1), + WINTC_UNUSED(guint item_hash2) +) +{ + // FIXME: Proper implementation + return -1; +} + static const gchar* wintc_sh_view_drives_get_display_name( WINTC_UNUSED(WinTCIShextView* view) ) diff --git a/shared/shell/src/vwfs.c b/shared/shell/src/vwfs.c index 3f3ead9..45c62c7 100644 --- a/shared/shell/src/vwfs.c +++ b/shared/shell/src/vwfs.c @@ -68,8 +68,10 @@ static gboolean wintc_sh_view_fs_activate_item( WinTCShextPathInfo* path_info, GError** error ); -static guint wintc_sh_view_fs_get_unique_hash( - WinTCIShextView* view +static gint wintc_sh_view_fs_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 ); static const gchar* wintc_sh_view_fs_get_display_name( WinTCIShextView* view @@ -92,6 +94,9 @@ static void wintc_sh_view_fs_get_path( WinTCIShextView* view, WinTCShextPathInfo* path_info ); +static guint wintc_sh_view_fs_get_unique_hash( + WinTCIShextView* view +); static gboolean wintc_sh_view_fs_has_parent( WinTCIShextView* view ); @@ -122,6 +127,10 @@ static gboolean real_activate_item( GError** error ); +static WinTCShextViewItem* wintc_sh_view_fs_get_view_item( + WinTCShViewFS* view_fs, + guint item_hash +); static void wintc_sh_view_fs_update_new_templates( WinTCShViewFS* view_fs ); @@ -246,6 +255,7 @@ static void wintc_sh_view_fs_ishext_view_interface_init( ) { iface->activate_item = wintc_sh_view_fs_activate_item; + iface->compare_items = wintc_sh_view_fs_compare_items; iface->get_display_name = wintc_sh_view_fs_get_display_name; iface->get_icon_name = wintc_sh_view_fs_get_icon_name; iface->get_operations_for_item = wintc_sh_view_fs_get_operations_for_item; @@ -396,11 +406,7 @@ static gboolean wintc_sh_view_fs_activate_item( // Retrieve the item itself // WinTCShextViewItem* item = - (WinTCShextViewItem*) - g_hash_table_lookup( - view_fs->fs_map_entries, - GUINT_TO_POINTER(item_hash) - ); + wintc_sh_view_fs_get_view_item(view_fs, item_hash); if (!item) { @@ -419,6 +425,20 @@ static gboolean wintc_sh_view_fs_activate_item( ); } +static gint wintc_sh_view_fs_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +) +{ + WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view); + + return wintc_shext_view_item_compare_by_fs_order( + wintc_sh_view_fs_get_view_item(view_fs, item_hash1), + wintc_sh_view_fs_get_view_item(view_fs, item_hash2) + ); +} + static const gchar* wintc_sh_view_fs_get_display_name( WinTCIShextView* view ) @@ -453,11 +473,7 @@ static GMenuModel* wintc_sh_view_fs_get_operations_for_item( WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view); WinTCShextViewItem* view_item = - (WinTCShextViewItem*) - g_hash_table_lookup( - view_fs->fs_map_entries, - GUINT_TO_POINTER(item_hash) - ); + wintc_sh_view_fs_get_view_item(view_fs, item_hash); if (!view_item) { @@ -953,6 +969,19 @@ static gboolean real_activate_item( return success; } +static WinTCShextViewItem* wintc_sh_view_fs_get_view_item( + WinTCShViewFS* view_fs, + guint item_hash +) +{ + return + (WinTCShextViewItem*) + g_hash_table_lookup( + view_fs->fs_map_entries, + GUINT_TO_POINTER(item_hash) + ); +} + static void wintc_sh_view_fs_update_new_templates( WinTCShViewFS* view_fs ) diff --git a/shared/shellext/CMakeLists.txt b/shared/shellext/CMakeLists.txt index e20b88a..3184571 100644 --- a/shared/shellext/CMakeLists.txt +++ b/shared/shellext/CMakeLists.txt @@ -44,6 +44,7 @@ add_library( public/if_view.h src/uictl.c public/uictl.h + src/viewitem.c public/viewitem.h public/viewops.h ) diff --git a/shared/shellext/public/if_view.h b/shared/shellext/public/if_view.h index 3da3251..ce5e765 100644 --- a/shared/shellext/public/if_view.h +++ b/shared/shellext/public/if_view.h @@ -42,6 +42,11 @@ struct _WinTCIShextViewInterface GError** error ); + gint (*compare_items) ( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 + ); const gchar* (*get_display_name) ( WinTCIShextView* view ); @@ -92,6 +97,11 @@ gboolean wintc_ishext_view_activate_item( GError** error ); +gint wintc_ishext_view_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +); void wintc_ishext_view_refresh_items( WinTCIShextView* view ); @@ -145,6 +155,10 @@ void _wintc_ishext_view_refreshing( WinTCIShextView* view ); +GCompareFunc wintc_ishext_view_get_sort_func( + WinTCIShextView* view +); + // WinTCShextPathInfo methods // void wintc_shext_path_info_demangle_uri( diff --git a/shared/shellext/public/viewitem.h b/shared/shellext/public/viewitem.h index b9cdc44..acf0d8d 100644 --- a/shared/shellext/public/viewitem.h +++ b/shared/shellext/public/viewitem.h @@ -33,4 +33,16 @@ typedef struct _WinTCShextViewItemsUpdate gboolean done; } WinTCShextViewItemsUpdate; +// +// PUBLIC FUNCTIONS +// +gint wintc_shext_view_item_compare_by_name( + const WinTCShextViewItem* item1, + const WinTCShextViewItem* item2 +); +gint wintc_shext_view_item_compare_by_fs_order( + const WinTCShextViewItem* item1, + const WinTCShextViewItem* item2 +); + #endif diff --git a/shared/shellext/src/if_view.c b/shared/shellext/src/if_view.c index a44bac7..e966b11 100644 --- a/shared/shellext/src/if_view.c +++ b/shared/shellext/src/if_view.c @@ -107,6 +107,18 @@ gboolean wintc_ishext_view_activate_item( ); } +gint wintc_ishext_view_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +) +{ + WinTCIShextViewInterface* iface = + WINTC_ISHEXT_VIEW_GET_IFACE(view); + + return iface->compare_items(view, item_hash1, item_hash2); +} + const gchar* wintc_ishext_view_get_display_name( WinTCIShextView* view ) @@ -258,6 +270,40 @@ void _wintc_ishext_view_refreshing( ); } +// HACKY SORT FUNC +static WinTCIShextView* S_CUR_VIEW_FOR_SORTING = NULL; + +gint _wintc_ishext_view_sort_func( + gconstpointer item_hash1, + gconstpointer item_hash2 +) +{ + if (!S_CUR_VIEW_FOR_SORTING) + { + g_critical("%s", "shellext: attempting to sort with no view!"); + return 0; + } + + return wintc_ishext_view_compare_items( + S_CUR_VIEW_FOR_SORTING, + GPOINTER_TO_UINT(item_hash1), + GPOINTER_TO_UINT(item_hash2) + ); +} + +GCompareFunc wintc_ishext_view_get_sort_func( + WinTCIShextView* view +) +{ + // + // FIXME: This is NOT thread-safe!! + // + S_CUR_VIEW_FOR_SORTING = view; + + return ((GCompareFunc) _wintc_ishext_view_sort_func); +} +// END HACKY SORT FUNC + void wintc_shext_path_info_demangle_uri( WinTCShextPathInfo* path_info, const gchar* uri diff --git a/shared/shellext/src/viewitem.c b/shared/shellext/src/viewitem.c new file mode 100644 index 0000000..01d8718 --- /dev/null +++ b/shared/shellext/src/viewitem.c @@ -0,0 +1,27 @@ +#include + +#include "../public/viewitem.h" + +// +// PUBLIC FUNCTIONS +// +gint wintc_shext_view_item_compare_by_name( + const WinTCShextViewItem* item1, + const WinTCShextViewItem* item2 +) +{ + return g_strcmp0(item1->display_name, item2->display_name); +} + +gint wintc_shext_view_item_compare_by_fs_order( + const WinTCShextViewItem* item1, + const WinTCShextViewItem* item2 +) +{ + if (item1->is_leaf == item2->is_leaf) + { + return wintc_shext_view_item_compare_by_name(item1, item2); + } + + return item1->is_leaf ? 1 : -1; +} diff --git a/shell/cpl/printers/src/vwprntrs.c b/shell/cpl/printers/src/vwprntrs.c index 319542d..b0789c8 100644 --- a/shell/cpl/printers/src/vwprntrs.c +++ b/shell/cpl/printers/src/vwprntrs.c @@ -55,6 +55,11 @@ static gboolean wintc_cpl_view_printers_activate_item( WinTCShextPathInfo* path_info, GError** error ); +static gint wintc_cpl_view_printers_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +); static const gchar* wintc_cpl_view_printers_get_display_name( WinTCIShextView* view ); @@ -153,6 +158,7 @@ static void wintc_cpl_view_printers_ishext_view_interface_init( ) { iface->activate_item = wintc_cpl_view_printers_activate_item; + iface->compare_items = wintc_cpl_view_printers_compare_items; iface->get_display_name = wintc_cpl_view_printers_get_display_name; iface->get_icon_name = wintc_cpl_view_printers_get_icon_name; iface->get_operations_for_item = @@ -208,6 +214,16 @@ static gboolean wintc_cpl_view_printers_activate_item( return FALSE; } +static gint wintc_cpl_view_printers_compare_items( + WINTC_UNUSED(WinTCIShextView* view), + WINTC_UNUSED(guint item_hash1), + WINTC_UNUSED(guint item_hash2) +) +{ + // FIXME: Proper implementation + return -1; +} + static GMenuModel* wintc_cpl_view_printers_get_operations_for_item( WINTC_UNUSED(WinTCIShextView* view), WINTC_UNUSED(guint item_hash) diff --git a/shell/shext/zip/src/vwzip.c b/shell/shext/zip/src/vwzip.c index dbaf488..65e31aa 100644 --- a/shell/shext/zip/src/vwzip.c +++ b/shell/shext/zip/src/vwzip.c @@ -45,6 +45,11 @@ static gboolean wintc_view_zip_activate_item( WinTCShextPathInfo* path_info, GError** error ); +static gint wintc_view_zip_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +); static GMenuModel* wintc_view_zip_get_operations_for_item( WinTCIShextView* view, guint item_hash @@ -76,6 +81,11 @@ static void wintc_view_zip_refresh_items( WinTCIShextView* view ); +static WinTCShextViewItem* wintc_view_zip_get_view_item( + WinTCViewZip* view_zip, + guint item_hash +); + static guint zip_entry_hash( const gchar* zip_file_path, const gchar* rel_entry_path @@ -173,6 +183,7 @@ static void wintc_view_zip_ishext_view_interface_init( ) { iface->activate_item = wintc_view_zip_activate_item; + iface->compare_items = wintc_view_zip_compare_items; iface->get_operations_for_item = wintc_view_zip_get_operations_for_item; iface->get_operations_for_view = wintc_view_zip_get_operations_for_view; iface->get_display_name = wintc_view_zip_get_display_name; @@ -272,11 +283,7 @@ static gboolean wintc_view_zip_activate_item( WINTC_SAFE_REF_CLEAR(error); WinTCShextViewItem* item = - (WinTCShextViewItem*) - g_hash_table_lookup( - view_zip->map_items, - GUINT_TO_POINTER(item_hash) - ); + wintc_view_zip_get_view_item(view_zip, item_hash); if (!item) { @@ -312,6 +319,20 @@ static gboolean wintc_view_zip_activate_item( return FALSE; } +static gint wintc_view_zip_compare_items( + WinTCIShextView* view, + guint item_hash1, + guint item_hash2 +) +{ + WinTCViewZip* view_zip = WINTC_VIEW_ZIP(view); + + return wintc_shext_view_item_compare_by_fs_order( + wintc_view_zip_get_view_item(view_zip, item_hash1), + wintc_view_zip_get_view_item(view_zip, item_hash2) + ); +} + static GMenuModel* wintc_view_zip_get_operations_for_item( WINTC_UNUSED(WinTCIShextView* view), WINTC_UNUSED(guint item_hash) @@ -585,6 +606,19 @@ WinTCIShextView* wintc_view_zip_new( // // PRIVATE FUNCTIONS // +static WinTCShextViewItem* wintc_view_zip_get_view_item( + WinTCViewZip* view_zip, + guint item_hash +) +{ + return + (WinTCShextViewItem*) + g_hash_table_lookup( + view_zip->map_items, + GUINT_TO_POINTER(item_hash) + ); +} + static guint zip_entry_hash( const gchar* zip_file_path, const gchar* rel_entry_path