Cleaning: Fixes #130, Refactor util.c in Start menu plugin

This commit is contained in:
Rory Fewell
2022-04-10 18:44:38 +01:00
parent 0d297b5dca
commit 959488cbb7
32 changed files with 950 additions and 905 deletions

View File

@@ -26,8 +26,14 @@ pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
add_library(
wintc-exec
src/action.h
src/action.c
src/desktop.h
src/desktop.c
src/exec.h
src/exec.c
src/mime.h
src/mime.c
)
set_target_properties(

View File

@@ -4,24 +4,66 @@
#include <gio/gdesktopappinfo.h>
#include <glib.h>
//
// Actions
//
typedef enum
{
WINTC_ACTION_MYDOCS,
WINTC_ACTION_MYRECENTS,
WINTC_ACTION_MYPICS,
WINTC_ACTION_MYMUSIC,
WINTC_ACTION_MYCOMP,
WINTC_ACTION_CONTROL,
WINTC_ACTION_MIMEMGMT,
WINTC_ACTION_CONNECTTO,
WINTC_ACTION_PRINTERS,
WINTC_ACTION_HELP,
WINTC_ACTION_SEARCH,
WINTC_ACTION_RUN,
WINTC_ACTION_LOGOFF,
WINTC_ACTION_SHUTDOWN
} WinTCAction;
gboolean wintc_launch_action(
WinTCAction action_id,
GError** out_error
);
//
// Desktop entries
//
gchar* wintc_desktop_app_info_get_command(
GDesktopAppInfo* entry
);
gchar* wintc_expand_desktop_entry_cmdline(
const gchar* cmdline,
const gchar* name,
const gchar* icon_name,
const gchar* entry_path,
gboolean needs_terminal
);
//
// Execution
//
gboolean wintc_launch_command(
const gchar* command,
GError** out_error
);
//
// MIME types
//
gchar* wintc_query_mime_for_file(
const gchar* filepath,
GError** out_error
);
gchar* wintc_query_mime_handler(
const gchar* mime_query,
GError** out_error,
GDesktopAppInfo** out_entry
GDesktopAppInfo* wintc_query_mime_handler(
const gchar* mime_query,
GError** out_error
);
#endif

82
shared/exec/src/action.c Normal file
View File

@@ -0,0 +1,82 @@
#include <glib.h>
#include <wintc-comgtk.h>
#include "action.h"
#include "exec.h"
//
// PUBLIC FUNCTIONS
//
gboolean wintc_launch_action(
WinTCAction action_id,
GError** out_error
)
{
const gchar* cmdline;
switch (action_id)
{
case WINTC_ACTION_MYDOCS:
cmdline = "exo-open --launch FileManager Documents";
break;
case WINTC_ACTION_MYPICS:
cmdline = "exo-open --launch FileManager Pictures";
break;
case WINTC_ACTION_MYMUSIC:
cmdline = "exo-open --launch FileManager Music";
break;
// TODO: There isn't really a good option for this at the moment, maybe if we
// implement an Explorer replica we can have it open a view of disks
//
case WINTC_ACTION_MYCOMP:
cmdline = "exo-open --launch FileManager /";
break;
case WINTC_ACTION_CONTROL:
cmdline = "xfce4-settings-manager";
break;
case WINTC_ACTION_MIMEMGMT:
cmdline = "xfce4-mime-settings";
break;
case WINTC_ACTION_PRINTERS:
cmdline = "system-config-printer";
break;
case WINTC_ACTION_RUN:
// TODO: In future we will handle missing components gracefully (say, if
// the Run component is missing here)
//
// See issue #134 for details
//
cmdline = "run";
break;
// TODO: One day write our own log off and shut down dialogs, and execute
// them here
//
case WINTC_ACTION_LOGOFF:
case WINTC_ACTION_SHUTDOWN:
cmdline = "xfce4-session-logout";
break;
// Default to 'not implemented' error
//
default:
g_set_error(
out_error,
WINTC_GENERAL_ERROR,
WINTC_GENERAL_ERROR_NOTIMPL,
"Action code is not implemented: %d",
action_id
);
return FALSE;
}
return wintc_launch_command(cmdline, out_error);
}

29
shared/exec/src/action.h Normal file
View File

@@ -0,0 +1,29 @@
#ifndef __ACTIONS_H__
#define __ACTIONS_H__
#include <glib.h>
typedef enum
{
WINTC_ACTION_MYDOCS,
WINTC_ACTION_MYRECENTS,
WINTC_ACTION_MYPICS,
WINTC_ACTION_MYMUSIC,
WINTC_ACTION_MYCOMP,
WINTC_ACTION_CONTROL,
WINTC_ACTION_MIMEMGMT,
WINTC_ACTION_CONNECTTO,
WINTC_ACTION_PRINTERS,
WINTC_ACTION_HELP,
WINTC_ACTION_SEARCH,
WINTC_ACTION_RUN,
WINTC_ACTION_LOGOFF,
WINTC_ACTION_SHUTDOWN
} WinTCAction;
gboolean wintc_launch_action(
WinTCAction action_id,
GError** out_error
);
#endif

115
shared/exec/src/desktop.c Normal file
View File

@@ -0,0 +1,115 @@
#include <gio/gdesktopappinfo.h>
#include <glib.h>
#include "desktop.h"
//
// PUBLIC FUNCTIONS
//
gchar* wintc_desktop_app_info_get_command(
GDesktopAppInfo* entry
)
{
GAppInfo* app_info = G_APP_INFO(entry);
const gchar* cmd_line = g_app_info_get_commandline(app_info);
const gchar* exe_path = g_app_info_get_executable(app_info);
if (cmd_line != NULL)
{
gchar* expanded;
gchar* icon_name = g_path_get_basename(exe_path);
expanded =
wintc_expand_desktop_entry_cmdline(
cmd_line,
g_app_info_get_name(app_info),
icon_name,
g_desktop_app_info_get_filename(entry),
FALSE
);
g_free(icon_name);
return expanded;
}
else
{
return g_strdup(exe_path);
}
}
gchar* wintc_expand_desktop_entry_cmdline(
const gchar* cmdline,
const gchar* name,
const gchar* icon_name,
const gchar* entry_path,
gboolean needs_terminal
)
{
GString* expanded = g_string_sized_new(250);
if (needs_terminal)
{
g_string_append(
expanded,
"exo-open --launch TerminalEmulator"
);
}
// Iterate through cmdline character by character to expand shortcodes
//
const gchar* iter;
for (iter = cmdline; *iter != '\0'; iter++)
{
if (
iter[0] == '%' &&
iter[1] != '\0'
)
{
switch (*++iter)
{
case 'c':
if (name != NULL)
{
g_string_append(
expanded,
name
);
}
break;
case 'i':
if (icon_name != NULL)
{
g_string_append(
expanded,
name
);
}
break;
case 'k':
g_string_append(
expanded,
entry_path
);
break;
case '%':
g_string_append_c(expanded, '%');
break;
}
}
else
{
g_string_append_c(expanded, *iter);
}
}
return g_string_free(expanded, FALSE);
}

19
shared/exec/src/desktop.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef __DESKTOP_H__
#define __DESKTOP_H__
#include <gio/gdesktopappinfo.h>
#include <glib.h>
gchar* wintc_desktop_app_info_get_command(
GDesktopAppInfo* entry
);
gchar* wintc_expand_desktop_entry_cmdline(
const gchar* cmdline,
const gchar* name,
const gchar* icon_name,
const gchar* entry_path,
gboolean needs_terminal
);
#endif

View File

@@ -4,6 +4,8 @@
#include <sys/wait.h>
#include <wintc-comgtk.h>
#include "desktop.h"
#include "mime.h"
#include "exec.h"
//
@@ -18,14 +20,6 @@ typedef gboolean (*CmdParseFunc) (
//
// FORWARD DECLARATIONS
//
static gchar* expand_desktop_entry_cmdline(
const gchar* cmdline,
const gchar* name,
const gchar* icon_name,
const gchar* entry_path,
gboolean needs_terminal
);
static gboolean parse_file_in_cmdline(
const gchar* cmdline,
gchar** out_cmdline,
@@ -66,39 +60,6 @@ static CmdParseFunc parsers[] = {
//
// PUBLIC FUNCTIONS
//
gchar* wintc_desktop_app_info_get_command(
GDesktopAppInfo* entry
)
{
GAppInfo* app_info = G_APP_INFO(entry);
const gchar* cmd_line = g_app_info_get_commandline(app_info);
const gchar* exe_path = g_app_info_get_executable(app_info);
if (cmd_line != NULL)
{
gchar* expanded;
gchar* icon_name = g_path_get_basename(exe_path);
expanded =
expand_desktop_entry_cmdline(
cmd_line,
g_app_info_get_name(app_info),
icon_name,
g_desktop_app_info_get_filename(entry),
FALSE
);
g_free(icon_name);
return expanded;
}
else
{
return g_strdup(exe_path);
}
}
gboolean wintc_launch_command(
const gchar* cmdline,
GError** out_error
@@ -193,285 +154,19 @@ gboolean wintc_launch_command(
return TRUE;
}
gchar* wintc_query_mime_for_file(
const gchar* filepath,
GError** out_error
)
{
gchar* xdg_query_cmd =
g_strconcat(
"xdg-mime query filetype \"",
filepath,
"\"",
NULL
);
gchar* cmd_output = NULL;
GError* error = NULL;
gint status;
gboolean success = FALSE;
WINTC_LOG_DEBUG("Querying MIME type for: %s", filepath);
WINTC_SAFE_REF_CLEAR(out_error);
// Run the query
//
success =
g_spawn_command_line_sync(
xdg_query_cmd,
&cmd_output,
NULL,
&status,
&error
);
status = WEXITSTATUS(status);
g_free(xdg_query_cmd);
if (success && status == 0)
{
g_strstrip(cmd_output);
WINTC_LOG_DEBUG("Determined: %s", cmd_output);
return cmd_output;
}
// Handle errors
//
if (error != NULL)
{
WINTC_LOG_DEBUG("An error occurred: %s", error->message);
g_propagate_error(out_error, error);
return NULL;
}
WINTC_LOG_DEBUG("Failed with code %d", status);
switch (status)
{
case 2: // File not found
g_set_error(
out_error,
G_FILE_ERROR,
G_FILE_ERROR_NOENT,
"Cannot find file or folder '%s'.",
filepath
);
break;
default:
g_set_error(
out_error,
G_FILE_ERROR,
G_FILE_ERROR_FAILED,
"Unknown error occurred."
);
break;
}
return NULL;
}
gchar* wintc_query_mime_handler(
const gchar* mime_query,
GError** out_error,
GDesktopAppInfo** out_entry
)
{
gchar* xdg_query_cmd =
g_strconcat(
"xdg-mime query default ",
mime_query,
NULL
);
GDesktopAppInfo* entry = NULL;
gchar* cmd_output = NULL;
GError* error = NULL;
gchar* filename = NULL;
gboolean success = FALSE;
WINTC_LOG_DEBUG("Querying handler for MIME type %s", mime_query);
WINTC_SAFE_REF_CLEAR(out_error);
WINTC_SAFE_REF_CLEAR(out_entry);
// Run the query
//
success =
g_spawn_command_line_sync(
xdg_query_cmd,
&cmd_output,
NULL,
NULL,
&error
);
g_free(xdg_query_cmd);
if (success)
{
// Did we actually get anything?
//
gint output_length = g_utf8_strlen(cmd_output, -1);
if (output_length == 0)
{
WINTC_LOG_DEBUG("No handler found!");
g_set_error(
out_error,
G_FILE_ERROR,
G_FILE_ERROR_NOSYS,
"No program is mapped to MIME type '%s'.",
mime_query
);
g_free(cmd_output);
return NULL;
}
// We did! It's a desktop entry, so retrieve it
//
filename = g_utf8_substring(
cmd_output,
0,
g_utf8_strlen(cmd_output, -1) - 1
);
entry = g_desktop_app_info_new(
filename
);
WINTC_LOG_DEBUG("Query returned: %s", filename);
g_free(cmd_output);
g_free(filename);
}
else
{
WINTC_LOG_DEBUG("Failed to query MIME type: %s", error->message);
g_propagate_error(out_error, error);
g_free(cmd_output);
return NULL;
}
if (entry == NULL)
{
g_set_error(
out_error,
G_FILE_ERROR,
G_FILE_ERROR_FAILED,
"Unable to load desktop entry for MIME type handler '%s'.",
mime_query
);
WINTC_LOG_DEBUG("Failed to load desktop entry!?");
return NULL;
}
WINTC_SAFE_REF_SET(out_entry, entry);
return wintc_desktop_app_info_get_command(entry);
}
//
// PRIVATE FUNCTIONS
//
static gchar* expand_desktop_entry_cmdline(
const gchar* cmdline,
const gchar* name,
const gchar* icon_name,
const gchar* entry_path,
gboolean needs_terminal
)
{
GString* expanded = g_string_sized_new(250);
if (needs_terminal)
{
g_string_append(
expanded,
"exo-open --launch TerminalEmulator"
);
}
// Iterate through cmdline character by character to expand shortcodes
//
const gchar* iter;
for (iter = cmdline; *iter != '\0'; iter++)
{
if (
iter[0] == '%' &&
iter[1] != '\0'
)
{
switch (*++iter)
{
case 'c':
if (name != NULL)
{
g_string_append(
expanded,
name
);
}
break;
case 'i':
if (icon_name != NULL)
{
g_string_append(
expanded,
name
);
}
break;
case 'k':
g_string_append(
expanded,
entry_path
);
break;
case '%':
g_string_append_c(expanded, '%');
break;
}
}
else
{
g_string_append_c(expanded, *iter);
}
}
return g_string_free(expanded, FALSE);
}
static gboolean parse_file_in_cmdline(
const gchar* cmdline,
gchar** out_cmdline,
GError** out_error
)
{
GError* error = NULL;
gchar* file_handler;
gchar* file_mime;
GError* error = NULL;
gchar* file_mime;
gchar* handler_cmdline;
GDesktopAppInfo* handler_entry;
WINTC_SAFE_REF_CLEAR(out_cmdline);
WINTC_SAFE_REF_CLEAR(out_error);
@@ -508,14 +203,13 @@ static gboolean parse_file_in_cmdline(
{
WINTC_LOG_DEBUG("Not an executable, will look for handler.");
file_handler =
handler_entry =
wintc_query_mime_handler(
file_mime,
&error,
NULL
&error
);
if (file_handler == NULL)
if (handler_entry == NULL)
{
WINTC_LOG_DEBUG("I have nothing to handle the file!");
@@ -529,18 +223,19 @@ static gboolean parse_file_in_cmdline(
// We found a handler, build the cmdline now and return
//
handler_cmdline = wintc_desktop_app_info_get_command(handler_entry);
WINTC_SAFE_REF_SET(
out_cmdline,
g_strconcat(
file_handler,
" \"",
cmdline,
"\"",
NULL
g_strdup_printf(
"%s \"%s\"",
handler_cmdline,
cmdline
)
);
g_free(file_handler);
g_clear_object(&handler_entry);
g_free(handler_cmdline);
g_free(file_mime);
return TRUE;
@@ -657,12 +352,12 @@ static gboolean parse_url_in_cmdline(
{
static GRegex* url_regex = NULL;
gchar* app_name;
GError* error = NULL;
GString* final_cmdline;
GMatchInfo* match_info;
gchar* mime_type;
gchar* uri_scheme;
GError* error = NULL;
GDesktopAppInfo* handler_entry;
gchar* handler_cmdline;
GMatchInfo* match_info;
gchar* mime_type;
gchar* uri_scheme;
WINTC_SAFE_REF_CLEAR(out_cmdline);
WINTC_SAFE_REF_CLEAR(out_error);
@@ -708,23 +403,23 @@ static gboolean parse_url_in_cmdline(
return FALSE;
}
// Command line IS a URL, retrieve the scheme, query the handling program, return
// program with URI as argument
// Command line IS a URL, retrieve the scheme, query the handling program...
//
WINTC_LOG_DEBUG("Yeah, looks like a URL.");
uri_scheme = g_match_info_fetch(match_info, 1);
mime_type = g_strconcat(
"x-scheme-handler/",
uri_scheme,
NULL
mime_type = g_strdup_printf(
"x-scheme-handler/%s",
uri_scheme
);
app_name = wintc_query_mime_handler(mime_type, &error, NULL);
handler_entry = wintc_query_mime_handler(mime_type, &error);
g_match_info_free(match_info);
g_free(mime_type);
g_free(uri_scheme);
if (app_name == NULL)
if (handler_entry == NULL)
{
WINTC_LOG_DEBUG("I have nothing to handle the URL!");
@@ -733,13 +428,22 @@ static gboolean parse_url_in_cmdline(
return FALSE;
}
final_cmdline = g_string_sized_new(500);
// Output the constructed cmdline, the application cmdline with the URL as the
// argument
//
handler_cmdline = wintc_desktop_app_info_get_command(handler_entry);
g_string_append(final_cmdline, app_name);
g_string_append(final_cmdline, " ");
g_string_append(final_cmdline, cmdline);
WINTC_SAFE_REF_SET(
out_cmdline,
g_strdup_printf(
"%s %s",
handler_cmdline,
cmdline
)
);
WINTC_SAFE_REF_SET(out_cmdline, g_string_free(final_cmdline, FALSE));
g_clear_object(&handler_entry);
g_free(handler_cmdline);
return TRUE;
}

View File

@@ -1,27 +1,11 @@
#ifndef __EXEC_H__
#define __EXEC_H__
#include <gio/gdesktopappinfo.h>
#include <glib.h>
gchar* wintc_desktop_app_info_get_command(
GDesktopAppInfo* entry
);
gboolean wintc_launch_command(
const gchar* command,
GError** out_error
);
gchar* wintc_query_mime_for_file(
const gchar* filepath,
GError** out_error
);
gchar* wintc_query_mime_handler(
const gchar* mime_query,
GError** out_error,
GDesktopAppInfo** out_entry
);
#endif

191
shared/exec/src/mime.c Normal file
View File

@@ -0,0 +1,191 @@
#include <gio/gdesktopappinfo.h>
#include <glib.h>
#include <sys/wait.h>
#include <wintc-comgtk.h>
#include "mime.h"
//
// PUBLIC FUNCTIONS
//
gchar* wintc_query_mime_for_file(
const gchar* filepath,
GError** out_error
)
{
gchar* xdg_query_cmd =
g_strdup_printf(
"xdg-mime query filetype \"%s\"",
filepath
);
gchar* cmd_output = NULL;
GError* error = NULL;
gint status;
gboolean success = FALSE;
WINTC_LOG_DEBUG("Querying MIME type for: %s", filepath);
WINTC_SAFE_REF_CLEAR(out_error);
// Run the query
//
success =
g_spawn_command_line_sync(
xdg_query_cmd,
&cmd_output,
NULL,
&status,
&error
);
status = WEXITSTATUS(status);
g_free(xdg_query_cmd);
if (success && status == 0)
{
g_strstrip(cmd_output);
WINTC_LOG_DEBUG("Determined: %s", cmd_output);
return cmd_output;
}
// Handle errors
//
if (error != NULL)
{
WINTC_LOG_DEBUG("An error occurred: %s", error->message);
g_propagate_error(out_error, error);
return NULL;
}
WINTC_LOG_DEBUG("Failed with code %d", status);
switch (status)
{
case 2: // File not found
g_set_error(
out_error,
G_FILE_ERROR,
G_FILE_ERROR_NOENT,
"Cannot find file or folder '%s'.",
filepath
);
break;
default:
g_set_error(
out_error,
G_FILE_ERROR,
G_FILE_ERROR_FAILED,
"Unknown error occurred."
);
break;
}
return NULL;
}
GDesktopAppInfo* wintc_query_mime_handler(
const gchar* mime_query,
GError** out_error
)
{
gchar* xdg_query_cmd =
g_strdup_printf(
"xdg-mime query default %s",
mime_query
);
gchar* cmd_output = NULL;
GDesktopAppInfo* entry = NULL;
GError* error = NULL;
gchar* filename = NULL;
gboolean success = FALSE;
WINTC_LOG_DEBUG("Querying handler for MIME type %s", mime_query);
WINTC_SAFE_REF_CLEAR(out_error);
// Run query
//
success =
g_spawn_command_line_sync(
xdg_query_cmd,
&cmd_output,
NULL,
NULL,
&error
);
g_free(xdg_query_cmd);
if (!success)
{
WINTC_LOG_DEBUG("Failed to query MIME type: %s", error->message);
g_propagate_error(out_error, error);
g_free(cmd_output);
return NULL;
}
// Did we really get anything
//
gint output_length = g_utf8_strlen(cmd_output, -1);
if (output_length == 0)
{
WINTC_LOG_DEBUG("No handler found!");
g_set_error(
out_error,
G_FILE_ERROR,
G_FILE_ERROR_NOSYS,
"No program is mapped to MIME type '%s'.",
mime_query
);
g_free(cmd_output);
return NULL;
}
// We did! It's a desktop entry, so retrieve it
//
filename = g_utf8_substring(
cmd_output,
0,
g_utf8_strlen(cmd_output, -1) - 1
);
entry = g_desktop_app_info_new(filename);
WINTC_LOG_DEBUG("Query returned: %s", filename);
g_free(cmd_output);
g_free(filename);
if (entry == NULL)
{
g_set_error(
out_error,
G_FILE_ERROR,
G_FILE_ERROR_FAILED,
"Unable to load desktop entry for MIME type handler '%s'.",
mime_query
);
WINTC_LOG_DEBUG("Association found, but the desktop entry doesn't exist.");
return NULL;
}
return entry;
}

17
shared/exec/src/mime.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef __MIME_H__
#define __MIME_H__
#include <gio/gdesktopappinfo.h>
#include <glib.h>
gchar* wintc_query_mime_for_file(
const gchar* filepath,
GError** out_error
);
GDesktopAppInfo* wintc_query_mime_handler(
const gchar* mime_query,
GError** out_error
);
#endif