mirror of
https://github.com/rozniak/xfce-winxp-tc.git
synced 2026-01-26 11:39:44 +00:00
Enhancement: Fixes #58, Top programs list should be weighted based on user's recent executions
This commit is contained in:
@@ -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
|
||||
|
||||
464
shell/taskband/src/start/mfu.c
Normal file
464
shell/taskband/src/start/mfu.c
Normal 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);
|
||||
}
|
||||
30
shell/taskband/src/start/mfu.h
Normal file
30
shell/taskband/src/start/mfu.h
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user