diff --git a/shared/comgtk/CMakeLists.txt b/shared/comgtk/CMakeLists.txt index da1b223..5c7b35e 100644 --- a/shared/comgtk/CMakeLists.txt +++ b/shared/comgtk/CMakeLists.txt @@ -47,6 +47,8 @@ add_library( public/icons.h src/list.c public/list.h + src/listbox.c + public/listbox.h src/marshal.c public/marshal.h src/memory.c diff --git a/shared/comgtk/public/libapi.h.in b/shared/comgtk/public/libapi.h.in index 14939ee..5afd201 100644 --- a/shared/comgtk/public/libapi.h.in +++ b/shared/comgtk/public/libapi.h.in @@ -9,6 +9,7 @@ #include "@LIB_HEADER_DIR@/errors.h" #include "@LIB_HEADER_DIR@/icons.h" #include "@LIB_HEADER_DIR@/list.h" +#include "@LIB_HEADER_DIR@/listbox.h" #include "@LIB_HEADER_DIR@/marshal.h" #include "@LIB_HEADER_DIR@/memory.h" #include "@LIB_HEADER_DIR@/menu.h" diff --git a/shared/comgtk/public/listbox.h b/shared/comgtk/public/listbox.h new file mode 100644 index 0000000..3b6b0da --- /dev/null +++ b/shared/comgtk/public/listbox.h @@ -0,0 +1,22 @@ +/** @file */ + +#ifndef __COMGTK_LISTBOX_H__ +#define __COMGTK_LISTBOX_H__ + +#include + +// +// PUBLIC FUNCTIONS +// + +/** + * Scrolls a list box to its selected item; this function is queued up as it + * must be performed after any newly added rows are realised. + * + * @param list_box The list box. + */ +void wintc_list_box_queue_scroll_to_selected( + GtkListBox* list_box +); + +#endif diff --git a/shared/comgtk/src/listbox.c b/shared/comgtk/src/listbox.c new file mode 100644 index 0000000..dda0b70 --- /dev/null +++ b/shared/comgtk/src/listbox.c @@ -0,0 +1,124 @@ +#include +#include + +#include "../public/debug.h" +#include "../public/listbox.h" +#include "../public/shorthand.h" + +// +// FORWARD DECLARATIONS +// +static gboolean cb_list_box_scroll_to_selected( + gpointer user_data +); + +static void on_list_box_realize( + GtkWidget* self, + gpointer user_data +); + +// +// PUBLIC FUNCTIONS +// +void wintc_list_box_queue_scroll_to_selected( + GtkListBox* list_box +) +{ + // If the list box itself isn't even realised then we must delay until + // then + // + if (gtk_widget_get_realized(GTK_WIDGET(list_box))) + { + g_idle_add( + (GSourceFunc) cb_list_box_scroll_to_selected, + list_box + ); + } + else + { + g_signal_connect( + list_box, + "realize", + G_CALLBACK(on_list_box_realize), + NULL + ); + } +} + +// +// CALLBACKS +// +static gboolean cb_list_box_scroll_to_selected( + gpointer user_data +) +{ + GtkListBox* list_box = GTK_LIST_BOX(user_data); + + // Find scrolled window and selected item... + // + GtkListBoxRow* row = gtk_list_box_get_selected_row(list_box); + GtkWidget* scrollwnd = gtk_widget_get_ancestor( + GTK_WIDGET(list_box), + GTK_TYPE_SCROLLED_WINDOW + ); + + if (!scrollwnd) + { + g_critical( + "%s", + "Can't scroll list box, it's not in a scrolled window." + ); + + return G_SOURCE_REMOVE; + } + + if (!row) + { + WINTC_LOG_DEBUG("Not scrolling list box - nothing selected."); + return G_SOURCE_REMOVE; + } + + // Perform the scroll + // + gint scroll_y = 0; + + if ( + gtk_widget_translate_coordinates( + GTK_WIDGET(row), + GTK_WIDGET(list_box), + 0, + 0, + NULL, + &scroll_y + ) + ) + { + gtk_adjustment_set_value( + gtk_scrolled_window_get_vadjustment( + GTK_SCROLLED_WINDOW(scrollwnd) + ), + (gdouble) scroll_y + ); + } + + return G_SOURCE_REMOVE; +} + +static void on_list_box_realize( + GtkWidget* self, + WINTC_UNUSED(gpointer user_data) +) +{ + g_idle_add( + (GSourceFunc) cb_list_box_scroll_to_selected, + GTK_LIST_BOX(self) + ); + + // Disconnect the signal, only needed this once + // + g_signal_handlers_disconnect_by_func( + self, + on_list_box_realize, + NULL + ); +} diff --git a/shell/cpl/desk/src/pagedesk.c b/shell/cpl/desk/src/pagedesk.c index 94a7cf0..683a02b 100644 --- a/shell/cpl/desk/src/pagedesk.c +++ b/shell/cpl/desk/src/pagedesk.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "monitor.h" @@ -16,7 +17,8 @@ // static void add_wallpaper_to_list( WinTCCplDeskWindow* wnd, - const gchar* path + const gchar* path, + gboolean new_item ); static void redraw_wallpaper_preview( WinTCCplDeskWindow* wnd @@ -29,6 +31,12 @@ static void select_wallpaper_from_list( const gchar* path ); +static void action_browse( + GSimpleAction* action, + GVariant* parameter, + gpointer user_data +); + static void on_combo_style_changed( GtkComboBox* self, gpointer user_data @@ -39,6 +47,19 @@ static void on_listbox_wallpapers_row_selected( gpointer user_data ); +// +// STATIC DATA +// +static GActionEntry s_actions[] = { + { + .name = "browse", + .activate = action_browse, + .parameter_type = NULL, + .state = NULL, + .change_state = NULL + } +}; + // // PUBLIC FUNCTIONS // @@ -55,6 +76,23 @@ void wintc_cpl_desk_window_append_desktop_page( NULL ); + // Define GActions + // + GSimpleActionGroup* action_group = g_simple_action_group_new(); + + g_action_map_add_action_entries( + G_ACTION_MAP(action_group), + s_actions, + G_N_ELEMENTS(s_actions), + wnd + ); + + gtk_widget_insert_action_group( + wnd->notebook_main, + "desktop", + G_ACTION_GROUP(action_group) + ); + // Connect signals // g_signal_connect( @@ -121,7 +159,8 @@ void wintc_cpl_desk_window_finalize_desktop_page( // static void add_wallpaper_to_list( WinTCCplDeskWindow* wnd, - const gchar* path + const gchar* path, + gboolean new_item ) { gchar* filename = g_path_get_basename(path); @@ -138,6 +177,17 @@ static void add_wallpaper_to_list( gtk_widget_show(label); g_free(filename); + + // Do we need to add this item to the backing list? + // + if (new_item) + { + wnd->list_wallpapers = + g_list_append( + wnd->list_wallpapers, + g_strdup(path) + ); + } } static void redraw_wallpaper_preview( @@ -249,7 +299,7 @@ static void refresh_wallpaper_list( for (GList* iter = wnd->list_wallpapers; iter; iter = iter->next) { - add_wallpaper_to_list(wnd, (gchar*) iter->data); + add_wallpaper_to_list(wnd, (gchar*) iter->data, FALSE); } } @@ -276,6 +326,11 @@ static void select_wallpaper_from_list( i ) ); + + wintc_list_box_queue_scroll_to_selected( + GTK_LIST_BOX(wnd->listbox_wallpapers) + ); + return; } @@ -284,7 +339,7 @@ static void select_wallpaper_from_list( // The path isn't in the listbox, so add it and select last item // - add_wallpaper_to_list(wnd, path); + add_wallpaper_to_list(wnd, path, TRUE); gtk_list_box_select_row( GTK_LIST_BOX(wnd->listbox_wallpapers), @@ -293,11 +348,87 @@ static void select_wallpaper_from_list( g_list_length(wnd->list_wallpapers) - 1 ) ); + + wintc_list_box_queue_scroll_to_selected( + GTK_LIST_BOX(wnd->listbox_wallpapers) + ); } // // CALLBACKS // +static void action_browse( + WINTC_UNUSED(GSimpleAction* action), + WINTC_UNUSED(GVariant* parameter), + gpointer user_data +) +{ + WinTCCplDeskWindow* wnd = WINTC_CPL_DESK_WINDOW(user_data); + + // + // FIXME: No support for Active Desktop at the moment, hence the lack of + // Background Files and Web page filters + // + + // Set up image filters + // + static const gchar* k_filters[] = { + "image/bmp", + "image/gif", + "image/jpeg", + "image/jpg", + "image/png" + }; + + GtkFileFilter* filter_images = gtk_file_filter_new(); + + gtk_file_filter_set_name( + filter_images, + "All Picture Files (*.bmp;*.gif;*.jpg;*.jpeg;*.dib;*.png)" + ); + + for (gulong i = 0; i < G_N_ELEMENTS(k_filters); i++) + { + gtk_file_filter_add_mime_type( + filter_images, + k_filters[i] + ); + } + + // Set up dialog + // + GtkWidget* dlg = + gtk_file_chooser_dialog_new( + wintc_lc_get_control_text(WINTC_CTLTXT_BROWSE, WINTC_PUNC_NONE), + GTK_WINDOW(wnd), + GTK_FILE_CHOOSER_ACTION_OPEN, + wintc_lc_get_control_text(WINTC_CTLTXT_CANCEL, WINTC_PUNC_NONE), + GTK_RESPONSE_CANCEL, + wintc_lc_get_control_text(WINTC_CTLTXT_OPEN, WINTC_PUNC_NONE), + GTK_RESPONSE_ACCEPT, + NULL + ); + + gtk_file_chooser_add_filter( + GTK_FILE_CHOOSER(dlg), + filter_images + ); + + // Launch dialog + // + gint result = gtk_dialog_run(GTK_DIALOG(dlg)); + + if (result == GTK_RESPONSE_ACCEPT) + { + select_wallpaper_from_list( + wnd, + gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg)) + ); + } + + gtk_widget_destroy(dlg); +} + static void on_combo_style_changed( GtkComboBox* self, gpointer user_data diff --git a/shell/cpl/desk/src/res/page-desktop.ui b/shell/cpl/desk/src/res/page-desktop.ui index 2425334..9bc237c 100644 --- a/shell/cpl/desk/src/res/page-desktop.ui +++ b/shell/cpl/desk/src/res/page-desktop.ui @@ -143,7 +143,7 @@ True True %PUNC_MOREINPUT%%CTL_BROWSE% - False + desktop.browse