Enhancement: Fixes #436, taskband - Start menu - All Programs items should be sorted by display name

This commit is contained in:
Rory Fewell
2025-03-06 18:19:10 +00:00
parent 7b269d373b
commit 8bbfb9abc5
7 changed files with 258 additions and 12 deletions

View File

@@ -31,6 +31,7 @@ wintc_resolve_library(gdk-pixbuf-2.0 GDK_PIXBUF)
wintc_resolve_library(glib-2.0 GLIB)
wintc_resolve_library(gtk+-3.0 GTK3)
wintc_resolve_library(upower-glib UPOWER_GLIB)
wintc_resolve_library(wintc-comctl WINTC_COMCTL)
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
wintc_resolve_library(wintc-exec WINTC_EXEC)
wintc_resolve_library(wintc-shcommon WINTC_SHCOMMON)
@@ -117,6 +118,7 @@ target_include_directories(
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GTK3_INCLUDE_DIRS}
PRIVATE ${UPOWER_GLIB_INCLUDE_DIRS}
PRIVATE ${WINTC_COMCTL_INCLUDE_DIRS}
PRIVATE ${WINTC_COMGTK_INCLUDE_DIRS}
PRIVATE ${WINTC_EXEC_INCLUDE_DIRS}
PRIVATE ${WINTC_SHCOMMON_INCLUDE_DIRS}
@@ -135,6 +137,7 @@ target_link_directories(
PRIVATE ${GLIB_LIBRARY_DIRS}
PRIVATE ${GTK3_LIBRARY_DIRS}
PRIVATE ${UPOWER_GLIB_LIBRARY_DIRS}
PRIVATE ${WINTC_COMCTL_LIBRARY_DIRS}
PRIVATE ${WINTC_COMGTK_LIBRARY_DIRS}
PRIVATE ${WINTC_EXEC_LIBRARY_DIRS}
PRIVATE ${WINTC_SHCOMMON_LIBRARY_DIRS}
@@ -153,6 +156,7 @@ target_link_libraries(
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GTK3_LIBRARIES}
PRIVATE ${UPOWER_GLIB_LIBRARIES}
PRIVATE ${WINTC_COMCTL_LIBRARIES}
PRIVATE ${WINTC_COMGTK_LIBRARIES}
PRIVATE ${WINTC_EXEC_LIBRARIES}
PRIVATE ${WINTC_SHCOMMON_LIBRARIES}

View File

@@ -7,6 +7,7 @@ bt,rt:glib2
bt,rt:gtk3
bt,rt:networkmanager
bt,rt:upower-glib
bt,rt:wintc-comctl
bt,rt:wintc-comgtk
bt,rt:wintc-exec
bt,rt:wintc-shcommon

View File

@@ -5,6 +5,7 @@
#include <gtk/gtk.h>
#include <pwd.h>
#include <sys/types.h>
#include <wintc/comctl.h>
#include <wintc/comgtk.h>
#include <wintc/exec.h>
#include <wintc/shelldpa.h>
@@ -264,7 +265,9 @@ void create_personal_menu(
//
gtk_menu_item_set_submenu(
GTK_MENU_ITEM(toolbar_start->personal.menuitem_all_programs),
wintc_toolbar_start_progmenu_new_gtk_menu()
wintc_toolbar_start_progmenu_new_gtk_menu(
&(toolbar_start->personal.all_programs_binding)
)
);
// Transfer to popup
@@ -395,6 +398,12 @@ void destroy_personal_menu(
g_steal_pointer(&(toolbar_start->personal.separator_all_programs))
);
// Clear all programs menu model binding object
//
g_clear_object(
&(toolbar_start->personal.all_programs_binding)
);
// Clear signal tuple data
//
g_array_unref(

View File

@@ -6,6 +6,7 @@
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wintc/comctl.h>
#include <wintc/comgtk.h>
#include <wintc/exec.h>
#include <wintc/shcommon.h>
@@ -48,6 +49,10 @@ static GMenu* wintc_toolbar_start_progmenu_menu_from_filelist(
GList* files,
GHashTable** map_dir_to_menu
);
static void wintc_toolbar_start_progmenu_menu_insert_sorted(
GMenu* menu,
GMenuItem* menu_item
);
static gboolean create_symlink(
const gchar* rel_path,
@@ -186,8 +191,6 @@ gboolean wintc_toolbar_start_progmenu_init(
);
}
files = g_list_sort(files, (GCompareFunc) g_ascii_strcasecmp);
// Construct the menu
//
S_MENU_PROGRAMS =
@@ -203,7 +206,9 @@ gboolean wintc_toolbar_start_progmenu_init(
return TRUE;
}
GtkWidget* wintc_toolbar_start_progmenu_new_gtk_menu()
GtkWidget* wintc_toolbar_start_progmenu_new_gtk_menu(
WinTCCtlMenuBinding** menu_binding
)
{
if (!S_INIT_DONE)
{
@@ -233,7 +238,15 @@ GtkWidget* wintc_toolbar_start_progmenu_new_gtk_menu()
// Create the menu
//
GtkWidget* menu = gtk_menu_new_from_model(G_MENU_MODEL(S_MENU_PROGRAMS));
GtkWidget* menu = gtk_menu_new();
gtk_menu_set_reserve_toggle_size(GTK_MENU(menu), FALSE);
*menu_binding =
wintc_ctl_menu_binding_new(
GTK_MENU_SHELL(menu),
G_MENU_MODEL(S_MENU_PROGRAMS)
);
gtk_widget_insert_action_group(
menu,
@@ -447,7 +460,7 @@ static GMenu* wintc_toolbar_start_progmenu_menu_from_filelist(
// Construct the menus from this file list
//
gint len_root = strlen(S_DIR_START_MENU);
gint len_root = g_utf8_strlen(S_DIR_START_MENU, -1);
for (GList* iter = files; iter; iter = iter->next)
{
@@ -460,7 +473,11 @@ static GMenu* wintc_toolbar_start_progmenu_menu_from_filelist(
// Pull the directory components out of the path to check the submenu
// that should own this item
//
const gchar* dir_end = strrchr(entry_path, G_DIR_SEPARATOR);
const gchar* dir_end = g_utf8_strrchr(
entry_path,
-1,
G_DIR_SEPARATOR
);
const gchar* dir_start = entry_path + len_root;
gchar* rel_dir = g_malloc0((dir_end - dir_start) + 1);
@@ -513,7 +530,10 @@ static GMenu* wintc_toolbar_start_progmenu_menu_from_filelist(
g_app_info_get_name(G_APP_INFO(entry))
);
g_menu_append_item(menu_owner, new_item);
wintc_toolbar_start_progmenu_menu_insert_sorted(
menu_owner,
new_item
);
g_free(cmd);
g_object_unref(new_item);
@@ -553,7 +573,7 @@ static GMenu* wintc_toolbar_start_progmenu_menu_from_filelist(
{
// Retrieve the parent path
//
const gchar* dir_end = strrchr(iter, G_DIR_SEPARATOR);
const gchar* dir_end = g_utf8_strrchr(iter, -1, G_DIR_SEPARATOR);
gchar* parent = g_malloc0(dir_end - iter + 1);
@@ -576,7 +596,7 @@ static GMenu* wintc_toolbar_start_progmenu_menu_from_filelist(
g_menu_item_set_icon(
submenu_item,
g_themed_icon_new("add")
s_icon_programs
);
g_menu_item_set_label(
submenu_item,
@@ -597,7 +617,7 @@ static GMenu* wintc_toolbar_start_progmenu_menu_from_filelist(
if (parent_menu)
{
g_menu_prepend_item(
wintc_toolbar_start_progmenu_menu_insert_sorted(
parent_menu,
submenu_item
);
@@ -642,6 +662,183 @@ static GMenu* wintc_toolbar_start_progmenu_menu_from_filelist(
return menu;
}
static void wintc_toolbar_start_progmenu_menu_insert_sorted(
GMenu* menu,
GMenuItem* menu_item
)
{
gint idx_start = 0;
gint idx_end = 0;
gint n_items = g_menu_model_get_n_items(G_MENU_MODEL(menu));
// Easy case - no items? Prepend
//
if (!n_items)
{
g_menu_prepend_item(menu, menu_item);
return;
}
// Find the end of submenu items
//
gint n_submenu_items = 0;
for (; n_submenu_items < n_items; n_submenu_items++)
{
// Hit a normal item? We've already hit the end then
//
if (
!g_menu_model_get_item_link(
G_MENU_MODEL(menu),
n_submenu_items,
G_MENU_LINK_SUBMENU
)
)
{
break;
}
}
// Set the start/end depending on whether we need to insert a normal item
// or submenu item
//
if (g_menu_item_get_link(menu_item, G_MENU_LINK_SUBMENU))
{
if (n_submenu_items)
{
idx_end = n_submenu_items - 1;
}
}
else
{
if (n_submenu_items)
{
idx_start = n_submenu_items;
}
idx_end = n_items - 1;
}
// Binary search and insert
//
gint idx_mid;
gchar* cmp_name = NULL;
gchar* our_name = NULL;
gint res;
g_menu_item_get_attribute(
menu_item,
G_MENU_ATTRIBUTE_LABEL,
"s",
&our_name
);
WINTC_UTF8_TRANSFORM(our_name, g_utf8_casefold);
while (idx_end - idx_start > 1)
{
idx_mid = idx_start + ((idx_end - idx_start) / 2);
g_menu_model_get_item_attribute(
G_MENU_MODEL(menu),
idx_mid,
G_MENU_ATTRIBUTE_LABEL,
"s",
&cmp_name
);
WINTC_UTF8_TRANSFORM(cmp_name, g_utf8_casefold);
res = g_utf8_collate(our_name, cmp_name);
if (res < 0)
{
idx_end = idx_mid;
}
else if (res > 0)
{
idx_start = idx_mid;
}
else
{
idx_start = idx_mid;
idx_end = idx_mid;
}
g_free(cmp_name);
}
// If we found an exact location, insert there
//
if (idx_start == idx_end)
{
g_menu_insert_item(
menu,
idx_start,
menu_item
);
g_free(our_name);
return;
}
// Otherwise determine between start and end
//
g_menu_model_get_item_attribute(
G_MENU_MODEL(menu),
idx_start,
G_MENU_ATTRIBUTE_LABEL,
"s",
&cmp_name
);
WINTC_UTF8_TRANSFORM(cmp_name, g_utf8_casefold);
if (g_utf8_collate(our_name, cmp_name) < 0)
{
g_menu_insert_item(
menu,
idx_start,
menu_item
);
}
else
{
g_free(cmp_name);
g_menu_model_get_item_attribute(
G_MENU_MODEL(menu),
idx_end,
G_MENU_ATTRIBUTE_LABEL,
"s",
&cmp_name
);
WINTC_UTF8_TRANSFORM(cmp_name, g_utf8_casefold);
if (g_utf8_collate(our_name, cmp_name) < 0)
{
g_menu_insert_item(
menu,
idx_end,
menu_item
);
}
else
{
g_menu_insert_item(
menu,
idx_end + 1,
menu_item
);
}
}
g_free(cmp_name);
g_free(our_name);
}
static gboolean create_symlink(
const gchar* rel_path,
const gchar* entry_name,

View File

@@ -3,6 +3,7 @@
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc/comctl.h>
//
// PUBLIC FUNCTIONS
@@ -11,6 +12,8 @@ gboolean wintc_toolbar_start_progmenu_init(
GError** error
);
GtkWidget* wintc_toolbar_start_progmenu_new_gtk_menu(void);
GtkWidget* wintc_toolbar_start_progmenu_new_gtk_menu(
WinTCCtlMenuBinding** menu_binding
);
#endif

View File

@@ -1,6 +1,10 @@
#ifndef __SHARED_START_H__
#define __SHARED_START_H__
#include <glib.h>
#include <gtk/gtk.h>
#include <wintc/comctl.h>
//
// INTERNAL STRUCTS
//
@@ -18,6 +22,8 @@ typedef struct _PersonalStartMenuData
GtkWidget* menuitem_all_programs;
GtkWidget* separator_all_programs;
WinTCCtlMenuBinding* all_programs_binding;
// UI state
//
gboolean sync_menu_refresh;