mirror of
https://github.com/rozniak/xfce-winxp-tc.git
synced 2026-01-26 11:39: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/
|
[Bb]uild/
|
||||||
config.h
|
config.h
|
||||||
libapi.h
|
libapi.h
|
||||||
|
marshal.c
|
||||||
|
marshal.h
|
||||||
meta.h
|
meta.h
|
||||||
resources.c
|
resources.c
|
||||||
*.deb
|
*.deb
|
||||||
|
|||||||
@@ -53,3 +53,45 @@ function(wintc_gdbus_codegen XML_FILE OUT_FILE_NOEXT CP_PUBLIC)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
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
|
// Change this to use either our binding or GTK
|
||||||
//
|
//
|
||||||
#define TEST_USE_CTL_BINDING 1
|
#define TEST_USE_CTL_BINDING 0
|
||||||
|
|
||||||
//
|
//
|
||||||
// FORWARD DECLARATIONS
|
// FORWARD DECLARATIONS
|
||||||
@@ -17,6 +17,20 @@ static void wintc_menu_test_window_dispose(
|
|||||||
GObject* object
|
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
|
// 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);
|
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!
|
// Show!
|
||||||
//
|
//
|
||||||
gtk_container_add(GTK_CONTAINER(self), box_container);
|
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;
|
GMenuModel* menu_model;
|
||||||
|
|
||||||
GList* sections;
|
GList* sections;
|
||||||
|
|
||||||
|
gulong sigid_items_changed;
|
||||||
} WinTCCtlMenuBindingMenu;
|
} WinTCCtlMenuBindingMenu;
|
||||||
|
|
||||||
typedef struct _WinTCCtlMenuBindingSection
|
typedef struct _WinTCCtlMenuBindingSection
|
||||||
@@ -70,6 +72,11 @@ static void wintc_ctl_menu_binding_insert_item(
|
|||||||
gint src_pos,
|
gint src_pos,
|
||||||
gint dst_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(
|
static void wintc_ctl_menu_binding_track_menu(
|
||||||
WinTCCtlMenuBinding* menu_binding,
|
WinTCCtlMenuBinding* menu_binding,
|
||||||
GtkMenuShell* menu_shell,
|
GtkMenuShell* menu_shell,
|
||||||
@@ -80,6 +87,14 @@ static void wintc_ctl_menu_binding_menu_free(
|
|||||||
WinTCCtlMenuBindingMenu* menu
|
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
|
// 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_margin_end(img_icon, 6); // Got this from Mousepad
|
||||||
gtk_widget_set_size_request(img_icon, 16, 16);
|
gtk_widget_set_size_request(img_icon, 16, 16);
|
||||||
|
|
||||||
|
gtk_menu_item_set_reserve_indicator(
|
||||||
|
GTK_MENU_ITEM(menu_item),
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
|
||||||
if (icon)
|
if (icon)
|
||||||
{
|
{
|
||||||
gtk_image_set_from_gicon(
|
gtk_image_set_from_gicon(
|
||||||
@@ -537,6 +557,8 @@ static void wintc_ctl_menu_binding_insert_item(
|
|||||||
g_free(label);
|
g_free(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gtk_widget_show_all(menu_item);
|
||||||
|
|
||||||
// Do we have a submenu for this item?
|
// Do we have a submenu for this item?
|
||||||
//
|
//
|
||||||
GMenuModel* submenu_model =
|
GMenuModel* submenu_model =
|
||||||
@@ -645,7 +667,7 @@ static void wintc_ctl_menu_binding_insert_item(
|
|||||||
//
|
//
|
||||||
gint i = 0;
|
gint i = 0;
|
||||||
|
|
||||||
while (i < dst_pos)
|
while (i < dst_pos && iter)
|
||||||
{
|
{
|
||||||
WinTCCtlMenuBindingSection* subsection =
|
WinTCCtlMenuBindingSection* subsection =
|
||||||
(WinTCCtlMenuBindingSection*) iter->data;
|
(WinTCCtlMenuBindingSection*) iter->data;
|
||||||
@@ -661,13 +683,6 @@ static void wintc_ctl_menu_binding_insert_item(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No where else to go?
|
|
||||||
//
|
|
||||||
if (!(iter->next))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Moving on...
|
// Moving on...
|
||||||
//
|
//
|
||||||
iter = iter->next;
|
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
|
// If we fell out, we need to add the item to the end of the menu
|
||||||
//
|
//
|
||||||
WinTCCtlMenuBindingSection* last_section =
|
WinTCCtlMenuBindingSection* last_section =
|
||||||
(WinTCCtlMenuBindingSection*) iter->data;
|
(WinTCCtlMenuBindingSection*) (g_list_last(menu->sections))->data;
|
||||||
|
|
||||||
if (last_section->menu_model)
|
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);
|
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(
|
static void wintc_ctl_menu_binding_track_menu(
|
||||||
WinTCCtlMenuBinding* menu_binding,
|
WinTCCtlMenuBinding* menu_binding,
|
||||||
GtkMenuShell* menu_shell,
|
GtkMenuShell* menu_shell,
|
||||||
@@ -725,6 +937,19 @@ static void wintc_ctl_menu_binding_track_menu(
|
|||||||
tracker->menu_model = menu_model;
|
tracker->menu_model = menu_model;
|
||||||
tracker->sections = NULL;
|
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 =
|
menu_binding->tracked_menus =
|
||||||
g_slist_append(
|
g_slist_append(
|
||||||
menu_binding->tracked_menus,
|
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_clear_list(&(menu->sections), (GDestroyNotify) g_free);
|
||||||
g_free(menu);
|
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
|
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
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/** @file */
|
||||||
|
|
||||||
#ifndef __COMGTK_MEMORY_H__
|
#ifndef __COMGTK_MEMORY_H__
|
||||||
#define __COMGTK_MEMORY_H__
|
#define __COMGTK_MEMORY_H__
|
||||||
|
|
||||||
@@ -6,15 +8,47 @@
|
|||||||
//
|
//
|
||||||
// PUBLIC FUNCTIONS
|
// 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(
|
void wintc_freev(
|
||||||
gpointer mem,
|
gpointer mem,
|
||||||
GDestroyNotify destroy
|
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(
|
void wintc_freenv(
|
||||||
gpointer mem,
|
gpointer mem,
|
||||||
guint n_elements,
|
guint n_elements,
|
||||||
GDestroyNotify destroy
|
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
|
#endif
|
||||||
|
|||||||
@@ -69,6 +69,24 @@ gchar* wintc_str_set_suffix(
|
|||||||
const gchar* 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
|
* 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.
|
* there was a string at the destination pointer, it will be freed.
|
||||||
@@ -130,4 +148,16 @@ guint wintc_strv_length(
|
|||||||
const gchar** str_array
|
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
|
#endif
|
||||||
|
|||||||
@@ -22,3 +22,18 @@ void wintc_container_clear(
|
|||||||
|
|
||||||
g_list_free(children);
|
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);
|
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 <glib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../public/shorthand.h"
|
||||||
#include "../public/strings.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(
|
void wintc_strdup_replace(
|
||||||
gchar** dest,
|
gchar** dest,
|
||||||
const gchar* src
|
const gchar* src
|
||||||
@@ -180,3 +218,24 @@ guint wintc_strv_length(
|
|||||||
|
|
||||||
return i;
|
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(PROJECT_ROOT ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
set(WINTC_NO_PEDANTIC_COMPILE true) # Necessary for glib-genmarshal
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
include(../../packaging/cmake-inc/common/CMakeLists.txt)
|
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/libraries/CMakeLists.txt)
|
||||||
include(../../packaging/cmake-inc/linking/CMakeLists.txt)
|
include(../../packaging/cmake-inc/linking/CMakeLists.txt)
|
||||||
include(../../packaging/cmake-inc/packaging/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(gtk+-3.0 GTK3)
|
||||||
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
|
wintc_resolve_library(wintc-comgtk WINTC_COMGTK)
|
||||||
|
|
||||||
|
wintc_glib_genmarshal()
|
||||||
|
|
||||||
add_library(
|
add_library(
|
||||||
libwintc-shcommon
|
libwintc-shcommon
|
||||||
src/fs.c
|
src/fs.c
|
||||||
public/fs.h
|
public/fs.h
|
||||||
|
src/marshal.c
|
||||||
|
src/marshal.h
|
||||||
|
src/monitor.c
|
||||||
|
public/monitor.h
|
||||||
src/path.c
|
src/path.c
|
||||||
public/path.h
|
public/path.h
|
||||||
src/places.c
|
src/places.c
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#ifndef __SHCOMMON_FS_H__
|
#ifndef __SHCOMMON_FS_H__
|
||||||
#define __SHCOMMON_FS_H__
|
#define __SHCOMMON_FS_H__
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
//
|
//
|
||||||
// PUBLIC FUNCTIONS
|
// PUBLIC FUNCTIONS
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define __WINTC_SHCOMMON_H__
|
#define __WINTC_SHCOMMON_H__
|
||||||
|
|
||||||
#include "@LIB_HEADER_DIR@/fs.h"
|
#include "@LIB_HEADER_DIR@/fs.h"
|
||||||
|
#include "@LIB_HEADER_DIR@/monitor.h"
|
||||||
#include "@LIB_HEADER_DIR@/path.h"
|
#include "@LIB_HEADER_DIR@/path.h"
|
||||||
#include "@LIB_HEADER_DIR@/places.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;
|
GtkBuilder* builder;
|
||||||
WinTCTaskbandToolbar* toolbar = WINTC_TASKBAND_TOOLBAR(toolbar_start);
|
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
|
// Set default states
|
||||||
//
|
//
|
||||||
toolbar_start->personal.sync_menu_refresh = TRUE;
|
toolbar_start->personal.sync_menu_refresh = TRUE;
|
||||||
@@ -266,6 +258,7 @@ void create_personal_menu(
|
|||||||
gtk_menu_item_set_submenu(
|
gtk_menu_item_set_submenu(
|
||||||
GTK_MENU_ITEM(toolbar_start->personal.menuitem_all_programs),
|
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->progmenu,
|
||||||
&(toolbar_start->personal.all_programs_binding)
|
&(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
|
// Add separator between defaults & MFU
|
||||||
//
|
//
|
||||||
gtk_menu_shell_append(
|
gtk_menu_shell_append(
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,15 +5,27 @@
|
|||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <wintc/comctl.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
|
// PUBLIC FUNCTIONS
|
||||||
//
|
//
|
||||||
gboolean wintc_toolbar_start_progmenu_init(
|
WinTCToolbarStartProgmenu* wintc_toolbar_start_progmenu_new(void);
|
||||||
GError** error
|
|
||||||
);
|
|
||||||
|
|
||||||
GtkWidget* wintc_toolbar_start_progmenu_new_gtk_menu(
|
GtkWidget* wintc_toolbar_start_progmenu_new_gtk_menu(
|
||||||
WinTCCtlMenuBinding** menu_binding
|
WinTCToolbarStartProgmenu* progmenu,
|
||||||
|
WinTCCtlMenuBinding** menu_binding
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <wintc/comctl.h>
|
#include <wintc/comctl.h>
|
||||||
|
|
||||||
|
#include "progmenu.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// INTERNAL STRUCTS
|
// INTERNAL STRUCTS
|
||||||
//
|
//
|
||||||
@@ -51,6 +53,8 @@ typedef struct _WinTCToolbarStart
|
|||||||
//
|
//
|
||||||
PersonalStartMenuData personal;
|
PersonalStartMenuData personal;
|
||||||
|
|
||||||
|
WinTCToolbarStartProgmenu* progmenu;
|
||||||
|
|
||||||
// UI state
|
// UI state
|
||||||
//
|
//
|
||||||
gboolean sync_button;
|
gboolean sync_button;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "../toolbar.h"
|
#include "../toolbar.h"
|
||||||
#include "personal.h"
|
#include "personal.h"
|
||||||
|
#include "progmenu.h"
|
||||||
#include "shared.h"
|
#include "shared.h"
|
||||||
#include "toolbar.h"
|
#include "toolbar.h"
|
||||||
|
|
||||||
@@ -66,6 +67,10 @@ static void wintc_toolbar_start_init(
|
|||||||
GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
|
GTK_STYLE_PROVIDER_PRIORITY_FALLBACK
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Initialize progmenu
|
||||||
|
//
|
||||||
|
self->progmenu = wintc_toolbar_start_progmenu_new();
|
||||||
|
|
||||||
// Create root widget (Start button)
|
// Create root widget (Start button)
|
||||||
//
|
//
|
||||||
builder =
|
builder =
|
||||||
@@ -120,6 +125,10 @@ static void wintc_toolbar_start_dispose(
|
|||||||
//
|
//
|
||||||
destroy_personal_menu(toolbar_start);
|
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);
|
(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);
|
update_client_on_battery(power, power->up_client);
|
||||||
|
|
||||||
|
g_ptr_array_unref(all_devices);
|
||||||
|
|
||||||
(G_OBJECT_CLASS(
|
(G_OBJECT_CLASS(
|
||||||
wintc_notification_power_parent_class
|
wintc_notification_power_parent_class
|
||||||
))->constructed(object);
|
))->constructed(object);
|
||||||
|
|||||||
Reference in New Issue
Block a user