mirror of
https://github.com/rozniak/xfce-winxp-tc.git
synced 2026-01-26 19:49:44 +00:00
Enhancement: Fixes #445, taskband - Start menu - All Programs needs to handle added/removed desktop entries
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -19,6 +19,8 @@ mui-stuff/
|
||||
[Bb]uild/
|
||||
config.h
|
||||
libapi.h
|
||||
marshal.c
|
||||
marshal.h
|
||||
meta.h
|
||||
resources.c
|
||||
*.deb
|
||||
|
||||
@@ -53,3 +53,45 @@ function(wintc_gdbus_codegen XML_FILE OUT_FILE_NOEXT CP_PUBLIC)
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Define function for glib-genmashal
|
||||
#
|
||||
function(wintc_glib_genmarshal)
|
||||
find_program(GLIB_GENMARSHAL glib-genmarshal REQUIRED)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/marshal.h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
COMMAND ${GLIB_GENMARSHAL}
|
||||
ARGS
|
||||
--header
|
||||
--prefix wintc_cclosure_marshal
|
||||
--output marshal.h
|
||||
marshals.list
|
||||
VERBATIM
|
||||
DEPENDS
|
||||
src/marshals.list
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/marshal.c
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
COMMAND ${GLIB_GENMARSHAL}
|
||||
ARGS
|
||||
--body
|
||||
--prefix wintc_cclosure_marshal
|
||||
--output marshal.c
|
||||
marshals.list
|
||||
VERBATIM
|
||||
DEPENDS
|
||||
src/marshals.list
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
marshal-codegen
|
||||
DEPENDS
|
||||
src/marshal.c
|
||||
src/marshal.h
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
// Change this to use either our binding or GTK
|
||||
//
|
||||
#define TEST_USE_CTL_BINDING 1
|
||||
#define TEST_USE_CTL_BINDING 0
|
||||
|
||||
//
|
||||
// FORWARD DECLARATIONS
|
||||
@@ -17,6 +17,20 @@ static void wintc_menu_test_window_dispose(
|
||||
GObject* object
|
||||
);
|
||||
|
||||
static gint wintc_menu_test_window_find_item_index(
|
||||
GMenuModel* model,
|
||||
GMenuModel** target_model
|
||||
);
|
||||
|
||||
static void on_button_add_clicked(
|
||||
GtkButton* button,
|
||||
gpointer user_data
|
||||
);
|
||||
static void on_button_del_clicked(
|
||||
GtkButton* button,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
//
|
||||
// GTK OOP CLASS/INSTANCE DEFINITIONS
|
||||
//
|
||||
@@ -100,6 +114,43 @@ static void wintc_menu_test_window_init(
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(box_container), menu_bar);
|
||||
|
||||
// Add a strip for buttons for doing random additions/deletions
|
||||
//
|
||||
GtkWidget* box_buttons = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
|
||||
GtkWidget* button_add = gtk_button_new_with_label("Random add");
|
||||
GtkWidget* button_del = gtk_button_new_with_label("Random del");
|
||||
|
||||
gtk_box_pack_start(
|
||||
GTK_BOX(box_buttons),
|
||||
button_add,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0
|
||||
);
|
||||
gtk_box_pack_start(
|
||||
GTK_BOX(box_buttons),
|
||||
button_del,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0
|
||||
);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(box_container), box_buttons);
|
||||
|
||||
g_signal_connect(
|
||||
button_add,
|
||||
"clicked",
|
||||
G_CALLBACK(on_button_add_clicked),
|
||||
model
|
||||
);
|
||||
g_signal_connect(
|
||||
button_del,
|
||||
"clicked",
|
||||
G_CALLBACK(on_button_del_clicked),
|
||||
model
|
||||
);
|
||||
|
||||
// Show!
|
||||
//
|
||||
gtk_container_add(GTK_CONTAINER(self), box_container);
|
||||
@@ -140,3 +191,150 @@ GtkWidget* wintc_menu_test_window_new(
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// PRIVATE FUNCTIONS
|
||||
//
|
||||
static gint wintc_menu_test_window_find_item_index(
|
||||
GMenuModel* model,
|
||||
GMenuModel** target_model
|
||||
)
|
||||
{
|
||||
// We receive a top level model (the menu bar) - pick a menu to work on
|
||||
//
|
||||
gint n_items = g_menu_model_get_n_items(model);
|
||||
|
||||
GMenuModel* menu =
|
||||
g_menu_model_get_item_link(
|
||||
model,
|
||||
g_random_int_range(0, n_items),
|
||||
G_MENU_LINK_SUBMENU
|
||||
);
|
||||
|
||||
// Find an item
|
||||
//
|
||||
gint idx_rand;
|
||||
GMenuModel* model_current = menu;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
n_items = g_menu_model_get_n_items(model_current);
|
||||
|
||||
// 0 items? It's over
|
||||
//
|
||||
if (!n_items)
|
||||
{
|
||||
*target_model = model_current;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Wahey we have items, let's pick one
|
||||
//
|
||||
idx_rand = g_random_int_range(0, n_items);
|
||||
|
||||
// If we hit a submenu, enter it
|
||||
//
|
||||
GMenuModel* model_submenu =
|
||||
g_menu_model_get_item_link(
|
||||
model_current,
|
||||
idx_rand,
|
||||
G_MENU_LINK_SUBMENU
|
||||
);
|
||||
|
||||
if (model_submenu)
|
||||
{
|
||||
model_current = model_submenu;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise return this index
|
||||
//
|
||||
*target_model = model_current;
|
||||
return idx_rand;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// CALLBACKS
|
||||
//
|
||||
static void on_button_add_clicked(
|
||||
WINTC_UNUSED(GtkButton* button),
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
GMenuModel* model = G_MENU_MODEL(user_data);
|
||||
|
||||
gint target_idx;
|
||||
GMenuModel* target_model = NULL;
|
||||
|
||||
target_idx =
|
||||
wintc_menu_test_window_find_item_index(model, &target_model);
|
||||
|
||||
// Create and add the menu item
|
||||
//
|
||||
GMenuItem* menu_item = g_menu_item_new("A random item.", NULL);
|
||||
|
||||
g_menu_item_set_icon(
|
||||
menu_item,
|
||||
g_themed_icon_new("emblem-favorite")
|
||||
);
|
||||
|
||||
g_menu_insert_item(G_MENU(target_model), target_idx, menu_item);
|
||||
|
||||
g_object_unref(menu_item);
|
||||
}
|
||||
|
||||
static void on_button_del_clicked(
|
||||
WINTC_UNUSED(GtkButton* button),
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
GMenuModel* model = G_MENU_MODEL(user_data);
|
||||
|
||||
gint target_idx;
|
||||
GMenuModel* target_model = NULL;
|
||||
|
||||
// We shouldn't delete section items... this is really rubbish but I'm also
|
||||
// REALLY lazy so just try a few times to find a normal item otherwise give
|
||||
// up
|
||||
//
|
||||
gint attempts = 0;
|
||||
|
||||
while (attempts < 3)
|
||||
{
|
||||
attempts++;
|
||||
|
||||
target_idx =
|
||||
wintc_menu_test_window_find_item_index(model, &target_model);
|
||||
|
||||
// Skip if this item is a section
|
||||
//
|
||||
if (
|
||||
g_menu_model_get_item_link(
|
||||
target_model,
|
||||
target_idx,
|
||||
G_MENU_LINK_SECTION
|
||||
)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't delete if there's actually no items in this model
|
||||
//
|
||||
if (!g_menu_model_get_n_items(target_model))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// All good, bin the item
|
||||
//
|
||||
g_menu_remove(G_MENU(target_model), target_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
g_message(
|
||||
"%s",
|
||||
"Didn't land on a normal item to bin, better luck next time."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ typedef struct _WinTCCtlMenuBindingMenu
|
||||
GMenuModel* menu_model;
|
||||
|
||||
GList* sections;
|
||||
|
||||
gulong sigid_items_changed;
|
||||
} WinTCCtlMenuBindingMenu;
|
||||
|
||||
typedef struct _WinTCCtlMenuBindingSection
|
||||
@@ -70,6 +72,11 @@ static void wintc_ctl_menu_binding_insert_item(
|
||||
gint src_pos,
|
||||
gint dst_pos
|
||||
);
|
||||
static void wintc_ctl_menu_binding_remove_item(
|
||||
WinTCCtlMenuBindingMenu* menu,
|
||||
GMenuModel* menu_model,
|
||||
gint src_pos
|
||||
);
|
||||
static void wintc_ctl_menu_binding_track_menu(
|
||||
WinTCCtlMenuBinding* menu_binding,
|
||||
GtkMenuShell* menu_shell,
|
||||
@@ -80,6 +87,14 @@ static void wintc_ctl_menu_binding_menu_free(
|
||||
WinTCCtlMenuBindingMenu* menu
|
||||
);
|
||||
|
||||
static void on_menu_model_menu_items_changed(
|
||||
GMenuModel* model,
|
||||
gint position,
|
||||
gint removed,
|
||||
gint added,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
//
|
||||
// GTK OOP CLASS/INSTANCE DEFINITIONS
|
||||
//
|
||||
@@ -481,6 +496,11 @@ static void wintc_ctl_menu_binding_insert_item(
|
||||
gtk_widget_set_margin_end(img_icon, 6); // Got this from Mousepad
|
||||
gtk_widget_set_size_request(img_icon, 16, 16);
|
||||
|
||||
gtk_menu_item_set_reserve_indicator(
|
||||
GTK_MENU_ITEM(menu_item),
|
||||
TRUE
|
||||
);
|
||||
|
||||
if (icon)
|
||||
{
|
||||
gtk_image_set_from_gicon(
|
||||
@@ -537,6 +557,8 @@ static void wintc_ctl_menu_binding_insert_item(
|
||||
g_free(label);
|
||||
}
|
||||
|
||||
gtk_widget_show_all(menu_item);
|
||||
|
||||
// Do we have a submenu for this item?
|
||||
//
|
||||
GMenuModel* submenu_model =
|
||||
@@ -645,7 +667,7 @@ static void wintc_ctl_menu_binding_insert_item(
|
||||
//
|
||||
gint i = 0;
|
||||
|
||||
while (i < dst_pos)
|
||||
while (i < dst_pos && iter)
|
||||
{
|
||||
WinTCCtlMenuBindingSection* subsection =
|
||||
(WinTCCtlMenuBindingSection*) iter->data;
|
||||
@@ -661,13 +683,6 @@ static void wintc_ctl_menu_binding_insert_item(
|
||||
break;
|
||||
}
|
||||
|
||||
// No where else to go?
|
||||
//
|
||||
if (!(iter->next))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Moving on...
|
||||
//
|
||||
iter = iter->next;
|
||||
@@ -683,10 +698,55 @@ static void wintc_ctl_menu_binding_insert_item(
|
||||
}
|
||||
}
|
||||
|
||||
// If we found where to insert, then get that sorted
|
||||
//
|
||||
if (iter)
|
||||
{
|
||||
WinTCCtlMenuBindingSection* found_section =
|
||||
(WinTCCtlMenuBindingSection*) iter->data;
|
||||
|
||||
// If this is a real section, look for a fake section before it to
|
||||
// insert into instead
|
||||
//
|
||||
if (found_section->menu_model && iter->prev)
|
||||
{
|
||||
WinTCCtlMenuBindingSection* prev_section =
|
||||
(WinTCCtlMenuBindingSection*) iter->prev->data;
|
||||
|
||||
if (!(prev_section->menu_model))
|
||||
{
|
||||
found_section = prev_section;
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have a fake section? If not, create a new one before the real
|
||||
// section
|
||||
//
|
||||
if (found_section->menu_model)
|
||||
{
|
||||
found_section = g_new(WinTCCtlMenuBindingSection, 1);
|
||||
|
||||
found_section->parent_menu = menu;
|
||||
found_section->menu_model = NULL;
|
||||
found_section->item_count = 0; // Will be incremented in a moment
|
||||
|
||||
menu->sections =
|
||||
g_list_insert_before(
|
||||
menu->sections,
|
||||
iter,
|
||||
found_section
|
||||
);
|
||||
}
|
||||
|
||||
found_section->item_count++;
|
||||
gtk_menu_shell_insert(menu->menu_shell, menu_item, real_pos);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we fell out, we need to add the item to the end of the menu
|
||||
//
|
||||
WinTCCtlMenuBindingSection* last_section =
|
||||
(WinTCCtlMenuBindingSection*) iter->data;
|
||||
(WinTCCtlMenuBindingSection*) (g_list_last(menu->sections))->data;
|
||||
|
||||
if (last_section->menu_model)
|
||||
{
|
||||
@@ -709,6 +769,158 @@ static void wintc_ctl_menu_binding_insert_item(
|
||||
gtk_menu_shell_append(menu->menu_shell, menu_item);
|
||||
}
|
||||
|
||||
static void wintc_ctl_menu_binding_remove_item(
|
||||
WinTCCtlMenuBindingMenu* menu,
|
||||
GMenuModel* menu_model,
|
||||
gint src_pos
|
||||
)
|
||||
{
|
||||
gboolean is_subsection = menu_model != menu->menu_model;
|
||||
|
||||
// Let's fine the position of the item to bin!
|
||||
//
|
||||
gint real_pos = 0;
|
||||
|
||||
if (is_subsection)
|
||||
{
|
||||
for (GList* iter = menu->sections; iter; iter = iter->next)
|
||||
{
|
||||
WinTCCtlMenuBindingSection* check_section =
|
||||
(WinTCCtlMenuBindingSection*) iter->data;
|
||||
|
||||
if (!(check_section->menu_model))
|
||||
{
|
||||
real_pos += check_section->item_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (check_section->menu_model == menu_model)
|
||||
{
|
||||
real_pos += src_pos;
|
||||
|
||||
check_section->item_count--;
|
||||
|
||||
gtk_widget_destroy(
|
||||
wintc_container_get_nth_child(
|
||||
GTK_CONTAINER(menu->menu_shell),
|
||||
real_pos
|
||||
)
|
||||
);
|
||||
|
||||
// Handle when we just destroyed the last item in a section
|
||||
//
|
||||
if (!(check_section->item_count))
|
||||
{
|
||||
menu->sections =
|
||||
g_list_delete_link(
|
||||
menu->sections,
|
||||
iter
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gint i = 0;
|
||||
|
||||
for (GList* iter = menu->sections; iter; iter = iter->next)
|
||||
{
|
||||
WinTCCtlMenuBindingSection* check_section =
|
||||
(WinTCCtlMenuBindingSection*) iter->data;
|
||||
|
||||
if (i == src_pos)
|
||||
{
|
||||
// If the item referred to is the section itself, we need to
|
||||
// delete the entire section
|
||||
//
|
||||
if (check_section->menu_model)
|
||||
{
|
||||
for (gint j = 0; j < check_section->item_count; j++)
|
||||
{
|
||||
gtk_widget_destroy(
|
||||
wintc_container_get_nth_child(
|
||||
GTK_CONTAINER(menu->menu_shell),
|
||||
real_pos
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
menu->sections =
|
||||
g_list_delete_link(
|
||||
menu->sections,
|
||||
iter
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
check_section->item_count--;
|
||||
|
||||
gtk_widget_destroy(
|
||||
wintc_container_get_nth_child(
|
||||
GTK_CONTAINER(menu->menu_shell),
|
||||
real_pos
|
||||
)
|
||||
);
|
||||
|
||||
if (!(check_section->item_count))
|
||||
{
|
||||
menu->sections =
|
||||
g_list_delete_link(
|
||||
menu->sections,
|
||||
iter
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep looking...
|
||||
//
|
||||
// If this section is real, then no fancy stuff is required - if
|
||||
// it's a 'fake' section then we need to check whether src_pos is
|
||||
// inside it
|
||||
//
|
||||
if (check_section->menu_model)
|
||||
{
|
||||
i++;
|
||||
real_pos += check_section->item_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i + check_section->item_count > src_pos)
|
||||
{
|
||||
real_pos += src_pos - i;
|
||||
|
||||
check_section->item_count--;
|
||||
|
||||
gtk_widget_destroy(
|
||||
wintc_container_get_nth_child(
|
||||
GTK_CONTAINER(menu->menu_shell),
|
||||
real_pos
|
||||
)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
i += check_section->item_count;
|
||||
real_pos += check_section->item_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_critical(
|
||||
"%s",
|
||||
"comctl - menu binding - somehow failed to find menu item to delete?"
|
||||
);
|
||||
}
|
||||
|
||||
static void wintc_ctl_menu_binding_track_menu(
|
||||
WinTCCtlMenuBinding* menu_binding,
|
||||
GtkMenuShell* menu_shell,
|
||||
@@ -725,6 +937,19 @@ static void wintc_ctl_menu_binding_track_menu(
|
||||
tracker->menu_model = menu_model;
|
||||
tracker->sections = NULL;
|
||||
|
||||
WINTC_LOG_DEBUG(
|
||||
"comctl - menu binding - new menu tracker: %p",
|
||||
(void*) tracker
|
||||
);
|
||||
|
||||
tracker->sigid_items_changed =
|
||||
g_signal_connect(
|
||||
menu_model,
|
||||
"items-changed",
|
||||
G_CALLBACK(on_menu_model_menu_items_changed),
|
||||
tracker
|
||||
);
|
||||
|
||||
menu_binding->tracked_menus =
|
||||
g_slist_append(
|
||||
menu_binding->tracked_menus,
|
||||
@@ -753,3 +978,38 @@ static void wintc_ctl_menu_binding_menu_free(
|
||||
g_clear_list(&(menu->sections), (GDestroyNotify) g_free);
|
||||
g_free(menu);
|
||||
}
|
||||
|
||||
//
|
||||
// CALLBACKS
|
||||
//
|
||||
static void on_menu_model_menu_items_changed(
|
||||
GMenuModel* model,
|
||||
gint position,
|
||||
gint removed,
|
||||
gint added,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
WinTCCtlMenuBindingMenu* menu = (WinTCCtlMenuBindingMenu*) user_data;
|
||||
|
||||
WINTC_LOG_DEBUG(
|
||||
"comctl - menubind - update pos %d, remove %d, add %d",
|
||||
position,
|
||||
removed,
|
||||
added
|
||||
);
|
||||
|
||||
// Removed items
|
||||
//
|
||||
for (gint i = position; i < position + removed; i++)
|
||||
{
|
||||
wintc_ctl_menu_binding_remove_item(menu, model, i);
|
||||
}
|
||||
|
||||
// Added items
|
||||
//
|
||||
for (gint i = position; i < position + added; i++)
|
||||
{
|
||||
wintc_ctl_menu_binding_insert_item(menu, model, i, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,16 @@ void wintc_container_clear(
|
||||
GtkContainer* container
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the nth child widget of a container.
|
||||
*
|
||||
* @param container The container.
|
||||
* @param pos The index of the widget.
|
||||
* @return The child widget at position N in the container.
|
||||
*/
|
||||
GtkWidget* wintc_container_get_nth_child(
|
||||
GtkContainer* container,
|
||||
gint pos
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/** @file */
|
||||
|
||||
#ifndef __COMGTK_MEMORY_H__
|
||||
#define __COMGTK_MEMORY_H__
|
||||
|
||||
@@ -6,15 +8,47 @@
|
||||
//
|
||||
// PUBLIC FUNCTIONS
|
||||
//
|
||||
|
||||
/**
|
||||
* Frees a null-terminated array - the provided function will be called to free
|
||||
* each of the array elements.
|
||||
*
|
||||
* @param mem The array.
|
||||
* @param destroy The function for freeing an individual element.
|
||||
*/
|
||||
void wintc_freev(
|
||||
gpointer mem,
|
||||
GDestroyNotify destroy
|
||||
);
|
||||
|
||||
/**
|
||||
* Frees an array of the specified size - the provided function will be called
|
||||
* to free each of the array elements.
|
||||
*
|
||||
* @param mem The array.
|
||||
* @param n_elements The number of elements in the array.
|
||||
* @param destroy The function for freeing an individual element.
|
||||
*/
|
||||
void wintc_freenv(
|
||||
gpointer mem,
|
||||
guint n_elements,
|
||||
GDestroyNotify destroy
|
||||
);
|
||||
|
||||
/**
|
||||
* Convenience function for using memcpy where potentially the destination
|
||||
* buffer is NULL, in which case nothing will be done.
|
||||
*
|
||||
* @param dst_buf The reference to the buffer to copy into.
|
||||
* @param offset The offset into the destination buffer to copy at.
|
||||
* @param src_buf The source buffer.
|
||||
* @param n The number of bytes to be copied.
|
||||
*/
|
||||
void wintc_memcpy_ref(
|
||||
void* dst_buf,
|
||||
glong offset,
|
||||
const void* src_buf,
|
||||
size_t n
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -69,6 +69,24 @@ gchar* wintc_str_set_suffix(
|
||||
const gchar* suffix
|
||||
);
|
||||
|
||||
/**
|
||||
* Duplicates part of a string from the start and ending at the first
|
||||
* occurrence of the specified delimiter (exclusive, so the delimiter will not
|
||||
* be included).
|
||||
*
|
||||
* @param str The string.
|
||||
* @param len The maximum length of str to use, -1 for null terminated string.
|
||||
* @param c The character to look for.
|
||||
* @param pos If not NULL, a storage location for position after the delimiter.
|
||||
* @return The new string, a complete copy of the string if c wasn't found.
|
||||
*/
|
||||
gchar* wintc_strdup_nextchr(
|
||||
const gchar* str,
|
||||
gssize len,
|
||||
gunichar c,
|
||||
const gchar** pos
|
||||
);
|
||||
|
||||
/**
|
||||
* Duplicates a string and replaces the string at the destination with it - if
|
||||
* there was a string at the destination pointer, it will be freed.
|
||||
@@ -130,4 +148,16 @@ guint wintc_strv_length(
|
||||
const gchar** str_array
|
||||
);
|
||||
|
||||
/**
|
||||
* Extracts a substring from one string to create a new string.
|
||||
*
|
||||
* @param start A pointer to the start of the substring.
|
||||
* @param end A pointer to the end of the substring.
|
||||
* @return A copy of the substring.
|
||||
*/
|
||||
gchar* wintc_substr(
|
||||
const gchar* start,
|
||||
const gchar* end
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,3 +22,18 @@ void wintc_container_clear(
|
||||
|
||||
g_list_free(children);
|
||||
}
|
||||
|
||||
GtkWidget* wintc_container_get_nth_child(
|
||||
GtkContainer* container,
|
||||
gint pos
|
||||
)
|
||||
{
|
||||
GList* children = gtk_container_get_children(container);
|
||||
|
||||
GtkWidget* nth_child =
|
||||
GTK_WIDGET(g_list_nth_data(children, pos));
|
||||
|
||||
g_list_free(children);
|
||||
|
||||
return nth_child;
|
||||
}
|
||||
|
||||
@@ -35,3 +35,18 @@ void wintc_freenv(
|
||||
|
||||
g_free(mem);
|
||||
}
|
||||
|
||||
void wintc_memcpy_ref(
|
||||
void* dst_buf,
|
||||
glong offset,
|
||||
const void* src_buf,
|
||||
size_t n
|
||||
)
|
||||
{
|
||||
if (!dst_buf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dst_buf + offset, src_buf, n);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../public/shorthand.h"
|
||||
#include "../public/strings.h"
|
||||
|
||||
//
|
||||
@@ -59,6 +60,43 @@ gchar* wintc_str_set_suffix(
|
||||
}
|
||||
}
|
||||
|
||||
gchar* wintc_strdup_nextchr(
|
||||
const gchar* str,
|
||||
gssize len,
|
||||
gunichar c,
|
||||
const gchar** pos
|
||||
)
|
||||
{
|
||||
const gchar* end;
|
||||
|
||||
if (!str)
|
||||
{
|
||||
WINTC_SAFE_REF_SET(pos, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end = g_utf8_strchr(str, len, c);
|
||||
|
||||
if (pos)
|
||||
{
|
||||
WINTC_SAFE_REF_SET(pos, end ? end + 1 : NULL);
|
||||
}
|
||||
|
||||
if (!end)
|
||||
{
|
||||
return g_strdup(str);
|
||||
}
|
||||
|
||||
// Allocate new string
|
||||
//
|
||||
gint diff = end - str;
|
||||
gchar* buf = g_malloc0(diff + 1);
|
||||
|
||||
memcpy(buf, str, diff);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void wintc_strdup_replace(
|
||||
gchar** dest,
|
||||
const gchar* src
|
||||
@@ -180,3 +218,24 @@ guint wintc_strv_length(
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
gchar* wintc_substr(
|
||||
const gchar* start,
|
||||
const gchar* end
|
||||
)
|
||||
{
|
||||
if (end < start)
|
||||
{
|
||||
g_critical("substr: invalid substring requested");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gchar* buf = g_malloc0(end - start + 1);
|
||||
|
||||
if (start != end)
|
||||
{
|
||||
memcpy(buf, start, end - start);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -13,9 +13,12 @@ set(PROJECT_MAINTAINER "Rory Fewell <roryf@oddmatics.uk>")
|
||||
|
||||
set(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
set(WINTC_NO_PEDANTIC_COMPILE true) # Necessary for glib-genmarshal
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
include(../../packaging/cmake-inc/common/CMakeLists.txt)
|
||||
include(../../packaging/cmake-inc/codegen/CMakeLists.txt)
|
||||
include(../../packaging/cmake-inc/libraries/CMakeLists.txt)
|
||||
include(../../packaging/cmake-inc/linking/CMakeLists.txt)
|
||||
include(../../packaging/cmake-inc/packaging/CMakeLists.txt)
|
||||
@@ -24,10 +27,16 @@ wintc_resolve_library(glib-2.0 GLIB)
|
||||
wintc_resolve_library(gtk+-3.0 GTK3)
|
||||
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
|
||||
|
||||
wintc_glib_genmarshal()
|
||||
|
||||
add_library(
|
||||
libwintc-shcommon
|
||||
src/fs.c
|
||||
public/fs.h
|
||||
src/marshal.c
|
||||
src/marshal.h
|
||||
src/monitor.c
|
||||
public/monitor.h
|
||||
src/path.c
|
||||
public/path.h
|
||||
src/places.c
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef __SHCOMMON_FS_H__
|
||||
#define __SHCOMMON_FS_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
//
|
||||
// PUBLIC FUNCTIONS
|
||||
//
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __WINTC_SHCOMMON_H__
|
||||
|
||||
#include "@LIB_HEADER_DIR@/fs.h"
|
||||
#include "@LIB_HEADER_DIR@/monitor.h"
|
||||
#include "@LIB_HEADER_DIR@/path.h"
|
||||
#include "@LIB_HEADER_DIR@/places.h"
|
||||
|
||||
|
||||
31
shared/shcommon/public/monitor.h
Normal file
31
shared/shcommon/public/monitor.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef __SHCOMMON_MONITOR_H__
|
||||
#define __SHCOMMON_MONITOR_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
|
||||
//
|
||||
// GTK OOP BOILERPLATE
|
||||
//
|
||||
#define WINTC_TYPE_SH_DIR_MONITOR_RECURSIVE (wintc_sh_dir_monitor_recursive_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE(
|
||||
WinTCShDirMonitorRecursive,
|
||||
wintc_sh_dir_monitor_recursive,
|
||||
WINTC,
|
||||
SH_DIR_MONITOR_RECURSIVE,
|
||||
GObject
|
||||
)
|
||||
|
||||
|
||||
//
|
||||
// PUBLIC FUNCTIONS
|
||||
//
|
||||
WinTCShDirMonitorRecursive* wintc_sh_fs_monitor_directory_recursive(
|
||||
GFile* file,
|
||||
GFileMonitorFlags flags,
|
||||
GCancellable* cancellable,
|
||||
GError** error
|
||||
);
|
||||
|
||||
#endif
|
||||
1
shared/shcommon/src/marshals.list
Normal file
1
shared/shcommon/src/marshals.list
Normal file
@@ -0,0 +1 @@
|
||||
VOID:OBJECT,OBJECT,INT
|
||||
537
shared/shcommon/src/monitor.c
Normal file
537
shared/shcommon/src/monitor.c
Normal file
@@ -0,0 +1,537 @@
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
#include <wintc/comgtk.h>
|
||||
|
||||
#include "../public/fs.h"
|
||||
#include "../public/monitor.h"
|
||||
#include "marshal.h"
|
||||
|
||||
//
|
||||
// PRIVATE ENUMS
|
||||
//
|
||||
enum
|
||||
{
|
||||
PROP_FILE = 1,
|
||||
PROP_FILE_MONITOR
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_CHANGED = 0,
|
||||
N_SIGNALS
|
||||
};
|
||||
|
||||
//
|
||||
// FORWARD DECLARATIONS
|
||||
//
|
||||
static void wintc_sh_dir_monitor_recursive_constructed(
|
||||
GObject* object
|
||||
);
|
||||
static void wintc_sh_dir_monitor_recursive_dispose(
|
||||
GObject* object
|
||||
);
|
||||
static void wintc_sh_dir_monitor_recursive_get_property(
|
||||
GObject* object,
|
||||
guint prop_id,
|
||||
GValue* value,
|
||||
GParamSpec* pspec
|
||||
);
|
||||
static void wintc_sh_dir_monitor_recursive_set_property(
|
||||
GObject* object,
|
||||
guint prop_id,
|
||||
const GValue* value,
|
||||
GParamSpec* pspec
|
||||
);
|
||||
|
||||
static void wintc_sh_dir_monitor_recursive_delete_monitor(
|
||||
WinTCShDirMonitorRecursive* monitor_recursive,
|
||||
GFile* file
|
||||
);
|
||||
static void wintc_sh_dir_monitor_recursive_new_monitor(
|
||||
WinTCShDirMonitorRecursive* monitor_recursive,
|
||||
GFile* file
|
||||
);
|
||||
|
||||
static void on_file_monitor_root_changed(
|
||||
GFileMonitor* monitor,
|
||||
GFile* file,
|
||||
GFile* other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data
|
||||
);
|
||||
static void on_file_monitor_subdir_changed(
|
||||
GFileMonitor* monitor,
|
||||
GFile* file,
|
||||
GFile* other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
//
|
||||
// STATIC DATA
|
||||
//
|
||||
static gint wintc_sh_dir_monitor_recursive_signals[N_SIGNALS] = { 0 };
|
||||
|
||||
//
|
||||
// GTK OOP CLASS/INSTANCE DEFINITIONS
|
||||
//
|
||||
struct _WinTCShDirMonitorRecursive
|
||||
{
|
||||
GObject __parent__;
|
||||
|
||||
GFile* file_root;
|
||||
GFileMonitor* monitor_root;
|
||||
|
||||
GHashTable* map_rel_path_to_monitor;
|
||||
};
|
||||
|
||||
//
|
||||
// GTK TYPE DEFINITIONS & CTORS
|
||||
//
|
||||
G_DEFINE_TYPE(
|
||||
WinTCShDirMonitorRecursive,
|
||||
wintc_sh_dir_monitor_recursive,
|
||||
G_TYPE_OBJECT
|
||||
)
|
||||
|
||||
static void wintc_sh_dir_monitor_recursive_class_init(
|
||||
WinTCShDirMonitorRecursiveClass* klass
|
||||
)
|
||||
{
|
||||
GObjectClass* object_class = G_OBJECT_CLASS(klass);
|
||||
|
||||
object_class->constructed = wintc_sh_dir_monitor_recursive_constructed;
|
||||
object_class->dispose = wintc_sh_dir_monitor_recursive_dispose;
|
||||
object_class->get_property = wintc_sh_dir_monitor_recursive_get_property;
|
||||
object_class->set_property = wintc_sh_dir_monitor_recursive_set_property;
|
||||
|
||||
g_object_class_install_property(
|
||||
object_class,
|
||||
PROP_FILE,
|
||||
g_param_spec_object(
|
||||
"file",
|
||||
"File",
|
||||
"The root directory to monitor recursively.",
|
||||
G_TYPE_FILE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
|
||||
)
|
||||
);
|
||||
g_object_class_install_property(
|
||||
object_class,
|
||||
PROP_FILE_MONITOR,
|
||||
g_param_spec_object(
|
||||
"file-monitor",
|
||||
"FileMonitor",
|
||||
"The file monitor for the root directory.",
|
||||
G_TYPE_FILE_MONITOR,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
|
||||
)
|
||||
);
|
||||
|
||||
wintc_sh_dir_monitor_recursive_signals[SIGNAL_CHANGED] =
|
||||
g_signal_new(
|
||||
"changed",
|
||||
G_TYPE_FROM_CLASS(object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
wintc_cclosure_marshal_VOID__OBJECT_OBJECT_INT,
|
||||
G_TYPE_NONE,
|
||||
3,
|
||||
G_TYPE_OBJECT,
|
||||
G_TYPE_OBJECT,
|
||||
G_TYPE_INT
|
||||
);
|
||||
}
|
||||
|
||||
static void wintc_sh_dir_monitor_recursive_init(
|
||||
WINTC_UNUSED(WinTCShDirMonitorRecursive* self)
|
||||
) {}
|
||||
|
||||
//
|
||||
// CLASS VIRTUAL METHODS
|
||||
//
|
||||
static void wintc_sh_dir_monitor_recursive_constructed(
|
||||
GObject* object
|
||||
)
|
||||
{
|
||||
WinTCShDirMonitorRecursive* monitor_recursive =
|
||||
WINTC_SH_DIR_MONITOR_RECURSIVE(object);
|
||||
|
||||
if (
|
||||
!(monitor_recursive->file_root) ||
|
||||
!(monitor_recursive->monitor_root)
|
||||
)
|
||||
{
|
||||
g_critical("%s", "shcommon: invalid dir monitor created");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up signal for the root monitor
|
||||
//
|
||||
g_signal_connect(
|
||||
monitor_recursive->monitor_root,
|
||||
"changed",
|
||||
G_CALLBACK(on_file_monitor_root_changed),
|
||||
monitor_recursive
|
||||
);
|
||||
|
||||
// Pull the root path details
|
||||
//
|
||||
const gchar* root_path = g_file_peek_path(monitor_recursive->file_root);
|
||||
gint root_len = g_utf8_strlen(root_path, -1);
|
||||
|
||||
// Build monitors recursively in the map
|
||||
//
|
||||
GList* files =
|
||||
wintc_sh_fs_get_names_as_list(
|
||||
root_path,
|
||||
TRUE,
|
||||
G_FILE_TEST_IS_DIR,
|
||||
TRUE,
|
||||
NULL // FIXME: Error handling
|
||||
);
|
||||
|
||||
monitor_recursive->map_rel_path_to_monitor =
|
||||
g_hash_table_new_full(
|
||||
g_str_hash,
|
||||
g_str_equal,
|
||||
(GDestroyNotify) g_free,
|
||||
(GDestroyNotify) g_object_unref
|
||||
);
|
||||
|
||||
for (GList* iter = files; iter; iter = iter->next)
|
||||
{
|
||||
GFile* file =
|
||||
g_file_new_for_path(
|
||||
(gchar*) iter->data
|
||||
);
|
||||
|
||||
GFileMonitor* monitor =
|
||||
g_file_monitor_directory(
|
||||
file,
|
||||
G_FILE_MONITOR_NONE,
|
||||
NULL,
|
||||
NULL // FIXME: Error handling
|
||||
);
|
||||
|
||||
|
||||
if (monitor)
|
||||
{
|
||||
g_signal_connect(
|
||||
monitor,
|
||||
"changed",
|
||||
G_CALLBACK(on_file_monitor_subdir_changed),
|
||||
monitor_recursive
|
||||
);
|
||||
|
||||
g_hash_table_insert(
|
||||
monitor_recursive->map_rel_path_to_monitor,
|
||||
g_strdup(root_path + root_len),
|
||||
monitor
|
||||
);
|
||||
}
|
||||
|
||||
g_object_unref(file);
|
||||
}
|
||||
|
||||
g_list_free_full(files, (GDestroyNotify) g_free);
|
||||
}
|
||||
|
||||
static void wintc_sh_dir_monitor_recursive_dispose(
|
||||
GObject* object
|
||||
)
|
||||
{
|
||||
WinTCShDirMonitorRecursive* monitor_recursive =
|
||||
WINTC_SH_DIR_MONITOR_RECURSIVE(object);
|
||||
|
||||
g_clear_object(&(monitor_recursive->file_root));
|
||||
g_clear_object(&(monitor_recursive->monitor_root));
|
||||
|
||||
g_hash_table_destroy(
|
||||
g_steal_pointer(&(monitor_recursive->map_rel_path_to_monitor))
|
||||
);
|
||||
|
||||
(G_OBJECT_CLASS(wintc_sh_dir_monitor_recursive_parent_class))
|
||||
->dispose(object);
|
||||
}
|
||||
|
||||
static void wintc_sh_dir_monitor_recursive_get_property(
|
||||
GObject* object,
|
||||
guint prop_id,
|
||||
GValue* value,
|
||||
GParamSpec* pspec
|
||||
)
|
||||
{
|
||||
WinTCShDirMonitorRecursive* monitor_recursive =
|
||||
WINTC_SH_DIR_MONITOR_RECURSIVE(object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FILE:
|
||||
g_value_set_object(value, monitor_recursive->file_root);
|
||||
break;
|
||||
|
||||
case PROP_FILE_MONITOR:
|
||||
g_value_set_object(value, monitor_recursive->monitor_root);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void wintc_sh_dir_monitor_recursive_set_property(
|
||||
GObject* object,
|
||||
guint prop_id,
|
||||
const GValue* value,
|
||||
GParamSpec* pspec
|
||||
)
|
||||
{
|
||||
WinTCShDirMonitorRecursive* monitor_recursive =
|
||||
WINTC_SH_DIR_MONITOR_RECURSIVE(object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FILE:
|
||||
monitor_recursive->file_root = g_value_dup_object(value);
|
||||
break;
|
||||
|
||||
case PROP_FILE_MONITOR:
|
||||
monitor_recursive->monitor_root = g_value_dup_object(value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PUBLIC FUNCTIONS
|
||||
//
|
||||
WinTCShDirMonitorRecursive* wintc_sh_fs_monitor_directory_recursive(
|
||||
GFile* file,
|
||||
GFileMonitorFlags flags,
|
||||
GCancellable* cancellable,
|
||||
GError** error
|
||||
)
|
||||
{
|
||||
GFileMonitor* monitor =
|
||||
g_file_monitor_directory(
|
||||
file,
|
||||
flags,
|
||||
cancellable,
|
||||
error
|
||||
);
|
||||
|
||||
if (!monitor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return WINTC_SH_DIR_MONITOR_RECURSIVE(
|
||||
g_object_new(
|
||||
WINTC_TYPE_SH_DIR_MONITOR_RECURSIVE,
|
||||
"file", file,
|
||||
"file-monitor", monitor,
|
||||
NULL
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// PRIVATE FUNCTIONS
|
||||
//
|
||||
static void wintc_sh_dir_monitor_recursive_delete_monitor(
|
||||
WinTCShDirMonitorRecursive* monitor_recursive,
|
||||
GFile* file
|
||||
)
|
||||
{
|
||||
const gchar* rel_path =
|
||||
g_file_peek_path(file) +
|
||||
g_utf8_strlen(
|
||||
g_file_peek_path(monitor_recursive->file_root),
|
||||
-1
|
||||
);
|
||||
|
||||
if (
|
||||
!g_hash_table_lookup(
|
||||
monitor_recursive->map_rel_path_to_monitor,
|
||||
rel_path
|
||||
)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_hash_table_remove(
|
||||
monitor_recursive->map_rel_path_to_monitor,
|
||||
rel_path
|
||||
);
|
||||
}
|
||||
|
||||
static void wintc_sh_dir_monitor_recursive_new_monitor(
|
||||
WinTCShDirMonitorRecursive* monitor_recursive,
|
||||
GFile* file
|
||||
)
|
||||
{
|
||||
const gchar* rel_path =
|
||||
g_file_peek_path(file) +
|
||||
g_utf8_strlen(
|
||||
g_file_peek_path(monitor_recursive->file_root),
|
||||
-1
|
||||
);
|
||||
|
||||
if (
|
||||
g_hash_table_lookup(
|
||||
monitor_recursive->map_rel_path_to_monitor,
|
||||
rel_path
|
||||
)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to create a directory monitor
|
||||
//
|
||||
GFileMonitor* monitor =
|
||||
g_file_monitor_directory(
|
||||
file,
|
||||
G_FILE_MONITOR_NONE,
|
||||
NULL,
|
||||
NULL // FIXME: Error handling
|
||||
);
|
||||
|
||||
if (!monitor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_hash_table_insert(
|
||||
monitor_recursive->map_rel_path_to_monitor,
|
||||
g_strdup(rel_path),
|
||||
monitor
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// CALLBACKS
|
||||
//
|
||||
static void on_file_monitor_root_changed(
|
||||
WINTC_UNUSED(GFileMonitor* monitor),
|
||||
GFile* file,
|
||||
WINTC_UNUSED(GFile* other_file),
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
WinTCShDirMonitorRecursive* monitor_recursive =
|
||||
WINTC_SH_DIR_MONITOR_RECURSIVE(user_data);
|
||||
|
||||
switch (event_type)
|
||||
{
|
||||
case G_FILE_MONITOR_EVENT_CREATED:
|
||||
WINTC_LOG_DEBUG(
|
||||
"shcommon: new item in root: %s",
|
||||
g_file_peek_path(file)
|
||||
);
|
||||
|
||||
wintc_sh_dir_monitor_recursive_new_monitor(
|
||||
monitor_recursive,
|
||||
file
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_DELETED:
|
||||
WINTC_LOG_DEBUG(
|
||||
"shcommon: deleted item in root: %s",
|
||||
g_file_peek_path(file)
|
||||
);
|
||||
|
||||
wintc_sh_dir_monitor_recursive_delete_monitor(
|
||||
monitor_recursive,
|
||||
file
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
WINTC_LOG_DEBUG(
|
||||
"shcommon: unhandled event in root: %s (%d)",
|
||||
g_file_peek_path(file),
|
||||
event_type
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
g_signal_emit(
|
||||
monitor_recursive,
|
||||
wintc_sh_dir_monitor_recursive_signals[SIGNAL_CHANGED],
|
||||
0,
|
||||
file,
|
||||
other_file,
|
||||
event_type
|
||||
);
|
||||
}
|
||||
|
||||
static void on_file_monitor_subdir_changed(
|
||||
WINTC_UNUSED(GFileMonitor* monitor),
|
||||
GFile* file,
|
||||
WINTC_UNUSED(GFile* other_file),
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
WinTCShDirMonitorRecursive* monitor_recursive =
|
||||
WINTC_SH_DIR_MONITOR_RECURSIVE(user_data);
|
||||
|
||||
switch (event_type)
|
||||
{
|
||||
case G_FILE_MONITOR_EVENT_CREATED:
|
||||
WINTC_LOG_DEBUG(
|
||||
"shcommon: new item in subdir: %s",
|
||||
g_file_peek_path(file)
|
||||
);
|
||||
|
||||
wintc_sh_dir_monitor_recursive_new_monitor(
|
||||
monitor_recursive,
|
||||
file
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case G_FILE_MONITOR_EVENT_DELETED:
|
||||
WINTC_LOG_DEBUG(
|
||||
"shcommon: deleted item in subdir: %s",
|
||||
g_file_peek_path(file)
|
||||
);
|
||||
|
||||
wintc_sh_dir_monitor_recursive_delete_monitor(
|
||||
monitor_recursive,
|
||||
file
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
WINTC_LOG_DEBUG(
|
||||
"shcommon: unhandled event in subdir: %s (%d)",
|
||||
g_file_peek_path(file),
|
||||
event_type
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
g_signal_emit(
|
||||
monitor_recursive,
|
||||
wintc_sh_dir_monitor_recursive_signals[SIGNAL_CHANGED],
|
||||
0,
|
||||
file,
|
||||
other_file,
|
||||
event_type
|
||||
);
|
||||
}
|
||||
@@ -127,14 +127,6 @@ void create_personal_menu(
|
||||
GtkBuilder* builder;
|
||||
WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(toolbar_start);
|
||||
|
||||
GError* error = NULL;
|
||||
|
||||
if (!wintc_toolbar_start_progmenu_init(&error))
|
||||
{
|
||||
wintc_display_error_and_clear(&error, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default states
|
||||
//
|
||||
toolbar_start->personal.sync_menu_refresh = TRUE;
|
||||
@@ -266,6 +258,7 @@ 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(
|
||||
toolbar_start->progmenu,
|
||||
&(toolbar_start->personal.all_programs_binding)
|
||||
)
|
||||
);
|
||||
@@ -858,6 +851,9 @@ static void refresh_personal_menu(
|
||||
)
|
||||
);
|
||||
|
||||
g_object_unref(entry_internet);
|
||||
g_object_unref(entry_email);
|
||||
|
||||
// Add separator between defaults & MFU
|
||||
//
|
||||
gtk_menu_shell_append(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,15 +5,27 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <wintc/comctl.h>
|
||||
|
||||
//
|
||||
// GTK OOP BOILERPLATE
|
||||
//
|
||||
#define WINTC_TYPE_TOOLBAR_START_PROGMENU (wintc_toolbar_start_progmenu_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE(
|
||||
WinTCToolbarStartProgmenu,
|
||||
wintc_toolbar_start_progmenu,
|
||||
WINTC,
|
||||
TOOLBAR_START_PROGMENU,
|
||||
GObject
|
||||
)
|
||||
|
||||
//
|
||||
// PUBLIC FUNCTIONS
|
||||
//
|
||||
gboolean wintc_toolbar_start_progmenu_init(
|
||||
GError** error
|
||||
);
|
||||
WinTCToolbarStartProgmenu* wintc_toolbar_start_progmenu_new(void);
|
||||
|
||||
GtkWidget* wintc_toolbar_start_progmenu_new_gtk_menu(
|
||||
WinTCCtlMenuBinding** menu_binding
|
||||
WinTCToolbarStartProgmenu* progmenu,
|
||||
WinTCCtlMenuBinding** menu_binding
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <wintc/comctl.h>
|
||||
|
||||
#include "progmenu.h"
|
||||
|
||||
//
|
||||
// INTERNAL STRUCTS
|
||||
//
|
||||
@@ -51,6 +53,8 @@ typedef struct _WinTCToolbarStart
|
||||
//
|
||||
PersonalStartMenuData personal;
|
||||
|
||||
WinTCToolbarStartProgmenu* progmenu;
|
||||
|
||||
// UI state
|
||||
//
|
||||
gboolean sync_button;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "../toolbar.h"
|
||||
#include "personal.h"
|
||||
#include "progmenu.h"
|
||||
#include "shared.h"
|
||||
#include "toolbar.h"
|
||||
|
||||
@@ -66,6 +67,10 @@ static void wintc_toolbar_start_init(
|
||||
GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
|
||||
);
|
||||
|
||||
// Initialize progmenu
|
||||
//
|
||||
self->progmenu = wintc_toolbar_start_progmenu_new();
|
||||
|
||||
// Create root widget (Start button)
|
||||
//
|
||||
builder =
|
||||
@@ -120,6 +125,10 @@ static void wintc_toolbar_start_dispose(
|
||||
//
|
||||
destroy_personal_menu(toolbar_start);
|
||||
|
||||
// Destroy progmenu - ensures the data will be saved
|
||||
//
|
||||
g_object_unref(toolbar_start->progmenu);
|
||||
|
||||
(G_OBJECT_CLASS(wintc_toolbar_start_parent_class))->dispose(object);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,8 @@ static void wintc_notification_power_constructed(
|
||||
|
||||
update_client_on_battery(power, power->up_client);
|
||||
|
||||
g_ptr_array_unref(all_devices);
|
||||
|
||||
(G_OBJECT_CLASS(
|
||||
wintc_notification_power_parent_class
|
||||
))->constructed(object);
|
||||
|
||||
Reference in New Issue
Block a user