Enhancement: Fixes #58, Top programs list should be weighted based on user's recent executions

This commit is contained in:
Rory Fewell
2025-09-10 20:00:01 +01:00
parent 21d2a15d77
commit 9cc2938a09
15 changed files with 760 additions and 114 deletions

View File

@@ -6,4 +6,4 @@ Icon=wintc-browser
Terminal=false
StartupNotify=false
Type=Application
Categories=Utility;GTK;
Categories=Utility;GTK;X-WinTC-Dev;

View File

@@ -6,4 +6,4 @@ Icon=wintc-dnd-test
Terminal=false
StartupNotify=false
Type=Application
Categories=Utility;GTK;
Categories=Utility;GTK;X-WinTC-Dev;

View File

@@ -6,4 +6,4 @@ Icon=wintc-menutest
Terminal=false
StartupNotify=false
Type=Application
Categories=Utility;GTK;
Categories=Utility;GTK;X-WinTC-Dev;

View File

@@ -6,4 +6,4 @@ Icon=wintc-patest
Terminal=false
StartupNotify=false
Type=Application
Categories=Utility;GTK;
Categories=Utility;GTK;X-WinTC-Dev;

View File

@@ -6,4 +6,4 @@ Icon=wintc-hello
Terminal=false
StartupNotify=false
Type=Application
Categories=Utility;GTK;
Categories=Utility;GTK;X-WinTC-Dev;

View File

@@ -6,4 +6,4 @@ Icon=wintc-hello
Terminal=false
StartupNotify=false
Type=Application
Categories=Utility;GTK;
Categories=Utility;GTK;X-WinTC-Dev;

View File

