diff --git a/libxapp/xapp-icon-chooser-button.h b/libxapp/xapp-icon-chooser-button.h index 418bf32..fd73f00 100644 --- a/libxapp/xapp-icon-chooser-button.h +++ b/libxapp/xapp-icon-chooser-button.h @@ -4,7 +4,6 @@ #include #include #include "xapp-icon-chooser-dialog.h" -#include "xapp-enums.h" G_BEGIN_DECLS diff --git a/libxapp/xapp-icon-chooser-dialog.c b/libxapp/xapp-icon-chooser-dialog.c index 13257e0..d08e0d1 100644 --- a/libxapp/xapp-icon-chooser-dialog.c +++ b/libxapp/xapp-icon-chooser-dialog.c @@ -48,7 +48,6 @@ typedef struct GtkWidget *default_button; GtkWidget *select_button; GtkWidget *browse_button; - GtkWidget *action_area; GtkWidget *loading_bar; GtkCellArea *ca_box; gchar *icon_string; @@ -61,7 +60,7 @@ typedef struct struct _XAppIconChooserDialog { - XAppGtkWindow parent_instance; + GtkDialog parent_instance; }; typedef struct @@ -128,7 +127,6 @@ static IconCategoryDefinition categories[] = { enum { - CLOSE, SELECT, LAST_SIGNAL }; @@ -153,7 +151,7 @@ static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; static guint signals[LAST_SIGNAL] = {0, }; -G_DEFINE_TYPE_WITH_PRIVATE (XAppIconChooserDialog, xapp_icon_chooser_dialog, XAPP_TYPE_GTK_WINDOW) +G_DEFINE_TYPE_WITH_PRIVATE (XAppIconChooserDialog, xapp_icon_chooser_dialog, GTK_TYPE_DIALOG) static void on_category_selected (GtkListBox *list_box, XAppIconChooserDialog *dialog); @@ -172,14 +170,8 @@ static void on_icon_store_icons_added (GtkTreeModel *tree_model, static void on_browse_button_clicked (GtkButton *button, gpointer user_data); -static void on_select_button_clicked (GtkButton *button, - gpointer user_data); - -static void on_cancel_button_clicked (GtkButton *button, - gpointer user_data); - static void on_default_button_clicked (GtkButton *button, - gpointer user_data); + gpointer user_data); static gboolean on_search_bar_key_pressed (GtkWidget *widget, GdkEvent *event, @@ -414,8 +406,6 @@ xapp_icon_chooser_dialog_init (XAppIconChooserDialog *dialog) GtkWidget *right_box; GtkStyleContext *style; GtkSizeGroup *button_size_group; - GtkWidget *cancel_button; - GtkWidget *button_area; GtkWidget *scrolled_window; priv = xapp_icon_chooser_dialog_get_instance_private (dialog); @@ -450,11 +440,10 @@ xapp_icon_chooser_dialog_init (XAppIconChooserDialog *dialog) gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 450); gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE); - gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG); gtk_window_set_title (GTK_WINDOW (dialog), _("Choose an icon")); main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_container_add (GTK_CONTAINER (dialog), main_box); + gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), main_box, TRUE, TRUE, 0); // toolbar toolbar = gtk_toolbar_new (); @@ -576,11 +565,6 @@ xapp_icon_chooser_dialog_init (XAppIconChooserDialog *dialog) g_signal_connect (priv->icon_view, "item-activated", G_CALLBACK (on_icon_view_item_activated), dialog); - // buttons - button_area = gtk_action_bar_new (); - priv->action_area = button_area; - gtk_box_pack_start (GTK_BOX (main_box), button_area, FALSE, FALSE, 0); - button_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); priv->default_button = gtk_button_new_with_label (_("Default")); @@ -588,28 +572,17 @@ xapp_icon_chooser_dialog_init (XAppIconChooserDialog *dialog) style = gtk_widget_get_style_context (GTK_WIDGET (priv->default_button)); gtk_style_context_add_class (style, "text-button"); gtk_size_group_add_widget (button_size_group, priv->default_button); - gtk_action_bar_pack_start (GTK_ACTION_BAR (button_area), priv->default_button); - + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), priv->default_button, GTK_RESPONSE_NONE); + gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (gtk_dialog_get_action_area (GTK_DIALOG (dialog))), + priv->default_button, TRUE); g_signal_connect (priv->default_button, "clicked", G_CALLBACK (on_default_button_clicked), dialog); - priv->select_button = gtk_button_new_with_label (_("Select")); - style = gtk_widget_get_style_context (GTK_WIDGET (priv->select_button)); - gtk_style_context_add_class (style, "text-button"); - gtk_size_group_add_widget (button_size_group, priv->select_button); - gtk_action_bar_pack_end (GTK_ACTION_BAR (button_area), priv->select_button); - - g_signal_connect (priv->select_button, "clicked", - G_CALLBACK (on_select_button_clicked), dialog); - - cancel_button = gtk_button_new_with_label (_("Cancel")); - style = gtk_widget_get_style_context (GTK_WIDGET (cancel_button)); - gtk_style_context_add_class (style, "text-button"); - gtk_size_group_add_widget (button_size_group, cancel_button); - gtk_action_bar_pack_end (GTK_ACTION_BAR (button_area), cancel_button); + gtk_dialog_add_button (GTK_DIALOG (dialog), _("Cancel"), GTK_RESPONSE_CANCEL); - g_signal_connect (cancel_button, "clicked", - G_CALLBACK (on_cancel_button_clicked), dialog); + priv->select_button = gtk_dialog_add_button (GTK_DIALOG (dialog), _("Select"), GTK_RESPONSE_OK); + gtk_widget_set_can_default (priv->select_button, TRUE); + gtk_widget_grab_default (priv->select_button); load_categories (dialog); } @@ -669,14 +642,6 @@ xapp_icon_chooser_dialog_class_init (XAppIconChooserDialogClass *klass) g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); // keybinding signals - signals[CLOSE] = - g_signal_new ("close", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GtkWidgetClass, delete_event), - NULL, NULL, NULL, - G_TYPE_NONE, 0); - signals[SELECT] = g_signal_new ("select", G_TYPE_FROM_CLASS (klass), @@ -723,15 +688,16 @@ gint xapp_icon_chooser_dialog_run (XAppIconChooserDialog *dialog) { XAppIconChooserDialogPrivate *priv; + gint response; priv = xapp_icon_chooser_dialog_get_instance_private (dialog); gtk_widget_show_all (GTK_WIDGET (dialog)); gtk_widget_grab_focus (priv->search_bar); - gtk_main (); + response = gtk_dialog_run (GTK_DIALOG (dialog)); - return priv->response; + return response; } /** @@ -758,6 +724,7 @@ xapp_icon_chooser_dialog_run_with_icon (XAppIconChooserDialog *dialog, gchar *icon) { XAppIconChooserDialogPrivate *priv; + gint response; priv = xapp_icon_chooser_dialog_get_instance_private (dialog); @@ -765,9 +732,9 @@ xapp_icon_chooser_dialog_run_with_icon (XAppIconChooserDialog *dialog, gtk_entry_set_text (GTK_ENTRY (priv->search_bar), icon); gtk_widget_grab_focus (priv->search_bar); - gtk_main (); + response = gtk_dialog_run (GTK_DIALOG (dialog)); - return priv->response; + return response; } /** @@ -792,6 +759,7 @@ xapp_icon_chooser_dialog_run_with_category (XAppIconChooserDialog *dialog, { XAppIconChooserDialogPrivate *priv; GList *children; + gint response; priv = xapp_icon_chooser_dialog_get_instance_private (dialog); @@ -815,9 +783,9 @@ xapp_icon_chooser_dialog_run_with_category (XAppIconChooserDialog *dialog, } } - gtk_main (); + response = gtk_dialog_run (GTK_DIALOG (dialog)); - return priv->response; + return response; } /** @@ -935,30 +903,19 @@ xapp_icon_chooser_dialog_close (XAppIconChooserDialog *dialog, priv = xapp_icon_chooser_dialog_get_instance_private (dialog); priv->response = response; - gtk_widget_hide (GTK_WIDGET (dialog)); - - gtk_main_quit (); -} - -static void -on_custom_button_clicked (GtkButton *button, - gpointer user_data) -{ - GtkResponseType response_id; - - response_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "response-id")); + gtk_dialog_response (GTK_DIALOG (dialog), response); - xapp_icon_chooser_dialog_close (XAPP_ICON_CHOOSER_DIALOG (user_data), response_id); + gtk_widget_hide (GTK_WIDGET (dialog)); } /** * xapp_icon_chooser_dialog_add_button: * @dialog: an #XAppIconChooserDialog * @button: a #GtkButton to add - * @packing: the #GtkPackType to specify start or end packing to the action bar + * @packing: the #GtkPackType to specify start or end packing to the action area * @response_id: the dialog response id to return when this button is clicked. * - * Allows a button to be added to the #GtkActionBar of the dialog with a custom + * Allows a button to be added to the action area of the dialog with a custom * response id. */ void @@ -967,26 +924,14 @@ xapp_icon_chooser_dialog_add_button (XAppIconChooserDialog *dialog, GtkPackType packing, GtkResponseType response_id) { - XAppIconChooserDialogPrivate *priv; + GtkWidget *action_area; - priv = xapp_icon_chooser_dialog_get_instance_private (dialog); - - g_signal_connect (button, - "clicked", - G_CALLBACK (on_custom_button_clicked), - dialog); - - /* This saves having to use a custom container for callback data. */ - g_object_set_data (G_OBJECT (button), - "response-id", GINT_TO_POINTER (response_id)); + gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id); if (packing == GTK_PACK_START) { - gtk_action_bar_pack_start (GTK_ACTION_BAR (priv->action_area), button); - } - else - { - gtk_action_bar_pack_end (GTK_ACTION_BAR (priv->action_area), button); + action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog)); + gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (action_area), button, TRUE); } } @@ -1972,20 +1917,6 @@ on_browse_button_clicked (GtkButton *button, gtk_widget_destroy (file_dialog); } -static void -on_select_button_clicked (GtkButton *button, - gpointer user_data) -{ - xapp_icon_chooser_dialog_close (XAPP_ICON_CHOOSER_DIALOG (user_data), GTK_RESPONSE_OK); -} - -static void -on_cancel_button_clicked (GtkButton *button, - gpointer user_data) -{ - xapp_icon_chooser_dialog_close (XAPP_ICON_CHOOSER_DIALOG (user_data), GTK_RESPONSE_CANCEL); -} - static gboolean on_delete_event (GtkWidget *widget, GdkEventAny *event) diff --git a/libxapp/xapp-icon-chooser-dialog.h b/libxapp/xapp-icon-chooser-dialog.h index 439039b..5da37ed 100644 --- a/libxapp/xapp-icon-chooser-dialog.h +++ b/libxapp/xapp-icon-chooser-dialog.h @@ -4,13 +4,11 @@ #include #include -#include "xapp-gtk-window.h" - G_BEGIN_DECLS #define XAPP_TYPE_ICON_CHOOSER_DIALOG (xapp_icon_chooser_dialog_get_type ()) -G_DECLARE_FINAL_TYPE (XAppIconChooserDialog, xapp_icon_chooser_dialog, XAPP, ICON_CHOOSER_DIALOG, XAppGtkWindow) +G_DECLARE_FINAL_TYPE (XAppIconChooserDialog, xapp_icon_chooser_dialog, XAPP, ICON_CHOOSER_DIALOG, GtkDialog) typedef enum { diff --git a/test-scripts/xapp-icon-chooser-dialog-full-test b/test-scripts/xapp-icon-chooser-dialog-full-test new file mode 100755 index 0000000..96db75d --- /dev/null +++ b/test-scripts/xapp-icon-chooser-dialog-full-test @@ -0,0 +1,203 @@ +#!/usr/bin/python3 + +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('XApp', '1.0') + +from gi.repository import Gtk, XApp, GLib + +import signal +signal.signal(signal.SIGINT, signal.SIG_DFL) + + +class TestWindow(Gtk.Window): + def __init__(self): + super().__init__(title="XAppIconChooserDialog Test") + self.set_default_size(400, 300) + self.set_border_width(10) + self.connect("destroy", Gtk.main_quit) + + self.selected_icon = None + + main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) + self.add(main_box) + + result_frame = Gtk.Frame(label="Selected Icon") + main_box.pack_start(result_frame, False, False, 0) + + result_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + result_box.set_margin_start(10) + result_box.set_margin_end(10) + result_box.set_margin_top(5) + result_box.set_margin_bottom(5) + result_frame.add(result_box) + + self.result_image = Gtk.Image() + self.result_image.set_size_request(48, 48) + result_box.pack_start(self.result_image, False, False, 0) + + self.result_label = Gtk.Label(label="(none)") + self.result_label.set_xalign(0) + self.result_label.set_line_wrap(True) + self.result_label.set_selectable(True) + result_box.pack_start(self.result_label, True, True, 0) + + # Test sections + # Section 1: Blocking run() methods + section1 = Gtk.Frame(label="1. Blocking run() Methods") + main_box.pack_start(section1, False, False, 0) + + box1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5) + box1.set_margin_start(10) + box1.set_margin_end(10) + box1.set_margin_top(5) + box1.set_margin_bottom(5) + section1.add(box1) + + btn_run = Gtk.Button(label="run()") + btn_run.connect("clicked", self.on_test_run) + box1.pack_start(btn_run, False, False, 0) + + hbox1 = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) + box1.pack_start(hbox1, False, False, 0) + + btn_run_icon = Gtk.Button(label="run_with_icon()") + btn_run_icon.connect("clicked", self.on_test_run_with_icon) + hbox1.pack_start(btn_run_icon, True, True, 0) + + self.icon_entry = Gtk.Entry() + self.icon_entry.set_text("folder") + self.icon_entry.set_placeholder_text("icon name or path") + hbox1.pack_start(self.icon_entry, True, True, 0) + + hbox2 = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) + box1.pack_start(hbox2, False, False, 0) + + btn_run_cat = Gtk.Button(label="run_with_category()") + btn_run_cat.connect("clicked", self.on_test_run_with_category) + hbox2.pack_start(btn_run_cat, True, True, 0) + + self.category_entry = Gtk.Entry() + self.category_entry.set_text("Places") + self.category_entry.set_placeholder_text("category name") + hbox2.pack_start(self.category_entry, True, True, 0) + + # Section 2: Non-blocking (response signal) + section2 = Gtk.Frame(label="2. Non-blocking (show + response signal)") + main_box.pack_start(section2, False, False, 0) + + box2 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5) + box2.set_margin_start(10) + box2.set_margin_end(10) + box2.set_margin_top(5) + box2.set_margin_bottom(5) + section2.add(box2) + + btn_async = Gtk.Button(label="Show Dialog (async)") + btn_async.connect("clicked", self.on_test_async) + box2.pack_start(btn_async, False, False, 0) + + section3 = Gtk.Frame(label="3. XAppIconChooserButton") + main_box.pack_start(section3, False, False, 0) + + box3 = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + box3.set_margin_start(10) + box3.set_margin_end(10) + box3.set_margin_top(5) + box3.set_margin_bottom(5) + section3.add(box3) + + label3 = Gtk.Label(label="Icon Button:") + box3.pack_start(label3, False, False, 0) + + self.icon_button = XApp.IconChooserButton() + self.icon_button.set_icon("application-x-executable") + self.icon_button.connect("notify::icon", self.on_icon_button_changed) + box3.pack_start(self.icon_button, False, False, 0) + + self.icon_button_label = Gtk.Label(label="(click button to choose)") + self.icon_button_label.set_xalign(0) + box3.pack_start(self.icon_button_label, True, True, 0) + + def update_result(self, icon_string, source): + if icon_string: + self.result_label.set_text(f"{icon_string}\n(from {source})") + if icon_string.startswith("/"): + self.result_image.set_from_file(icon_string) + else: + self.result_image.set_from_icon_name(icon_string, Gtk.IconSize.DIALOG) + else: + self.result_label.set_text("(canceled)") + self.result_image.clear() + + def on_test_run(self, button): + dialog = XApp.IconChooserDialog() + dialog.set_transient_for(self) + dialog.set_default_icon("folder") + + response = dialog.run() + + if response == Gtk.ResponseType.OK: + self.update_result(dialog.get_icon_string(), "run()") + else: + self.update_result(None, "run()") + + dialog.destroy() + + def on_test_run_with_icon(self, button): + icon = self.icon_entry.get_text() + dialog = XApp.IconChooserDialog() + dialog.set_transient_for(self) + + response = dialog.run_with_icon(icon) + + if response == Gtk.ResponseType.OK: + self.update_result(dialog.get_icon_string(), f"run_with_icon('{icon}')") + else: + self.update_result(None, f"run_with_icon('{icon}')") + + dialog.destroy() + + def on_test_run_with_category(self, button): + category = self.category_entry.get_text() + dialog = XApp.IconChooserDialog() + dialog.set_transient_for(self) + + response = dialog.run_with_category(category) + + if response == Gtk.ResponseType.OK: + self.update_result(dialog.get_icon_string(), f"run_with_category('{category}')") + else: + self.update_result(None, f"run_with_category('{category}')") + + dialog.destroy() + + def on_test_async(self, button): + dialog = XApp.IconChooserDialog() + dialog.set_transient_for(self) + dialog.set_modal(True) + dialog.set_default_icon("folder") + + dialog.connect("response", self.on_async_response) + dialog.show_all() + + def on_async_response(self, dialog, response): + if response == Gtk.ResponseType.OK: + self.update_result(dialog.get_icon_string(), "async (response signal)") + else: + self.update_result(None, "async (response signal)") + + dialog.hide() + GLib.idle_add(dialog.destroy) + + def on_icon_button_changed(self, button, pspec): + icon = button.get_icon() + self.icon_button_label.set_text(icon if icon else "(none)") + if icon: + self.update_result(icon, "XAppIconChooserButton") + + +if __name__ == '__main__': + win = TestWindow() + win.show_all() + Gtk.main()