From a24da67855b77dc34173e2c27ea49792cc467b42 Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Mon, 7 Dec 2020 19:09:45 +0500 Subject: [PATCH 01/12] swipe-away-bin: Add hide() and reveal() Support programmatic revealing and not just removing. --- src/swipe-away-bin.c | 24 ++++++++++++++++++++++++ src/swipe-away-bin.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/src/swipe-away-bin.c b/src/swipe-away-bin.c index dca4723c4..629805161 100644 --- a/src/swipe-away-bin.c +++ b/src/swipe-away-bin.c @@ -262,6 +262,30 @@ phosh_swipe_away_bin_swipeable_init (HdySwipeableInterface *iface) } +void +phosh_swipe_away_bin_hide (PhoshSwipeAwayBin *self) +{ + g_return_if_fail (PHOSH_IS_SWIPE_AWAY_BIN (self)); + + if (self->animation) + phosh_animation_stop (self->animation); + + set_progress (self, 1); +} + + +void +phosh_swipe_away_bin_reveal (PhoshSwipeAwayBin *self) +{ + g_return_if_fail (PHOSH_IS_SWIPE_AWAY_BIN (self)); + + if (self->animation) + phosh_animation_stop (self->animation); + + animate (self, 200, 0, PHOSH_ANIMATION_TYPE_EASE_OUT_CUBIC); +} + + void phosh_swipe_away_bin_remove (PhoshSwipeAwayBin *self) { diff --git a/src/swipe-away-bin.h b/src/swipe-away-bin.h index 67930046e..2f37d8557 100644 --- a/src/swipe-away-bin.h +++ b/src/swipe-away-bin.h @@ -13,5 +13,7 @@ G_DECLARE_FINAL_TYPE (PhoshSwipeAwayBin, phosh_swipe_away_bin, PHOSH, SWIPE_AWAY_BIN, GtkEventBox) +void phosh_swipe_away_bin_hide (PhoshSwipeAwayBin *self); +void phosh_swipe_away_bin_reveal (PhoshSwipeAwayBin *self); void phosh_swipe_away_bin_remove (PhoshSwipeAwayBin *self); void phosh_swipe_away_bin_undo (PhoshSwipeAwayBin *self); -- GitLab From 816d4eda94d96afa5a9e73aa16ac8dce5011f83f Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Tue, 8 Dec 2020 12:51:29 +0500 Subject: [PATCH 02/12] swipe-away-bin: Make orientable --- src/swipe-away-bin.c | 114 +++++++++++++++++++++++++++++++++++++++++-- src/ui/activity.ui | 1 + 2 files changed, 110 insertions(+), 5 deletions(-) diff --git a/src/swipe-away-bin.c b/src/swipe-away-bin.c index 629805161..61103a5af 100644 --- a/src/swipe-away-bin.c +++ b/src/swipe-away-bin.c @@ -18,10 +18,21 @@ enum { }; static guint signals[N_SIGNALS] = { 0 }; + +enum { + PROP_0, + PROP_ORIENTATION, + + LAST_PROP = PROP_ORIENTATION +}; + + struct _PhoshSwipeAwayBin { GtkEventBox parent_instance; + GtkOrientation orientation; + double progress; HdySwipeTracker *tracker; PhoshAnimation *animation; @@ -30,6 +41,7 @@ struct _PhoshSwipeAwayBin static void phosh_swipe_away_bin_swipeable_init (HdySwipeableInterface *iface); G_DEFINE_TYPE_WITH_CODE (PhoshSwipeAwayBin, phosh_swipe_away_bin, GTK_TYPE_EVENT_BOX, + G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL) G_IMPLEMENT_INTERFACE (HDY_TYPE_SWIPEABLE, phosh_swipe_away_bin_swipeable_init)) @@ -118,6 +130,19 @@ end_swipe_cb (PhoshSwipeAwayBin *self, } +static void +update_orientation (PhoshSwipeAwayBin *self) +{ + gboolean reversed = + self->orientation == GTK_ORIENTATION_HORIZONTAL && + gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL; + + hdy_swipe_tracker_set_reversed (self->tracker, reversed); + + gtk_widget_queue_allocate (GTK_WIDGET (self)); +} + + static void phosh_swipe_away_bin_finalize (GObject *object) { @@ -130,6 +155,51 @@ phosh_swipe_away_bin_finalize (GObject *object) } +static void +phosh_swipe_away_bin_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (object); + + switch (prop_id) { + case PROP_ORIENTATION: + g_value_set_enum (value, self->orientation); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + + +static void +phosh_swipe_away_bin_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (object); + + switch (prop_id) { + case PROP_ORIENTATION: + { + GtkOrientation orientation = g_value_get_enum (value); + if (orientation != self->orientation) { + self->orientation = orientation; + update_orientation (self); + g_object_notify (G_OBJECT (self), "orientation"); + } + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + + static void phosh_swipe_away_bin_size_allocate (GtkWidget *widget, GtkAllocation *alloc) @@ -143,8 +213,18 @@ phosh_swipe_away_bin_size_allocate (GtkWidget *widget, if (!child || !gtk_widget_get_visible (child)) return; - child_alloc.x = alloc->x; - child_alloc.y = alloc->y - (int) (self->progress * alloc->height); + if (self->orientation == GTK_ORIENTATION_HORIZONTAL) { + if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL) + child_alloc.x = alloc->x + (int) (self->progress * alloc->width); + else + child_alloc.x = alloc->x - (int) (self->progress * alloc->width); + + child_alloc.y = alloc->y; + } else { + child_alloc.x = alloc->x; + child_alloc.y = alloc->y - (int) (self->progress * alloc->height); + } + child_alloc.width = alloc->width; child_alloc.height = alloc->height; @@ -152,6 +232,16 @@ phosh_swipe_away_bin_size_allocate (GtkWidget *widget, } +static void +phosh_swipe_away_bin_direction_changed (GtkWidget *widget, + GtkTextDirection previous_direction) +{ + PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (widget); + + update_orientation (self); +} + + static void phosh_swipe_away_bin_class_init (PhoshSwipeAwayBinClass *klass) { @@ -159,7 +249,14 @@ phosh_swipe_away_bin_class_init (PhoshSwipeAwayBinClass *klass) GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->finalize = phosh_swipe_away_bin_finalize; + object_class->get_property = phosh_swipe_away_bin_get_property; + object_class->set_property = phosh_swipe_away_bin_set_property; widget_class->size_allocate = phosh_swipe_away_bin_size_allocate; + widget_class->direction_changed = phosh_swipe_away_bin_direction_changed; + + g_object_class_override_property (object_class, + PROP_ORIENTATION, + "orientation"); signals[REMOVED] = g_signal_new ("removed", @@ -179,9 +276,11 @@ phosh_swipe_away_bin_init (PhoshSwipeAwayBin *self) { self->tracker = hdy_swipe_tracker_new (HDY_SWIPEABLE (self)); - gtk_orientable_set_orientation (GTK_ORIENTABLE (self->tracker), - GTK_ORIENTATION_VERTICAL); + g_object_bind_property (self, "orientation", + self->tracker, "orientation", + G_BINDING_SYNC_CREATE); hdy_swipe_tracker_set_allow_mouse_drag (self->tracker, TRUE); + update_orientation (self); g_signal_connect_object (self->tracker, "begin-swipe", G_CALLBACK (begin_swipe_cb), self, @@ -207,7 +306,12 @@ phosh_swipe_away_bin_get_swipe_tracker (HdySwipeable *swipeable) static double phosh_swipe_away_bin_get_distance (HdySwipeable *swipeable) { - return (double) gtk_widget_get_allocated_height (GTK_WIDGET (swipeable)); + PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (swipeable); + + if (self->orientation == GTK_ORIENTATION_HORIZONTAL) + return (double) gtk_widget_get_allocated_width (GTK_WIDGET (self)); + else + return (double) gtk_widget_get_allocated_height (GTK_WIDGET (self)); } diff --git a/src/ui/activity.ui b/src/ui/activity.ui index 30d22abd4..98675d474 100644 --- a/src/ui/activity.ui +++ b/src/ui/activity.ui @@ -9,6 +9,7 @@ True + vertical -- GitLab From 2a7248924916f768be3d4dbcf3c8128bee083adc Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Tue, 8 Dec 2020 13:23:16 +0500 Subject: [PATCH 03/12] swipe-away-bin: Add property to allow swipes in the other direction --- src/swipe-away-bin.c | 61 +++++++++++++++++++++++++++++++++++++++++--- src/swipe-away-bin.h | 4 +++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/swipe-away-bin.c b/src/swipe-away-bin.c index 61103a5af..f29e84e77 100644 --- a/src/swipe-away-bin.c +++ b/src/swipe-away-bin.c @@ -21,10 +21,12 @@ static guint signals[N_SIGNALS] = { 0 }; enum { PROP_0, + PROP_ALLOW_NEGATIVE, PROP_ORIENTATION, LAST_PROP = PROP_ORIENTATION }; +static GParamSpec *props[LAST_PROP]; struct _PhoshSwipeAwayBin @@ -32,6 +34,7 @@ struct _PhoshSwipeAwayBin GtkEventBox parent_instance; GtkOrientation orientation; + gboolean allow_negative; double progress; HdySwipeTracker *tracker; @@ -164,6 +167,10 @@ phosh_swipe_away_bin_get_property (GObject *object, PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (object); switch (prop_id) { + case PROP_ALLOW_NEGATIVE: + g_value_set_boolean (value, phosh_swipe_away_bin_get_allow_negative (self)); + break; + case PROP_ORIENTATION: g_value_set_enum (value, self->orientation); break; @@ -183,6 +190,10 @@ phosh_swipe_away_bin_set_property (GObject *object, PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (object); switch (prop_id) { + case PROP_ALLOW_NEGATIVE: + phosh_swipe_away_bin_set_allow_negative (self, g_value_get_boolean (value)); + break; + case PROP_ORIENTATION: { GtkOrientation orientation = g_value_get_enum (value); @@ -254,6 +265,15 @@ phosh_swipe_away_bin_class_init (PhoshSwipeAwayBinClass *klass) widget_class->size_allocate = phosh_swipe_away_bin_size_allocate; widget_class->direction_changed = phosh_swipe_away_bin_direction_changed; + props[PROP_ALLOW_NEGATIVE] = + g_param_spec_boolean ("allow-negative", + "Allow Negative", + "Use [-1:1] progress range instead of [0:1]", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, LAST_PROP, props); + g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation"); @@ -335,12 +355,21 @@ static double * phosh_swipe_away_bin_get_snap_points (HdySwipeable *swipeable, int *n_snap_points) { - double *points = g_new0 (double, 2); + PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (swipeable); + int n = self->allow_negative ? 3 : 2; + double *points; - points[1] = 1; + points = g_new0 (double, n); + + if (self->allow_negative) { + points[0] = -1; + points[2] = 1; + } else { + points[1] = 1; + } if (n_snap_points) - *n_snap_points = 2; + *n_snap_points = n; return points; } @@ -366,6 +395,32 @@ phosh_swipe_away_bin_swipeable_init (HdySwipeableInterface *iface) } +gboolean +phosh_swipe_away_bin_get_allow_negative (PhoshSwipeAwayBin *self) +{ + g_return_val_if_fail (PHOSH_IS_SWIPE_AWAY_BIN (self), FALSE); + + return self->allow_negative; +} + + +void +phosh_swipe_away_bin_set_allow_negative (PhoshSwipeAwayBin *self, + gboolean allow_negative) +{ + g_return_if_fail (PHOSH_IS_SWIPE_AWAY_BIN (self)); + + allow_negative = !!allow_negative; + + if (allow_negative == self->allow_negative) + return; + + self->allow_negative = allow_negative; + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ALLOW_NEGATIVE]); +} + + void phosh_swipe_away_bin_hide (PhoshSwipeAwayBin *self) { diff --git a/src/swipe-away-bin.h b/src/swipe-away-bin.h index 2f37d8557..6a72b996c 100644 --- a/src/swipe-away-bin.h +++ b/src/swipe-away-bin.h @@ -13,6 +13,10 @@ G_DECLARE_FINAL_TYPE (PhoshSwipeAwayBin, phosh_swipe_away_bin, PHOSH, SWIPE_AWAY_BIN, GtkEventBox) +gboolean phosh_swipe_away_bin_get_allow_negative (PhoshSwipeAwayBin *self); +void phosh_swipe_away_bin_set_allow_negative (PhoshSwipeAwayBin *self, + gboolean allow_negative); + void phosh_swipe_away_bin_hide (PhoshSwipeAwayBin *self); void phosh_swipe_away_bin_reveal (PhoshSwipeAwayBin *self); void phosh_swipe_away_bin_remove (PhoshSwipeAwayBin *self); -- GitLab From f2f45032a0ca135843e5000bf73751ac4a4a537f Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Tue, 8 Dec 2020 17:56:23 +0500 Subject: [PATCH 04/12] swipe-away-bin: Add reserve-size property --- src/swipe-away-bin.c | 126 +++++++++++++++++++++++++++++++++++++++---- src/swipe-away-bin.h | 4 ++ 2 files changed, 119 insertions(+), 11 deletions(-) diff --git a/src/swipe-away-bin.c b/src/swipe-away-bin.c index f29e84e77..46ccf565f 100644 --- a/src/swipe-away-bin.c +++ b/src/swipe-away-bin.c @@ -22,6 +22,7 @@ static guint signals[N_SIGNALS] = { 0 }; enum { PROP_0, PROP_ALLOW_NEGATIVE, + PROP_RESERVE_SIZE, PROP_ORIENTATION, LAST_PROP = PROP_ORIENTATION @@ -35,8 +36,10 @@ struct _PhoshSwipeAwayBin GtkOrientation orientation; gboolean allow_negative; + gboolean reserve_size; double progress; + int distance; HdySwipeTracker *tracker; PhoshAnimation *animation; }; @@ -171,6 +174,10 @@ phosh_swipe_away_bin_get_property (GObject *object, g_value_set_boolean (value, phosh_swipe_away_bin_get_allow_negative (self)); break; + case PROP_RESERVE_SIZE: + g_value_set_boolean (value, phosh_swipe_away_bin_get_reserve_size (self)); + break; + case PROP_ORIENTATION: g_value_set_enum (value, self->orientation); break; @@ -194,6 +201,10 @@ phosh_swipe_away_bin_set_property (GObject *object, phosh_swipe_away_bin_set_allow_negative (self, g_value_get_boolean (value)); break; + case PROP_RESERVE_SIZE: + phosh_swipe_away_bin_set_reserve_size (self, g_value_get_boolean (value)); + break; + case PROP_ORIENTATION: { GtkOrientation orientation = g_value_get_enum (value); @@ -224,25 +235,84 @@ phosh_swipe_away_bin_size_allocate (GtkWidget *widget, if (!child || !gtk_widget_get_visible (child)) return; + child_alloc.y = alloc->y; + child_alloc.x = alloc->x; + child_alloc.width = alloc->width; + child_alloc.height = alloc->height; + if (self->orientation == GTK_ORIENTATION_HORIZONTAL) { + if (self->reserve_size) { + self->distance = alloc->width / 3; + + child_alloc.width = self->distance; + child_alloc.x += self->distance; + } else { + self->distance = alloc->width; + } + if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL) - child_alloc.x = alloc->x + (int) (self->progress * alloc->width); + child_alloc.x += (int) (self->progress * self->distance); else - child_alloc.x = alloc->x - (int) (self->progress * alloc->width); + child_alloc.x -= (int) (self->progress * self->distance); - child_alloc.y = alloc->y; } else { - child_alloc.x = alloc->x; - child_alloc.y = alloc->y - (int) (self->progress * alloc->height); + if (self->reserve_size) { + self->distance = alloc->height / 3; + + child_alloc.height = self->distance; + child_alloc.y += self->distance; + } else { + self->distance = alloc->height; + } + + child_alloc.y -= (int) (self->progress * self->distance); } - child_alloc.width = alloc->width; - child_alloc.height = alloc->height; gtk_widget_size_allocate (child, &child_alloc); } +static void +phosh_swipe_away_bin_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (widget); + + GTK_WIDGET_CLASS (phosh_swipe_away_bin_parent_class)->get_preferred_width (widget, minimum, natural); + + if (self->reserve_size && + self->orientation == GTK_ORIENTATION_HORIZONTAL) { + if (minimum) + *minimum *= 3; + + if (natural) + *natural *= 3; + } +} + + +static void +phosh_swipe_away_bin_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (widget); + + GTK_WIDGET_CLASS (phosh_swipe_away_bin_parent_class)->get_preferred_height (widget, minimum, natural); + + if (self->reserve_size && + self->orientation == GTK_ORIENTATION_VERTICAL) { + if (minimum) + *minimum *= 3; + + if (natural) + *natural *= 3; + } +} + + static void phosh_swipe_away_bin_direction_changed (GtkWidget *widget, GtkTextDirection previous_direction) @@ -263,6 +333,8 @@ phosh_swipe_away_bin_class_init (PhoshSwipeAwayBinClass *klass) object_class->get_property = phosh_swipe_away_bin_get_property; object_class->set_property = phosh_swipe_away_bin_set_property; widget_class->size_allocate = phosh_swipe_away_bin_size_allocate; + widget_class->get_preferred_width = phosh_swipe_away_bin_get_preferred_width; + widget_class->get_preferred_height = phosh_swipe_away_bin_get_preferred_height; widget_class->direction_changed = phosh_swipe_away_bin_direction_changed; props[PROP_ALLOW_NEGATIVE] = @@ -272,6 +344,13 @@ phosh_swipe_away_bin_class_init (PhoshSwipeAwayBinClass *klass) FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + props[PROP_RESERVE_SIZE] = + g_param_spec_boolean ("reserve-size", + "Reserve Size", + "Allocate larger size than the child so that the child is never clipped when animating", + FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_properties (object_class, LAST_PROP, props); g_object_class_override_property (object_class, @@ -328,10 +407,7 @@ phosh_swipe_away_bin_get_distance (HdySwipeable *swipeable) { PhoshSwipeAwayBin *self = PHOSH_SWIPE_AWAY_BIN (swipeable); - if (self->orientation == GTK_ORIENTATION_HORIZONTAL) - return (double) gtk_widget_get_allocated_width (GTK_WIDGET (self)); - else - return (double) gtk_widget_get_allocated_height (GTK_WIDGET (self)); + return self->distance; } @@ -421,6 +497,34 @@ phosh_swipe_away_bin_set_allow_negative (PhoshSwipeAwayBin *self, } +gboolean +phosh_swipe_away_bin_get_reserve_size (PhoshSwipeAwayBin *self) +{ + g_return_val_if_fail (PHOSH_IS_SWIPE_AWAY_BIN (self), FALSE); + + return self->reserve_size; +} + + +void +phosh_swipe_away_bin_set_reserve_size (PhoshSwipeAwayBin *self, + gboolean reserve_size) +{ + g_return_if_fail (PHOSH_IS_SWIPE_AWAY_BIN (self)); + + reserve_size = !!reserve_size; + + if (reserve_size == self->reserve_size) + return; + + self->reserve_size = reserve_size; + + gtk_widget_queue_resize (GTK_WIDGET (self)); + + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_RESERVE_SIZE]); +} + + void phosh_swipe_away_bin_hide (PhoshSwipeAwayBin *self) { diff --git a/src/swipe-away-bin.h b/src/swipe-away-bin.h index 6a72b996c..73ab3e96e 100644 --- a/src/swipe-away-bin.h +++ b/src/swipe-away-bin.h @@ -17,6 +17,10 @@ gboolean phosh_swipe_away_bin_get_allow_negative (PhoshSwipeAwayBin *self); void phosh_swipe_away_bin_set_allow_negative (PhoshSwipeAwayBin *self, gboolean allow_negative); +gboolean phosh_swipe_away_bin_get_reserve_size (PhoshSwipeAwayBin *self); +void phosh_swipe_away_bin_set_reserve_size (PhoshSwipeAwayBin *self, + gboolean reserve_size); + void phosh_swipe_away_bin_hide (PhoshSwipeAwayBin *self); void phosh_swipe_away_bin_reveal (PhoshSwipeAwayBin *self); void phosh_swipe_away_bin_remove (PhoshSwipeAwayBin *self); -- GitLab From 33ac5435e868aa962a4df57583d58133bb8227d9 Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Tue, 8 Dec 2020 18:26:01 +0500 Subject: [PATCH 05/12] panel: Use GtkGestureMultiPress and released signal for closing Make sure we don't interfere with swipes in future. --- src/top-panel.c | 17 ++++++++--------- src/ui/top-panel.ui | 4 ++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/top-panel.c b/src/top-panel.c index 739aff96c..92c915b24 100644 --- a/src/top-panel.c +++ b/src/top-panel.c @@ -63,6 +63,8 @@ typedef struct _PhoshTopPanel { GdkSeat *seat; GSimpleActionGroup *actions; + + GtkGesture *click_gesture; /* needed so that the gesture isn't destroyed immediately */ } PhoshTopPanel; G_DEFINE_TYPE (PhoshTopPanel, phosh_top_panel, PHOSH_TYPE_LAYER_SURFACE) @@ -244,10 +246,10 @@ on_key_press_event (PhoshTopPanel *self, GdkEventKey *event, gpointer data) } -static gboolean -on_button_press_event (PhoshTopPanel *self, GdkEventButton *event, gpointer data) +static void +released_cb (PhoshTopPanel *self) { - phosh_trigger_feedback ("button-pressed"); + phosh_trigger_feedback ("button-released"); /* * The popover has to be popdown manually as it doesn't happen @@ -258,7 +260,6 @@ on_button_press_event (PhoshTopPanel *self, GdkEventButton *event, gpointer data else phosh_top_panel_fold (self); - return GDK_EVENT_PROPAGATE; } @@ -321,15 +322,11 @@ phosh_top_panel_constructed (GObject *object) } /* Settings menu and it's top-bar / menu */ - gtk_widget_add_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK); + gtk_widget_add_events (GTK_WIDGET (self), GDK_ALL_EVENTS_MASK); g_signal_connect (G_OBJECT (self), "key-press-event", G_CALLBACK (on_key_press_event), NULL); - g_signal_connect (G_OBJECT (self), - "button-press-event", - G_CALLBACK (on_button_press_event), - NULL); g_signal_connect_swapped (self->settings, "setting-done", G_CALLBACK (phosh_top_panel_fold), @@ -398,6 +395,8 @@ phosh_top_panel_class_init (PhoshTopPanelClass *klass) gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, box); gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, stack); gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, settings); + gtk_widget_class_bind_template_child (widget_class, PhoshTopPanel, click_gesture); + gtk_widget_class_bind_template_callback (widget_class, released_cb); } diff --git a/src/ui/top-panel.ui b/src/ui/top-panel.ui index 2d730a019..828a8d3c2 100644 --- a/src/ui/top-panel.ui +++ b/src/ui/top-panel.ui @@ -302,4 +302,8 @@ + + PhoshTopPanel + + -- GitLab From 8db51c721c03b7634999c9c490231b73f661fadc Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Wed, 9 Dec 2020 14:02:10 +0500 Subject: [PATCH 06/12] notification-frame: Reimplement activation via GtkGestureMultiPress Unfortunately, in GTK 3 it's not possible to use single click row activation together with swipes; they will interfere. Meanwhile, we still need activation for keynav, so switch to double click activation and implement it manually instead. Use this chance to unify click handling with the header. --- src/notifications/notification-frame.c | 135 +++++++++++++++++++++++-- src/ui/notification-frame.ui | 18 +++- tests/test-notification-frame.c | 35 ------- 3 files changed, 140 insertions(+), 48 deletions(-) diff --git a/src/notifications/notification-frame.c b/src/notifications/notification-frame.c index 801becae3..cc912cba4 100644 --- a/src/notifications/notification-frame.c +++ b/src/notifications/notification-frame.c @@ -15,6 +15,8 @@ #include "util.h" #include "timestamp-label.h" +#include + /** * SECTION:notification-frame * @short_description: A frame containing one or more notifications @@ -46,6 +48,14 @@ struct _PhoshNotificationFrame { GtkWidget *updated; gboolean show_body; + + /* needed so that the gestures aren't immediately destroyed */ + GtkGesture *header_click_gesture; + GtkGesture *list_click_gesture; + + int start_x; + int start_y; + GtkListBoxRow *active_row; }; typedef struct _PhoshNotificationFrame PhoshNotificationFrame; @@ -53,6 +63,9 @@ typedef struct _PhoshNotificationFrame PhoshNotificationFrame; G_DEFINE_TYPE (PhoshNotificationFrame, phosh_notification_frame, GTK_TYPE_BOX) +#define DRAG_THRESHOLD_DISTANCE 16 + + enum { SIGNAL_EMPTY, N_SIGNALS @@ -113,22 +126,118 @@ phosh_notification_frame_finalize (GObject *object) } -/* When the title row is clicked we proxy it to the first item */ static gboolean -header_activated (PhoshNotificationFrame *self, GdkEventButton *event) +motion_notify (PhoshNotificationFrame *self, + GdkEventMotion *event) { - g_autoptr (PhoshNotification) notification = NULL; + if (self->start_x >= 0 && self->start_y >= 0) { + int current_x, current_y; + double dx, dy; + + gtk_widget_translate_coordinates (GTK_WIDGET (self), + gtk_widget_get_toplevel (GTK_WIDGET (self)), + event->x, event->y, + ¤t_x, ¤t_y); + + dx = current_x - self->start_x; + dy = current_y - self->start_y; + + if (sqrt (dx * dx + dy * dy) > DRAG_THRESHOLD_DISTANCE) { + gtk_gesture_set_state (self->header_click_gesture, GTK_EVENT_SEQUENCE_DENIED); + gtk_gesture_set_state (self->list_click_gesture, GTK_EVENT_SEQUENCE_DENIED); + } + } - g_return_val_if_fail (PHOSH_IS_NOTIFICATION_FRAME (self), FALSE); + return GDK_EVENT_PROPAGATE; +} - notification = g_list_model_get_item (self->model, 0); - g_return_val_if_fail (PHOSH_IS_NOTIFICATION (notification), FALSE); +static void +pressed (PhoshNotificationFrame *self, + int n_press, + double x, + double y, + GtkGesture *gesture, + GtkGesture *other_gesture) +{ + GdkEventSequence *sequence = + gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)); + + if (n_press != 1) { + gtk_gesture_set_sequence_state (gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); + + return; + } + + gtk_widget_translate_coordinates (self->box, + gtk_widget_get_toplevel (GTK_WIDGET (self)), + x, y, + &self->start_x, &self->start_y); + + /* When the title row is clicked we proxy it to the first item */ + self->active_row = + gtk_list_box_get_row_at_y (GTK_LIST_BOX (self->list_notifs), + gesture == self->header_click_gesture ? 0 : y); + + gtk_gesture_set_sequence_state (other_gesture, sequence, GTK_EVENT_SEQUENCE_DENIED); +} + +static void +header_pressed (PhoshNotificationFrame *self, + int n_press, + double x, + double y) +{ + pressed (self, n_press, x, y, + self->header_click_gesture, + self->list_click_gesture); +} + + +static void +list_pressed (PhoshNotificationFrame *self, + int n_press, + double x, + double y) +{ + pressed (self, n_press, x, y, + self->list_click_gesture, + self->header_click_gesture); +} + + +static void +released (PhoshNotificationFrame *self, + int n_press, + double x, + double y, + GtkGesture *gesture) +{ + GtkListBoxRow *pressed_row = self->active_row; + GtkListBoxRow *active_row; + PhoshNotificationContent *content; + PhoshNotification *notification; + + /* When the title row is clicked we proxy it to the first item */ + active_row = + gtk_list_box_get_row_at_y (GTK_LIST_BOX (self->list_notifs), + gesture == self->header_click_gesture ? 0 : y); + + self->active_row = NULL; + self->start_x = -1; + self->start_y = -1; + + if (pressed_row != active_row) { + gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED); + + return; + } + + content = PHOSH_NOTIFICATION_CONTENT (active_row); + notification = phosh_notification_content_get_notification (content); phosh_notification_activate (notification, PHOSH_NOTIFICATION_DEFAULT_ACTION); - - return FALSE; } @@ -192,8 +301,13 @@ phosh_notification_frame_class_init (PhoshNotificationFrameClass *klass) gtk_widget_class_bind_template_child (widget_class, PhoshNotificationFrame, img_icon); gtk_widget_class_bind_template_child (widget_class, PhoshNotificationFrame, list_notifs); gtk_widget_class_bind_template_child (widget_class, PhoshNotificationFrame, updated); + gtk_widget_class_bind_template_child (widget_class, PhoshNotificationFrame, header_click_gesture); + gtk_widget_class_bind_template_child (widget_class, PhoshNotificationFrame, list_click_gesture); - gtk_widget_class_bind_template_callback (widget_class, header_activated); + gtk_widget_class_bind_template_callback (widget_class, motion_notify); + gtk_widget_class_bind_template_callback (widget_class, header_pressed); + gtk_widget_class_bind_template_callback (widget_class, list_pressed); + gtk_widget_class_bind_template_callback (widget_class, released); gtk_widget_class_bind_template_callback (widget_class, notification_activated); gtk_widget_class_set_css_name (widget_class, "phosh-notification-frame"); @@ -204,6 +318,9 @@ static void phosh_notification_frame_init (PhoshNotificationFrame *self) { self->show_body = TRUE; + self->start_x = -1; + self->start_y = -1; + gtk_widget_init_template (GTK_WIDGET (self)); } diff --git a/src/ui/notification-frame.ui b/src/ui/notification-frame.ui index 1ac860a8a..c9f0ec7bc 100644 --- a/src/ui/notification-frame.ui +++ b/src/ui/notification-frame.ui @@ -5,12 +5,12 @@ True vertical start + - + True False - GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK - + GDK_ALL_EVENTS_MASK True @@ -74,10 +74,20 @@ True - True + False none + + header + + + + + list_notifs + + + diff --git a/tests/test-notification-frame.c b/tests/test-notification-frame.c index 8e3267e7c..d7afe135b 100644 --- a/tests/test-notification-frame.c +++ b/tests/test-notification-frame.c @@ -50,40 +50,6 @@ test_phosh_notification_frame_new (void) } -static void -test_phosh_notification_frame_header_activated (void) -{ - g_autoptr (PhoshNotification) noti = NULL; - GtkWidget *frame = NULL; - g_autoptr (GDateTime) now = g_date_time_new_now_local (); - - noti = phosh_notification_new (0, - NULL, - NULL, - "Hey", - "Testing", - NULL, - NULL, - PHOSH_NOTIFICATION_URGENCY_NORMAL, - NULL, - FALSE, - FALSE, - NULL, - now); - - frame = phosh_notification_frame_new (TRUE); - phosh_notification_frame_bind_notification (PHOSH_NOTIFICATION_FRAME (frame), - noti); - g_signal_connect (noti, "actioned", G_CALLBACK (actioned), NULL); - - actioned_called = FALSE; - - header_activated (PHOSH_NOTIFICATION_FRAME (frame), - (GdkEventButton *) gdk_event_new (GDK_BUTTON_PRESS)); - g_assert_true (actioned_called); -} - - static void test_phosh_notification_frame_notification_activated (void) { @@ -130,7 +96,6 @@ main (int argc, char **argv) gtk_test_init (&argc, &argv, NULL); g_test_add_func ("/phosh/notification-frame/new", test_phosh_notification_frame_new); - g_test_add_func ("/phosh/notification-frame/header-activated", test_phosh_notification_frame_header_activated); g_test_add_func ("/phosh/notification-frame/notification-activated", test_phosh_notification_frame_notification_activated); return g_test_run (); -- GitLab From 8310fff562466f1064abc893d0a24e48e58884a6 Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Mon, 7 Dec 2020 18:01:27 +0500 Subject: [PATCH 07/12] notification-banner: Use template --- src/notifications/notification-banner.c | 9 +++++---- src/phosh.gresources.xml | 1 + src/ui/notification-banner.ui | 10 ++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 src/ui/notification-banner.ui diff --git a/src/notifications/notification-banner.c b/src/notifications/notification-banner.c index 8ff4419a3..76ac0f877 100644 --- a/src/notifications/notification-banner.c +++ b/src/notifications/notification-banner.c @@ -249,6 +249,9 @@ phosh_notification_banner_class_init (PhoshNotificationBannerClass *klass) g_object_class_install_properties (object_class, LAST_PROP, props); + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/phosh/ui/notification-banner.ui"); + gtk_widget_class_set_css_name (widget_class, "phosh-notification-banner"); } @@ -257,6 +260,8 @@ static void phosh_notification_banner_init (PhoshNotificationBanner *self) { self->animation.progress = 0.0; + + gtk_widget_init_template (GTK_WIDGET (self)); } @@ -277,12 +282,8 @@ phosh_notification_banner_new (PhoshNotification *notification) "layer-shell", phosh_wayland_get_zwlr_layer_shell_v1 (wl), "wl-output", monitor ? monitor->wl_output : NULL, "anchor", ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - "height", 50, "width", MIN (width, 450), "layer", ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - "kbd-interactivity", FALSE, - "exclusive-zone", 0, - "namespace", "phosh notification", NULL); } diff --git a/src/phosh.gresources.xml b/src/phosh.gresources.xml index 428fe7605..5ca4e19e5 100644 --- a/src/phosh.gresources.xml +++ b/src/phosh.gresources.xml @@ -11,6 +11,7 @@ ui/home.ui ui/lockscreen.ui ui/media-player.ui + ui/notification-banner.ui ui/notification-content.ui ui/notification-frame.ui ui/polkit-auth-prompt.ui diff --git a/src/ui/notification-banner.ui b/src/ui/notification-banner.ui new file mode 100644 index 000000000..c1308ea65 --- /dev/null +++ b/src/ui/notification-banner.ui @@ -0,0 +1,10 @@ + + + + + -- GitLab From e38315bdaaed41597670cc33f744fc93ab37b2ac Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Wed, 9 Dec 2020 15:10:33 +0500 Subject: [PATCH 08/12] notification-frame: Support swipe-to-remove --- src/notifications/notification-frame.c | 28 +++++- src/notifications/notification-frame.h | 2 +- src/stylesheet/common.css | 6 +- src/ui/notification-frame.ui | 134 ++++++++++++++----------- 4 files changed, 104 insertions(+), 66 deletions(-) diff --git a/src/notifications/notification-frame.c b/src/notifications/notification-frame.c index cc912cba4..54ace4196 100644 --- a/src/notifications/notification-frame.c +++ b/src/notifications/notification-frame.c @@ -12,6 +12,7 @@ #include "notification-content.h" #include "notification-frame.h" #include "notification-source.h" +#include "swipe-away-bin.h" #include "util.h" #include "timestamp-label.h" @@ -33,7 +34,7 @@ static GParamSpec *props[LAST_PROP]; struct _PhoshNotificationFrame { - GtkBox parent; + GtkEventBox parent; GListModel *model; gulong model_watch; @@ -42,6 +43,7 @@ struct _PhoshNotificationFrame { GBinding *bind_icon; GBinding *bind_timestamp; + GtkWidget *box; GtkWidget *lbl_app_name; GtkWidget *img_icon; GtkWidget *list_notifs; @@ -60,7 +62,7 @@ struct _PhoshNotificationFrame { typedef struct _PhoshNotificationFrame PhoshNotificationFrame; -G_DEFINE_TYPE (PhoshNotificationFrame, phosh_notification_frame, GTK_TYPE_BOX) +G_DEFINE_TYPE (PhoshNotificationFrame, phosh_notification_frame, GTK_TYPE_EVENT_BOX) #define DRAG_THRESHOLD_DISTANCE 16 @@ -134,7 +136,7 @@ motion_notify (PhoshNotificationFrame *self, int current_x, current_y; double dx, dy; - gtk_widget_translate_coordinates (GTK_WIDGET (self), + gtk_widget_translate_coordinates (GTK_WIDGET (self->box), gtk_widget_get_toplevel (GTK_WIDGET (self)), event->x, event->y, ¤t_x, ¤t_y); @@ -259,6 +261,22 @@ notification_activated (PhoshNotificationFrame *self, } +static void +removed (PhoshNotificationFrame *self) +{ + guint i, n; + + n = g_list_model_get_n_items (self->model); + for (i = 0; i < n; i++) { + g_autoptr (PhoshNotification) notification = NULL; + + notification = g_list_model_get_item (self->model, 0); + + phosh_notification_close (notification, PHOSH_NOTIFICATION_REASON_CLOSED); + } +} + + static void phosh_notification_frame_class_init (PhoshNotificationFrameClass *klass) { @@ -297,6 +315,7 @@ phosh_notification_frame_class_init (PhoshNotificationFrameClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/sm/puri/phosh/ui/notification-frame.ui"); + gtk_widget_class_bind_template_child (widget_class, PhoshNotificationFrame, box); gtk_widget_class_bind_template_child (widget_class, PhoshNotificationFrame, lbl_app_name); gtk_widget_class_bind_template_child (widget_class, PhoshNotificationFrame, img_icon); gtk_widget_class_bind_template_child (widget_class, PhoshNotificationFrame, list_notifs); @@ -309,6 +328,7 @@ phosh_notification_frame_class_init (PhoshNotificationFrameClass *klass) gtk_widget_class_bind_template_callback (widget_class, list_pressed); gtk_widget_class_bind_template_callback (widget_class, released); gtk_widget_class_bind_template_callback (widget_class, notification_activated); + gtk_widget_class_bind_template_callback (widget_class, removed); gtk_widget_class_set_css_name (widget_class, "phosh-notification-frame"); } @@ -321,6 +341,8 @@ phosh_notification_frame_init (PhoshNotificationFrame *self) self->start_x = -1; self->start_y = -1; + g_type_ensure (PHOSH_TYPE_SWIPE_AWAY_BIN); + gtk_widget_init_template (GTK_WIDGET (self)); } diff --git a/src/notifications/notification-frame.h b/src/notifications/notification-frame.h index 843fa0ab3..05741559e 100644 --- a/src/notifications/notification-frame.h +++ b/src/notifications/notification-frame.h @@ -18,7 +18,7 @@ G_BEGIN_DECLS #define PHOSH_TYPE_NOTIFICATION_FRAME (phosh_notification_frame_get_type ()) -G_DECLARE_FINAL_TYPE (PhoshNotificationFrame, phosh_notification_frame, PHOSH, NOTIFICATION_FRAME, GtkBox) +G_DECLARE_FINAL_TYPE (PhoshNotificationFrame, phosh_notification_frame, PHOSH, NOTIFICATION_FRAME, GtkEventBox) GtkWidget *phosh_notification_frame_new (gboolean show_body); diff --git a/src/stylesheet/common.css b/src/stylesheet/common.css index 576a7acc9..eb6dab068 100644 --- a/src/stylesheet/common.css +++ b/src/stylesheet/common.css @@ -258,7 +258,7 @@ phosh-lockscreen .phosh-notification-tray row { margin-right: 12px; } -phosh-lockscreen .phosh-notification-tray phosh-notification-frame { +phosh-lockscreen .phosh-notification-tray phosh-notification-frame .notification-container { background-color: @phosh_notification_bg_color; margin: 3px 0px 0px 0px; } @@ -393,13 +393,13 @@ phosh-notification-content:last-child .actions-area button:last-child { border-bottom: none; } -phosh-notification-frame { +phosh-notification-frame .notification-container { border-radius: 6px; background-color: @phosh_notification_bg_color; margin: 12px; } -phosh-notification-banner > phosh-notification-frame { +phosh-notification-banner .notification-container { box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.33), 0px 5px 6px 0px rgba(0, 0, 0, 0.07), 0px 0px 0px 1px rgba(0, 0, 0, 0.2); diff --git a/src/ui/notification-frame.ui b/src/ui/notification-frame.ui index c9f0ec7bc..0a5be17c7 100644 --- a/src/ui/notification-frame.ui +++ b/src/ui/notification-frame.ui @@ -1,84 +1,100 @@ -