Enhancement: Fixes #324, ZIP archive shell extension

This commit is contained in:
Rory Fewell
2024-06-30 20:06:04 +01:00
parent 52980c3c66
commit 85f9a55288
25 changed files with 1016 additions and 97 deletions

View File

@@ -23,7 +23,8 @@ GType wintc_sh_view_fs_get_type(void) G_GNUC_CONST;
// PUBLIC FUNCTIONS
//
WinTCIShextView* wintc_sh_view_fs_new(
const gchar* path
WinTCShextHost* shext_host,
const gchar* path
);
#endif

View File

@@ -14,14 +14,16 @@
// FORWARD DECLARATIONS
//
static WinTCIShextView* factory_view_by_guid_cb(
WinTCShextViewAssoc assoc,
const gchar* assoc_str,
const gchar* url
WinTCShextHost* shext_host,
WinTCShextViewAssoc assoc,
const gchar* assoc_str,
const WinTCShextPathInfo* path_info
);
static WinTCIShextView* factory_view_for_filesystem(
WinTCShextViewAssoc assoc,
const gchar* assoc_str,
const gchar* url
WinTCShextHost* shext_host,
WinTCShextViewAssoc assoc,
const gchar* assoc_str,
const WinTCShextPathInfo* path_info
);
//
@@ -79,9 +81,10 @@ void wintc_sh_init_namespace_tree(
// CALLBACKS
//
static WinTCIShextView* factory_view_by_guid_cb(
WINTC_UNUSED(WinTCShextViewAssoc assoc),
WINTC_UNUSED(WinTCShextHost* shext_host),
WINTC_UNUSED(WinTCShextViewAssoc assoc),
const gchar* assoc_str,
WINTC_UNUSED(const gchar* url)
WINTC_UNUSED(const WinTCShextPathInfo* url)
)
{
WINTC_LOG_DEBUG("shell: create new shell view for %s", assoc_str);
@@ -107,14 +110,16 @@ static WinTCIShextView* factory_view_by_guid_cb(
}
static WinTCIShextView* factory_view_for_filesystem(
WinTCShextHost* shext_host,
WINTC_UNUSED(WinTCShextViewAssoc assoc),
WINTC_UNUSED(const gchar* assoc_str),
const gchar* url
const WinTCShextPathInfo* path_info
)
{
const gchar* path_in_url = url + g_utf8_strlen("file://", -1);
const gchar* path_in_url =
path_info->base_path + g_utf8_strlen("file://", -1);
WINTC_LOG_DEBUG("shell: create new fs view for %s", url);
WINTC_LOG_DEBUG("shell: create new fs view for %s", path_in_url);
return wintc_sh_view_fs_new(path_in_url);
return wintc_sh_view_fs_new(shext_host, path_in_url);
}

View File

@@ -1,6 +1,8 @@
#include <glib.h>
#include <wintc/comgtk.h>
#include <wintc/exec.h>
#include <wintc/shcommon.h>
#include <wintc/shellext.h>
#include "../public/vwfs.h"
@@ -9,7 +11,8 @@
//
enum
{
PROP_PATH = 1
PROP_SHEXT_HOST = 1,
PROP_PATH
};
//
@@ -19,6 +22,9 @@ static void wintc_sh_view_fs_ishext_view_interface_init(
WinTCIShextViewInterface* iface
);
static void wintc_sh_view_fs_dispose(
GObject* object
);
static void wintc_sh_view_fs_finalize(
GObject* object
);
@@ -94,6 +100,8 @@ struct _WinTCShViewFS
GArray* items;
gchar* parent_path;
gchar* path;
WinTCShextHost* shext_host;
};
//
@@ -115,10 +123,22 @@ static void wintc_sh_view_fs_class_init(
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->dispose = wintc_sh_view_fs_dispose;
object_class->finalize = wintc_sh_view_fs_finalize;
object_class->get_property = wintc_sh_view_fs_get_property;
object_class->set_property = wintc_sh_view_fs_set_property;
g_object_class_install_property(
object_class,
PROP_SHEXT_HOST,
g_param_spec_object(
"shext-host",
"ShextHost",
"The shell extension host.",
WINTC_TYPE_SHEXT_HOST,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY
)
);
g_object_class_install_property(
object_class,
PROP_PATH,
@@ -161,6 +181,17 @@ static void wintc_sh_view_fs_ishext_view_interface_init(
//
// CLASS VIRTUAL METHODS
//
static void wintc_sh_view_fs_dispose(
GObject* object
)
{
WinTCShViewFS* view = WINTC_SH_VIEW_FS(object);
g_clear_object(&(view->shext_host));
(G_OBJECT_CLASS(wintc_sh_view_fs_parent_class))->dispose(object);
}
static void wintc_sh_view_fs_finalize(
GObject* object
)
@@ -206,6 +237,10 @@ static void wintc_sh_view_fs_set_property(
switch (prop_id)
{
case PROP_SHEXT_HOST:
view->shext_host = g_value_dup_object(value);
break;
case PROP_PATH:
view->path = g_value_dup_string(value);
@@ -234,20 +269,54 @@ static gboolean wintc_sh_view_fs_activate_item(
GError** error
)
{
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
GError* local_error = NULL;
WinTCShViewFS* view_fs = WINTC_SH_VIEW_FS(view);
WINTC_SAFE_REF_CLEAR(error);
gchar* next_path =
g_build_path(
G_DIR_SEPARATOR_S,
view_fs->path,
item->display_name,
NULL
);
// 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
);
path_info->base_path = g_strdup_printf("file://%s", next_path);
if (!mime_type)
{
g_propagate_error(error, local_error);
return FALSE;
}
// 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
//
if (g_strcmp0(mime_type, "inode/directory") == 0)
{
path_info->base_path = g_strdup_printf("file://%s", next_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);
}
}
}
g_free(mime_type);
g_free(next_path);
return TRUE;
@@ -411,13 +480,15 @@ static gboolean wintc_sh_view_fs_has_parent(
// PUBLIC FUNCTIONS
//
WinTCIShextView* wintc_sh_view_fs_new(
const gchar* path
WinTCShextHost* shext_host,
const gchar* path
)
{
return WINTC_ISHEXT_VIEW(
g_object_new(
WINTC_TYPE_SH_VIEW_FS,
"path", path,
"path", path,
"shext-host", shext_host,
NULL
)
);

View File

@@ -26,6 +26,7 @@ include(../../packaging/cmake-inc/resources/CMakeLists.txt)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-exec WINTC_EXEC)
configure_file(src/host_priv.h.in ${PROJECT_ROOT}/src/host_priv.h @ONLY)
@@ -61,6 +62,7 @@ target_include_directories(
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
PRIVATE ${WINTC_EXEC_INCLUDE_DIRS}
)
target_link_directories(
@@ -68,6 +70,7 @@ target_link_directories(
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
PRIVATE ${WINTC_EXEC_LIBRARY_DIRS}
)
target_link_libraries(
@@ -75,6 +78,7 @@ target_link_libraries(
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
PRIVATE ${WINTC_EXEC_LIBRARIES}
)
# Installation

View File

@@ -1,3 +1,4 @@
bt,rt:glib2
bt,rt:gtk3
bt,rt:wintc-comgtk
bt,rt:wintc-exec

View File

@@ -29,24 +29,11 @@ typedef enum
WINTC_SHEXT_VIEW_ASSOC_PATH
} WinTCShextViewAssoc;
//
// PUBLIC CALLBACK PROTOTYPES
//
typedef GtkWidget** (*WinTCShextPropertyPagesCtor) (
const gchar* url,
const gchar* mime_type
);
typedef WinTCIShextView* (*WinTCShextViewCtor) (
WinTCShextViewAssoc assoc,
const gchar* assoc_str,
const gchar* url
);
//
// GTK OOP BOILERPLATE
//
typedef struct _WinTCShextHostClass WinTCShextHostClass;
typedef struct _WinTCShextHost WinTCShextHost;
typedef struct _WinTCShextHost WinTCShextHost;
#define WINTC_TYPE_SHEXT_HOST (wintc_shext_host_get_type())
#define WINTC_SHEXT_HOST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WINTC_TYPE_SHEXT_HOST, WinTCShextHost))
@@ -57,6 +44,21 @@ typedef struct _WinTCShextHost WinTCShextHost;
GType wintc_shext_host_get_type(void) G_GNUC_CONST;
//
// PUBLIC CALLBACK PROTOTYPES
//
typedef GtkWidget** (*WinTCShextPropertyPagesCtor) (
WinTCShextHost* shext_host,
const gchar* url,
const gchar* mime_type
);
typedef WinTCIShextView* (*WinTCShextViewCtor) (
WinTCShextHost* shext_host,
WinTCShextViewAssoc assoc,
const gchar* assoc_str,
const WinTCShextPathInfo* path_info
);
//
// PUBLIC FUNCTIONS
//
@@ -84,6 +86,11 @@ WinTCIShextView* wintc_shext_host_get_view_for_path(
GError** error
);
gboolean wintc_shext_host_has_view_for_mime(
WinTCShextHost* host,
const gchar* mime_type
);
gboolean wintc_shext_host_load_extensions(
WinTCShextHost* host,
WinTCShextLoadMode mode,

View File

@@ -1,6 +1,7 @@
#include <dlfcn.h>
#include <glib.h>
#include <wintc/comgtk.h>
#include <wintc/exec.h>
#include "../public/category.h"
#include "../public/error.h"
@@ -17,9 +18,9 @@ typedef gboolean (*ShextInitFunc) (
);
typedef WinTCIShextView* (*LookupViewFunc) (
WinTCShextHost* host,
const gchar* path,
GError** error
WinTCShextHost* host,
const WinTCShextPathInfo* path_info,
GError** error
);
//
@@ -30,14 +31,14 @@ static void wintc_shext_host_finalize(
);
WinTCIShextView* lookup_view_for_path_by_guid(
WinTCShextHost* host,
const gchar* path,
GError** error
WinTCShextHost* host,
const WinTCShextPathInfo* path_info,
GError** error
);
WinTCIShextView* lookup_view_for_path_by_mime(
WinTCShextHost* host,
const gchar* path,
GError** error
WinTCShextHost* host,
const WinTCShextPathInfo* path_info,
GError** error
);
//
@@ -186,7 +187,7 @@ WinTCIShextView* wintc_shext_host_get_view_for_path(
view =
s_lookup_view_funcs[i](
host,
path_info->base_path,
path_info,
&local_error
);
@@ -231,6 +232,19 @@ WinTCIShextView* wintc_shext_host_get_view_for_path(
return view;
}
gboolean wintc_shext_host_has_view_for_mime(
WinTCShextHost* host,
const gchar* mime_type
)
{
gchar* mime_u = g_ascii_strup(mime_type, -1);
gboolean ret = g_hash_table_contains(host->map_views_by_mime, mime_u);
g_free(mime_u);
return ret;
}
gboolean wintc_shext_host_load_extensions(
WinTCShextHost* host,
WINTC_UNUSED(WinTCShextLoadMode mode),
@@ -360,7 +374,7 @@ gboolean wintc_shext_host_use_view_for_mime(
factory_cb
);
return FALSE;
return TRUE;
}
gboolean wintc_shext_host_use_view_for_path_regex(
@@ -387,9 +401,9 @@ gboolean wintc_shext_host_use_view_for_real_path(
// PRIVATE FUNCTIONS
//
WinTCIShextView* lookup_view_for_path_by_guid(
WinTCShextHost* host,
const gchar* path,
GError** error
WinTCShextHost* host,
const WinTCShextPathInfo* path_info,
GError** error
)
{
static GRegex* regex_guid = NULL;
@@ -420,7 +434,12 @@ WinTCIShextView* lookup_view_for_path_by_guid(
WINTC_LOG_DEBUG("%s", "shellext: view lookup - try guid...");
g_regex_match(regex_guid, path, 0, &match_info);
g_regex_match(
regex_guid,
path_info->base_path,
0,
&match_info
);
if (g_match_info_get_match_count(match_info))
{
@@ -439,9 +458,10 @@ WinTCIShextView* lookup_view_for_path_by_guid(
{
view =
ctor(
host,
WINTC_SHEXT_VIEW_ASSOC_VIEW_GUID,
guid_u,
path
path_info
);
}
else
@@ -460,18 +480,15 @@ WinTCIShextView* lookup_view_for_path_by_guid(
}
WinTCIShextView* lookup_view_for_path_by_mime(
WinTCShextHost* host,
const gchar* path,
GError** error
WinTCShextHost* host,
const WinTCShextPathInfo* path_info,
GError** error
)
{
static GRegex* regex_scheme = NULL;
WinTCShextViewCtor ctor;
GMatchInfo* match_info = NULL;
gchar* mime;
gchar* mime_u;
gchar* scheme;
WinTCIShextView* view = NULL;
if (!regex_scheme)
@@ -492,16 +509,87 @@ WinTCIShextView* lookup_view_for_path_by_mime(
WINTC_LOG_DEBUG("%s", "shellext: view lookup - try scheme...");
g_regex_match(regex_scheme, path, 0, &match_info);
if (g_match_info_get_match_count(match_info))
if (
!g_regex_match(
regex_scheme,
path_info->base_path,
0,
&match_info
)
)
{
scheme = g_match_info_fetch(match_info, 1);
mime = g_strdup_printf("x-scheme-handler/%s", scheme);
mime_u = g_ascii_strup(mime, -1);
g_match_info_free(match_info);
return NULL;
}
WINTC_LOG_DEBUG("shellext: view lookup - match scheme %s", mime_u);
// Matched a scheme successfully, pull it out...
//
gchar* scheme = g_match_info_fetch(match_info, 1);
gchar* mime = g_strdup_printf("x-scheme-handler/%s", scheme);
gchar* mime_u = g_ascii_strup(mime, -1);
g_match_info_free(match_info);
// ...if it's file://, first see if it's a file that we have a more
// specific MIME type handler for...
//
if (g_strcmp0(mime_u, "X-SCHEME-HANDLER/FILE") == 0)
{
const gchar* local_path = path_info->base_path + strlen("file://");
gchar* target_mime = wintc_query_mime_for_file(
local_path,
error
);
gchar* target_mime_u;
if (!target_mime)
{
g_free(scheme);
g_free(mime);
g_free(mime_u);
return NULL;
}
target_mime_u = g_ascii_strup(target_mime, -1);
// No special handling for inode/directory, it should be the same as
// the file:// URI scheme
//
if (g_strcmp0(target_mime_u, "INODE/DIRECTORY") != 0)
{
ctor =
g_hash_table_lookup(
host->map_views_by_mime,
target_mime_u
);
if (ctor)
{
WINTC_LOG_DEBUG(
"shellext: view lookup - match file MIME %s",
target_mime_u
);
view =
ctor(
host,
WINTC_SHEXT_VIEW_ASSOC_MIME,
target_mime_u,
path_info
);
}
}
g_free(target_mime);
g_free(target_mime_u);
}
// ...if no special handling occurred, just look up a handler for the
// scheme and use that
//
if (!view)
{
ctor =
g_hash_table_lookup(
host->map_views_by_mime,
@@ -510,20 +598,24 @@ WinTCIShextView* lookup_view_for_path_by_mime(
if (ctor)
{
WINTC_LOG_DEBUG(
"shellext: view lookup - match scheme %s",
mime_u
);
view =
ctor(
host,
WINTC_SHEXT_VIEW_ASSOC_MIME,
mime_u,
path
path_info
);
}
g_free(scheme);
g_free(mime);
g_free(mime_u);
}
g_match_info_free(match_info);
g_free(scheme);
g_free(mime);
g_free(mime_u);
return view;
}