From 8c7ce98188ea4cf807a6f88209d910239827f488 Mon Sep 17 00:00:00 2001 From: Alexander Vanhee <160625516+AlexanderVanhee@users.noreply.github.com> Date: Sat, 15 Aug 2026 17:05:06 +0200 Subject: [PATCH 1/3] Add drop overlay --- src/bz-application.c | 47 +++++++++++++++++-- src/bz-window.blp | 9 ++++ src/bz-window.c | 108 +++++++++++++++++++++++++++++++++++++++++++ src/style.css | 19 ++++++++ 4 files changed, 178 insertions(+), 5 deletions(-) diff --git a/src/bz-application.c b/src/bz-application.c index 824cfa96..b6c0545d 100644 --- a/src/bz-application.c +++ b/src/bz-application.c @@ -189,6 +189,11 @@ static void open_metainfo_take (BzApplication *self, GFile *file); +static void +open_location_take (BzApplication *self, + const char *name_for_suffix_check, + GFile *file); + static DexFuture * backend_sync_finally (DexFuture *future, BzWeakRef *wr); @@ -673,6 +678,28 @@ bz_application_show_app_id_action (GSimpleAction *action, } } +static void +bz_application_open_location_action (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + BzApplication *self = user_data; + const char *uri = NULL; + g_autoptr (GFile) file = NULL; + g_autofree char *basename = NULL; + + g_assert (BZ_IS_APPLICATION (self)); + + uri = g_variant_get_string (parameter, NULL); + if (uri == NULL || *uri == '\0') + return; + + file = g_file_new_for_uri (uri); + basename = g_file_get_basename (file); + + open_location_take (self, basename, g_object_ref (file)); +} + static void bz_application_sync_remotes_action (GSimpleAction *action, GVariant *parameter, @@ -848,6 +875,7 @@ static const GActionEntry app_actions[] = { { "donate", bz_application_donate_action, NULL }, { "bazaar-inspector", bz_application_bazaar_inspector_action, NULL }, { "toggle-debug-mode", bz_application_toggle_debug_mode_action, NULL }, + { "open-location", bz_application_open_location_action, "s" }, }; static void @@ -3790,6 +3818,19 @@ open_metainfo_take (BzApplication *self, g_object_unref (file); } +static void +open_location_take (BzApplication *self, + const char *name_for_suffix_check, + GFile *file) +{ + if (name_for_suffix_check != NULL && + (g_str_has_suffix (name_for_suffix_check, ".metainfo.xml") || + g_str_has_suffix (name_for_suffix_check, ".appdata.xml"))) + open_metainfo_take (self, file); + else + open_flatpakref_take (self, file); +} + static void command_line_open_location (BzApplication *self, GApplicationCommandLine *cmdline, @@ -3818,11 +3859,7 @@ command_line_open_location (BzApplication *self, : g_file_new_for_path (location); } - if (g_str_has_suffix (location, ".metainfo.xml") || - g_str_has_suffix (location, ".appdata.xml")) - open_metainfo_take (self, g_steal_pointer (&file)); - else - open_flatpakref_take (self, g_steal_pointer (&file)); + open_location_take (self, location, g_steal_pointer (&file)); } static void diff --git a/src/bz-window.blp b/src/bz-window.blp index 2b4397e6..a444dde0 100644 --- a/src/bz-window.blp +++ b/src/bz-window.blp @@ -32,6 +32,15 @@ template $BzWindow: Adw.ApplicationWindow { } } + DropTarget drop_target { + actions: copy; + + accept => $drop_accept_cb(template); + drop => $drop_cb(template); + enter => $drop_enter_cb(template); + leave => $drop_leave_cb(template); + } + content: Gtk.Overlay window_overlay { child: Adw.ToolbarView { content: Adw.BreakpointBin split_breakpoint_bin { diff --git a/src/bz-window.c b/src/bz-window.c index d1c8a796..67ccf9da 100644 --- a/src/bz-window.c +++ b/src/bz-window.c @@ -56,6 +56,8 @@ struct _BzWindow GtkEventController *key_controller; BzScreenshotPage *screenshot_page; + GtkWidget *drop_overlay; + GtkRevealer *drop_revealer; gboolean breakpoint_applied; @@ -67,6 +69,7 @@ struct _BzWindow AdwViewStack *main_view_stack; GtkStack *main_stack; GtkOverlay *window_overlay; + GtkDropTarget *drop_target; }; G_DEFINE_FINAL_TYPE (BzWindow, bz_window, ADW_TYPE_APPLICATION_WINDOW) @@ -149,6 +152,9 @@ emit_hook_disown (BzWindow *self, BzHookSignal signal, BzEntryGroup *group); +static gboolean +can_accept_drop (BzWindow *self); + static void bz_window_dispose (GObject *object) { @@ -394,6 +400,94 @@ format_title (gpointer object, return g_strdup_printf (_ ("Bazaar — %s"), title); } +static gboolean +drop_accept_cb (BzWindow *self, + GdkDrop *drop, + GtkDropTarget *target) +{ + return can_accept_drop (self); +} + +static gboolean +drop_cb (BzWindow *self, + const GValue *value, + double x, + double y, + GtkDropTarget *target) +{ + GFile *file = NULL; + g_autofree char *uri = NULL; + + file = G_FILE (g_value_get_object (value)); + uri = g_file_get_uri (file); + + gtk_widget_activate_action (GTK_WIDGET (self), "app.open-location", "s", uri); + + return TRUE; +} + +static GdkDragAction +drop_enter_cb (BzWindow *self, + double x, + double y, + GtkDropTarget *target) +{ + GtkWidget *inner = NULL; + GtkWidget *status = NULL; + + if (!can_accept_drop (self)) + return 0; + + if (self->drop_revealer != NULL) + { + gtk_revealer_set_reveal_child (self->drop_revealer, TRUE); + return GDK_ACTION_COPY; + } + + /* We initialize it here instead of the Blueprint to not cause issues with + * the GTK Inspectors object selector */ + self->drop_overlay = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_add_css_class (self->drop_overlay, "bz-drop-overlay"); + gtk_widget_set_can_target (self->drop_overlay, FALSE); + + inner = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_add_css_class (inner, "bz-drop-overlay-inner"); + gtk_widget_set_hexpand (inner, TRUE); + gtk_widget_set_vexpand (inner, TRUE); + + status = adw_status_page_new (); + adw_status_page_set_icon_name (ADW_STATUS_PAGE (status), "folder-open-symbolic"); + adw_status_page_set_title (ADW_STATUS_PAGE (status), _ ("Drop to Open")); + adw_status_page_set_description (ADW_STATUS_PAGE (status), _ ("Flatpak & Flatpak ref files")); + gtk_widget_set_valign (status, GTK_ALIGN_CENTER); + gtk_widget_set_vexpand (status, TRUE); + + gtk_box_append (GTK_BOX (inner), status); + gtk_box_append (GTK_BOX (self->drop_overlay), inner); + + self->drop_revealer = GTK_REVEALER (gtk_revealer_new ()); + gtk_revealer_set_transition_type (self->drop_revealer, GTK_REVEALER_TRANSITION_TYPE_CROSSFADE); + gtk_revealer_set_transition_duration (self->drop_revealer, 150); + gtk_revealer_set_child (self->drop_revealer, self->drop_overlay); + gtk_widget_set_can_target (GTK_WIDGET (self->drop_revealer), FALSE); + + gtk_overlay_add_overlay (self->window_overlay, GTK_WIDGET (self->drop_revealer)); + + gtk_revealer_set_reveal_child (self->drop_revealer, TRUE); + + return GDK_ACTION_COPY; +} + +static void +drop_leave_cb (BzWindow *self, + GtkDropTarget *target) +{ + if (self->drop_revealer == NULL) + return; + + gtk_revealer_set_reveal_child (self->drop_revealer, FALSE); +} + static BzEntryGroup * resolve_group_from_parameter (BzWindow *self, GVariant *parameter, @@ -786,6 +880,7 @@ bz_window_class_init (BzWindowClass *klass) gtk_widget_class_bind_template_child (widget_class, BzWindow, main_view_stack); gtk_widget_class_bind_template_child (widget_class, BzWindow, main_stack); gtk_widget_class_bind_template_child (widget_class, BzWindow, window_overlay); + gtk_widget_class_bind_template_child (widget_class, BzWindow, drop_target); gtk_widget_class_bind_template_callback (widget_class, list_length); gtk_widget_class_bind_template_callback (widget_class, update_cb); gtk_widget_class_bind_template_callback (widget_class, page_toggled_cb); @@ -797,6 +892,10 @@ bz_window_class_init (BzWindowClass *klass) gtk_widget_class_bind_template_callback (widget_class, open_search_cb); gtk_widget_class_bind_template_callback (widget_class, format_progress); gtk_widget_class_bind_template_callback (widget_class, format_title); + gtk_widget_class_bind_template_callback (widget_class, drop_accept_cb); + gtk_widget_class_bind_template_callback (widget_class, drop_cb); + gtk_widget_class_bind_template_callback (widget_class, drop_enter_cb); + gtk_widget_class_bind_template_callback (widget_class, drop_leave_cb); gtk_widget_class_install_action (widget_class, "escape", NULL, action_escape); gtk_widget_class_install_action (widget_class, "window.user-data", NULL, action_user_data); @@ -874,6 +973,7 @@ bz_window_init (BzWindow *self) G_CALLBACK (key_pressed), self); gtk_widget_add_controller (GTK_WIDGET (self), self->key_controller); + gtk_drop_target_set_gtypes (self->drop_target, (GType[]) { G_TYPE_FILE }, 1); } static void @@ -1411,3 +1511,11 @@ emit_hook_disown (BzWindow *self, dex_future_disown (bz_run_hook_emission ( hooks, signal, 0, NULL, group)); } + +static gboolean +can_accept_drop (BzWindow *self) +{ + return !bz_state_info_get_busy (self->state) && + self->screenshot_page == NULL && + adw_application_window_get_visible_dialog (ADW_APPLICATION_WINDOW (self)) == NULL; +} diff --git a/src/style.css b/src/style.css index 33ccb081..741bdf26 100644 --- a/src/style.css +++ b/src/style.css @@ -56,6 +56,25 @@ --banner-color: var(--accent-bg-color); } +.bz-drop-overlay { + background-color: alpha(color-mix(in srgb, @accent_bg_color 50%, @window_bg_color 75%), 0.80); + backdrop-filter: blur(4px); +} + +.bz-drop-overlay-inner { + border: 2px dashed alpha(@accent_color, 0.65); + border-radius: 12px; + margin: 6px; +} + +.bz-drop-overlay statuspage { + color: @accent_color; +} + +.bz-drop-overlay statuspage image { + color: @accent_color; +} + .updates-amount { background-color: white; color: var(--accent-bg-color); From 201b29b258ce9c7a28d387e7ab03d4c7b5022c6b Mon Sep 17 00:00:00 2001 From: Alexander Vanhee <160625516+AlexanderVanhee@users.noreply.github.com> Date: Sat, 15 Aug 2026 19:13:44 +0200 Subject: [PATCH 2/3] Update border radius --- src/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/style.css b/src/style.css index 741bdf26..452a7b11 100644 --- a/src/style.css +++ b/src/style.css @@ -63,7 +63,7 @@ .bz-drop-overlay-inner { border: 2px dashed alpha(@accent_color, 0.65); - border-radius: 12px; + border-radius: max(0px, calc(var(--window-radius) - 3px)); margin: 6px; } From 33fc657e14ba569554882b36b06cd7abd934f347 Mon Sep 17 00:00:00 2001 From: Alexander Vanhee <160625516+AlexanderVanhee@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:30:52 +0200 Subject: [PATCH 3/3] Remove overlay part --- src/bz-window.blp | 2 -- src/bz-window.c | 81 ++--------------------------------------------- src/style.css | 19 ----------- 3 files changed, 3 insertions(+), 99 deletions(-) diff --git a/src/bz-window.blp b/src/bz-window.blp index a444dde0..6740db77 100644 --- a/src/bz-window.blp +++ b/src/bz-window.blp @@ -37,8 +37,6 @@ template $BzWindow: Adw.ApplicationWindow { accept => $drop_accept_cb(template); drop => $drop_cb(template); - enter => $drop_enter_cb(template); - leave => $drop_leave_cb(template); } content: Gtk.Overlay window_overlay { diff --git a/src/bz-window.c b/src/bz-window.c index 67ccf9da..83858926 100644 --- a/src/bz-window.c +++ b/src/bz-window.c @@ -56,8 +56,6 @@ struct _BzWindow GtkEventController *key_controller; BzScreenshotPage *screenshot_page; - GtkWidget *drop_overlay; - GtkRevealer *drop_revealer; gboolean breakpoint_applied; @@ -152,9 +150,6 @@ emit_hook_disown (BzWindow *self, BzHookSignal signal, BzEntryGroup *group); -static gboolean -can_accept_drop (BzWindow *self); - static void bz_window_dispose (GObject *object) { @@ -405,7 +400,9 @@ drop_accept_cb (BzWindow *self, GdkDrop *drop, GtkDropTarget *target) { - return can_accept_drop (self); + return !bz_state_info_get_busy (self->state) && + self->screenshot_page == NULL && + adw_application_window_get_visible_dialog (ADW_APPLICATION_WINDOW (self)) == NULL; } static gboolean @@ -426,68 +423,6 @@ drop_cb (BzWindow *self, return TRUE; } -static GdkDragAction -drop_enter_cb (BzWindow *self, - double x, - double y, - GtkDropTarget *target) -{ - GtkWidget *inner = NULL; - GtkWidget *status = NULL; - - if (!can_accept_drop (self)) - return 0; - - if (self->drop_revealer != NULL) - { - gtk_revealer_set_reveal_child (self->drop_revealer, TRUE); - return GDK_ACTION_COPY; - } - - /* We initialize it here instead of the Blueprint to not cause issues with - * the GTK Inspectors object selector */ - self->drop_overlay = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_add_css_class (self->drop_overlay, "bz-drop-overlay"); - gtk_widget_set_can_target (self->drop_overlay, FALSE); - - inner = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_add_css_class (inner, "bz-drop-overlay-inner"); - gtk_widget_set_hexpand (inner, TRUE); - gtk_widget_set_vexpand (inner, TRUE); - - status = adw_status_page_new (); - adw_status_page_set_icon_name (ADW_STATUS_PAGE (status), "folder-open-symbolic"); - adw_status_page_set_title (ADW_STATUS_PAGE (status), _ ("Drop to Open")); - adw_status_page_set_description (ADW_STATUS_PAGE (status), _ ("Flatpak & Flatpak ref files")); - gtk_widget_set_valign (status, GTK_ALIGN_CENTER); - gtk_widget_set_vexpand (status, TRUE); - - gtk_box_append (GTK_BOX (inner), status); - gtk_box_append (GTK_BOX (self->drop_overlay), inner); - - self->drop_revealer = GTK_REVEALER (gtk_revealer_new ()); - gtk_revealer_set_transition_type (self->drop_revealer, GTK_REVEALER_TRANSITION_TYPE_CROSSFADE); - gtk_revealer_set_transition_duration (self->drop_revealer, 150); - gtk_revealer_set_child (self->drop_revealer, self->drop_overlay); - gtk_widget_set_can_target (GTK_WIDGET (self->drop_revealer), FALSE); - - gtk_overlay_add_overlay (self->window_overlay, GTK_WIDGET (self->drop_revealer)); - - gtk_revealer_set_reveal_child (self->drop_revealer, TRUE); - - return GDK_ACTION_COPY; -} - -static void -drop_leave_cb (BzWindow *self, - GtkDropTarget *target) -{ - if (self->drop_revealer == NULL) - return; - - gtk_revealer_set_reveal_child (self->drop_revealer, FALSE); -} - static BzEntryGroup * resolve_group_from_parameter (BzWindow *self, GVariant *parameter, @@ -894,8 +829,6 @@ bz_window_class_init (BzWindowClass *klass) gtk_widget_class_bind_template_callback (widget_class, format_title); gtk_widget_class_bind_template_callback (widget_class, drop_accept_cb); gtk_widget_class_bind_template_callback (widget_class, drop_cb); - gtk_widget_class_bind_template_callback (widget_class, drop_enter_cb); - gtk_widget_class_bind_template_callback (widget_class, drop_leave_cb); gtk_widget_class_install_action (widget_class, "escape", NULL, action_escape); gtk_widget_class_install_action (widget_class, "window.user-data", NULL, action_user_data); @@ -1511,11 +1444,3 @@ emit_hook_disown (BzWindow *self, dex_future_disown (bz_run_hook_emission ( hooks, signal, 0, NULL, group)); } - -static gboolean -can_accept_drop (BzWindow *self) -{ - return !bz_state_info_get_busy (self->state) && - self->screenshot_page == NULL && - adw_application_window_get_visible_dialog (ADW_APPLICATION_WINDOW (self)) == NULL; -} diff --git a/src/style.css b/src/style.css index 452a7b11..33ccb081 100644 --- a/src/style.css +++ b/src/style.css @@ -56,25 +56,6 @@ --banner-color: var(--accent-bg-color); } -.bz-drop-overlay { - background-color: alpha(color-mix(in srgb, @accent_bg_color 50%, @window_bg_color 75%), 0.80); - backdrop-filter: blur(4px); -} - -.bz-drop-overlay-inner { - border: 2px dashed alpha(@accent_color, 0.65); - border-radius: max(0px, calc(var(--window-radius) - 3px)); - margin: 6px; -} - -.bz-drop-overlay statuspage { - color: @accent_color; -} - -.bz-drop-overlay statuspage image { - color: @accent_color; -} - .updates-amount { background-color: white; color: var(--accent-bg-color);