Enhancement: Fixes #385, shell/shellext - implement operations on views

This commit is contained in:
Rory Fewell
2024-12-06 23:23:15 +00:00
parent 12486d619f
commit ed056d7201
23 changed files with 1539 additions and 541 deletions

View File

@@ -24,6 +24,7 @@ include(../../packaging/cmake-inc/libraries/CMakeLists.txt)
include(../../packaging/cmake-inc/linking/CMakeLists.txt)
include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
wintc_resolve_library(gio-2.0 GIO)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
@@ -50,6 +51,8 @@ add_library(
public/marshal.h
src/memory.c
public/memory.h
src/menu.c
public/menu.h
src/msgbox.c
public/msgbox.h
src/profile.c
@@ -85,18 +88,21 @@ target_include_directories(
libwintc-comgtk
SYSTEM
BEFORE
PRIVATE ${GIO_INCLUDE_DIRS}
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
)
target_link_directories(
libwintc-comgtk
PRIVATE ${GIO_LIBRARY_DIRS}
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
)
target_link_libraries(
libwintc-comgtk
PRIVATE ${GIO_LIBRARIES}
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
)

View File

@@ -11,6 +11,7 @@
#include "@LIB_HEADER_DIR@/list.h"
#include "@LIB_HEADER_DIR@/marshal.h"
#include "@LIB_HEADER_DIR@/memory.h"
#include "@LIB_HEADER_DIR@/menu.h"
#include "@LIB_HEADER_DIR@/msgbox.h"
#include "@LIB_HEADER_DIR@/profile.h"
#include "@LIB_HEADER_DIR@/regex.h"

View File

@@ -0,0 +1,25 @@
/** @file */
#ifndef __COMGTK_MENU_H__
#define __COMGTK_MENU_H__
#include <gio/gio.h>
#include <glib.h>
//
// PUBLIC FUNCTIONS
//
/**
* Merges multiple menu models to create a new one.
*
* @param menu1 The first menu.
* @param ... The other menus to merge, followed by NULL.
* @return A new menu, created by merging the provided ones.
*/
GMenuModel* wintc_menu_model_merge(
GMenuModel* menu1,
...
);
#endif

71
shared/comgtk/src/menu.c Normal file
View File

@@ -0,0 +1,71 @@
#include <gio/gio.h>
#include <glib.h>
#include "../public/menu.h"
//
// FORWARD DECLARATIONS
//
static void menu_merge_model(
GMenu* menu,
GMenuModel* menu_model
);
//
// PUBLIC FUNCTIONS
//
GMenuModel* wintc_menu_model_merge(
GMenuModel* menu1,
...
)
{
GMenu* menu = g_menu_new();
menu_merge_model(menu, menu1);
// Iterate over models
//
va_list ap;
GMenuModel* next_model;
va_start(ap, menu1);
next_model = va_arg(ap, GMenuModel*);
while (next_model)
{
menu_merge_model(menu, next_model);
next_model = va_arg(ap, GMenuModel*);
}
va_end(ap);
return G_MENU_MODEL(menu);
}
//
// PRIVATE FUNCTIONS
//
static void menu_merge_model(
GMenu* menu,
GMenuModel* menu_model
)
{
// This seems really dumb... but in order to merge menus you essentially
// have to copy TWICE - first to copy out into a new item, then copy that
// item into the target menu
//
// I would've thought there be a better way, but I am not sure there is
//
gint n_items = g_menu_model_get_n_items(menu_model);
for (gint i = 0; i < n_items; i++)
{
GMenuItem* menu_item = g_menu_item_new_from_model(menu_model, i);
g_menu_append_item(menu, menu_item);
g_object_unref(menu_item);
}
}

View File

@@ -90,6 +90,10 @@ gboolean wintc_launch_command(
if (error != NULL)
{
g_propagate_error(out_error, error);
g_free(real_cmdline);
g_free(tmp_cmdline);
return FALSE;
}
@@ -188,8 +192,10 @@ static gboolean parse_file_in_cmdline(
{
g_propagate_error(out_error, error);
}
g_clear_error(&error);
else
{
g_clear_error(&error);
}
WINTC_SAFE_REF_SET(out_cmdline, g_strdup(cmdline));

View File

@@ -28,6 +28,9 @@ wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-exec WINTC_EXEC)
wintc_resolve_library(wintc-shcommon WINTC_SHCOMMON)
wintc_resolve_library(wintc-shellext WINTC_SHELLEXT)
wintc_resolve_library(wintc-shlang WINTC_SHLANG)
wintc_compile_resources()
add_library(
libwintc-shell
@@ -39,6 +42,7 @@ add_library(
public/error.h
src/icnvwbeh.c
public/icnvwbeh.h
src/resources.c
src/trevwbeh.c
public/trevwbeh.h
src/nmspace.c
@@ -76,6 +80,7 @@ target_include_directories(
PRIVATE ${WINTC_EXEC_INCLUDE_DIRS}
PRIVATE ${WINTC_SHCOMMON_INCLUDE_DIRS}
PRIVATE ${WINTC_SHELLEXT_INCLUDE_DIRS}
PRIVATE ${WINTC_SHLANG_INCLUDE_DIRS}
)
target_link_directories(
@@ -87,6 +92,7 @@ target_link_directories(
PRIVATE ${WINTC_EXEC_LIBRARY_DIRS}
PRIVATE ${WINTC_SHCOMMON_LIBRARY_DIRS}
PRIVATE ${WINTC_SHELLEXT_LIBRARY_DIRS}
PRIVATE ${WINTC_SHLANG_LIBRARY_DIRS}
)
target_link_libraries(
@@ -98,6 +104,7 @@ target_link_libraries(
PRIVATE ${WINTC_EXEC_LIBRARIES}
PRIVATE ${WINTC_SHCOMMON_LIBRARIES}
PRIVATE ${WINTC_SHELLEXT_LIBRARIES}
PRIVATE ${WINTC_SHLANG_LIBRARIES}
)
# Installation

View File

@@ -1,6 +1,7 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc/comgtk.h>
#include <wintc/shlang.h>
#include "../public/browser.h"
#include "../public/icnvwbeh.h"
@@ -30,12 +31,38 @@ static void wintc_sh_icon_view_behaviour_set_property(
GParamSpec* pspec
);
static void action_view_operation(
GSimpleAction* action,
GVariant* parameter,
gpointer user_data
);
static gboolean on_icon_view_button_press_event(
GtkIconView* self,
GdkEventButton* event,
gpointer user_data
);
static void on_icon_view_item_activated(
GtkIconView* self,
GtkTreePath* path,
gpointer user_data
);
//
// STATIC DATA
//
static GSimpleAction* s_action_noop = NULL;
static GActionEntry s_actions[] = {
{
.name = "view-op",
.activate = action_view_operation,
.parameter_type = "i",
.state = NULL,
.change_state = NULL
}
};
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
@@ -115,6 +142,40 @@ static void wintc_sh_icon_view_behaviour_constructed(
return;
}
// Define GActions
//
GSimpleActionGroup* action_group = g_simple_action_group_new();
if (!s_action_noop)
{
s_action_noop =
g_simple_action_new("no-op", NULL);
g_simple_action_set_enabled(
s_action_noop,
FALSE
);
}
g_action_map_add_action_entries(
G_ACTION_MAP(action_group),
s_actions,
G_N_ELEMENTS(s_actions),
behaviour
);
g_action_map_add_action(
G_ACTION_MAP(action_group),
G_ACTION(s_action_noop)
);
gtk_widget_insert_action_group(
behaviour->icon_view,
"control",
G_ACTION_GROUP(action_group)
);
g_object_unref(action_group);
// Attach stuff to view
//
gtk_icon_view_set_model(
@@ -130,8 +191,19 @@ static void wintc_sh_icon_view_behaviour_constructed(
1
);
gtk_icon_view_set_selection_mode(
GTK_ICON_VIEW(behaviour->icon_view),
GTK_SELECTION_MULTIPLE
);
// Attach signals
//
g_signal_connect(
behaviour->icon_view,
"button-press-event",
G_CALLBACK(on_icon_view_button_press_event),
behaviour
);
g_signal_connect(
behaviour->icon_view,
"item-activated",
@@ -150,6 +222,13 @@ static void wintc_sh_icon_view_behaviour_dispose(
WinTCShIconViewBehaviour* behaviour =
WINTC_SH_ICON_VIEW_BEHAVIOUR(object);
// Cheeky? Deselect items from the icon view, otherwise it might throw
// GTK-Critical errors during destruction (?)
//
gtk_icon_view_unselect_all(
GTK_ICON_VIEW(behaviour->icon_view)
);
g_clear_object(&(behaviour->browser));
g_clear_object(&(behaviour->icon_view));
@@ -204,6 +283,266 @@ WinTCShIconViewBehaviour* wintc_sh_icon_view_behaviour_new(
//
// CALLBACKS
//
static void action_view_operation(
WINTC_UNUSED(GSimpleAction* action),
GVariant* parameter,
gpointer user_data
)
{
WinTCShIconViewBehaviour* behaviour =
WINTC_SH_ICON_VIEW_BEHAVIOUR(user_data);
WINTC_LOG_DEBUG("op selected: %d", g_variant_get_int32(parameter));
// Prepare items - need to convert the selected items to their hashes
//
GList* item_hashes = NULL;
GtkTreeModel* model = gtk_icon_view_get_model(
GTK_ICON_VIEW(behaviour->icon_view)
);
GList* selected_items = gtk_icon_view_get_selected_items(
GTK_ICON_VIEW(behaviour->icon_view)
);
GtkTreeIter tree_iter;
for (GList* iter = selected_items; iter; iter = iter->next)
{
guint hash;
gtk_tree_model_get_iter(
model,
&tree_iter,
(GtkTreePath*) iter->data
);
gtk_tree_model_get(
model,
&tree_iter,
2, &hash,
-1
);
WINTC_LOG_DEBUG("shell: icnvw - append item to op: %u", hash);
item_hashes =
g_list_prepend(
item_hashes,
GUINT_TO_POINTER(hash)
);
}
item_hashes = g_list_reverse(item_hashes);
g_list_free_full(
selected_items,
(GDestroyNotify) gtk_tree_path_free
);
// Ask the view to spawn the operation
//
GError* error = NULL;
WinTCShextOperation* operation;
gint operation_id = g_variant_get_int32(parameter);
WinTCIShextView* view = wintc_sh_browser_get_current_view(
behaviour->browser
);
operation =
wintc_ishext_view_spawn_operation(
view,
operation_id,
item_hashes, // Ownership transferred
&error
);
// g_list_free(item_hashes);
if (!operation)
{
wintc_display_error_and_clear(&error);
return;
}
// Execute!
//
GtkWidget* toplevel = gtk_widget_get_toplevel(behaviour->icon_view);
GtkWindow* wnd = NULL;
if (GTK_IS_WINDOW(toplevel))
{
wnd = GTK_WINDOW(toplevel);
}
if (!(operation->func) (view, operation, wnd, &error))
{
wintc_display_error_and_clear(&error);
}
g_free(operation);
}
static gboolean on_icon_view_button_press_event(
GtkIconView* self,
GdkEventButton* event,
gpointer user_data
)
{
WinTCShIconViewBehaviour* behaviour =
WINTC_SH_ICON_VIEW_BEHAVIOUR(user_data);
if (event->button == GDK_BUTTON_SECONDARY)
{
// We need to update the hit test target ourselves, since this signal
// always runs before the icon view handles clicks
//
gboolean found = FALSE;
GList* selected_items = gtk_icon_view_get_selected_items(self);
GtkTreePath* target_item = gtk_icon_view_get_path_at_pos(
self,
event->x,
event->y
);
if (target_item)
{
// See if the item is in the selected items, otherwise we must
// select this one
//
for (GList* iter = selected_items; iter; iter = iter->next)
{
GtkTreePath* check_item = (GtkTreePath*) iter->data;
if (gtk_tree_path_compare(target_item, check_item) == 0)
{
found = TRUE;
break;
}
}
if (!found)
{
gtk_icon_view_unselect_all(self);
gtk_icon_view_select_path(self, target_item);
}
}
g_list_free_full(
selected_items,
(GDestroyNotify) gtk_tree_path_free
);
// Determine the target...
// the view itself?
// single view item?
// multiple view items?
//
GtkWidget* menu = NULL;
GMenuModel* menu_model = NULL;
if (!target_item) // The view itself
{
menu_model =
wintc_ishext_view_get_operations_for_view(
wintc_sh_browser_get_current_view(
behaviour->browser
)
);
if (menu_model)
{
// We merge the common context menu with this one
//
GtkBuilder* builder;
GMenuModel* menu_model_cmn;
GMenuModel* menu_model_merged;
builder =
gtk_builder_new_from_resource(
"/uk/oddmatics/wintc/shell/menuctx.ui"
);
wintc_lc_builder_preprocess_widget_text(builder);
menu_model_cmn =
G_MENU_MODEL(
g_object_ref(
gtk_builder_get_object(builder, "menu")
)
);
menu_model_merged =
wintc_menu_model_merge(
menu_model_cmn,
menu_model,
NULL
);
// Now create the actual popup menu
//
menu = gtk_menu_new_from_model(menu_model_merged);
g_object_unref(builder);
g_object_unref(menu_model);
g_object_unref(menu_model_cmn);
}
}
else // Item(s)
{
// Always use the menu for the target item, nothing fancy required
//
guint item_hash;
GtkTreeIter iter;
GtkTreeModel* model = gtk_icon_view_get_model(self);
gtk_tree_model_get_iter(
model,
&iter,
target_item
);
gtk_tree_model_get(
model,
&iter,
2, &item_hash,
-1
);
menu_model =
wintc_ishext_view_get_operations_for_item(
wintc_sh_browser_get_current_view(behaviour->browser),
item_hash
);
if (menu_model)
{
menu = gtk_menu_new_from_model(menu_model);
g_object_unref(menu_model);
}
gtk_tree_path_free(target_item);
}
if (menu)
{
gtk_menu_attach_to_widget(
GTK_MENU(menu),
behaviour->icon_view,
NULL
);
gtk_menu_popup_at_pointer(
GTK_MENU(menu),
(GdkEvent*) event
);
}
return GDK_EVENT_STOP;
}
return GDK_EVENT_PROPAGATE;
}
static void on_icon_view_item_activated(
GtkIconView* self,
GtkTreePath* path,

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="menu">
<section>
<item>
<attribute name="label">View</attribute>
</item>
</section>
<section>
<item>
<attribute name="label">Arrange Icons By</attribute>
</item>
<item>
<attribute name="label">Refresh</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="menu">
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Customize This Folder...</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Paste</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Paste Shortcut</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">New</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Properties</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="menu">
<section>
<item>
<attribute name="action">control.view-op</attribute>
<attribute name="label">Open</attribute>
<attribute name="target" type="i">1</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Open With</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Send To</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Cut</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Copy</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Create Shortcut</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Delete</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Rename</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Properties</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="menu">
<section>
<item>
<attribute name="action">control.view-op</attribute>
<attribute name="label">Open</attribute>
<attribute name="target" type="i">1</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Explore</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Search</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Sharing and Security...</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Send To</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Cut</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Copy</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Create Shortcut</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Delete</attribute>
</item>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Rename</attribute>
</item>
</section>
<section>
<item>
<attribute name="action">control.no-op</attribute>
<attribute name="label">Properties</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/uk/oddmatics/wintc/shell">
<!-- MENUS -->
<file>menuctx.ui</file>
<file>menufs.ui</file>
<file>menufslf.ui</file>
<file>menufsvw.ui</file>
</gresource>
</gresources>

View File

@@ -38,22 +38,19 @@ static gboolean wintc_sh_view_cpl_activate_item(
WinTCShextPathInfo* path_info,
GError** error
);
static void wintc_sh_view_cpl_refresh_items(
WinTCIShextView* view
);
static void wintc_sh_view_cpl_get_actions_for_item(
WinTCIShextView* view,
WinTCShextViewItem* item
);
static void wintc_sh_view_cpl_get_actions_for_view(
WinTCIShextView* view
);
static const gchar* wintc_sh_view_cpl_get_display_name(
WinTCIShextView* view
);
static const gchar* wintc_sh_view_cpl_get_icon_name(
WinTCIShextView* view
);
static GMenuModel* wintc_sh_view_cpl_get_operations_for_item(
WinTCIShextView* view,
guint item_hash
);
static GMenuModel* wintc_sh_view_cpl_get_operations_for_view(
WinTCIShextView* view
);
static void wintc_sh_view_cpl_get_parent_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
@@ -68,6 +65,15 @@ static guint wintc_sh_view_cpl_get_unique_hash(
static gboolean wintc_sh_view_cpl_has_parent(
WinTCIShextView* view
);
static void wintc_sh_view_cpl_refresh_items(
WinTCIShextView* view
);
static WinTCShextOperation* wintc_sh_view_cpl_spawn_operation(
WinTCIShextView* view,
gint operation_id,
GList* targets,
GError** error
);
//
// GLIB OOP/CLASS INSTANCE DEFINITIONS
@@ -124,16 +130,17 @@ static void wintc_sh_view_cpl_ishext_view_interface_init(
WinTCIShextViewInterface* iface
)
{
iface->activate_item = wintc_sh_view_cpl_activate_item;
iface->refresh_items = wintc_sh_view_cpl_refresh_items;
iface->get_actions_for_item = wintc_sh_view_cpl_get_actions_for_item;
iface->get_actions_for_view = wintc_sh_view_cpl_get_actions_for_view;
iface->get_display_name = wintc_sh_view_cpl_get_display_name;
iface->get_icon_name = wintc_sh_view_cpl_get_icon_name;
iface->get_parent_path = wintc_sh_view_cpl_get_parent_path;
iface->get_path = wintc_sh_view_cpl_get_path;
iface->get_unique_hash = wintc_sh_view_cpl_get_unique_hash;
iface->has_parent = wintc_sh_view_cpl_has_parent;
iface->activate_item = wintc_sh_view_cpl_activate_item;
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;
iface->get_operations_for_view = wintc_sh_view_cpl_get_operations_for_view;
iface->get_parent_path = wintc_sh_view_cpl_get_parent_path;
iface->get_path = wintc_sh_view_cpl_get_path;
iface->get_unique_hash = wintc_sh_view_cpl_get_unique_hash;
iface->has_parent = wintc_sh_view_cpl_has_parent;
iface->refresh_items = wintc_sh_view_cpl_refresh_items;
iface->spawn_operation = wintc_sh_view_cpl_spawn_operation;
}
//
@@ -216,6 +223,75 @@ static gboolean wintc_sh_view_cpl_activate_item(
return TRUE;
}
static const gchar* wintc_sh_view_cpl_get_display_name(
WINTC_UNUSED(WinTCIShextView* view)
)
{
// FIXME: Localisation
//
return "Control Panel";
}
static const gchar* wintc_sh_view_cpl_get_icon_name(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return "preferences-other";
}
static GMenuModel* wintc_sh_view_cpl_get_operations_for_item(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(guint item_hash)
)
{
g_warning("%s Not Implemented", __func__);
return NULL;
}
static GMenuModel* wintc_sh_view_cpl_get_operations_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
g_warning("%s Not Implemented", __func__);
return NULL;
}
static void wintc_sh_view_cpl_get_parent_path(
WINTC_UNUSED(WinTCIShextView* view),
WinTCShextPathInfo* path_info
)
{
path_info->base_path =
g_strdup(
wintc_sh_get_place_path(WINTC_SH_PLACE_DRIVES)
);
}
static void wintc_sh_view_cpl_get_path(
WINTC_UNUSED(WinTCIShextView* view),
WinTCShextPathInfo* path_info
)
{
path_info->base_path =
g_strdup(
wintc_sh_get_place_path(WINTC_SH_PLACE_CONTROLPANEL)
);
}
static guint wintc_sh_view_cpl_get_unique_hash(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return g_str_hash(wintc_sh_get_place_path(WINTC_SH_PLACE_CONTROLPANEL));
}
static gboolean wintc_sh_view_cpl_has_parent(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return TRUE;
}
static void wintc_sh_view_cpl_refresh_items(
WinTCIShextView* view
)
@@ -280,71 +356,15 @@ static void wintc_sh_view_cpl_refresh_items(
g_list_free(items);
}
static void wintc_sh_view_cpl_get_actions_for_item(
static WinTCShextOperation* wintc_sh_view_cpl_spawn_operation(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(WinTCShextViewItem* item)
WINTC_UNUSED(gint operation_id),
WINTC_UNUSED(GList* targets),
WINTC_UNUSED(GError** error)
)
{
g_critical("%s Not Implemented", __func__);
}
static void wintc_sh_view_cpl_get_actions_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
g_critical("%s Not Implemented", __func__);
}
static const gchar* wintc_sh_view_cpl_get_display_name(
WINTC_UNUSED(WinTCIShextView* view)
)
{
// FIXME: Localisation
//
return "Control Panel";
}
static const gchar* wintc_sh_view_cpl_get_icon_name(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return "preferences-other";
}
static void wintc_sh_view_cpl_get_parent_path(
WINTC_UNUSED(WinTCIShextView* view),
WinTCShextPathInfo* path_info
)
{
path_info->base_path =
g_strdup(
wintc_sh_get_place_path(WINTC_SH_PLACE_DRIVES)
);
}
static void wintc_sh_view_cpl_get_path(
WINTC_UNUSED(WinTCIShextView* view),
WinTCShextPathInfo* path_info
)
{
path_info->base_path =
g_strdup(
wintc_sh_get_place_path(WINTC_SH_PLACE_CONTROLPANEL)
);
}
static guint wintc_sh_view_cpl_get_unique_hash(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return g_str_hash(wintc_sh_get_place_path(WINTC_SH_PLACE_CONTROLPANEL));
}
static gboolean wintc_sh_view_cpl_has_parent(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return TRUE;
g_critical("Not implemented %s", __func__);
return NULL;
}
//

View File

@@ -75,22 +75,19 @@ static gboolean wintc_sh_view_desktop_activate_item(
WinTCShextPathInfo* path_info,
GError** error
);
static void wintc_sh_view_desktop_refresh_items(
WinTCIShextView* view
);
static void wintc_sh_view_desktop_get_actions_for_item(
WinTCIShextView* view,
WinTCShextViewItem* item
);
static void wintc_sh_view_desktop_get_actions_for_view(
WinTCIShextView* view
);
static const gchar* wintc_sh_view_desktop_get_display_name(
WinTCIShextView* view
);
static const gchar* wintc_sh_view_desktop_get_icon_name(
WinTCIShextView* view
);
static GMenuModel* wintc_sh_view_desktop_get_operations_for_item(
WinTCIShextView* view,
guint item_hash
);
static GMenuModel* wintc_sh_view_desktop_get_operations_for_view(
WinTCIShextView* view
);
static void wintc_sh_view_desktop_get_parent_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
@@ -105,6 +102,15 @@ static guint wintc_sh_view_desktop_get_unique_hash(
static gboolean wintc_sh_view_desktop_has_parent(
WinTCIShextView* view
);
static void wintc_sh_view_desktop_refresh_items(
WinTCIShextView* view
);
static WinTCShextOperation* wintc_sh_view_desktop_spawn_operation(
WinTCIShextView* view,
gint operation_id,
GList* targets,
GError** error
);
//
// GLIB OOP CLASS/INSTANCE DEFINITIONS
@@ -190,16 +196,19 @@ static void wintc_sh_view_desktop_ishext_view_interface_init(
WinTCIShextViewInterface* iface
)
{
iface->activate_item = wintc_sh_view_desktop_activate_item;
iface->refresh_items = wintc_sh_view_desktop_refresh_items;
iface->get_actions_for_item = wintc_sh_view_desktop_get_actions_for_item;
iface->get_actions_for_view = wintc_sh_view_desktop_get_actions_for_view;
iface->get_display_name = wintc_sh_view_desktop_get_display_name;
iface->get_icon_name = wintc_sh_view_desktop_get_icon_name;
iface->get_parent_path = wintc_sh_view_desktop_get_parent_path;
iface->get_path = wintc_sh_view_desktop_get_path;
iface->get_unique_hash = wintc_sh_view_desktop_get_unique_hash;
iface->has_parent = wintc_sh_view_desktop_has_parent;
iface->activate_item = wintc_sh_view_desktop_activate_item;
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 =
wintc_sh_view_desktop_get_operations_for_item;
iface->get_operations_for_view =
wintc_sh_view_desktop_get_operations_for_view;
iface->get_parent_path = wintc_sh_view_desktop_get_parent_path;
iface->get_path = wintc_sh_view_desktop_get_path;
iface->get_unique_hash = wintc_sh_view_desktop_get_unique_hash;
iface->has_parent = wintc_sh_view_desktop_has_parent;
iface->refresh_items = wintc_sh_view_desktop_refresh_items;
iface->spawn_operation = wintc_sh_view_desktop_spawn_operation;
}
//
@@ -259,44 +268,6 @@ static gboolean wintc_sh_view_desktop_activate_item(
return TRUE;
}
static void wintc_sh_view_desktop_refresh_items(
WinTCIShextView* view
)
{
WINTC_LOG_DEBUG("%s", "shell: refresh desktop view");
_wintc_ishext_view_refreshing(view);
// Just emit the default items for now
// TODO: Should aggregate with user desktop files
//
WinTCShextViewItemsUpdate update = { 0 };
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(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(WinTCShextViewItem* item)
)
{
g_critical("%s Not Implemented", __func__);
}
static void wintc_sh_view_desktop_get_actions_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
g_critical("%s Not Implemented", __func__);
}
static const gchar* wintc_sh_view_desktop_get_display_name(
WINTC_UNUSED(WinTCIShextView* view)
)
@@ -312,6 +283,23 @@ static const gchar* wintc_sh_view_desktop_get_icon_name(
return "user-desktop";
}
static GMenuModel* wintc_sh_view_desktop_get_operations_for_item(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(guint item_hash)
)
{
g_warning("%s Not Implemented", __func__);
return NULL;
}
static GMenuModel* wintc_sh_view_desktop_get_operations_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
g_warning("%s Not Implemented", __func__);
return NULL;
}
static void wintc_sh_view_desktop_get_parent_path(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(WinTCShextPathInfo* path_info)
@@ -342,6 +330,40 @@ static gboolean wintc_sh_view_desktop_has_parent(
return FALSE;
}
static void wintc_sh_view_desktop_refresh_items(
WinTCIShextView* view
)
{
WINTC_LOG_DEBUG("%s", "shell: refresh desktop view");
_wintc_ishext_view_refreshing(view);
// Just emit the default items for now
// TODO: Should aggregate with user desktop files
//
WinTCShextViewItemsUpdate update = { 0 };
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 WinTCShextOperation* wintc_sh_view_desktop_spawn_operation(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(gint operation_id),
WINTC_UNUSED(GList* targets),
WINTC_UNUSED(GError** error)
)
{
g_critical("Not implemented %s", __func__);
return NULL;
}
//
// PUBLIC FUNCTIONS
//

View File

@@ -48,22 +48,19 @@ static gboolean wintc_sh_view_drives_activate_item(
WinTCShextPathInfo* path_info,
GError** error
);
static void wintc_sh_view_drives_refresh_items(
WinTCIShextView* view
);
static void wintc_sh_view_drives_get_actions_for_item(
WinTCIShextView* view,
WinTCShextViewItem* item
);
static void wintc_sh_view_drives_get_actions_for_view(
WinTCIShextView* view
);
static const gchar* wintc_sh_view_drives_get_display_name(
WinTCIShextView* view
);
static const gchar* wintc_sh_view_drives_get_icon_name(
WinTCIShextView* view
);
static GMenuModel* wintc_sh_view_drives_get_operations_for_item(
WinTCIShextView* view,
guint item_hash
);
static GMenuModel* wintc_sh_view_drives_get_operations_for_view(
WinTCIShextView* view
);
static void wintc_sh_view_drives_get_parent_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
@@ -78,6 +75,15 @@ static guint wintc_sh_view_drives_get_unique_hash(
static gboolean wintc_sh_view_drives_has_parent(
WinTCIShextView* view
);
static void wintc_sh_view_drives_refresh_items(
WinTCIShextView* view
);
static WinTCShextOperation* wintc_sh_view_drives_spawn_operation(
WinTCIShextView* view,
gint operation_id,
GList* targets,
GError** error
);
//
// GLIB OOP/CLASS INSTANCE DEFINITIONS
@@ -154,16 +160,19 @@ static void wintc_sh_view_drives_ishext_view_interface_init(
WinTCIShextViewInterface* iface
)
{
iface->activate_item = wintc_sh_view_drives_activate_item;
iface->refresh_items = wintc_sh_view_drives_refresh_items;
iface->get_actions_for_item = wintc_sh_view_drives_get_actions_for_item;
iface->get_actions_for_view = wintc_sh_view_drives_get_actions_for_view;
iface->get_display_name = wintc_sh_view_drives_get_display_name;
iface->get_icon_name = wintc_sh_view_drives_get_icon_name;
iface->get_parent_path = wintc_sh_view_drives_get_parent_path;
iface->get_path = wintc_sh_view_drives_get_path;
iface->get_unique_hash = wintc_sh_view_drives_get_unique_hash;
iface->has_parent = wintc_sh_view_drives_has_parent;
iface->activate_item = wintc_sh_view_drives_activate_item;
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 =
wintc_sh_view_drives_get_operations_for_item;
iface->get_operations_for_view =
wintc_sh_view_drives_get_operations_for_view;
iface->get_parent_path = wintc_sh_view_drives_get_parent_path;
iface->get_path = wintc_sh_view_drives_get_path;
iface->get_unique_hash = wintc_sh_view_drives_get_unique_hash;
iface->has_parent = wintc_sh_view_drives_has_parent;
iface->refresh_items = wintc_sh_view_drives_refresh_items;
iface->spawn_operation = wintc_sh_view_drives_spawn_operation;
}
//
@@ -219,44 +228,6 @@ static gboolean wintc_sh_view_drives_activate_item(
return TRUE;
}
static void wintc_sh_view_drives_refresh_items(
WinTCIShextView* view
)
{
WINTC_LOG_DEBUG("%s", "shell: refresh drives view");
_wintc_ishext_view_refreshing(view);
// Emit only the root '/' for now
// TODO: Basically everything in My Computer!
//
WinTCShextViewItemsUpdate update = { 0 };
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(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(WinTCShextViewItem* item)
)
{
g_critical("%s Not Implemented", __func__);
}
static void wintc_sh_view_drives_get_actions_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
g_critical("%s Not Implemented", __func__);
}
static const gchar* wintc_sh_view_drives_get_display_name(
WINTC_UNUSED(WinTCIShextView* view)
)
@@ -273,6 +244,23 @@ static const gchar* wintc_sh_view_drives_get_icon_name(
return "computer";
}
static GMenuModel* wintc_sh_view_drives_get_operations_for_item(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(guint item_hash)
)
{
g_warning("%s Not Implemented", __func__);
return NULL;
}
static GMenuModel* wintc_sh_view_drives_get_operations_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
g_warning("%s Not Implemented", __func__);
return NULL;
}
static void wintc_sh_view_drives_get_parent_path(
WINTC_UNUSED(WinTCIShextView* view),
WinTCShextPathInfo* path_info
@@ -309,6 +297,40 @@ static gboolean wintc_sh_view_drives_has_parent(
return TRUE;
}
static void wintc_sh_view_drives_refresh_items(
WinTCIShextView* view
)
{
WINTC_LOG_DEBUG("%s", "shell: refresh drives view");
_wintc_ishext_view_refreshing(view);
// Emit only the root '/' for now
// TODO: Basically everything in My Computer!
//
WinTCShextViewItemsUpdate update = { 0 };
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 WinTCShextOperation* wintc_sh_view_drives_spawn_operation(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(gint operation_id),
WINTC_UNUSED(GList* targets),
WINTC_UNUSED(GError** error)
)
{
g_critical("Not implemented %s", __func__);
return NULL;
}
//
// PUBLIC FUNCTIONS
//

View File

@@ -4,6 +4,7 @@
#include <wintc/exec.h>
#include <wintc/shcommon.h>
#include <wintc/shellext.h>
#include <wintc/shlang.h>
#include "../public/vwfs.h"
@@ -49,16 +50,6 @@ static gboolean wintc_sh_view_fs_activate_item(
WinTCShextPathInfo* path_info,
GError** error
);
static void wintc_sh_view_fs_refresh_items(
WinTCIShextView* view
);
static void wintc_sh_view_fs_get_actions_for_item(
WinTCIShextView* view,
WinTCShextViewItem* item
);
static void wintc_sh_view_fs_get_actions_for_view(
WinTCIShextView* view
);
static guint wintc_sh_view_fs_get_unique_hash(
WinTCIShextView* view
);
@@ -68,6 +59,13 @@ static const gchar* wintc_sh_view_fs_get_display_name(
static const gchar* wintc_sh_view_fs_get_icon_name(
WinTCIShextView* view
);
static GMenuModel* wintc_sh_view_fs_get_operations_for_item(
WinTCIShextView* view,
guint item_hash
);
static GMenuModel* wintc_sh_view_fs_get_operations_for_view(
WinTCIShextView* view
);
static void wintc_sh_view_fs_get_parent_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
@@ -79,11 +77,34 @@ static void wintc_sh_view_fs_get_path(
static gboolean wintc_sh_view_fs_has_parent(
WinTCIShextView* view
);
static void wintc_sh_view_fs_refresh_items(
WinTCIShextView* view
);
static WinTCShextOperation* wintc_sh_view_fs_spawn_operation(
WinTCIShextView* view,
gint operation_id,
GList* targets,
GError** error
);
static void clear_view_item(
WinTCShextViewItem* item
);
static gboolean real_activate_item(
WinTCShViewFS* view_fs,
WinTCShextViewItem* item,
WinTCShextPathInfo* path_info,
GError** error
);
static gboolean shopr_open(
WinTCIShextView* view,
WinTCShextOperation* operation,
GtkWindow* wnd,
GError** error
);
static void on_file_monitor_changed(
GFileMonitor* self,
GFile* file,
@@ -177,16 +198,17 @@ static void wintc_sh_view_fs_ishext_view_interface_init(
WinTCIShextViewInterface* iface
)
{
iface->activate_item = wintc_sh_view_fs_activate_item;
iface->refresh_items = wintc_sh_view_fs_refresh_items;
iface->get_actions_for_item = wintc_sh_view_fs_get_actions_for_item;
iface->get_actions_for_view = wintc_sh_view_fs_get_actions_for_view;
iface->get_display_name = wintc_sh_view_fs_get_display_name;
iface->get_icon_name = wintc_sh_view_fs_get_icon_name;
iface->get_parent_path = wintc_sh_view_fs_get_parent_path;
iface->get_path = wintc_sh_view_fs_get_path;
iface->get_unique_hash = wintc_sh_view_fs_get_unique_hash;
iface->has_parent = wintc_sh_view_fs_has_parent;
iface->activate_item = wintc_sh_view_fs_activate_item;
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;
iface->get_operations_for_view = wintc_sh_view_fs_get_operations_for_view;
iface->get_parent_path = wintc_sh_view_fs_get_parent_path;
iface->get_path = wintc_sh_view_fs_get_path;
iface->get_unique_hash = wintc_sh_view_fs_get_unique_hash;
iface->has_parent = wintc_sh_view_fs_has_parent;
iface->refresh_items = wintc_sh_view_fs_refresh_items;
iface->spawn_operation = wintc_sh_view_fs_spawn_operation;
}
//
@@ -295,8 +317,7 @@ static gboolean wintc_sh_view_fs_activate_item(
GError** error
)
{
GError* local_error = NULL;
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
WINTC_SAFE_REF_CLEAR(error);
@@ -318,51 +339,160 @@ static gboolean wintc_sh_view_fs_activate_item(
return FALSE;
}
// Retrieve MIME for the item
//
gchar* next_path = g_build_path(
G_DIR_SEPARATOR_S,
view_fs->path,
item->display_name,
NULL
);
gchar* mime_type = wintc_query_mime_for_file(
next_path,
&local_error
);
return real_activate_item(
view_fs,
item,
path_info,
error
);
}
if (!mime_type)
static const gchar* wintc_sh_view_fs_get_display_name(
WinTCIShextView* view
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
if (g_strcmp0(view_fs->path, "/") == 0)
{
g_propagate_error(error, local_error);
return FALSE;
return view_fs->path;
}
// Handle the item based on MIME, if it's a directory then we can set that
// as our next location - otherwise, it depends if there is a shell
// extension for handling the MIME type or not
// FIXME: This could be broken if the path itself contains an escaped dir
// separator, cba for now
//
if (g_strcmp0(mime_type, "inode/directory") == 0)
return g_strrstr(view_fs->path, G_DIR_SEPARATOR_S) + 1;
}
static const gchar* wintc_sh_view_fs_get_icon_name(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return "inode-directory";
}
static GMenuModel* wintc_sh_view_fs_get_operations_for_item(
WinTCIShextView* view,
guint item_hash
)
{
// Retrieve the view item itself
//
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)
);
if (!view_item)
{
path_info->base_path = g_strdup_printf("file://%s", next_path);
g_critical("%s", "shell: fs - no such item for menu");
return NULL;
}
// FIXME: Extremely simplistic for now, does not cover shell extensions or
// anything!
//
GtkBuilder* builder;
GMenuModel* menu;
builder =
gtk_builder_new_from_resource(
view_item->is_leaf ?
"/uk/oddmatics/wintc/shell/menufslf.ui" :
"/uk/oddmatics/wintc/shell/menufsvw.ui"
);
wintc_lc_builder_preprocess_widget_text(builder);
menu =
G_MENU_MODEL(
g_object_ref(
gtk_builder_get_object(builder, "menu")
)
);
g_object_unref(builder);
return menu;
}
static GMenuModel* wintc_sh_view_fs_get_operations_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
GtkBuilder* builder;
GMenuModel* menu;
builder =
gtk_builder_new_from_resource(
"/uk/oddmatics/wintc/shell/menufs.ui"
);
wintc_lc_builder_preprocess_widget_text(builder);
menu =
G_MENU_MODEL(
g_object_ref(
gtk_builder_get_object(builder, "menu")
)
);
g_object_unref(builder);
return menu;
}
static void wintc_sh_view_fs_get_parent_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
if (view_fs->parent_path)
{
path_info->base_path =
g_strdup_printf("file://%s", view_fs->parent_path);
}
else
{
if (wintc_shext_host_has_view_for_mime(view_fs->shext_host, mime_type))
{
path_info->base_path = g_strdup_printf("file://%s", next_path);
}
else
{
if (!wintc_launch_command(next_path, &local_error))
{
g_propagate_error(error, local_error);
}
}
path_info->base_path =
g_strdup(
wintc_sh_get_place_path(
WINTC_SH_PLACE_DRIVES
)
);
}
}
g_free(mime_type);
g_free(next_path);
static void wintc_sh_view_fs_get_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
path_info->base_path =
g_strdup_printf("file://%s", view_fs->path);
}
static guint wintc_sh_view_fs_get_unique_hash(
WinTCIShextView* view
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
return g_str_hash(view_fs->path);
}
static gboolean wintc_sh_view_fs_has_parent(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return TRUE;
}
@@ -478,93 +608,37 @@ static void wintc_sh_view_fs_refresh_items(
g_list_free(items);
}
static void wintc_sh_view_fs_get_actions_for_item(
static WinTCShextOperation* wintc_sh_view_fs_spawn_operation(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(WinTCShextViewItem* item)
gint operation_id,
GList* targets,
WINTC_UNUSED(GError** error)
)
{
g_critical("%s Not Implemented", __func__);
}
static void wintc_sh_view_fs_get_actions_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
g_critical("%s Not Implemented", __func__);
}
static const gchar* wintc_sh_view_fs_get_display_name(
WinTCIShextView* view
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
if (g_strcmp0(view_fs->path, "/") == 0)
if (operation_id > WINTC_SHEXT_KNOWN_OP_OPEN)
{
return view_fs->path;
g_critical("Not implemented %s", __func__);
return NULL;
}
// FIXME: This could be broken if the path itself contains an escaped dir
// separator, cba for now
// Spawn op
//
return g_strrstr(view_fs->path, G_DIR_SEPARATOR_S) + 1;
}
WinTCShextOperation* ret = g_new(WinTCShextOperation, 1);
static const gchar* wintc_sh_view_fs_get_icon_name(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return "inode-directory";
}
static void wintc_sh_view_fs_get_parent_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
if (view_fs->parent_path)
switch (operation_id)
{
path_info->base_path =
g_strdup_printf("file://%s", view_fs->parent_path);
case WINTC_SHEXT_KNOWN_OP_OPEN:
ret->func = shopr_open;
ret->priv = targets;
break;
default:
g_free(ret);
g_critical("%s", "shell: fs - invalid op");
return NULL;
}
else
{
path_info->base_path =
g_strdup(
wintc_sh_get_place_path(
WINTC_SH_PLACE_DRIVES
)
);
}
}
static void wintc_sh_view_fs_get_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
path_info->base_path =
g_strdup_printf("file://%s", view_fs->path);
}
static guint wintc_sh_view_fs_get_unique_hash(
WinTCIShextView* view
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
return g_str_hash(view_fs->path);
}
static gboolean wintc_sh_view_fs_has_parent(
WINTC_UNUSED(WinTCIShextView* view)
)
{
return TRUE;
return ret;
}
//
@@ -596,6 +670,136 @@ static void clear_view_item(
g_free(item);
}
static gboolean real_activate_item(
WinTCShViewFS* view_fs,
WinTCShextViewItem* item,
WinTCShextPathInfo* path_info,
GError** error
)
{
// If the target is a dir or has a shell extension then set that as
// the target path
//
gchar* next_path = g_build_path(
G_DIR_SEPARATOR_S,
view_fs->path,
item->display_name,
NULL
);
gchar* target_path = NULL;
if (!(item->is_leaf))
{
target_path = g_strdup_printf("file://%s", next_path);
}
else
{
gchar* mime_type = wintc_query_mime_for_file(next_path, error);
if (!mime_type)
{
g_free(next_path);
return FALSE;
}
if (wintc_shext_host_has_view_for_mime(view_fs->shext_host, mime_type))
{
target_path = g_strdup_printf("file://%s", next_path);
}
}
// If there is a target path, then either navigate there, or open a new
// window to navigate there
//
// Otherwise just run the command
//
gboolean success = TRUE;
if (target_path)
{
if (path_info)
{
path_info->base_path = target_path;
}
else
{
success = wintc_launch_command(target_path, error);
g_free(target_path);
}
}
else
{
success = wintc_launch_command(next_path, error);
}
g_free(next_path);
return success;
}
static gboolean shopr_open(
WinTCIShextView* view,
WinTCShextOperation* operation,
WINTC_UNUSED(GtkWindow* wnd),
GError** error
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
GList* targets = operation->priv;
if (!targets)
{
g_warning("%s", "shell: fs open op - no files specified?");
return TRUE;
}
// Iterate over to activate the items
//
GError* local_error = NULL;
gboolean success = TRUE;
for (GList* iter = targets; iter; iter = iter->next)
{
WinTCShextViewItem* item =
g_hash_table_lookup(
view_fs->fs_map_entries,
iter->data
);
if (!item)
{
continue;
}
// Valid - attempt launch
//
// Only store the first error
//
if (
!real_activate_item(
view_fs,
item,
NULL,
local_error ? NULL : &local_error
)
)
{
success = FALSE;
}
}
if (!success && local_error)
{
g_propagate_error(error, local_error);
}
g_list_free(targets);
return success;
}
static void on_file_monitor_changed(
WINTC_UNUSED(GFileMonitor* self),
GFile* file,

View File

@@ -41,6 +41,7 @@ add_library(
src/if_view.c
public/if_view.h
public/viewitem.h
public/viewops.h
)
set_target_properties(

View File

@@ -7,6 +7,7 @@
#include <gtk/gtk.h>
#include "viewitem.h"
#include "viewops.h"
//
// PUBLIC STRUCTURES
@@ -41,20 +42,19 @@ struct _WinTCIShextViewInterface
GError** error
);
void (*get_actions_for_item) (
WinTCIShextView* view,
WinTCShextViewItem* item
);
void (*get_actions_for_view) (
WinTCIShextView* view
);
const gchar* (*get_display_name) (
WinTCIShextView* view
);
const gchar* (*get_icon_name) (
WinTCIShextView* view
);
GMenuModel* (*get_operations_for_item) (
WinTCIShextView* view,
guint item_hash
);
GMenuModel* (*get_operations_for_view) (
WinTCIShextView* view
);
void (*get_parent_path) (
WinTCIShextView* view,
WinTCShextPathInfo* path_info
@@ -73,6 +73,13 @@ struct _WinTCIShextViewInterface
void (*refresh_items) (
WinTCIShextView* view
);
WinTCShextOperation* (*spawn_operation) (
WinTCIShextView* view,
gint operation_id,
GList* targets,
GError** error
);
};
//
@@ -89,20 +96,19 @@ void wintc_ishext_view_refresh_items(
WinTCIShextView* view
);
void wintc_ishext_view_get_actions_for_item(
WinTCIShextView* view,
WinTCShextViewItem* item
);
void wintc_ishext_view_get_actions_for_view(
WinTCIShextView* view
);
const gchar* wintc_ishext_view_get_display_name(
WinTCIShextView* view
);
const gchar* wintc_ishext_view_get_icon_name(
WinTCIShextView* view
);
GMenuModel* wintc_ishext_view_get_operations_for_item(
WinTCIShextView* view,
guint item_hash
);
GMenuModel* wintc_ishext_view_get_operations_for_view(
WinTCIShextView* view
);
void wintc_ishext_view_get_parent_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
@@ -117,6 +123,12 @@ guint wintc_ishext_view_get_unique_hash(
gboolean wintc_ishext_view_has_parent(
WinTCIShextView* view
);
WinTCShextOperation* wintc_ishext_view_spawn_operation(
WinTCIShextView* view,
gint operation_id,
GList* targets,
GError** error
);
//
// PUBLIC FUNCTIONS

View File

@@ -6,5 +6,6 @@
#include "@LIB_HEADER_DIR@/host.h"
#include "@LIB_HEADER_DIR@/if_view.h"
#include "@LIB_HEADER_DIR@/viewitem.h"
#include "@LIB_HEADER_DIR@/viewops.h"
#endif

View File

@@ -0,0 +1,62 @@
/** @file */
#ifndef __SHELLEXT_VIEWOPS_H__
#define __SHELLEXT_VIEWOPS_H__
#include <glib.h>
//
// FORWARD DECLARATIONS
//
typedef struct _WinTCIShextView WinTCIShextView;
typedef struct _WinTCShextOperation WinTCShextOperation;
//
// PUBLIC ENUMS
//
typedef enum
{
WINTC_SHEXT_OP_PRIORITY_NONE,
WINTC_SHEXT_OP_PRIORITY_PRIMARY,
WINTC_SHEXT_OP_PRIORITY_SECONDARY
} WinTCShextOperationPriority;
typedef enum
{
WINTC_SHEXT_OP_INVALID = 0,
WINTC_SHEXT_KNOWN_OP_OPEN = 1,
WINTC_SHEXT_KNOWN_OP_OPEN_WITH,
WINTC_SHEXT_KNOWN_OP_RUN_AS,
WINTC_SHEXT_KNOWN_OP_CUT,
WINTC_SHEXT_KNOWN_OP_COPY,
WINTC_SHEXT_KNOWN_OP_PASTE,
WINTC_SHEXT_KNOWN_OP_PASTE_SHORTCUT,
WINTC_SHEXT_KNOWN_OP_CREATE_SHORTCUT,
WINTC_SHEXT_KNOWN_OP_DELETE,
WINTC_SHEXT_KNOWN_OP_RENAME,
WINTC_SHEXT_KNOWN_OP_SEND_TO,
WINTC_SHEXT_KNOWN_OP_MOVE_TO,
WINTC_SHEXT_KNOWN_OP_COPY_TO,
WINTC_SHEXT_KNOWN_OP_PROPERTIES,
WINTC_SHEXT_OP_CUSTOM = 100
} WinTCShextOperationId;
//
// PUBLIC STRUCTURES
//
typedef gboolean (*WinTCShextOperationFunc) (
WinTCIShextView* view,
WinTCShextOperation* operation,
GtkWindow* wnd,
GError** error
);
struct _WinTCShextOperation
{
WinTCShextOperationFunc func;
gpointer priv;
};
#endif

View File

@@ -107,27 +107,6 @@ gboolean wintc_ishext_view_activate_item(
);
}
void wintc_ishext_view_get_actions_for_item(
WinTCIShextView* view,
WinTCShextViewItem* item
)
{
WinTCIShextViewInterface* iface =
WINTC_ISHEXT_VIEW_GET_IFACE(view);
iface->get_actions_for_item(view, item);
}
void wintc_ishext_view_get_actions_for_view(
WinTCIShextView* view
)
{
WinTCIShextViewInterface* iface =
WINTC_ISHEXT_VIEW_GET_IFACE(view);
iface->get_actions_for_view(view);
}
const gchar* wintc_ishext_view_get_display_name(
WinTCIShextView* view
)
@@ -148,6 +127,27 @@ const gchar* wintc_ishext_view_get_icon_name(
return iface->get_icon_name(view);
}
GMenuModel* wintc_ishext_view_get_operations_for_item(
WinTCIShextView* view,
guint item_hash
)
{
WinTCIShextViewInterface* iface =
WINTC_ISHEXT_VIEW_GET_IFACE(view);
return iface->get_operations_for_item(view, item_hash);
}
GMenuModel* wintc_ishext_view_get_operations_for_view(
WinTCIShextView* view
)
{
WinTCIShextViewInterface* iface =
WINTC_ISHEXT_VIEW_GET_IFACE(view);
return iface->get_operations_for_view(view);
}
void wintc_ishext_view_get_parent_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
@@ -200,6 +200,24 @@ void wintc_ishext_view_refresh_items(
iface->refresh_items(view);
}
WinTCShextOperation* wintc_ishext_view_spawn_operation(
WinTCIShextView* view,
gint operation_id,
GList* targets,
GError** error
)
{
WinTCIShextViewInterface* iface =
WINTC_ISHEXT_VIEW_GET_IFACE(view);
return iface->spawn_operation(
view,
operation_id,
targets,
error
);
}
//
// PUBLIC FUNCTIONS
//

View File

@@ -48,22 +48,19 @@ static gboolean wintc_cpl_view_printers_activate_item(
WinTCShextPathInfo* path_info,
GError** error
);
static void wintc_cpl_view_printers_refresh_items(
WinTCIShextView* view
);
static void wintc_cpl_view_printers_get_actions_for_item(
WinTCIShextView* view,
WinTCShextViewItem* item
);
static void wintc_cpl_view_printers_get_actions_for_view(
WinTCIShextView* view
);
static const gchar* wintc_cpl_view_printers_get_display_name(
WinTCIShextView* view
);
static const gchar* wintc_cpl_view_printers_get_icon_name(
WinTCIShextView* view
);
static GMenuModel* wintc_cpl_view_printers_get_operations_for_item(
WinTCIShextView* view,
guint item_hash
);
static GMenuModel* wintc_cpl_view_printers_get_operations_for_view(
WinTCIShextView* view
);
static void wintc_cpl_view_printers_get_parent_path(
WinTCIShextView* view,
WinTCShextPathInfo* path_info
@@ -78,6 +75,9 @@ static guint wintc_cpl_view_printers_get_unique_hash(
static gboolean wintc_cpl_view_printers_has_parent(
WinTCIShextView* view
);
static void wintc_cpl_view_printers_refresh_items(
WinTCIShextView* view
);
//
// GLIB OOP/CLASS INSTANCE DEFINITIONS
@@ -145,16 +145,18 @@ static void wintc_cpl_view_printers_ishext_view_interface_init(
WinTCIShextViewInterface* iface
)
{
iface->activate_item = wintc_cpl_view_printers_activate_item;
iface->refresh_items = wintc_cpl_view_printers_refresh_items;
iface->get_actions_for_item = wintc_cpl_view_printers_get_actions_for_item;
iface->get_actions_for_view = wintc_cpl_view_printers_get_actions_for_view;
iface->get_display_name = wintc_cpl_view_printers_get_display_name;
iface->get_icon_name = wintc_cpl_view_printers_get_icon_name;
iface->get_parent_path = wintc_cpl_view_printers_get_parent_path;
iface->get_path = wintc_cpl_view_printers_get_path;
iface->get_unique_hash = wintc_cpl_view_printers_get_unique_hash;
iface->has_parent = wintc_cpl_view_printers_has_parent;
iface->activate_item = wintc_cpl_view_printers_activate_item;
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 =
wintc_cpl_view_printers_get_operations_for_item;
iface->get_operations_for_view =
wintc_cpl_view_printers_get_operations_for_view;
iface->get_parent_path = wintc_cpl_view_printers_get_parent_path;
iface->get_path = wintc_cpl_view_printers_get_path;
iface->get_unique_hash = wintc_cpl_view_printers_get_unique_hash;
iface->has_parent = wintc_cpl_view_printers_has_parent;
iface->refresh_items = wintc_cpl_view_printers_refresh_items;
}
//
@@ -199,42 +201,21 @@ static gboolean wintc_cpl_view_printers_activate_item(
return FALSE;
}
static void wintc_cpl_view_printers_refresh_items(
WinTCIShextView* view
static GMenuModel* wintc_cpl_view_printers_get_operations_for_item(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(guint item_hash)
)
{
WINTC_LOG_DEBUG("%s", "cpl-prntrs: refresh printers view");
_wintc_ishext_view_refreshing(view);
// Emit the FPO printer for now
// TODO: Implement this!
//
WinTCShextViewItemsUpdate update = { 0 };
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);
g_warning("%s Not Implemented", __func__);
return NULL;
}
static void wintc_cpl_view_printers_get_actions_for_item(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(WinTCShextViewItem* item)
)
{
g_critical("%s Not Implemented", __func__);
}
static void wintc_cpl_view_printers_get_actions_for_view(
static GMenuModel* wintc_cpl_view_printers_get_operations_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
g_critical("%s Not Implemented", __func__);
g_warning("%s Not Implemented", __func__);
return NULL;
}
static const gchar* wintc_cpl_view_printers_get_display_name(
@@ -289,6 +270,29 @@ static gboolean wintc_cpl_view_printers_has_parent(
return TRUE;
}
static void wintc_cpl_view_printers_refresh_items(
WinTCIShextView* view
)
{
WINTC_LOG_DEBUG("%s", "cpl-prntrs: refresh printers view");
_wintc_ishext_view_refreshing(view);
// Emit the FPO printer for now
// TODO: Implement this!
//
WinTCShextViewItemsUpdate update = { 0 };
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);
}
//
// PUBLIC FUNCTIONS
//

View File

@@ -45,14 +45,11 @@ static gboolean wintc_view_zip_activate_item(
WinTCShextPathInfo* path_info,
GError** error
);
static void wintc_view_zip_refresh_items(
WinTCIShextView* view
static GMenuModel* wintc_view_zip_get_operations_for_item(
WinTCIShextView* view,
guint item_hash
);
static void wintc_view_zip_get_actions_for_item(
WinTCIShextView* view,
WinTCShextViewItem* item
);
static void wintc_view_zip_get_actions_for_view(
static GMenuModel* wintc_view_zip_get_operations_for_view(
WinTCIShextView* view
);
static const gchar* wintc_view_zip_get_display_name(
@@ -75,6 +72,9 @@ static guint wintc_view_zip_get_unique_hash(
static gboolean wintc_view_zip_has_parent(
WinTCIShextView* view
);
static void wintc_view_zip_refresh_items(
WinTCIShextView* view
);
static guint zip_entry_hash(
const gchar* zip_file_path,
@@ -172,16 +172,16 @@ static void wintc_view_zip_ishext_view_interface_init(
WinTCIShextViewInterface* iface
)
{
iface->activate_item = wintc_view_zip_activate_item;
iface->refresh_items = wintc_view_zip_refresh_items;
iface->get_actions_for_item = wintc_view_zip_get_actions_for_item;
iface->get_actions_for_view = wintc_view_zip_get_actions_for_view;
iface->get_display_name = wintc_view_zip_get_display_name;
iface->get_icon_name = wintc_view_zip_get_icon_name;
iface->get_parent_path = wintc_view_zip_get_parent_path;
iface->get_path = wintc_view_zip_get_path;
iface->get_unique_hash = wintc_view_zip_get_unique_hash;
iface->has_parent = wintc_view_zip_has_parent;
iface->activate_item = wintc_view_zip_activate_item;
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;
iface->get_icon_name = wintc_view_zip_get_icon_name;
iface->get_parent_path = wintc_view_zip_get_parent_path;
iface->get_path = wintc_view_zip_get_path;
iface->get_unique_hash = wintc_view_zip_get_unique_hash;
iface->has_parent = wintc_view_zip_has_parent;
iface->refresh_items = wintc_view_zip_refresh_items;
}
//
@@ -312,120 +312,21 @@ static gboolean wintc_view_zip_activate_item(
return FALSE;
}
static void wintc_view_zip_refresh_items(
WinTCIShextView* view
static GMenuModel* wintc_view_zip_get_operations_for_item(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(guint item_hash)
)
{
WinTCViewZip* view_zip = WINTC_VIEW_ZIP(view);
WINTC_LOG_DEBUG("%s", "shext-zip: refresh zip view");
_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://");
gint zip_error = 0;
zip_t* zip_file = zip_open(path, 0, &zip_error);
if (!zip_file)
{
zip_error_t zip_error_st;
zip_error_init_with_code(&zip_error_st, zip_error);
// FIXME: Need a proper way of returning error to caller!
g_critical(
"shext-zip: can't open %s , %s",
path,
zip_error_strerror(&zip_error_st)
);
zip_error_fini(&zip_error_st);
return;
}
// Read through the entries
// 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);
for (gint64 i = 0; i < n_entries; i++)
{
const gchar* entry_name = zip_get_name(zip_file, (guint64) i, 0);
// Only want to add the entries in the current relative dir
//
gint name_offset = 0;
if (!zip_entry_is_in_dir(view_zip->rel_path, entry_name, &name_offset))
{
continue;
}
gchar* entry_copy = g_strdup(entry_name);
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);
item->icon_name = item->is_leaf ? "empty" : "inode-directory";
item->hash = zip_entry_hash(path, entry_name);
item->priv = entry_copy;
g_hash_table_insert(
view_zip->map_items,
GUINT_TO_POINTER(item->hash),
item
);
}
zip_close(zip_file);
// Emit the entries
//
WinTCShextViewItemsUpdate update = { 0 };
GList* items = g_hash_table_get_values(view_zip->map_items);
update.data = items;
update.done = TRUE;
_wintc_ishext_view_items_added(view, &update);
g_list_free(items);
g_warning("%s Not Implemented", __func__);
return NULL;
}
static void wintc_view_zip_get_actions_for_item(
WINTC_UNUSED(WinTCIShextView* view),
WINTC_UNUSED(WinTCShextViewItem* item)
)
{
g_critical("%s Not Implemented", __func__);
}
static void wintc_view_zip_get_actions_for_view(
static GMenuModel* wintc_view_zip_get_operations_for_view(
WINTC_UNUSED(WinTCIShextView* view)
)
{
g_critical("%s Not Implemented", __func__);
g_warning("%s Not Implemented", __func__);
return NULL;
}
static const gchar* wintc_view_zip_get_display_name(
@@ -562,6 +463,107 @@ static gboolean wintc_view_zip_has_parent(
return TRUE;
}
static void wintc_view_zip_refresh_items(
WinTCIShextView* view
)
{
WinTCViewZip* view_zip = WINTC_VIEW_ZIP(view);
WINTC_LOG_DEBUG("%s", "shext-zip: refresh zip view");
_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://");
gint zip_error = 0;
zip_t* zip_file = zip_open(path, 0, &zip_error);
if (!zip_file)
{
zip_error_t zip_error_st;
zip_error_init_with_code(&zip_error_st, zip_error);
// FIXME: Need a proper way of returning error to caller!
g_critical(
"shext-zip: can't open %s , %s",
path,
zip_error_strerror(&zip_error_st)
);
zip_error_fini(&zip_error_st);
return;
}
// Read through the entries
// 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);
for (gint64 i = 0; i < n_entries; i++)
{
const gchar* entry_name = zip_get_name(zip_file, (guint64) i, 0);
// Only want to add the entries in the current relative dir
//
gint name_offset = 0;
if (!zip_entry_is_in_dir(view_zip->rel_path, entry_name, &name_offset))
{
continue;
}
gchar* entry_copy = g_strdup(entry_name);
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);
item->icon_name = item->is_leaf ? "empty" : "inode-directory";
item->hash = zip_entry_hash(path, entry_name);
item->priv = entry_copy;
g_hash_table_insert(
view_zip->map_items,
GUINT_TO_POINTER(item->hash),
item
);
}
zip_close(zip_file);
// Emit the entries
//
WinTCShextViewItemsUpdate update = { 0 };
GList* items = g_hash_table_get_values(view_zip->map_items);
update.data = items;
update.done = TRUE;
_wintc_ishext_view_items_added(view, &update);
g_list_free(items);
}
//
// PUBLIC FUNCTIONS
//