From 4e0711a9f7d1dc40680f837066cfd8749b63b8e1 Mon Sep 17 00:00:00 2001 From: Rory Fewell Date: Fri, 29 Nov 2024 22:01:10 +0000 Subject: [PATCH] Enhancement: Fixes #380, shell - file system watcher for FS view --- shared/shcommon/public/fs.h | 2 +- shared/shcommon/src/fs.c | 8 +- shared/shell/public/browser.h | 2 +- shared/shell/public/cpl.h | 2 +- shared/shell/src/browser.c | 160 ++++++++++++++------ shared/shell/src/cpl.c | 12 +- shared/shell/src/icnvwbeh.c | 12 +- shared/shell/src/trevwbeh.c | 108 +++++++++++--- shared/shell/src/vwcpl.c | 101 +++++++------ shared/shell/src/vwdesk.c | 42 ++++-- shared/shell/src/vwdrives.c | 45 +++++- shared/shell/src/vwfs.c | 238 +++++++++++++++++++++++------- shared/shellext/public/if_view.h | 12 +- shared/shellext/public/viewitem.h | 9 +- shared/shellext/src/if_view.c | 16 +- shell/cpl/printers/src/vwprntrs.c | 32 +++- shell/shext/zip/src/vwzip.c | 106 +++++++------ 17 files changed, 632 insertions(+), 275 deletions(-) diff --git a/shared/shcommon/public/fs.h b/shared/shcommon/public/fs.h index 206e5a7..d916b3a 100644 --- a/shared/shcommon/public/fs.h +++ b/shared/shcommon/public/fs.h @@ -4,7 +4,7 @@ // // PUBLIC FUNCTIONS // -GSList* wintc_sh_fs_get_names_as_list( +GList* wintc_sh_fs_get_names_as_list( const gchar* path, gboolean full_names, GFileTest test, diff --git a/shared/shcommon/src/fs.c b/shared/shcommon/src/fs.c index ae7790a..1f9bfa1 100644 --- a/shared/shcommon/src/fs.c +++ b/shared/shcommon/src/fs.c @@ -6,7 +6,7 @@ // // PUBLIC FUNCTIONS // -GSList* wintc_sh_fs_get_names_as_list( +GList* wintc_sh_fs_get_names_as_list( const gchar* path, gboolean full_names, GFileTest test, @@ -17,7 +17,7 @@ GSList* wintc_sh_fs_get_names_as_list( GDir* dir; const gchar* dir_entry = NULL; GSList* dirs_to_enum = NULL; - GSList* entries = NULL; + GList* entries = NULL; GSList* iter = NULL; WINTC_SAFE_REF_CLEAR(error); @@ -42,7 +42,7 @@ GSList* wintc_sh_fs_get_names_as_list( if (!dir) { g_slist_free_full(dirs_to_enum, g_free); - g_slist_free_full(entries, g_free); + g_list_free_full(entries, g_free); return NULL; } @@ -71,7 +71,7 @@ GSList* wintc_sh_fs_get_names_as_list( if (!test || g_file_test(full_path, test)) { entries = - g_slist_append( + g_list_append( entries, g_strdup(full_names ? full_path : dir_entry) ); diff --git a/shared/shell/public/browser.h b/shared/shell/public/browser.h index 505ca81..84e2b8e 100644 --- a/shared/shell/public/browser.h +++ b/shared/shell/public/browser.h @@ -44,7 +44,7 @@ WinTCShBrowser* wintc_sh_browser_new( gboolean wintc_sh_browser_activate_item( WinTCShBrowser* browser, - WinTCShextViewItem* item, + guint item_hash, GError** error ); diff --git a/shared/shell/public/cpl.h b/shared/shell/public/cpl.h index cf4ec74..1d6ea7f 100644 --- a/shared/shell/public/cpl.h +++ b/shared/shell/public/cpl.h @@ -17,7 +17,7 @@ typedef struct _WinTCShCplApplet // // PUBLIC FUNCTIONS // -GSList* wintc_sh_cpl_applet_get_all(void); +GList* wintc_sh_cpl_applet_get_all(void); gboolean wintc_sh_cpl_applet_is_executable( WinTCShCplApplet* applet diff --git a/shared/shell/src/browser.c b/shared/shell/src/browser.c index 2284a70..ce0d587 100644 --- a/shared/shell/src/browser.c +++ b/shared/shell/src/browser.c @@ -22,9 +22,9 @@ enum enum { - COLUMN_VIEWITEM = 0, - COLUMN_ICON, - COLUMN_DISPLAY_NAME, + COLUMN_ICON = 0, + COLUMN_ENTRY_NAME, + COLUMN_VIEW_HASH, N_COLUMNS }; @@ -53,14 +53,14 @@ static void wintc_sh_browser_set_property( ); static void on_current_view_items_added( - WinTCIShextView* view, - WinTCShextViewItemsAddedData* event_data, - gpointer user_data + WinTCIShextView* view, + WinTCShextViewItemsUpdate* update, + gpointer user_data ); static void on_current_view_items_removed( - WinTCIShextView* view, - WinTCShextViewItem** items, - gpointer user_data + WinTCIShextView* view, + WinTCShextViewItemsUpdate* update, + gpointer user_data ); static void on_current_view_refreshing( WinTCIShextView* view, @@ -85,6 +85,10 @@ struct _WinTCShBrowser // WinTCIShextView* current_view; GtkListStore* view_model; + + gulong sigid_items_added; + gulong sigid_items_removed; + gulong sigid_refreshing; }; // @@ -142,9 +146,9 @@ static void wintc_sh_browser_init( self->view_model = gtk_list_store_new( 3, - G_TYPE_POINTER, GDK_TYPE_PIXBUF, - G_TYPE_STRING + G_TYPE_STRING, + G_TYPE_UINT ); } @@ -218,7 +222,7 @@ WinTCShBrowser* wintc_sh_browser_new( gboolean wintc_sh_browser_activate_item( WinTCShBrowser* browser, - WinTCShextViewItem* item, + guint item_hash, GError** error ) { @@ -238,7 +242,7 @@ gboolean wintc_sh_browser_activate_item( if ( !wintc_ishext_view_activate_item( browser->current_view, - item, + item_hash, &path_info, &local_error ) @@ -388,29 +392,54 @@ gboolean wintc_sh_browser_set_location( return FALSE; } + // Disconnect from old view + // + if (browser->current_view) + { + g_signal_handler_disconnect( + browser->current_view, + browser->sigid_items_added + ); + g_signal_handler_disconnect( + browser->current_view, + browser->sigid_items_removed + ); + g_signal_handler_disconnect( + browser->current_view, + browser->sigid_refreshing + ); + + g_clear_object(&(browser->current_view)); + } + // Update the view // - g_clear_object(&(browser->current_view)); browser->current_view = new_view; - g_signal_connect( - browser->current_view, - "items-added", - G_CALLBACK(on_current_view_items_added), - browser - ); - g_signal_connect( - browser->current_view, - "items-removed", - G_CALLBACK(on_current_view_items_removed), - browser - ); - g_signal_connect( - browser->current_view, - "refreshing", - G_CALLBACK(on_current_view_refreshing), - browser - ); + browser->sigid_items_added = + g_signal_connect_object( + browser->current_view, + "items-added", + G_CALLBACK(on_current_view_items_added), + browser, + G_CONNECT_DEFAULT + ); + browser->sigid_items_removed = + g_signal_connect_object( + browser->current_view, + "items-removed", + G_CALLBACK(on_current_view_items_removed), + browser, + G_CONNECT_DEFAULT + ); + browser->sigid_refreshing = + g_signal_connect_object( + browser->current_view, + "refreshing", + G_CALLBACK(on_current_view_refreshing), + browser, + G_CONNECT_DEFAULT + ); // Notify that we're loading... // @@ -433,15 +462,15 @@ gboolean wintc_sh_browser_set_location( // static void on_current_view_items_added( WINTC_UNUSED(WinTCIShextView* view), - WinTCShextViewItemsAddedData* event_data, - gpointer user_data + WinTCShextViewItemsUpdate* update, + gpointer user_data ) { WinTCShBrowser* browser = WINTC_SH_BROWSER(user_data); - for (int i = 0; i < event_data->num_items; i++) + for (GList* iter = update->data; iter; iter = iter->next) { - WinTCShextViewItem* item = &(event_data->items[i]); + WinTCShextViewItem* item = iter->data; // Load icon // @@ -462,16 +491,16 @@ static void on_current_view_items_added( gtk_list_store_set( browser->view_model, &iter, - COLUMN_VIEWITEM, item, - COLUMN_ICON, icon, - COLUMN_DISPLAY_NAME, item->display_name, + COLUMN_ICON, icon, + COLUMN_ENTRY_NAME, item->display_name, + COLUMN_VIEW_HASH, item->hash, -1 ); } // Check if done // - if (event_data->done) + if (update->done) { WINTC_LOG_DEBUG("%s", "shell: current view finished refreshing"); @@ -486,18 +515,55 @@ static void on_current_view_items_added( static void on_current_view_items_removed( WINTC_UNUSED(WinTCIShextView* view), - WinTCShextViewItem** items, - WINTC_UNUSED(gpointer user_data) + WinTCShextViewItemsUpdate* update, + gpointer user_data ) { - WinTCShextViewItem* p_item = items[0]; + WinTCShBrowser* browser = WINTC_SH_BROWSER(user_data); - // FIXME: Proper implementation later, just print the names for now + // FIXME: Inefficient linear search - improve later // - while (p_item) + GtkTreeIter iter; + gboolean searching; + + for (GList* upd_iter = update->data; upd_iter; upd_iter = upd_iter->next) { - g_message("Item removed: %s", p_item->display_name); - p_item++; + guint item_hash = GPOINTER_TO_UINT(upd_iter->data); + + searching = + gtk_tree_model_iter_children( + GTK_TREE_MODEL(browser->view_model), + &iter, + NULL + ); + + while (searching) + { + guint hash; + + gtk_tree_model_get( + GTK_TREE_MODEL(browser->view_model), + &iter, + COLUMN_VIEW_HASH, &hash, + -1 + ); + + if (item_hash == hash) + { + gtk_list_store_remove( + browser->view_model, + &iter + ); + + break; + } + + searching = + gtk_tree_model_iter_next( + GTK_TREE_MODEL(browser->view_model), + &iter + ); + } } } diff --git a/shared/shell/src/cpl.c b/shared/shell/src/cpl.c index 2445156..aec20be 100644 --- a/shared/shell/src/cpl.c +++ b/shared/shell/src/cpl.c @@ -18,9 +18,9 @@ static const gchar* S_CPL_KEY_ICON_NAME = "Icon"; // // PUBLIC FUNCTIONS // -GSList* wintc_sh_cpl_applet_get_all(void) +GList* wintc_sh_cpl_applet_get_all(void) { - GSList* entries = + GList* entries = wintc_sh_fs_get_names_as_list( S_CPL_ENTRIES_DIR, TRUE, @@ -35,12 +35,12 @@ GSList* wintc_sh_cpl_applet_get_all(void) } WinTCShCplApplet* applet; - GSList* cpls = NULL; + GList* cpls = NULL; GError* error = NULL; GKeyFile* key_file = g_key_file_new(); gboolean success = TRUE; - for (GSList* iter = entries; iter; iter = iter->next) + for (GList* iter = entries; iter; iter = iter->next) { WINTC_LOG_DEBUG("shell: cpl parse %s", (gchar*) iter->data); @@ -107,7 +107,7 @@ GSList* wintc_sh_cpl_applet_get_all(void) if (success) { - cpls = g_slist_append(cpls, applet); + cpls = g_list_append(cpls, applet); } else { @@ -119,7 +119,7 @@ GSList* wintc_sh_cpl_applet_get_all(void) success = TRUE; } - g_slist_free_full(entries, g_free); + g_list_free_full(entries, g_free); g_key_file_free(key_file); return cpls; diff --git a/shared/shell/src/icnvwbeh.c b/shared/shell/src/icnvwbeh.c index fc978d2..9c89a23 100644 --- a/shared/shell/src/icnvwbeh.c +++ b/shared/shell/src/icnvwbeh.c @@ -123,11 +123,11 @@ static void wintc_sh_icon_view_behaviour_constructed( ); gtk_icon_view_set_pixbuf_column( GTK_ICON_VIEW(behaviour->icon_view), - 1 + 0 ); gtk_icon_view_set_text_column( GTK_ICON_VIEW(behaviour->icon_view), - 2 + 1 ); // Attach signals @@ -218,19 +218,19 @@ static void on_icon_view_item_activated( if (gtk_tree_model_get_iter(model, &iter, path)) { - GError* error = NULL; - WinTCShextViewItem* item = NULL; + GError* error = NULL; + guint hash; gtk_tree_model_get( model, &iter, - 0, &item, // FIXME: Guess we should make the columns public + 2, &hash, // FIXME: Guess we should make the columns public -1 ); wintc_sh_browser_activate_item( behaviour->browser, - item, + hash, &error ); diff --git a/shared/shell/src/trevwbeh.c b/shared/shell/src/trevwbeh.c index c79dc94..5a3c2ce 100644 --- a/shared/shell/src/trevwbeh.c +++ b/shared/shell/src/trevwbeh.c @@ -16,10 +16,10 @@ enum enum { - COL_ICON_NAME = 0, - COL_ENTRY_NAME, - COL_VIEW_HASH, - NUM_COLS + COLUMN_ICON_NAME = 0, + COLUMN_ENTRY_NAME, + COLUMN_VIEW_HASH, + N_COLUMNS }; // @@ -54,9 +54,14 @@ static void on_browser_load_changed( ); static void on_view_items_added( - WinTCIShextView* view, - WinTCShextViewItemsAddedData* items_data, - gpointer user_data + WinTCIShextView* view, + WinTCShextViewItemsUpdate* update, + gpointer user_data +); +static void on_view_items_removed( + WinTCIShextView* view, + WinTCShextViewItemsUpdate* update, + gpointer user_data ); // @@ -216,7 +221,7 @@ static void wintc_sh_tree_view_behaviour_constructed( new_column, new_cell, "icon-name", - COL_ICON_NAME + COLUMN_ICON_NAME ); new_cell = gtk_cell_renderer_text_new(); @@ -226,7 +231,7 @@ static void wintc_sh_tree_view_behaviour_constructed( new_column, new_cell, "text", - COL_ENTRY_NAME + COLUMN_ENTRY_NAME ); gtk_tree_view_append_column( @@ -493,9 +498,9 @@ static void wintc_sh_tree_view_behaviour_update_view( gtk_tree_store_set( behaviour->tree_model, &next, - COL_ICON_NAME, wintc_ishext_view_get_icon_name(view), - COL_ENTRY_NAME, wintc_ishext_view_get_display_name(view), - COL_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, -1 ); @@ -549,9 +554,9 @@ static void wintc_sh_tree_view_behaviour_update_view( gtk_tree_store_set( behaviour->tree_model, &next, - COL_ICON_NAME, wintc_ishext_view_get_icon_name(next_view), - COL_ENTRY_NAME, wintc_ishext_view_get_display_name(next_view), - COL_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, -1 ); @@ -584,6 +589,13 @@ static void wintc_sh_tree_view_behaviour_update_view( behaviour, G_CONNECT_DEFAULT ); + g_signal_connect_object( + view, + "items-removed", + G_CALLBACK(on_view_items_removed), + behaviour, + G_CONNECT_DEFAULT + ); wintc_ishext_view_refresh_items(view); } @@ -634,9 +646,9 @@ static void on_browser_load_changed( } static void on_view_items_added( - WinTCIShextView* view, - WinTCShextViewItemsAddedData* items_data, - gpointer user_data + WinTCIShextView* view, + WinTCShextViewItemsUpdate* update, + gpointer user_data ) { WinTCShTreeViewBehaviour* behaviour = @@ -674,9 +686,9 @@ static void on_view_items_added( // WinTCShextViewItem* view_item; - for (gint i = 0; i < items_data->num_items; i++) + for (GList* iter = update->data; iter; iter = iter->next) { - view_item = &(items_data->items[i]); + view_item = iter->data; // Skip leaf nodes and nodes that already exist // @@ -704,9 +716,9 @@ static void on_view_items_added( gtk_tree_store_set( behaviour->tree_model, &child, - COL_ICON_NAME, view_item->icon_name, - COL_ENTRY_NAME, view_item->display_name, - COL_VIEW_HASH, view_item->hash, + COLUMN_ICON_NAME, view_item->icon_name, + COLUMN_ENTRY_NAME, view_item->display_name, + COLUMN_VIEW_HASH, view_item->hash, -1 ); @@ -720,3 +732,53 @@ static void on_view_items_added( ); } } + +static void on_view_items_removed( + WINTC_UNUSED(WinTCIShextView* view), + WinTCShextViewItemsUpdate* update, + gpointer user_data +) +{ + WinTCShTreeViewBehaviour* behaviour = + WINTC_SH_TREE_VIEW_BEHAVIOUR(user_data); + + // Track down and bin via the maps + // + GtkTreeIter iter; + + for (GList* upd_iter = update->data; upd_iter; upd_iter = upd_iter->next) + { + guint item_hash = GPOINTER_TO_UINT(upd_iter->data); + + const gchar* iter_path = + g_hash_table_lookup( + behaviour->map_hash_to_iter, + GUINT_TO_POINTER(item_hash) + ); + + if (!iter_path) + { + continue; + } + + gtk_tree_model_get_iter_from_string( + GTK_TREE_MODEL(behaviour->tree_model), + &iter, + iter_path + ); + + 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, + GUINT_TO_POINTER(item_hash) + ); + } +} diff --git a/shared/shell/src/vwcpl.c b/shared/shell/src/vwcpl.c index 5c9fa1b..40000ef 100644 --- a/shared/shell/src/vwcpl.c +++ b/shared/shell/src/vwcpl.c @@ -34,7 +34,7 @@ static void wintc_sh_view_cpl_get_property( static gboolean wintc_sh_view_cpl_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ); @@ -83,8 +83,8 @@ struct _WinTCShViewCpl // State // - GSList* list_cpls; - GArray* view_items; + GList* cpls; + GHashTable* map_items; }; // @@ -117,11 +117,8 @@ static void wintc_sh_view_cpl_class_init( } static void wintc_sh_view_cpl_init( - WinTCShViewCpl* self -) -{ - self->view_items = g_array_new(FALSE, TRUE, sizeof (WinTCShextViewItem)); -} + WINTC_UNUSED(WinTCShViewCpl* self) +) {} static void wintc_sh_view_cpl_ishext_view_interface_init( WinTCIShextViewInterface* iface @@ -148,11 +145,17 @@ static void wintc_sh_view_cpl_finalize( { WinTCShViewCpl* view_cpl = WINTC_SH_VIEW_CPL(object); - g_clear_slist( - &(view_cpl->list_cpls), + g_clear_list( + &(view_cpl->cpls), (GDestroyNotify) wintc_sh_cpl_applet_free ); - g_array_free(view_cpl->view_items, TRUE); + + if (view_cpl->map_items) + { + g_hash_table_destroy( + g_steal_pointer(&(view_cpl->map_items)) + ); + } (G_OBJECT_CLASS(wintc_sh_view_cpl_parent_class))->finalize(object); } @@ -185,13 +188,23 @@ static void wintc_sh_view_cpl_get_property( // INTERFACE METHODS (WinTCIShextView) // static gboolean wintc_sh_view_cpl_activate_item( - WINTC_UNUSED(WinTCIShextView* view), - WinTCShextViewItem* item, + WinTCIShextView* view, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ) { - WinTCShCplApplet* applet = (WinTCShCplApplet*) item->priv; + WinTCShViewCpl* view_cpl = WINTC_SH_VIEW_CPL(view); + + WinTCShCplApplet* applet; + WinTCShextViewItem* item; + + item = (WinTCShextViewItem*) + g_hash_table_lookup( + view_cpl->map_items, + GUINT_TO_POINTER(item_hash) + ); + applet = (WinTCShCplApplet*) item->priv; if (wintc_sh_cpl_applet_is_executable(applet)) { @@ -211,37 +224,32 @@ static void wintc_sh_view_cpl_refresh_items( _wintc_ishext_view_refreshing(view); - // Refresh list - // - g_clear_slist( - &(view_cpl->list_cpls), + g_clear_list( + &(view_cpl->cpls), (GDestroyNotify) wintc_sh_cpl_applet_free ); - view_cpl->list_cpls = wintc_sh_cpl_applet_get_all(); - - g_array_remove_range( - view_cpl->view_items, - 0, - view_cpl->view_items->len - ); - g_array_set_size( - view_cpl->view_items, - g_slist_length(view_cpl->list_cpls) - ); + if (view_cpl->map_items) + { + g_hash_table_destroy( + g_steal_pointer(&(view_cpl->map_items)) + ); + } // Create view items // - gint i = 0; + view_cpl->cpls = wintc_sh_cpl_applet_get_all(); + view_cpl->map_items = g_hash_table_new_full( + g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) g_free + ); - for (GSList* iter = view_cpl->list_cpls; iter; iter = iter->next) + for (GList* iter = view_cpl->cpls; iter; iter = iter->next) { WinTCShCplApplet* applet = (WinTCShCplApplet*) iter->data; - WinTCShextViewItem* view_item = &g_array_index( - view_cpl->view_items, - WinTCShextViewItem, - i - ); + WinTCShextViewItem* view_item = g_new(WinTCShextViewItem, 1); view_item->display_name = applet->display_name; view_item->icon_name = applet->icon_name ? @@ -251,22 +259,25 @@ static void wintc_sh_view_cpl_refresh_items( view_item->hash = g_str_hash(applet->exec); view_item->priv = applet; - i++; + g_hash_table_insert( + view_cpl->map_items, + GUINT_TO_POINTER(view_item->hash), + view_item + ); } // Provide update // - WinTCShextViewItemsAddedData update = { 0 }; + WinTCShextViewItemsUpdate update = { 0 }; - update.items = &g_array_index( - view_cpl->view_items, - WinTCShextViewItem, - 0 - ); - update.num_items = view_cpl->view_items->len; - update.done = TRUE; + GList* items = g_hash_table_get_values(view_cpl->map_items); + + update.data = items; + update.done = TRUE; _wintc_ishext_view_items_added(view, &update); + + g_list_free(items); } static void wintc_sh_view_cpl_get_actions_for_item( diff --git a/shared/shell/src/vwdesk.c b/shared/shell/src/vwdesk.c index a70f16b..0a62eab 100644 --- a/shared/shell/src/vwdesk.c +++ b/shared/shell/src/vwdesk.c @@ -17,6 +17,10 @@ enum // STATIC DATA // +// FIXME: Temp +// +static GHashTable* s_desktop_map = NULL; + // FIXME: LAZY AGAIN! Use shlang!!!!!! Temporary as well cos the user can // toggle which items are present // @@ -67,7 +71,7 @@ static void wintc_sh_view_desktop_get_property( static gboolean wintc_sh_view_desktop_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ); @@ -132,6 +136,8 @@ static void wintc_sh_view_desktop_class_init( WinTCShViewDesktopClass* klass ) { + s_desktop_map = g_hash_table_new(g_direct_hash, g_direct_equal); + // Assign GUID paths to built-in desktop items - kind of rubbish but // whatever // @@ -155,6 +161,12 @@ static void wintc_sh_view_desktop_class_init( g_free(temp); } + + g_hash_table_insert( + s_desktop_map, + GUINT_TO_POINTER(s_desktop_items[i].hash), + &(s_desktop_items[i]) + ); } // GObject initialization @@ -222,22 +234,27 @@ static void wintc_sh_view_desktop_get_property( // static gboolean wintc_sh_view_desktop_activate_item( WINTC_UNUSED(WinTCIShextView* view), - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ) { WINTC_SAFE_REF_CLEAR(error); - gchar* target = (gchar*) item->priv; + WinTCShextViewItem* item = + (WinTCShextViewItem*) + g_hash_table_lookup( + s_desktop_map, + GUINT_TO_POINTER(item_hash) + ); - if (!target) + if (!(item->priv)) { g_critical("%s", "shell: desk view can't activate item, no target"); return FALSE; } - path_info->base_path = g_strdup(target); + path_info->base_path = g_strdup(item->priv); return TRUE; } @@ -253,13 +270,16 @@ static void wintc_sh_view_desktop_refresh_items( // Just emit the default items for now // TODO: Should aggregate with user desktop files // - WinTCShextViewItemsAddedData items = { - &(s_desktop_items[0]), - G_N_ELEMENTS(s_desktop_items), - TRUE - }; + WinTCShextViewItemsUpdate update = { 0 }; - _wintc_ishext_view_items_added(view, &items); + GList* items = g_hash_table_get_values(s_desktop_map); + + update.data = items; + update.done = TRUE; + + _wintc_ishext_view_items_added(view, &update); + + g_list_free(items); } static void wintc_sh_view_desktop_get_actions_for_item( diff --git a/shared/shell/src/vwdrives.c b/shared/shell/src/vwdrives.c index 114e296..776fb83 100644 --- a/shared/shell/src/vwdrives.c +++ b/shared/shell/src/vwdrives.c @@ -17,6 +17,10 @@ enum // STATIC DATA // +// FIXME: Temp +// +static GHashTable* s_drives_map = NULL; + // FIXME: Temporary - only item is the drive root atm // static WinTCShextViewItem s_temp_items[] = { @@ -40,7 +44,7 @@ static void wintc_sh_view_drives_get_property( static gboolean wintc_sh_view_drives_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_data, WinTCShextPathInfo* path_info, GError** error ); @@ -105,6 +109,8 @@ static void wintc_sh_view_drives_class_init( WinTCShViewDrivesClass* klass ) { + s_drives_map = g_hash_table_new(g_direct_hash, g_direct_equal); + // TEMP: Assign CPL view path // s_temp_items[1].priv = wintc_sh_path_for_guid(WINTC_SH_GUID_CPL); @@ -114,6 +120,19 @@ static void wintc_sh_view_drives_class_init( s_temp_items[0].hash = g_str_hash("/"); s_temp_items[1].hash = g_str_hash(s_temp_items[1].priv); + // TEMP: Prepend items + // + g_hash_table_insert( + s_drives_map, + GUINT_TO_POINTER(s_temp_items[0].hash), + &(s_temp_items[0]) + ); + g_hash_table_insert( + s_drives_map, + GUINT_TO_POINTER(s_temp_items[1].hash), + &(s_temp_items[1]) + ); + // GObject initialisation // GObjectClass* object_class = G_OBJECT_CLASS(klass); @@ -179,13 +198,20 @@ static void wintc_sh_view_drives_get_property( // static gboolean wintc_sh_view_drives_activate_item( WINTC_UNUSED(WinTCIShextView* view), - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ) { WINTC_SAFE_REF_CLEAR(error); + WinTCShextViewItem* item = + (WinTCShextViewItem*) + g_hash_table_lookup( + s_drives_map, + GUINT_TO_POINTER(item_hash) + ); + // TODO: Handle properly, we're using temp items for now // path_info->base_path = g_strdup(item->priv); @@ -204,13 +230,16 @@ static void wintc_sh_view_drives_refresh_items( // Emit only the root '/' for now // TODO: Basically everything in My Computer! // - WinTCShextViewItemsAddedData items = { - &(s_temp_items[0]), - G_N_ELEMENTS(s_temp_items), - TRUE - }; + WinTCShextViewItemsUpdate update = { 0 }; - _wintc_ishext_view_items_added(view, &items); + GList* items = g_hash_table_get_values(s_drives_map); + + update.data = items; + update.done = TRUE; + + _wintc_ishext_view_items_added(view, &update); + + g_list_free(items); } static void wintc_sh_view_drives_get_actions_for_item( diff --git a/shared/shell/src/vwfs.c b/shared/shell/src/vwfs.c index ccbc316..e23e6bb 100644 --- a/shared/shell/src/vwfs.c +++ b/shared/shell/src/vwfs.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -44,7 +45,7 @@ static void wintc_sh_view_fs_set_property( static gboolean wintc_sh_view_fs_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ); @@ -83,6 +84,14 @@ static void clear_view_item( WinTCShextViewItem* item ); +static void on_file_monitor_changed( + GFileMonitor* self, + GFile* file, + GFile* other_file, + GFileMonitorEvent event_type, + gpointer user_data +); + // // GLIB OOP/CLASS INSTANCE DEFINITIONS // @@ -97,10 +106,12 @@ struct _WinTCShViewFS // FS state // - GArray* items; gchar* parent_path; gchar* path; + GFileMonitor* fs_monitor; + GHashTable* fs_map_entries; + WinTCShextHost* shext_host; }; @@ -159,16 +170,8 @@ static void wintc_sh_view_fs_class_init( } static void wintc_sh_view_fs_init( - WinTCShViewFS* self -) -{ - self->items = g_array_new(FALSE, TRUE, sizeof (WinTCShextViewItem)); - - g_array_set_clear_func( - self->items, - (GDestroyNotify) clear_view_item - ); -} + WINTC_UNUSED(WinTCShViewFS* self) +) {} static void wintc_sh_view_fs_ishext_view_interface_init( WinTCIShextViewInterface* iface @@ -193,9 +196,10 @@ static void wintc_sh_view_fs_dispose( GObject* object ) { - WinTCShViewFS* view = WINTC_SH_VIEW_FS(object); + WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(object); - g_clear_object(&(view->shext_host)); + g_clear_object(&(view_fs->fs_monitor)); + g_clear_object(&(view_fs->shext_host)); (G_OBJECT_CLASS(wintc_sh_view_fs_parent_class))->dispose(object); } @@ -204,11 +208,17 @@ static void wintc_sh_view_fs_finalize( GObject* object ) { - WinTCShViewFS* view = WINTC_SH_VIEW_FS(object); + WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(object); - g_array_free(view->items, TRUE); - g_free(view->parent_path); - g_free(view->path); + g_free(view_fs->parent_path); + g_free(view_fs->path); + + if (view_fs->fs_map_entries) + { + g_hash_table_destroy( + g_steal_pointer(&(view_fs->fs_map_entries)) + ); + } (G_OBJECT_CLASS(wintc_sh_view_fs_parent_class))->finalize(object); } @@ -280,7 +290,7 @@ static void wintc_sh_view_fs_set_property( // static gboolean wintc_sh_view_fs_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ) @@ -290,6 +300,24 @@ static gboolean wintc_sh_view_fs_activate_item( WINTC_SAFE_REF_CLEAR(error); + // Retrieve the item itself + // + WinTCShextViewItem* item = + (WinTCShextViewItem*) + g_hash_table_lookup( + view_fs->fs_map_entries, + GUINT_TO_POINTER(item_hash) + ); + + if (!item) + { + g_critical( + "%s", + "shell: fs - attempt to activate non-existent item" + ); + return FALSE; + } + // Retrieve MIME for the item // gchar* next_path = g_build_path( @@ -348,9 +376,16 @@ static void wintc_sh_view_fs_refresh_items( _wintc_ishext_view_refreshing(view); + if (view_fs->fs_map_entries) + { + g_hash_table_destroy( + g_steal_pointer(&(view_fs->fs_map_entries)) + ); + } + // FIXME: Error handling (no way of passing to caller) // - GSList* entries = + GList* entries = wintc_sh_fs_get_names_as_list( view_fs->path, FALSE, @@ -359,31 +394,49 @@ static void wintc_sh_view_fs_refresh_items( NULL ); - // Create actual array - // FIXME: list->array should probs be in comgtk + // Spawn file monitor if needed + // + if (!view_fs->fs_monitor) + { + GFile* this_dir = g_file_new_for_path(view_fs->path); + + view_fs->fs_monitor = + g_file_monitor_directory( + this_dir, + 0, + NULL, + NULL + ); + + if (view_fs->fs_monitor) + { + g_signal_connect( + view_fs->fs_monitor, + "changed", + G_CALLBACK(on_file_monitor_changed), + view_fs + ); + } + + g_object_unref(this_dir); + } + + // Enumerate the entries now // gchar* entry_path; - gint i = 0; - g_array_remove_range( - view_fs->items, - 0, - view_fs->items->len - ); - g_array_set_size( - view_fs->items, - g_slist_length(entries) - ); + view_fs->fs_map_entries = + g_hash_table_new_full( + g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) clear_view_item + ); - for (GSList* iter = entries; iter; iter = iter->next) + for (GList* iter = entries; iter; iter = iter->next) { gboolean is_dir; - WinTCShextViewItem* item = - &g_array_index( - view_fs->items, - WinTCShextViewItem, - i - ); + WinTCShextViewItem* item = g_new(WinTCShextViewItem, 1); entry_path = g_build_path( @@ -402,24 +455,27 @@ static void wintc_sh_view_fs_refresh_items( g_free(entry_path); - i++; + g_hash_table_insert( + view_fs->fs_map_entries, + GUINT_TO_POINTER(item->hash), + item + ); } - g_slist_free(entries); + g_list_free(entries); // Provide update // - WinTCShextViewItemsAddedData update = { 0 }; + WinTCShextViewItemsUpdate update = { 0 }; - update.items = &g_array_index( - view_fs->items, - WinTCShextViewItem, - 0 - ); - update.num_items = view_fs->items->len; - update.done = TRUE; + GList* items = g_hash_table_get_values(view_fs->fs_map_entries); + + update.data = items; + update.done = TRUE; _wintc_ishext_view_items_added(view, &update); + + g_list_free(items); } static void wintc_sh_view_fs_get_actions_for_item( @@ -536,5 +592,87 @@ static void clear_view_item( WinTCShextViewItem* item ) { - g_clear_pointer(&(item->display_name), g_free); + g_free(item->display_name); + g_free(item); +} + +static void on_file_monitor_changed( + WINTC_UNUSED(GFileMonitor* self), + GFile* file, + WINTC_UNUSED(GFile* other_file), + GFileMonitorEvent event_type, + gpointer user_data +) +{ + WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(user_data); + + GList* data = NULL; + gchar* file_path = NULL; + gboolean is_dir; + WinTCShextViewItem* item; + WinTCShextViewItemsUpdate update = { 0 }; + + switch (event_type) + { + case G_FILE_MONITOR_EVENT_CREATED: + file_path = g_file_get_path(file); + is_dir = + g_file_query_file_type(file, 0, NULL) == G_FILE_TYPE_DIRECTORY; + + WINTC_LOG_DEBUG("shell: fs monitor - %s created", file_path); + + item = g_new(WinTCShextViewItem, 1); + + item->display_name = g_file_get_basename(file); + item->icon_name = is_dir ? "inode-directory" : "empty"; + item->is_leaf = !is_dir; + item->hash = g_str_hash(file_path); + + g_hash_table_insert( + view_fs->fs_map_entries, + GUINT_TO_POINTER(item->hash), + item + ); + + // Issue update + // + data = g_list_prepend(data, item); + + update.data = data; + update.done = TRUE; + + _wintc_ishext_view_items_added( + WINTC_ISHEXT_VIEW(view_fs), + &update + ); + + break; + + case G_FILE_MONITOR_EVENT_DELETED: + file_path = g_file_get_path(file); + + WINTC_LOG_DEBUG("shell: fs monitor - %s deleted", file_path); + + // Issue update + data = + g_list_prepend( + data, + GUINT_TO_POINTER(g_str_hash(file_path)) + ); + + update.data = data; + update.done = TRUE; + + _wintc_ishext_view_items_removed( + WINTC_ISHEXT_VIEW(view_fs), + &update + ); + + break; + + default: break; + } + + g_list_free(data); + g_free(file_path); } diff --git a/shared/shellext/public/if_view.h b/shared/shellext/public/if_view.h index 4b1e8e3..e8a5fe4 100644 --- a/shared/shellext/public/if_view.h +++ b/shared/shellext/public/if_view.h @@ -36,7 +36,7 @@ struct _WinTCIShextViewInterface gboolean (*activate_item) ( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ); @@ -80,7 +80,7 @@ struct _WinTCIShextViewInterface // gboolean wintc_ishext_view_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ); @@ -122,12 +122,12 @@ gboolean wintc_ishext_view_has_parent( // PUBLIC FUNCTIONS // void _wintc_ishext_view_items_added( - WinTCIShextView* view, - WinTCShextViewItemsAddedData* items + WinTCIShextView* view, + WinTCShextViewItemsUpdate* update ); void _wintc_ishext_view_items_removed( - WinTCIShextView* view, - WinTCShextViewItem** items + WinTCIShextView* view, + WinTCShextViewItemsUpdate* update ); void _wintc_ishext_view_refreshing( WinTCIShextView* view diff --git a/shared/shellext/public/viewitem.h b/shared/shellext/public/viewitem.h index c8e02e2..952b7b8 100644 --- a/shared/shellext/public/viewitem.h +++ b/shared/shellext/public/viewitem.h @@ -17,11 +17,10 @@ typedef struct _WinTCShextViewItem gpointer priv; } WinTCShextViewItem; -typedef struct _WinTCShextViewItemsAddedData +typedef struct _WinTCShextViewItemsUpdate { - WinTCShextViewItem* items; - gint num_items; - gboolean done; -} WinTCShextViewItemsAddedData; + GList* data; + gboolean done; +} WinTCShextViewItemsUpdate; #endif diff --git a/shared/shellext/src/if_view.c b/shared/shellext/src/if_view.c index bccc7e7..af604e1 100644 --- a/shared/shellext/src/if_view.c +++ b/shared/shellext/src/if_view.c @@ -91,7 +91,7 @@ static void wintc_ishext_view_default_init( // gboolean wintc_ishext_view_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ) @@ -101,7 +101,7 @@ gboolean wintc_ishext_view_activate_item( return iface->activate_item( view, - item, + item_hash, path_info, error ); @@ -204,28 +204,28 @@ void wintc_ishext_view_refresh_items( // PUBLIC FUNCTIONS // void _wintc_ishext_view_items_added( - WinTCIShextView* view, - WinTCShextViewItemsAddedData* items + WinTCIShextView* view, + WinTCShextViewItemsUpdate* update ) { g_signal_emit( view, wintc_ishext_view_signals[SIGNAL_ITEMS_ADDED], 0, - items + update ); } void _wintc_ishext_view_items_removed( - WinTCIShextView* view, - WinTCShextViewItem** items + WinTCIShextView* view, + WinTCShextViewItemsUpdate* update ) { g_signal_emit( view, wintc_ishext_view_signals[SIGNAL_ITEMS_REMOVED], 0, - items + update ); } diff --git a/shell/cpl/printers/src/vwprntrs.c b/shell/cpl/printers/src/vwprntrs.c index 6d664bc..fd3996a 100644 --- a/shell/cpl/printers/src/vwprntrs.c +++ b/shell/cpl/printers/src/vwprntrs.c @@ -18,6 +18,10 @@ enum // STATIC DATA // +// FIXME: Temp +// +static GHashTable* s_printers_map = NULL; + // FIXME: Temporary, until we display printers // static WinTCShextViewItem s_temp_items[] = { @@ -40,7 +44,7 @@ static void wintc_cpl_view_printers_get_property( static gboolean wintc_cpl_view_printers_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ); @@ -111,6 +115,15 @@ static void wintc_cpl_view_printers_class_init( g_free(temp); + s_printers_map = + g_hash_table_new(g_direct_hash, g_direct_equal); + + g_hash_table_insert( + s_printers_map, + GUINT_TO_POINTER(s_temp_items[0].hash), + &(s_temp_items[0]) + ); + // GObject initialisation // GObjectClass* object_class = G_OBJECT_CLASS(klass); @@ -176,7 +189,7 @@ static void wintc_cpl_view_printers_get_property( // static gboolean wintc_cpl_view_printers_activate_item( WINTC_UNUSED(WinTCIShextView* view), - WINTC_UNUSED(WinTCShextViewItem* item), + WINTC_UNUSED(guint item_hash), WINTC_UNUSED(WinTCShextPathInfo* path_info), GError** error ) @@ -197,13 +210,16 @@ static void wintc_cpl_view_printers_refresh_items( // Emit the FPO printer for now // TODO: Implement this! // - WinTCShextViewItemsAddedData items = { - &(s_temp_items[0]), - G_N_ELEMENTS(s_temp_items), - TRUE - }; + WinTCShextViewItemsUpdate update = { 0 }; - _wintc_ishext_view_items_added(view, &items); + GList* items = g_hash_table_get_values(s_printers_map); + + update.data = items; + update.done = TRUE; + + _wintc_ishext_view_items_added(view, &update); + + g_list_free(items); } static void wintc_cpl_view_printers_get_actions_for_item( diff --git a/shell/shext/zip/src/vwzip.c b/shell/shext/zip/src/vwzip.c index d0f7556..093a6a9 100644 --- a/shell/shext/zip/src/vwzip.c +++ b/shell/shext/zip/src/vwzip.c @@ -41,7 +41,7 @@ static void wintc_view_zip_set_property( static gboolean wintc_view_zip_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ); @@ -104,10 +104,11 @@ struct _WinTCViewZip // ZIP state // - GArray* items; gchar* parent_path; gchar* rel_path; gchar* zip_uri; + + GHashTable* map_items; }; // @@ -164,16 +165,8 @@ static void wintc_view_zip_class_init( } static void wintc_view_zip_init( - WinTCViewZip* self -) -{ - self->items = g_array_new(FALSE, TRUE, sizeof (WinTCShextViewItem)); - - g_array_set_clear_func( - self->items, - (GDestroyNotify) clear_view_item - ); -} + WINTC_UNUSED(WinTCViewZip* self) +) {} static void wintc_view_zip_ishext_view_interface_init( WinTCIShextViewInterface* iface @@ -200,11 +193,17 @@ static void wintc_view_zip_finalize( { WinTCViewZip* view_zip = WINTC_VIEW_ZIP(object); - g_array_free(view_zip->items, TRUE); g_free(view_zip->parent_path); g_free(view_zip->rel_path); g_free(view_zip->zip_uri); + if (view_zip->map_items) + { + g_hash_table_destroy( + g_steal_pointer(&(view_zip->map_items)) + ); + } + (G_OBJECT_CLASS(wintc_view_zip_parent_class))->finalize(object); } @@ -263,7 +262,7 @@ static void wintc_view_zip_set_property( // static gboolean wintc_view_zip_activate_item( WinTCIShextView* view, - WinTCShextViewItem* item, + guint item_hash, WinTCShextPathInfo* path_info, GError** error ) @@ -272,6 +271,24 @@ 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) + ); + + if (!item) + { + g_critical( + "%s", + "shell: zip - attempt to activate non-existent item" + ); + return FALSE; + } + + // Handle opening directories + // gboolean is_dir = g_str_has_suffix(item->priv, G_DIR_SEPARATOR_S); if (is_dir) @@ -305,6 +322,21 @@ static void wintc_view_zip_refresh_items( _wintc_ishext_view_refreshing(view); + if (view_zip->map_items) + { + g_hash_table_destroy( + g_steal_pointer(&(view_zip->map_items)) + ); + } + + view_zip->map_items = + g_hash_table_new_full( + g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) clear_view_item + ); + // Open the archive // const gchar* path = view_zip->zip_uri + strlen("file://"); @@ -334,18 +366,7 @@ static void wintc_view_zip_refresh_items( // FIXME: Probably want to cap max num of entries? Check zip bombs to see // what happens - don't want to get nuked by a crazy zip archive // - gint64 n_entries = zip_get_num_entries(zip_file, 0); - gint64 n_local_entries = 0; - - g_array_remove_range( - view_zip->items, - 0, - view_zip->items->len - ); - g_array_set_size( - view_zip->items, - n_entries - ); + gint64 n_entries = zip_get_num_entries(zip_file, 0); for (gint64 i = 0; i < n_entries; i++) { @@ -361,11 +382,7 @@ static void wintc_view_zip_refresh_items( } gchar* entry_copy = g_strdup(entry_name); - WinTCShextViewItem* item = &g_array_index( - view_zip->items, - WinTCShextViewItem, - n_local_entries - ); + WinTCShextViewItem* item = g_new(WinTCShextViewItem, 1); item->display_name = entry_copy + name_offset; item->is_leaf = !g_str_has_suffix(entry_name, G_DIR_SEPARATOR_S); @@ -373,29 +390,27 @@ static void wintc_view_zip_refresh_items( item->hash = zip_entry_hash(path, entry_name); item->priv = entry_copy; - n_local_entries++; + g_hash_table_insert( + view_zip->map_items, + GUINT_TO_POINTER(item->hash), + item + ); } zip_close(zip_file); // Emit the entries // - WinTCShextViewItemsAddedData update = { 0 }; + WinTCShextViewItemsUpdate update = { 0 }; - g_array_set_size( - view_zip->items, - n_local_entries - ); + GList* items = g_hash_table_get_values(view_zip->map_items); - update.items = &g_array_index( - view_zip->items, - WinTCShextViewItem, - 0 - ); - update.num_items = n_local_entries; - update.done = TRUE; + update.data = items; + update.done = TRUE; _wintc_ishext_view_items_added(view, &update); + + g_list_free(items); } static void wintc_view_zip_get_actions_for_item( @@ -643,5 +658,6 @@ static void clear_view_item( // Don't need to bin display_name as it's an offset into priv which // contains the full path in the zip // - g_clear_pointer(&(item->priv), g_free); + g_free(item->priv); + g_free(item); }