@@ -56,6 +56,8 @@ set(
src/window.h
src/start/menumod.c
src/start/menumod.h
src/start/mfu.c
src/start/mfu.h
src/start/personal.c
src/start/personal.h
src/start/progmenu.c

View File

@@ -0,0 +1,464 @@
#include <garcon/garcon.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc/comgtk.h>
#include "mfu.h"
#include "util.h"
#define MFU_WINNERS_FILENAME "mfu-winners"
//
// PRIVATE ENUMS
//
enum
{
SIGNAL_MFU_UPDATED = 0,
N_SIGNALS
};
//
// PRIVATE STRUCTS
//
typedef struct _WinTCStartMfuEntry
{
GarconMenuItem* garcon_item;
gint score;
} WinTCStartMfuEntry;
//
// FORWARD DECLARATIONS
//
static void wintc_start_mfu_tracker_dispose(
GObject* object
);
static void wintc_start_mfu_tracker_bubble_entry(
WinTCStartMfuTracker* mfu_tracker,
GList* li_entry
);
static void wintc_start_mfu_tracker_load_winners(
WinTCStartMfuTracker* mfu_tracker
);
static void wintc_start_mfu_tracker_save_winners(
WinTCStartMfuTracker* mfu_tracker
);
//
// STATIC DATA
//
static gint wintc_start_mfu_tracker_signals[N_SIGNALS] = { 0 };
//
// GTK OOP CLASS/INSTANCE DEFINITIONS
//
struct _WinTCStartMfuTracker
{
GObject __parent__;
gboolean loading_winners;
GList* list_scores;
GHashTable* map_cmdline_to_list_item;
GarconMenu* menu_all;
};
//
// GTK TYPE DEFINITIONS & CTORS
//
G_DEFINE_TYPE(
WinTCStartMfuTracker,
wintc_start_mfu_tracker,
G_TYPE_OBJECT
)
static void wintc_start_mfu_tracker_class_init(
WinTCStartMfuTrackerClass* klass
)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->dispose = wintc_start_mfu_tracker_dispose;
wintc_start_mfu_tracker_signals[SIGNAL_MFU_UPDATED] =
g_signal_new(
"mfu-updated",
G_TYPE_FROM_CLASS(object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0
);
}
static void wintc_start_mfu_tracker_init(
WinTCStartMfuTracker* self
)
{
GError* error = NULL;
// Internally, we track pretty much every possible item that could be
// launched
//
self->menu_all =
garcon_menu_new_for_path(
WINTC_ASSETS_DIR "/shell-res/all.menu"
);
if (!garcon_menu_load(self->menu_all, NULL, &error))
{
wintc_display_error_and_clear(&error, NULL);
return;
}
// Populate collections with the garcon items
//
// --> The list tracks the score of each garcon item, as programs are
// launched, their score increases and they are 'bubbled up' in the
// score list
// --> The map allows translation of cmdline to the item in the
// list
//
GList* elements = garcon_menu_get_elements(self->menu_all);
self->map_cmdline_to_list_item =
g_hash_table_new_full(
g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
NULL
);
for (GList* iter = elements; iter; iter = iter->next)
{
WinTCStartMfuEntry* entry = g_new0(WinTCStartMfuEntry, 1);
entry->garcon_item = GARCON_MENU_ITEM(iter->data);
self->list_scores =
g_list_prepend(
self->list_scores,
entry
);
g_hash_table_insert(
self->map_cmdline_to_list_item,
garcon_menu_item_get_command_expanded(entry->garcon_item),
self->list_scores
);
}
self->list_scores = g_list_reverse(self->list_scores);
g_list_free(elements);
// Load the previous winners (if applicable)
//
wintc_start_mfu_tracker_load_winners(self);
}
//
// CLASS VIRTUAL METHODS
//
static void wintc_start_mfu_tracker_dispose(
GObject* object
)
{
WinTCStartMfuTracker* mfu_tracker = WINTC_START_MFU_TRACKER(object);
g_hash_table_destroy(
g_steal_pointer(&(mfu_tracker->map_cmdline_to_list_item))
);
g_clear_list(
&(mfu_tracker->list_scores),
(GDestroyNotify) g_free
);
g_clear_object(&(mfu_tracker->menu_all));
(G_OBJECT_CLASS(wintc_start_mfu_tracker_parent_class))
->dispose(object);
}
//
// PUBLIC FUNCTIONS
//
WinTCStartMfuTracker* wintc_start_mfu_tracker_get_default(void)
{
static WinTCStartMfuTracker* singleton_tracker = NULL;
if (!singleton_tracker)
{
singleton_tracker =
WINTC_START_MFU_TRACKER(
g_object_new(
WINTC_TYPE_START_MFU_TRACKER,
NULL
)
);
}
g_object_ref(singleton_tracker);
return singleton_tracker;
}
void wintc_start_mfu_tracker_bump_cmdline(
WinTCStartMfuTracker* mfu_tracker,
const gchar* cmdline
)
{
GList* li_entry =
g_hash_table_lookup(
mfu_tracker->map_cmdline_to_list_item,
cmdline
);
// For now, just find the Garcon item and report on it
//
if (li_entry)
{
WinTCStartMfuEntry* entry = (WinTCStartMfuEntry*) li_entry->data;
entry->score++;
wintc_start_mfu_tracker_bubble_entry(
mfu_tracker,
li_entry
);
WINTC_LOG_DEBUG(
"mfu: bumped %s",
garcon_menu_item_get_name(entry->garcon_item)
);
WINTC_LOG_DEBUG(
"mfu: new pos: %d",
g_list_position(
mfu_tracker->list_scores,
li_entry
)
);
}
else
{
WINTC_LOG_DEBUG("mfu: unknown cmdline '%s'", cmdline);
}
}
GList* wintc_start_mfu_tracker_get_mfu_list(
WinTCStartMfuTracker* mfu_tracker
)
{
GList* list_mfu = NULL;
// We return the top 6 items here, if possible
//
gint i;
GList* iter;
for (
iter = mfu_tracker->list_scores, i = 0;
iter && i < 6;
iter = iter->next, i++
)
{
list_mfu =
g_list_prepend(
list_mfu,
((WinTCStartMfuEntry*) iter->data)->garcon_item
);
}
return g_list_reverse(list_mfu);
}
//
// PRIVATE FUNCTIONS
//
static void wintc_start_mfu_tracker_bubble_entry(
WinTCStartMfuTracker* mfu_tracker,
GList* li_entry
)
{
WinTCStartMfuEntry* this_entry = (WinTCStartMfuEntry*) li_entry->data;
// Very crude method of bubbling up the item based on score, we check
//
GList* iter;
for (iter = li_entry->prev; iter; iter = iter->prev)
{
WinTCStartMfuEntry* cmp_entry = (WinTCStartMfuEntry*) iter->data;
if (this_entry->score < cmp_entry->score)
{
break;
}
}
// Did we move at all?
//
if (iter == li_entry->prev)
{
return;
}
// Reinsert the list item in the right place
//
mfu_tracker->list_scores =
g_list_remove_link(
mfu_tracker->list_scores,
li_entry
);
if (!iter)
{
mfu_tracker->list_scores =
g_list_insert_before_link(
mfu_tracker->list_scores,
mfu_tracker->list_scores,
li_entry
);
}
else
{
mfu_tracker->list_scores =
g_list_insert_before_link(
mfu_tracker->list_scores,
iter->next,
li_entry
);
}
g_signal_emit(
mfu_tracker,
wintc_start_mfu_tracker_signals[SIGNAL_MFU_UPDATED],
0
);
if (!(mfu_tracker->loading_winners))
{
wintc_start_mfu_tracker_save_winners(mfu_tracker);
}
}
static void wintc_start_mfu_tracker_load_winners(
WinTCStartMfuTracker* mfu_tracker
)
{
GError* error = NULL;
// Reset all scores to 0 to start with, a clean slate
//
for (GList* iter = mfu_tracker->list_scores; iter; iter = iter->next)
{
((WinTCStartMfuEntry*) iter->data)->score = 0;
}
// Grab the winners
//
GList* list_winners;
gchar* winners_text = NULL;
if (
!wintc_profile_get_file_contents(
WINTC_COMPONENT_SHELL,
MFU_WINNERS_FILENAME,
&winners_text,
NULL,
&error
)
)
{
wintc_log_error_and_clear(&error);
return;
}
list_winners = wintc_list_read_from_string(winners_text);
g_free(winners_text);
// Translate to list and look up the winners, set some initial scores
//
gint i;
GList* iter;
mfu_tracker->loading_winners = TRUE; // Will prevent saving during bumps
for (
iter = list_winners, i = 6;
iter && i > 0;
iter = iter->next, i--
)
{
GList* li_entry =
g_hash_table_lookup(
mfu_tracker->map_cmdline_to_list_item,
(gchar*) iter->data
);
if (!li_entry)
{
continue;
}
((WinTCStartMfuEntry*) li_entry->data)->score = i * 2;
wintc_start_mfu_tracker_bubble_entry(
mfu_tracker,
li_entry
);
}
mfu_tracker->loading_winners = FALSE;
g_list_free_full(list_winners, (GDestroyNotify) g_free);
}
static void wintc_start_mfu_tracker_save_winners(
WinTCStartMfuTracker* mfu_tracker
)
{
GError* error = NULL;
// Get all the cmdlines for the winners
//
GList* list_cmd = NULL;
GList* list_mfu = wintc_start_mfu_tracker_get_mfu_list(mfu_tracker);
for (GList* iter = list_mfu; iter; iter = iter->next)
{
list_cmd =
g_list_prepend(
list_cmd,
garcon_menu_item_get_command_expanded(
GARCON_MENU_ITEM(iter->data)
)
);
}
list_cmd = g_list_reverse(list_cmd);
// Write out to profile
//
gchar* winners_file =
wintc_list_implode_strings(list_cmd);
if (
!wintc_profile_set_file_contents(
WINTC_COMPONENT_SHELL,
MFU_WINNERS_FILENAME,
winners_file,
-1,
&error
)
)
{
wintc_log_error_and_clear(&error);
}
g_free(winners_file);
g_list_free_full(list_cmd, (GDestroyNotify) g_free);
g_list_free(list_mfu);
}

View File

@@ -0,0 +1,30 @@
#ifndef __START_MFU_H__
#define __START_MFU_H__
//
// GTK OOP BOILERPLATE
//
#define WINTC_TYPE_START_MFU_TRACKER (wintc_start_mfu_tracker_get_type())
G_DECLARE_FINAL_TYPE(
WinTCStartMfuTracker,
wintc_start_mfu_tracker,
WINTC,
START_MFU_TRACKER,
GObject
)
//
// PUBLIC FUNCTIONS
//
WinTCStartMfuTracker* wintc_start_mfu_tracker_get_default(void);
void wintc_start_mfu_tracker_bump_cmdline(
WinTCStartMfuTracker* mfu_tracker,
const gchar* cmdline
);
GList* wintc_start_mfu_tracker_get_mfu_list(
WinTCStartMfuTracker* mfu_tracker
);
#endif

View File

@@ -12,6 +12,7 @@
#include <wintc/shlang.h>
#include "menumod.h"
#include "mfu.h"
#include "personal.h"
#include "progmenu.h"
#include "shared.h"
@@ -55,16 +56,15 @@ static GtkWidget* create_personal_menu_item_from_desktop_entry(
const gchar* comment,
const gchar* generic_name
);
static GtkWidget* create_personal_menu_item_from_garcon_item(
GarconMenuItem* garcon_item,
StartSignalTuple* signal_tuple
);
static void refresh_personal_menu(
WinTCToolbarStart* toolbar_start
);
static void refresh_userpic(
WinTCToolbarStart* toolbar_start
);
static void update_personal_menu_mfu_items(
WinTCToolbarStart* toolbar_start
);
static void clear_signal_tuple(
StartSignalTuple* tuple
@@ -104,11 +104,20 @@ static void on_menu_shell_submenu_selection_done(
GtkMenuShell* self,
gpointer user_data
);
static void on_mfu_tracker_updated(
WinTCStartMfuTracker* self,
gpointer user_data
);
static void on_personal_menu_hide(
GtkWidget* self,
gpointer user_data
);
//
// STATIC DATA
//
static GQuark S_QUARK_PERSONAL_ITEM_TUPLE = 0;
//
// INTERNAL FUNCTIONS
//
@@ -125,6 +134,12 @@ void create_personal_menu(
{
GtkBuilder* builder;
if (!S_QUARK_PERSONAL_ITEM_TUPLE)
{
S_QUARK_PERSONAL_ITEM_TUPLE =
g_quark_from_static_string("personal-tuple");
}
// Set default states
//
toolbar_start->personal.sync_menu_refresh = TRUE;
@@ -515,34 +530,37 @@ static GtkWidget* create_personal_menu_item(
// Attempt to load the icon...
//
GdkPixbuf* pixbuf_icon =
gtk_icon_theme_load_icon(
gtk_icon_theme_get_default(),
icon_name ? icon_name : "application-x-generic",
PROGRAM_ICON_SIZE,
GTK_ICON_LOOKUP_FORCE_SIZE,
NULL
);
if (!pixbuf_icon)
if (icon_name)
{
gtk_icon_theme_load_icon(
gtk_icon_theme_get_default(),
"application-x-generic",
PROGRAM_ICON_SIZE,
GTK_ICON_LOOKUP_FORCE_SIZE,
NULL
);
}
GdkPixbuf* pixbuf_icon =
gtk_icon_theme_load_icon(
gtk_icon_theme_get_default(),
icon_name,
PROGRAM_ICON_SIZE,
GTK_ICON_LOOKUP_FORCE_SIZE,
NULL
);
if (pixbuf_icon)
{
gtk_image_set_from_pixbuf(
GTK_IMAGE(image_icon),
pixbuf_icon
);
if (!pixbuf_icon)
{
gtk_icon_theme_load_icon(
gtk_icon_theme_get_default(),
"application-x-generic",
PROGRAM_ICON_SIZE,
GTK_ICON_LOOKUP_FORCE_SIZE,
NULL
);
}
g_object_unref(pixbuf_icon);
if (pixbuf_icon)
{
gtk_image_set_from_pixbuf(
GTK_IMAGE(image_icon),
pixbuf_icon
);
g_object_unref(pixbuf_icon);
}
}
// Set up label properties
@@ -563,6 +581,10 @@ static GtkWidget* create_personal_menu_item(
// Ensure image widget always requests the right size, in case no icon was
// loaded
//
gtk_image_set_pixel_size(
GTK_IMAGE(image_icon),
PROGRAM_ICON_SIZE
);
gtk_widget_set_size_request(
image_icon,
PROGRAM_ICON_SIZE,
@@ -737,36 +759,6 @@ static GtkWidget* create_personal_menu_item_from_desktop_entry(
return menu_item;
}
static GtkWidget* create_personal_menu_item_from_garcon_item(
GarconMenuItem* garcon_item,
StartSignalTuple* signal_tuple
)
{
GtkWidget* menu_item =
create_personal_menu_item(
GTK_MENU_SHELL(
signal_tuple->toolbar_start->personal.menubar_programs
),
garcon_menu_item_get_icon_name(garcon_item),
garcon_menu_item_get_name(garcon_item),
garcon_menu_item_get_comment(garcon_item),
NULL
);
signal_tuple->is_action = FALSE;
signal_tuple->user_data =
garcon_menu_item_get_command_expanded(garcon_item);
g_signal_connect(
menu_item,
"activate",
G_CALLBACK(on_menu_item_launcher_activate),
signal_tuple
);
return menu_item;
}
static void refresh_personal_menu(
WinTCToolbarStart* toolbar_start
)
@@ -860,54 +852,58 @@ static void refresh_personal_menu(
gtk_separator_menu_item_new()
);
// Add MFU items
// FIXME: In future we will need some >>>algorithm<<< to come up with a
// 'top' programs list to display here, and also reserve the last
// slot for the latest newly added program, if any
// Loop over to add the MFU items
//
// For now we simply grab the first items that are pulled in via the
// all.menu file
//
GarconMenu* all_entries = garcon_menu_new_for_path(
WINTC_ASSETS_DIR "/shell-res/all.menu"
);
GError* error = NULL;
if (!garcon_menu_load(all_entries, NULL, &error))
for (gint i = 0; i < MAX_MFU_ITEM_COUNT; i++)
{
wintc_display_error_and_clear(&error, NULL);
return;
}
GtkWidget* personal_item =
create_personal_menu_item(
GTK_MENU_SHELL(
toolbar_start->personal.menubar_programs
),
NULL,
NULL,
NULL,
NULL
);
// Loop over to add the items
//
GList* elements = garcon_menu_get_elements(all_entries);
GList* li = elements;
gint i = 0;
while (i < MAX_MFU_ITEM_COUNT && li != NULL)
{
tuple =
&g_array_index(
toolbar_start->personal.tuples_programs,
StartSignalTuple,
DEFAULT_ITEM_COUNT + i
);
tuple->is_action = FALSE;
tuple->toolbar_start = toolbar_start;
g_object_set_qdata(
G_OBJECT(personal_item),
S_QUARK_PERSONAL_ITEM_TUPLE,
tuple
);
g_signal_connect(
personal_item,
"activate",
G_CALLBACK(on_menu_item_launcher_activate),
tuple
);
gtk_menu_shell_append(
GTK_MENU_SHELL(toolbar_start->personal.menubar_programs),
create_personal_menu_item_from_garcon_item(
GARCON_MENU_ITEM(li->data),
tuple
)
personal_item
);
i++;
li = li->next;
}
g_list_free(g_steal_pointer(&elements));
update_personal_menu_mfu_items(toolbar_start);
g_signal_connect(
wintc_start_mfu_tracker_get_default(),
"mfu-updated",
G_CALLBACK(on_mfu_tracker_updated),
toolbar_start
);
// Re-append All Programs items
//
@@ -947,6 +943,135 @@ static void refresh_userpic(
);
}
static void update_personal_menu_mfu_items(
WinTCToolbarStart* toolbar_start
)
{
// Find the first MFU item
//
GList* li_mfu = NULL;
GList* list_children =
gtk_container_get_children(
GTK_CONTAINER(toolbar_start->personal.menubar_programs)
);
for (GList* iter = list_children; iter; iter = iter->next)
{
if (
g_object_get_qdata(
G_OBJECT(iter->data),
S_QUARK_PERSONAL_ITEM_TUPLE
)
)
{
li_mfu = iter;
break;
}
}
if (!li_mfu)
{
g_critical("%s", "taskband: somehow found no mfu items");
g_list_free(list_children);
return;
}
// Start updating the items
//
GList* list_mfu =
wintc_start_mfu_tracker_get_mfu_list(
wintc_start_mfu_tracker_get_default()
);
for (
GList* iter = list_mfu;
iter;
iter = iter->next, li_mfu = li_mfu->next
)
{
StartSignalTuple* tuple =
g_object_get_qdata(
G_OBJECT(li_mfu->data),
S_QUARK_PERSONAL_ITEM_TUPLE
);
// Protect against the case where there could be more MFU items tracked
// than personal menu items
//
if (!tuple)
{
break;
}
// Update the menu item and tuple
//
GarconMenuItem* garcon_item = GARCON_MENU_ITEM(iter->data);
const gchar* icon_name = garcon_menu_item_get_icon_name(
garcon_item
);
GList* list_menu_children;
GtkWidget* menu_item = GTK_WIDGET(li_mfu->data);
GdkPixbuf* pixbuf_icon = NULL;
list_menu_children =
gtk_container_get_children(
GTK_CONTAINER(
gtk_bin_get_child(GTK_BIN(menu_item))
)
);
if (icon_name)
{
pixbuf_icon =
gtk_icon_theme_load_icon(
gtk_icon_theme_get_default(),
icon_name,
PROGRAM_ICON_SIZE,
GTK_ICON_LOOKUP_FORCE_SIZE,
NULL
);
}
if (!pixbuf_icon)
{
gtk_icon_theme_load_icon(
gtk_icon_theme_get_default(),
"application-x-generic",
PROGRAM_ICON_SIZE,
GTK_ICON_LOOKUP_FORCE_SIZE,
NULL
);
}
gtk_image_set_from_pixbuf(
GTK_IMAGE(list_menu_children->data),
pixbuf_icon
);
gtk_label_set_text(
GTK_LABEL(list_menu_children->next->data),
garcon_menu_item_get_name(garcon_item)
);
gtk_widget_set_tooltip_text(
menu_item,
garcon_menu_item_get_comment(garcon_item)
);
g_free(tuple->user_data);
tuple->user_data =
garcon_menu_item_get_command_expanded(garcon_item);
if (pixbuf_icon)
{
g_object_unref(pixbuf_icon);
}
g_list_free(list_menu_children);
}
g_list_free(list_mfu);
g_list_free(list_children);
}
//
// CALLBACKS
//
@@ -1055,7 +1180,13 @@ static void on_menu_item_launcher_activate(
}
else
{
wintc_launch_command(tuple->user_data, &error);
if (wintc_launch_command(tuple->user_data, &error))
{
wintc_start_mfu_tracker_bump_cmdline(
wintc_start_mfu_tracker_get_default(),
tuple->user_data
);
}
}
if (error)
@@ -1128,12 +1259,22 @@ static void on_menu_shell_submenu_selection_done(
toolbar_start->sync_menu_should_close = TRUE;
}
static void on_mfu_tracker_updated(
WINTC_UNUSED(WinTCStartMfuTracker* self),
gpointer user_data
)
{
WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(user_data);
update_personal_menu_mfu_items(toolbar_start);
}
static void on_personal_menu_hide(
WINTC_UNUSED(GtkWidget* self),
gpointer user_data
)
{
WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(user_data);
WinTCToolbarStart* toolbar_start = WINTC_TOOLBAR_START(user_data);
// Track the last closed time, important for toggling the menu properly
// (see toolbar.c)

View File

@@ -13,6 +13,7 @@
#include <wintc/shcommon.h>
#include "progmenu.h"
#include "mfu.h"
#define WINTC_COMPONENT_START_MENU "start-menu"
@@ -27,8 +28,9 @@
#define K_DIR_GAMES "/Games"
#define K_DIR_STARTUP "/Startup"
#define K_DIR_GNOME "/GNOME"
#define K_DIR_KDE "/KDE"
#define K_DIR_GNOME "/GNOME"
#define K_DIR_KDE "/KDE"
#define K_DIR_WINTC_DEV "/WinTC Developer"
#define K_DIR_DOOM "/DOOM"
#define K_DIR_LIBREOFFICE "/LibreOffice"
@@ -190,8 +192,9 @@ static const gchar* S_EXCLUDED_CATEGORIES[] = {
};
static const gchar* S_VENDOR_MAPPINGS[] = {
"GNOME", K_DIR_GNOME,
"KDE", K_DIR_KDE
"GNOME", K_DIR_GNOME,
"KDE", K_DIR_KDE,
"X-WinTC-Dev", K_DIR_WINTC_DEV
};
static DesktopAppInfoFilterFunc S_ENTRY_FILTERS[] = {
@@ -1865,17 +1868,19 @@ static void action_launch(
WINTC_UNUSED(gpointer user_data)
)
{
GError* error = NULL;
const gchar* cmdline = g_variant_get_string(parameter, NULL);
GError* error = NULL;
if (
!wintc_launch_command(
g_variant_get_string(parameter, NULL),
&error
)
)
if (!wintc_launch_command(cmdline, &error))
{
wintc_display_error_and_clear(&error, NULL);
return;
}
wintc_start_mfu_tracker_bump_cmdline(
wintc_start_mfu_tracker_get_default(),
cmdline
);
}
static const gchar* filter_doom(

View File

@@ -404,7 +404,7 @@ static void wintc_notif_area_icon_unmap(
}
(GTK_WIDGET_CLASS(wintc_notif_area_icon_parent_class))
->map(widget);
->unmap(widget);
}
static void wintc_notif_area_icon_unrealize(

View File

@@ -160,7 +160,11 @@ static void wintc_taskband_window_dispose(
{
WinTCTaskbandWindow* taskband = WINTC_TASKBAND_WINDOW(object);
g_clear_slist(&(taskband->toolbars), g_object_unref);
g_clear_slist(&(taskband->toolbars), NULL);
g_clear_object(&(taskband->uictl_notifarea));
g_clear_object(&(taskband->uictl_start));
g_clear_object(&(taskband->uictl_taskbuttons));
(G_OBJECT_CLASS(wintc_taskband_window_parent_class))->dispose(object);
}

View File

@@ -364,7 +364,7 @@ static void wintc_resvwr_window_refresh(
}
else
{
wintc_display_error_and_clear(&error);
wintc_display_error_and_clear(&error, GTK_WINDOW(wnd));
}
g_object_unref(builder);

View File

@@ -6,4 +6,4 @@ Icon=wintc-resvwr
Terminal=false
StartupNotify=false
Type=Application
Categories=Development;GTK;
Categories=Development;GTK;X-WinTC-Dev;