This commit is contained in:
Page Asgardius 2024-08-13 08:17:11 -07:00
parent ca4d6cfcf8
commit 5ab8da5e08
91 changed files with 20730 additions and 0 deletions

View file

@ -0,0 +1,23 @@
[org.gnome.desktop.session]
idle-delay=60
[org.gnome.Epiphany.web]
user-agent='Mozilla/5.0 (PinePhone, like iPhone; Linux aarch64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Chrome/64 Mobile/15E148 Safari/605.1.15'
[org.gnome.desktop.background]
picture-uri='file:///usr/share/danctnix/adwaita-phone.jpg'
[org.gnome.desktop.sound]
theme-name='librem5'
[org.gnome.settings-daemon.peripherals.touchscreen]
orientation-lock=true
[org.gnome.settings-daemon.plugins.wwan]
unlock-sim=true
[org.gnome.software]
download-updates=false
[sm.puri.phosh]
enable-suspend=true

View file

@ -0,0 +1,31 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=danctnix-phosh-settings
pkgver=0.5
pkgrel=3
pkgdesc="Settings for Phosh UI"
arch=(any)
url="https://github.com/dreemurrs-embedded/Pine64-Arch"
license=('MIT')
install="$pkgname.install"
source=(adwaita-phone.jpg
pa-phosh.pa
phosh-wayland.sh
11_mobile.gschema.override)
package() {
# Add custom PA config
install -Dm755 -t "$pkgdir/etc/pulse/default.pa.d" "$srcdir/pa-phosh.pa"
# Envscripts
install -Dm755 -t "$pkgdir/etc/profile.d" "$srcdir/phosh-wayland.sh"
install -Dm644 -t "$pkgdir/usr/share/glib-2.0/schemas" "$srcdir/11_mobile.gschema.override"
install -Dm644 -t "$pkgdir/usr/share/danctnix" "$srcdir/adwaita-phone.jpg"
}
md5sums=('cdc223b00b4e98f77286df98b1cddb4b'
'fe7dc2d103ce11388af9ed555578fbf7'
'7580818750c3dad45819f0e3345169a7'
'9caef3d24adc4d10528eac294353b167')

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 KiB

View file

@ -0,0 +1,9 @@
post_install() {
dconf update
glib-compile-schemas /usr/share/glib-2.0/schemas
}
post_upgrade() {
dconf update
glib-compile-schemas /usr/share/glib-2.0/schemas
}

View file

@ -0,0 +1,5 @@
# duck volume of audio streams when notification or accessibility sounds are played
load-module module-role-ducking trigger_roles=event,a11y ducking_roles=no_role,music,video,game global=true
# automatically switch default source/sink to a new device (Bluetooth, USB)
load-module module-switch-on-connect

View file

@ -0,0 +1,10 @@
#!/bin/sh
# Sometimes users may have multiple UI installed and they may choose to run a non-Wayland environment,
# so let's only set these when the session type is Wayland.
if [ "$XDG_SESSION_TYPE" = "wayland" ]; then
export MOZ_ENABLE_WAYLAND=1
export QT_QPA_PLATFORM=wayland
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
fi

View file

@ -0,0 +1,24 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=danctnix-phosh-ui-meta
pkgver=0.2
pkgrel=4
pkgdesc="Meta package for Phosh"
arch=(any)
url="https://github.com/dreemurrs-embedded/Pine64-Arch"
depends=(
danctnix-phosh-settings
dconf
gtk3
gnome-keyring
phoc
phosh
feedbackd
squeekboard
dnsmasq
gnome-control-center
sound-theme-librem5
iio-sensor-proxy
wys
xdg-desktop-portal-gtk
)

View file

@ -0,0 +1,45 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Wed, 11 Dec 2019 16:24:31 +0100
Subject: toolbar: Allow to toggle the sidebar button
This will allow updating the button's state when gestures will allow
closing the sidebar in the next commit.
---
shell/ev-toolbar.c | 14 ++++++++++++++
shell/ev-toolbar.h | 3 +++
2 files changed, 17 insertions(+)
diff --git a/shell/ev-toolbar.c b/shell/ev-toolbar.c
index bb20887..6c5521f 100644
--- a/shell/ev-toolbar.c
+++ b/shell/ev-toolbar.c
@@ -264,3 +264,17 @@ ev_toolbar_get_mode (EvToolbar *ev_toolbar)
return priv->toolbar_mode;
}
+
+void
+ev_toolbar_set_sidebar_visible (EvToolbar *ev_toolbar,
+ gboolean visible)
+{
+ EvToolbarPrivate *priv;
+
+ g_return_if_fail (EV_IS_TOOLBAR (ev_toolbar));
+
+ priv = GET_PRIVATE (ev_toolbar);
+ visible = !!visible;
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->sidebar_button), visible);
+}
diff --git a/shell/ev-toolbar.h b/shell/ev-toolbar.h
index 6cb8ae4..1b15e80 100644
--- a/shell/ev-toolbar.h
+++ b/shell/ev-toolbar.h
@@ -58,4 +58,7 @@ void ev_toolbar_set_mode (EvToolbar *ev_toolbar,
EvToolbarMode mode);
EvToolbarMode ev_toolbar_get_mode (EvToolbar *ev_toolbar);
+void ev_toolbar_set_sidebar_visible (EvToolbar *ev_toolbar,
+ gboolean visible);
+
G_END_DECLS

View file

@ -0,0 +1,197 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Thu, 15 Apr 2021 12:28:10 +0500
Subject: toolbar: Allow hiding zoom, annotation and page widgets
This will be useful to make it adaptive.
---
shell/ev-toolbar.c | 32 +++++++++++++++----
shell/ev-toolbar.h | 2 ++
shell/evince-toolbar.ui | 84 ++++++++++++++++++++++++++++++-------------------
3 files changed, 79 insertions(+), 39 deletions(-)
diff --git a/shell/ev-toolbar.c b/shell/ev-toolbar.c
index 6c5521f..83ba22a 100644
--- a/shell/ev-toolbar.c
+++ b/shell/ev-toolbar.c
@@ -51,6 +51,8 @@ typedef struct {
GtkWidget *zoom_action;
GtkWidget *find_button;
GtkWidget *action_menu_button;
+ GtkWidget *zoom_revealer;
+ GtkWidget *page_annots_revealer;
EvToolbarMode toolbar_mode;
} EvToolbarPrivate;
@@ -141,6 +143,8 @@ ev_toolbar_class_init (EvToolbarClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, EvToolbar, action_menu_button);
gtk_widget_class_bind_template_child_private (widget_class, EvToolbar, find_button);
gtk_widget_class_bind_template_child_private (widget_class, EvToolbar, zoom_action);
+ gtk_widget_class_bind_template_child_private (widget_class, EvToolbar, page_annots_revealer);
+ gtk_widget_class_bind_template_child_private (widget_class, EvToolbar, zoom_revealer);
gtk_widget_class_bind_template_callback (widget_class, ev_toolbar_find_button_sensitive_changed);
gtk_widget_class_bind_template_callback (widget_class, ev_toolbar_zoom_selector_activated);
@@ -235,19 +239,17 @@ ev_toolbar_set_mode (EvToolbar *ev_toolbar,
case EV_TOOLBAR_MODE_FULLSCREEN:
gtk_widget_show (priv->sidebar_button);
gtk_widget_show (priv->action_menu_button);
- gtk_widget_show (priv->zoom_action);
- gtk_widget_show (priv->page_selector);
+ gtk_widget_show (priv->zoom_revealer);
+ gtk_widget_show (priv->page_annots_revealer);
gtk_widget_show (priv->find_button);
- gtk_widget_show (priv->annots_button);
gtk_widget_hide (priv->open_button);
break;
case EV_TOOLBAR_MODE_RECENT_VIEW:
gtk_widget_hide (priv->sidebar_button);
gtk_widget_hide (priv->action_menu_button);
- gtk_widget_hide (priv->zoom_action);
- gtk_widget_hide (priv->page_selector);
+ gtk_widget_hide (priv->zoom_revealer);
+ gtk_widget_hide (priv->page_annots_revealer);
gtk_widget_hide (priv->find_button);
- gtk_widget_hide (priv->annots_button);
gtk_widget_show (priv->open_button);
break;
}
@@ -278,3 +280,21 @@ ev_toolbar_set_sidebar_visible (EvToolbar *ev_toolbar,
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->sidebar_button), visible);
}
+
+void
+ev_toolbar_set_mobile (EvToolbar *ev_toolbar,
+ gboolean mobile)
+{
+ EvToolbarPrivate *priv;
+
+ g_return_if_fail (EV_IS_TOOLBAR (ev_toolbar));
+
+ priv = GET_PRIVATE (ev_toolbar);
+ mobile = !!mobile;
+
+ gtk_revealer_set_reveal_child (GTK_REVEALER (priv->zoom_revealer), !mobile);
+ gtk_revealer_set_reveal_child (GTK_REVEALER (priv->page_annots_revealer), !mobile);
+
+ if (mobile)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->annots_button), FALSE);
+}
diff --git a/shell/ev-toolbar.h b/shell/ev-toolbar.h
index 1b15e80..1c1f0a2 100644
--- a/shell/ev-toolbar.h
+++ b/shell/ev-toolbar.h
@@ -60,5 +60,7 @@ EvToolbarMode ev_toolbar_get_mode (EvToolbar *ev_toolbar);
void ev_toolbar_set_sidebar_visible (EvToolbar *ev_toolbar,
gboolean visible);
+void ev_toolbar_set_mobile (EvToolbar *ev_toolbar,
+ gboolean mobile);
G_END_DECLS
diff --git a/shell/evince-toolbar.ui b/shell/evince-toolbar.ui
index 4add3ec..f35b961 100644
--- a/shell/evince-toolbar.ui
+++ b/shell/evince-toolbar.ui
@@ -31,38 +31,50 @@
</packing>
</child>
<child>
- <object class="EvPageActionWidget" id="page_selector">
- <property name="tooltip-text" translatable="yes">Select page or search in the outline</property>
- <child internal-child="accessible">
- <object class="AtkObject">
- <property name="AtkObject::accessible-name" translatable="yes">Select page</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack-type">start</property>
- </packing>
- </child>
- <child>
- <object class="GtkToggleButton" id="annots_button">
- <property name="action-name">win.toggle-edit-annots</property>
- <property name="tooltip-text" translatable="yes">Annotate the document</property>
+ <object class="GtkRevealer" id="page_annots_revealer">
+ <property name="reveal-child">True</property>
+ <property name="transition-type">slide-right</property>
<child>
- <object class="GtkImage">
- <property name="icon-name">document-edit-symbolic</property>
- <property name="icon-size">1</property>
- <property name="visible">true</property>
- </object>
- </child>
- <child internal-child="accessible">
- <object class="AtkObject">
- <property name="AtkObject::accessible-name" translatable="yes">Annotate document</property>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="EvPageActionWidget" id="page_selector">
+ <property name="tooltip-text" translatable="yes">Select page or search in the outline</property>
+ <child internal-child="accessible">
+ <object class="AtkObject">
+ <property name="AtkObject::accessible-name" translatable="yes">Select page</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="annots_button">
+ <property name="action-name">win.toggle-edit-annots</property>
+ <property name="tooltip-text" translatable="yes">Annotate the document</property>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">document-edit-symbolic</property>
+ <property name="icon-size">1</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ <child internal-child="accessible">
+ <object class="AtkObject">
+ <property name="AtkObject::accessible-name" translatable="yes">Annotate document</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">start</property>
+ </packing>
+ </child>
</object>
</child>
</object>
- <packing>
- <property name="pack-type">start</property>
- </packing>
</child>
<child>
<object class="GtkMenuButton" id="action_menu_button">
@@ -103,11 +115,17 @@
</packing>
</child>
<child>
- <object class="EvZoomAction" id="zoom_action">
- <signal name="activated" handler="ev_toolbar_zoom_selector_activated"/>
- <child internal-child="accessible">
- <object class="AtkObject">
- <property name="AtkObject::accessible-name" translatable="yes">Set zoom level</property>
+ <object class="GtkRevealer" id="zoom_revealer">
+ <property name="reveal-child">True</property>
+ <property name="transition-type">slide-left</property>
+ <child>
+ <object class="EvZoomAction" id="zoom_action">
+ <signal name="activated" handler="ev_toolbar_zoom_selector_activated"/>
+ <child internal-child="accessible">
+ <object class="AtkObject">
+ <property name="AtkObject::accessible-name" translatable="yes">Set zoom level</property>
+ </object>
+ </child>
</object>
</child>
</object>

View file

@ -0,0 +1,22 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Wed, 11 Dec 2019 14:48:15 +0100
Subject: properties-view: Reduce the label width chars
This allows the window to fit phones.
---
properties/ev-properties-view.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/properties/ev-properties-view.c b/properties/ev-properties-view.c
index 04aa656..972027a 100644
--- a/properties/ev-properties-view.c
+++ b/properties/ev-properties-view.c
@@ -208,7 +208,7 @@ set_property (EvPropertiesView *properties,
g_object_set (G_OBJECT (value_label),
"xalign", 0.0,
- "width_chars", 25,
+ "width_chars", 20,
"selectable", TRUE,
"ellipsize", PANGO_ELLIPSIZE_END,
"hexpand", TRUE,

View file

@ -0,0 +1,467 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Tue, 10 Dec 2019 10:04:30 +0100
Subject: window: Port it to phones
Fixes https://source.puri.sm/Librem5/Apps_Issues/issues/150.
---
shell/ev-window.c | 193 ++++++++++++++++++++++++++++++++----------------------
1 file changed, 113 insertions(+), 80 deletions(-)
diff --git a/shell/ev-window.c b/shell/ev-window.c
index d8970e3..93ce02c 100644
--- a/shell/ev-window.c
+++ b/shell/ev-window.c
@@ -135,8 +135,9 @@ typedef struct {
GtkWidget *main_box;
GtkWidget *toolbar;
- GtkWidget *hpaned;
+ GtkWidget *flap;
GtkWidget *view_box;
+ GtkWidget *sidebar_stack;
GtkWidget *sidebar;
GtkWidget *search_box;
GtkWidget *search_bar;
@@ -264,7 +265,7 @@ typedef struct {
#define GS_LAST_PICTURES_DIRECTORY "pictures-directory"
#define GS_ALLOW_LINKS_CHANGE_ZOOM "allow-links-change-zoom"
-#define SIDEBAR_DEFAULT_SIZE 132
+#define SIDEBAR_DEFAULT_SIZE 246
#define LINKS_SIDEBAR_ID "links"
#define THUMBNAILS_SIDEBAR_ID "thumbnails"
#define ATTACHMENTS_SIDEBAR_ID "attachments"
@@ -294,9 +295,6 @@ static const gchar *document_print_settings[] = {
};
static void ev_window_update_actions_sensitivity (EvWindow *ev_window);
-static void ev_window_sidebar_visibility_changed_cb (EvSidebar *ev_sidebar,
- GParamSpec *pspec,
- EvWindow *ev_window);
static void ev_window_set_page_mode (EvWindow *window,
EvWindowPageMode page_mode);
static void ev_window_load_job_cb (EvJob *job,
@@ -667,7 +665,8 @@ update_chrome_visibility (EvWindow *window)
sidebar = (priv->chrome & EV_CHROME_SIDEBAR) != 0 && priv->document && !presentation;
set_widget_visibility (priv->toolbar, toolbar);
- set_widget_visibility (priv->sidebar, sidebar);
+ set_widget_visibility (priv->sidebar, TRUE);
+ hdy_flap_set_reveal_flap (HDY_FLAP (priv->flap), sidebar);
}
static void
@@ -1280,15 +1279,11 @@ static void
setup_sidebar_from_metadata (EvWindow *window)
{
gchar *page_id;
- gint sidebar_size;
EvWindowPrivate *priv = GET_PRIVATE (window);
if (!priv->metadata)
return;
- if (ev_metadata_get_int (priv->metadata, "sidebar_size", &sidebar_size))
- gtk_paned_set_position (GTK_PANED (priv->hpaned), sidebar_size);
-
if (ev_metadata_get_string (priv->metadata, "sidebar_page", &page_id))
ev_window_sidebar_set_current_page (window, page_id);
}
@@ -1583,10 +1578,6 @@ ev_window_setup_default (EvWindow *ev_window)
g_settings_get_boolean (settings, "show-sidebar"));
update_chrome_visibility (ev_window);
- /* Sidebar */
- gtk_paned_set_position (GTK_PANED (priv->hpaned),
- g_settings_get_int (settings, "sidebar-size"));
-
/* Document model */
ev_document_model_set_continuous (model, g_settings_get_boolean (settings, "continuous"));
ev_document_model_set_dual_page (model, g_settings_get_boolean (settings, "dual-page"));
@@ -1705,7 +1696,7 @@ ev_window_setup_document (EvWindow *ev_window)
if (EV_WINDOW_IS_PRESENTATION (priv))
gtk_widget_grab_focus (priv->presentation_view);
- else if (!gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (priv->search_bar)))
+ else if (!hdy_search_bar_get_search_mode (HDY_SEARCH_BAR (priv->search_bar)))
gtk_widget_grab_focus (priv->view);
return G_SOURCE_REMOVE;
@@ -2023,7 +2014,7 @@ ev_window_reload_job_cb (EvJob *job,
}
/* Restart the search after reloading */
- if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (priv->search_bar)))
+ if (hdy_search_bar_get_search_mode (HDY_SEARCH_BAR (priv->search_bar)))
ev_search_box_restart (EV_SEARCH_BOX (priv->search_box));
ev_window_clear_reload_job (ev_window);
@@ -2536,7 +2527,7 @@ ev_window_open_recent_view (EvWindow *ev_window)
if (priv->recent_view)
return;
- gtk_widget_hide (priv->hpaned);
+ gtk_widget_hide (priv->flap);
priv->recent_view = EV_RECENT_VIEW (ev_recent_view_new ());
g_signal_connect_object (priv->recent_view,
@@ -2565,7 +2556,7 @@ ev_window_destroy_recent_view (EvWindow *ev_window)
gtk_widget_destroy (GTK_WIDGET (priv->recent_view));
priv->recent_view = NULL;
- gtk_widget_show (priv->hpaned);
+ gtk_widget_show (priv->flap);
}
static void
@@ -4099,9 +4090,7 @@ ev_window_save_settings (EvWindow *ev_window)
g_settings_set_double (settings, "zoom", zoom);
}
g_settings_set_boolean (settings, "show-sidebar",
- gtk_widget_get_visible (priv->sidebar));
- g_settings_set_int (settings, "sidebar-size",
- gtk_paned_get_position (GTK_PANED (priv->hpaned)));
+ hdy_flap_get_reveal_flap (HDY_FLAP (priv->flap)));
g_settings_set_string (settings, "sidebar-page",
ev_window_sidebar_get_current_page_id (ev_window));
g_settings_set_boolean (settings, "enable-spellchecking",
@@ -4536,7 +4525,7 @@ ev_window_cmd_edit_find_next (GSimpleAction *action,
if (EV_WINDOW_IS_PRESENTATION (priv))
return;
- search_mode_enabled = gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (priv->search_bar));
+ search_mode_enabled = hdy_search_bar_get_search_mode (HDY_SEARCH_BAR (priv->search_bar));
ev_window_show_find_bar (ev_window, FALSE);
/* Use idle to make sure view allocation happens before find */
@@ -4565,7 +4554,7 @@ ev_window_cmd_edit_find_previous (GSimpleAction *action,
if (EV_WINDOW_IS_PRESENTATION (priv))
return;
- search_mode_enabled = gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (priv->search_bar));
+ search_mode_enabled = hdy_search_bar_get_search_mode (HDY_SEARCH_BAR (priv->search_bar));
ev_window_show_find_bar (ev_window, FALSE);
/* Use idle to make sure view allocation happens before find */
@@ -4586,18 +4575,6 @@ ev_window_cmd_edit_copy (GSimpleAction *action,
ev_view_copy (EV_VIEW (priv->view));
}
-static void
-ev_window_sidebar_position_change_cb (GObject *object,
- GParamSpec *pspec,
- EvWindow *ev_window)
-{
- EvWindowPrivate *priv = GET_PRIVATE (ev_window);
-
- if (priv->metadata && !ev_window_is_empty (ev_window))
- ev_metadata_set_int (priv->metadata, "sidebar_size",
- gtk_paned_get_position (GTK_PANED (object)));
-}
-
static void
ev_window_update_links_model (EvWindow *window)
{
@@ -4805,7 +4782,7 @@ ev_window_run_presentation (EvWindow *window)
priv->presentation_view,
TRUE, TRUE, 0);
- gtk_widget_hide (priv->hpaned);
+ gtk_widget_hide (priv->flap);
update_chrome_visibility (window);
gtk_widget_grab_focus (priv->presentation_view);
@@ -4840,7 +4817,7 @@ ev_window_stop_presentation (EvWindow *window,
priv->presentation_view);
priv->presentation_view = NULL;
- gtk_widget_show (priv->hpaned);
+ gtk_widget_show (priv->flap);
update_chrome_visibility (window);
if (unfullscreen_window)
gtk_window_unfullscreen (GTK_WINDOW (window));
@@ -5208,7 +5185,7 @@ ev_window_cmd_escape (GSimpleAction *action,
ev_view_autoscroll_stop (EV_VIEW (priv->view));
- if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (priv->search_bar)))
+ if (hdy_search_bar_get_search_mode (HDY_SEARCH_BAR (priv->search_bar)))
ev_window_close_find_bar (window);
else if (ev_document_model_get_fullscreen (priv->model))
ev_window_stop_fullscreen (window, TRUE);
@@ -5463,14 +5440,12 @@ ev_window_sidebar_current_page_changed_cb (EvSidebar *ev_sidebar,
}
static void
-ev_window_sidebar_visibility_changed_cb (EvSidebar *ev_sidebar,
- GParamSpec *pspec,
- EvWindow *ev_window)
+flap_reveal_changed_cb (EvWindow *ev_window)
{
EvWindowPrivate *priv = GET_PRIVATE (ev_window);
if (!EV_WINDOW_IS_PRESENTATION (priv)) {
- gboolean visible = gtk_widget_get_visible (GTK_WIDGET (ev_sidebar));
+ gboolean visible = hdy_flap_get_reveal_flap (HDY_FLAP (priv->flap));
g_action_group_change_action_state (G_ACTION_GROUP (ev_window), "show-side-pane",
g_variant_new_boolean (visible));
@@ -5480,6 +5455,10 @@ ev_window_sidebar_visibility_changed_cb (EvSidebar *ev_sidebar,
visible);
if (!visible)
gtk_widget_grab_focus (priv->view);
+
+ update_chrome_flag (ev_window, EV_CHROME_SIDEBAR, visible);
+ update_chrome_visibility (ev_window);
+ ev_toolbar_set_sidebar_visible (EV_TOOLBAR (priv->toolbar), visible);
}
}
@@ -5829,12 +5808,12 @@ search_next_cb (EvSearchBox *search_box,
}
static void
-search_bar_search_mode_enabled_changed (GtkSearchBar *search_bar,
+search_bar_search_mode_enabled_changed (HdySearchBar *search_bar,
GParamSpec *param,
EvWindow *ev_window)
{
EvWindowPrivate *priv = GET_PRIVATE (ev_window);
- gboolean enabled = gtk_search_bar_get_search_mode (search_bar);
+ gboolean enabled = hdy_search_bar_get_search_mode (search_bar);
ev_view_find_set_highlight_search (EV_VIEW (priv->view), enabled);
ev_window_update_actions_sensitivity (ev_window);
@@ -5858,7 +5837,8 @@ ev_window_show_find_bar (EvWindow *ev_window,
{
EvWindowPrivate *priv = GET_PRIVATE (ev_window);
- if (gtk_widget_get_visible (priv->find_sidebar)) {
+ if (gtk_stack_get_visible_child (GTK_STACK (priv->sidebar_stack)) == priv->find_sidebar) {
+ hdy_flap_set_reveal_flap (HDY_FLAP (priv->flap), TRUE);
gtk_widget_grab_focus (priv->search_box);
return;
}
@@ -5874,13 +5854,10 @@ ev_window_show_find_bar (EvWindow *ev_window,
ev_history_freeze (priv->history);
g_object_ref (priv->sidebar);
- gtk_container_remove (GTK_CONTAINER (priv->hpaned), priv->sidebar);
- gtk_paned_pack1 (GTK_PANED (priv->hpaned),
- priv->find_sidebar, FALSE, FALSE);
- gtk_widget_show (priv->find_sidebar);
+ gtk_stack_set_visible_child (GTK_STACK (priv->sidebar_stack), priv->find_sidebar);
- gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (priv->search_bar), TRUE);
+ hdy_search_bar_set_search_mode (HDY_SEARCH_BAR (priv->search_bar), TRUE);
gtk_widget_grab_focus (priv->search_box);
g_action_group_change_action_state (G_ACTION_GROUP (ev_window), "toggle-find", g_variant_new_boolean (TRUE));
@@ -5898,17 +5875,13 @@ ev_window_close_find_bar (EvWindow *ev_window)
{
EvWindowPrivate *priv = GET_PRIVATE (ev_window);
- if (!gtk_widget_get_visible (priv->find_sidebar))
+ if (gtk_stack_get_visible_child (GTK_STACK (priv->sidebar_stack)) != priv->find_sidebar)
return;
g_object_ref (priv->find_sidebar);
- gtk_container_remove (GTK_CONTAINER (priv->hpaned),
- priv->find_sidebar);
- gtk_paned_pack1 (GTK_PANED (priv->hpaned),
- priv->sidebar, FALSE, FALSE);
- gtk_widget_hide (priv->find_sidebar);
+ gtk_stack_set_visible_child (GTK_STACK (priv->sidebar_stack), priv->sidebar);
- gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (priv->search_bar), FALSE);
+ hdy_search_bar_set_search_mode (HDY_SEARCH_BAR (priv->search_bar), FALSE);
gtk_widget_grab_focus (priv->view);
g_action_group_change_action_state (G_ACTION_GROUP (ev_window), "toggle-find", g_variant_new_boolean (FALSE));
@@ -6514,6 +6487,48 @@ window_state_event_cb (EvWindow *window, GdkEventWindowState *event, gpointer du
return FALSE;
}
+static void
+window_size_allocate_cb (EvWindow *window)
+{
+ EvWindowPrivate *priv = GET_PRIVATE (window);
+ gboolean is_maximized, is_fullscreen;
+ gboolean is_narrow, is_mobile_landscape, is_mobile;
+ int width, height;
+ GdkDisplay *display;
+ GdkWindow *surface;
+ GdkMonitor *monitor = NULL;
+ GdkRectangle geometry = {};
+
+ gtk_window_get_size (GTK_WINDOW (window), &width, &height);
+
+ /* Get the monitor to guess whether we are on a mobile or not. If not found,
+ * fallback to the window size.
+ */
+ display = gtk_widget_get_display (GTK_WIDGET (window));
+ surface = gtk_widget_get_window (GTK_WIDGET (window));
+
+ if (display != NULL && surface != NULL)
+ monitor = gdk_display_get_monitor_at_window (display, surface);
+
+ if (monitor != NULL)
+ gdk_monitor_get_geometry (monitor, &geometry);
+ else
+ geometry.height = height;
+
+ is_maximized = gtk_window_is_maximized (GTK_WINDOW (window));
+ is_fullscreen = GDK_IS_WINDOW (surface) && (gdk_window_get_state (surface) & GDK_WINDOW_STATE_FULLSCREEN) > 0;
+
+ is_narrow = width <= 600;
+ is_mobile_landscape = geometry.height <= 400 &&
+ (is_maximized || is_fullscreen);
+
+ is_mobile = is_narrow || is_mobile_landscape;
+
+ hdy_flap_set_fold_policy (HDY_FLAP (priv->flap),
+ is_mobile ? HDY_FLAP_FOLD_POLICY_ALWAYS : HDY_FLAP_FOLD_POLICY_AUTO);
+ ev_toolbar_set_mobile (EV_TOOLBAR (priv->toolbar), is_mobile);
+}
+
static gboolean
window_configure_event_cb (EvWindow *window, GdkEventConfigure *event, gpointer dummy)
{
@@ -7409,7 +7424,9 @@ ev_window_init (EvWindow *ev_window)
GtkBuilder *builder;
GError *error = NULL;
GtkWidget *sidebar_widget;
+ GtkWidget *separator;
GtkWidget *overlay;
+ GtkWidget *clamp;
GObject *mpkeys;
guint page_cache_mb;
gboolean allow_links_change_zoom;
@@ -7425,6 +7442,8 @@ ev_window_init (EvWindow *ev_window)
G_CALLBACK (window_configure_event_cb), NULL);
g_signal_connect (ev_window, "window_state_event",
G_CALLBACK (window_state_event_cb), NULL);
+ g_signal_connect (ev_window, "size-allocate",
+ G_CALLBACK (window_size_allocate_cb), NULL);
priv = GET_PRIVATE (ev_window);
@@ -7512,17 +7531,19 @@ ev_window_init (EvWindow *ev_window)
priv->annots_toolbar, FALSE, TRUE, 0);
/* Search Bar */
- priv->search_bar = gtk_search_bar_new ();
+ priv->search_bar = hdy_search_bar_new ();
+
+ clamp = hdy_clamp_new ();
+ gtk_container_add (GTK_CONTAINER (priv->search_bar), clamp);
+ gtk_widget_show (clamp);
priv->search_box = ev_search_box_new (priv->model);
search_entry = GTK_ENTRY (ev_search_box_get_entry (EV_SEARCH_BOX (priv->search_box)));
- gtk_entry_set_width_chars (search_entry, 32);
- gtk_entry_set_max_length (search_entry, 512);
- gtk_container_add (GTK_CONTAINER (priv->search_bar),
+ gtk_container_add (GTK_CONTAINER (clamp),
priv->search_box);
gtk_widget_show (priv->search_box);
- /* We don't use gtk_search_bar_connect_entry, because it clears the entry when the
+ /* We don't use hdy_search_bar_connect_entry, because it clears the entry when the
* search is closed, but we want to keep the current search.
*/
gtk_box_pack_start (GTK_BOX (priv->main_box),
@@ -7530,22 +7551,26 @@ ev_window_init (EvWindow *ev_window)
gtk_widget_show (priv->search_bar);
/* Add the main area */
- priv->hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
- g_signal_connect (priv->hpaned,
- "notify::position",
- G_CALLBACK (ev_window_sidebar_position_change_cb),
- ev_window);
-
- gtk_paned_set_position (GTK_PANED (priv->hpaned), SIDEBAR_DEFAULT_SIZE);
- gtk_box_pack_start (GTK_BOX (priv->main_box), priv->hpaned,
+ priv->flap = hdy_flap_new ();
+ hdy_flap_set_swipe_to_open (HDY_FLAP (priv->flap), FALSE);
+ hdy_flap_set_locked (HDY_FLAP (priv->flap), TRUE);
+ gtk_box_pack_start (GTK_BOX (priv->main_box), priv->flap,
TRUE, TRUE, 0);
- gtk_widget_show (priv->hpaned);
+ gtk_widget_show (priv->flap);
+
+ priv->sidebar_stack = gtk_stack_new ();
+ hdy_flap_set_flap (HDY_FLAP (priv->flap), priv->sidebar_stack);
+ gtk_widget_set_size_request (priv->sidebar_stack, SIDEBAR_DEFAULT_SIZE, -1);
+ gtk_widget_set_hexpand (priv->sidebar_stack, FALSE);
+ gtk_widget_set_hexpand_set (priv->sidebar_stack, TRUE);
+ gtk_style_context_add_class (gtk_widget_get_style_context (priv->sidebar_stack),
+ "background");
+ gtk_widget_show (priv->sidebar_stack);
priv->sidebar = ev_sidebar_new ();
ev_sidebar_set_model (EV_SIDEBAR (priv->sidebar),
priv->model);
- gtk_paned_pack1 (GTK_PANED (priv->hpaned),
- priv->sidebar, FALSE, FALSE);
+ gtk_container_add (GTK_CONTAINER (priv->sidebar_stack), priv->sidebar);
gtk_widget_show (priv->sidebar);
/* Stub sidebar, for now */
@@ -7628,6 +7653,10 @@ ev_window_init (EvWindow *ev_window)
LAYERS_SIDEBAR_ID, _("Layers"),
LAYERS_SIDEBAR_ICON);
+ separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
+ hdy_flap_set_separator (HDY_FLAP (priv->flap), separator);
+ gtk_widget_show (separator);
+
priv->view_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
overlay = gtk_overlay_new ();
@@ -7647,8 +7676,10 @@ ev_window_init (EvWindow *ev_window)
TRUE, TRUE, 0);
gtk_widget_show (overlay);
- gtk_paned_add2 (GTK_PANED (priv->hpaned),
- priv->view_box);
+ hdy_flap_set_content (HDY_FLAP (priv->flap), priv->view_box);
+ hdy_flap_set_reveal_flap (HDY_FLAP (priv->flap), FALSE);
+ gtk_widget_set_size_request (priv->view_box, 360, -1);
+ gtk_widget_set_hexpand (priv->view_box, TRUE);
gtk_widget_show (priv->view_box);
priv->view = ev_view_new ();
@@ -7734,6 +7765,8 @@ ev_window_init (EvWindow *ev_window)
"result-activated",
G_CALLBACK (find_sidebar_result_activated_cb),
ev_window);
+ gtk_container_add (GTK_CONTAINER (priv->sidebar_stack), priv->find_sidebar);
+ gtk_widget_show (priv->find_sidebar);
/* We own a ref on these widgets, as we can swap them in and out */
g_object_ref (priv->view);
@@ -7785,10 +7818,10 @@ ev_window_init (EvWindow *ev_window)
ev_window);
/* Connect sidebar signals */
- g_signal_connect (priv->sidebar,
- "notify::visible",
- G_CALLBACK (ev_window_sidebar_visibility_changed_cb),
- ev_window);
+ g_signal_connect_swapped (priv->flap,
+ "notify::reveal-flap",
+ G_CALLBACK (flap_reveal_changed_cb),
+ ev_window);
g_signal_connect (priv->sidebar,
"notify::current-page",
G_CALLBACK (ev_window_sidebar_current_page_changed_cb),
@@ -7969,5 +8002,5 @@ ev_window_set_divider_position (EvWindow *ev_window,
priv = GET_PRIVATE (ev_window);
- gtk_paned_set_position (GTK_PANED (priv->hpaned), sidebar_width);
+ gtk_widget_set_size_request (priv->sidebar_stack, sidebar_width, -1);
}

93
evince-mobile/PKGBUILD Normal file
View file

@ -0,0 +1,93 @@
# Maintainer: Danct12 <danct12@disroot.org>
# Contributor: Kevin MacMartin <prurigro@gmail.com>
# Contributor: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
# Contributor: Jan de Groot <jgc@archlinux.org>
_pkgname=evince
pkgname=$_pkgname-mobile
pkgver=46.0
pkgrel=1
pkgdesc="Document viewer (PDF, PostScript, XPS, djvu, dvi, tiff, cbr, cbz, cb7, cbt)"
url="https://wiki.gnome.org/Apps/Evince"
arch=('x86_64' 'armv7h' 'aarch64')
license=('GPL-2.0-or-later')
depends=(
dconf
djvulibre
gnome-desktop
gsettings-desktop-schemas
gsfonts
gspell
gst-plugins-base-libs
gtk3
gvfs
libarchive
libgxps
libhandy
libsecret
libspectre
libsynctex
libxml2
poppler-glib
)
makedepends=(
appstream-glib
gi-docgen
git
gobject-introspection
meson
texlive-bin
yelp-tools
)
optdepends=('texlive-bin: DVI support')
provides=(libev{document,view}3.so $_pkgname)
conflicts=($_pkgname)
_commit=87a7a199c785e9b53279b2ba20134a341786ce3f # tags/46.0^0
source=("git+https://gitlab.gnome.org/GNOME/evince.git#commit=$_commit"
'0001-toolbar-Allow-to-toggle-the-sidebar-button.patch'
'0002-toolbar-Allow-hiding-zoom-annotation-and-page-widgets.patch'
'0003-properties-view-Reduce-the-label-width-chars.patch'
'0004-window-Port-it-to-phones.patch')
sha256sums=('c1fb163ba552999714380c05d9189019f221b6de7b7554fb09d6dfbc74b5638d'
'22a5c037d60cce4869193a294f90c071dab2a47ff97f9632eb22ba0f8377b4a0'
'0153d21c3da3a65c28c246bc31a44b307c1af4e6e56f897b8e8ec15b92974df3'
'b184beef8d11f3d1196869744865b94343b75440f326582e51cb7fb3f4beb176'
'f125e441c0d5cc80599859347903f6b3e1d82cab25b30df508ed0bb6892c8a45')
pkgver() {
cd $_pkgname
git describe --tags | sed 's/[^-]*-g/r&/;s/-/+/g'
}
prepare() {
cd $_pkgname
local src
for src in "${source[@]}"; do
src="${src%%::*}"
src="${src##*/}"
[[ $src = *.patch ]] || continue
echo "Applying patch $src..."
patch -Np1 < "../$src"
done
}
build() {
local meson_options=(
-D ps=enabled
)
arch-meson $_pkgname build "${meson_options[@]}"
meson compile -C build
}
check() {
meson test -C build --print-errorlogs
}
package() {
meson install -C build --destdir "$pkgdir"
# We don't need to provide evince-lib-docs.
rm -r "$pkgdir"/usr/share/doc/lib*
}

41
feedbackd/PKGBUILD Normal file
View file

@ -0,0 +1,41 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=feedbackd
pkgver=0.3.0
pkgrel=1
pkgdesc="A daemon to provide haptic, led and audio feedback triggered by application events"
url="https://source.puri.sm/Librem5/feedbackd"
arch=('x86_64' 'armv7h' 'aarch64')
license=('GPL-3.0-or-later AND LGPL-2.1-or-later')
depends=('gobject-introspection' 'gsound' 'json-glib' 'libgmobile' 'libgudev')
makedepends=('git' 'meson' 'vala')
_fbd_themes_name=feedbackd-device-themes
_fbd_themes_ver=0.1.0
source=(https://source.puri.sm/Librem5/$pkgname/-/archive/v$pkgver/$pkgname-v$pkgver.tar.gz
https://source.puri.sm/Librem5/${_fbd_themes_name}/-/archive/v${_fbd_themes_ver}/${_fbd_themes_name}-v${_fbd_themes_ver}.tar.gz)
build() {
arch-meson $pkgname-v${pkgver} output
ninja -C output
}
check() {
ninja -C output test
}
package() {
DESTDIR="$pkgdir" ninja -C output install
install -Dm644 "$srcdir"/$pkgname-v${pkgver}/debian/feedbackd.udev \
"$pkgdir"/usr/lib/udev/rules.d/90-feedbackd.rules
sed -i 's/libexec/lib/g' "$pkgdir"/usr/lib/udev/rules.d/90-feedbackd.rules
# FIXME: We aren't supposed to abuse video group, but we need to find a
# efficient way to add user to feedbackd group.
sed -i 's/-G feedbackd/-G video/g' "$pkgdir"/usr/lib/udev/rules.d/90-feedbackd.rules
# It would make much more sense to bundle fbd device configuration with the pkg.
find ${srcdir}/${_fbd_themes_name}-v${_fbd_themes_ver}/data -name \*.json \
-exec cp {} ${pkgdir}/usr/share/feedbackd/themes \;
}
md5sums=('9203393ae6e2d9debdd58ec32a827a24'
'bf51ba9cb3dbd19878781bd2544c4b02')

71
gnome-calls/PKGBUILD Normal file
View file

@ -0,0 +1,71 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=gnome-calls
pkgver=46.3
pkgrel=1
pkgdesc="Make and receive PSTN phone calls"
url="https://gitlab.gnome.org/GNOME/calls"
license=('GPL-3.0-or-later')
arch=('x86_64' 'armv7h' 'aarch64')
depends=(
'callaudiod'
'evolution-data-server'
'feedbackd'
'folks'
'gobject-introspection'
'gom'
'gst-plugins-bad'
'gst-plugins-good'
'gtk3'
'libhandy'
'libpeas'
'modemmanager'
'sofia-sip'
'wayland-protocols'
)
makedepends=(
'git'
'glib2-devel'
'meson'
'ninja'
'python-docutils'
'python-packaging'
'vala'
)
checkdepends=('xorg-server-xvfb')
replaces=('calls')
_commit="f8c247148717bbad9414a9b246d88d1e685e68ed" # tags/v46.3
source=("git+https://gitlab.gnome.org/GNOME/calls.git#commit=$_commit")
sha256sums=('4eddd4cbdd10c9f3f611573b05b5ce7275f1dab3f6ae1aeda9e4b2fc2ea2494b')
pkgver() {
cd calls
git describe --tags | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
}
prepare() {
cd calls
git submodule--helper update --init
local src
for src in "${source[@]}"; do
src="${src%%::*}"
src="${src##*/}"
[[ $src = *.patch ]] || continue
echo "Applying patch $src..."
patch -Np1 < "../$src"
done
}
build() {
arch-meson calls output
ninja -C output
}
## SIP test hanging
#check() {
# xvfb-run ninja -C output test
#}
package() {
DESTDIR="$pkgdir" ninja -C output install
}

View file

@ -0,0 +1,26 @@
From 43940ccd1f5976b54fc39b0882512815cdf6a0c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Guido=20G=C3=BCnther?= <agx@sigxcpu.org>
Date: Mon, 24 Feb 2020 13:00:59 +0100
Subject: [PATCH 01/16] timer: Use name that can be added to the event naming
spec
---
src/timer-face.vala | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/timer-face.vala b/src/timer-face.vala
index 5cad12f..8ee6732 100644
--- a/src/timer-face.vala
+++ b/src/timer-face.vala
@@ -71,7 +71,7 @@ public class Face : Gtk.Stack, Clocks.Clock {
save ();
});
- bell = new Utils.Bell ("complete");
+ bell = new Utils.Bell ("timeout-completed");
notification = new GLib.Notification (_("Time is up!"));
notification.set_body (_("Timer countdown finished"));
notification.set_priority (HIGH);
--
2.34.1

View file

@ -0,0 +1,151 @@
From 91f0925ed8ffea4898840cd0c7e9c43c5487d2ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Guido=20G=C3=BCnther?= <agx@sigxcpu.org>
Date: Sat, 22 Feb 2020 18:51:42 +0100
Subject: [PATCH 02/16] Use libfeedback in instead of GSound
This allows to use haptic (and later led) based
feedback on top of audio.
---
meson.build | 2 +-
src/main.vala | 9 ++++++++-
src/meson.build | 3 ++-
src/utils.vala | 47 +++++++++++++++++++++--------------------------
4 files changed, 32 insertions(+), 29 deletions(-)
diff --git a/meson.build b/meson.build
index 032f16d..a5ffc9b 100644
--- a/meson.build
+++ b/meson.build
@@ -14,7 +14,7 @@ glib = dependency('glib-2.0', version: '>= 2.68')
gio = dependency('gio-2.0', version: '>= 2.58')
gobject = dependency('gobject-2.0', version: '>= 2.58')
gtk = dependency('gtk+-3.0', version: '>=3.20')
-gsound = dependency('gsound', version: '>=0.98')
+libfeedback = dependency('libfeedback-0.0', version: '>= 0.0.0')
gweather = dependency('gweather-3.0', version: '>=3.32.0')
gnomedesktop = dependency('gnome-desktop-3.0', version: '>=3.8')
geocodeglib = dependency('geocode-glib-1.0', version: '>=1.0')
diff --git a/src/main.vala b/src/main.vala
index 97d3350..905ef7f 100644
--- a/src/main.vala
+++ b/src/main.vala
@@ -24,6 +24,13 @@ int main (string[] args) {
Environment.set_application_name (_("Clocks"));
+ try {
+ Lfb.init(Config.APP_ID);
+ } catch (GLib.Error e) {
+ warning ("Couldn't init libfeedback: %s", e.message);
+ }
var app = new Clocks.Application ();
- return app.run (args);
+ var ret = app.run (args);
+ Lfb.uninit();
+ return ret;
}
diff --git a/src/meson.build b/src/meson.build
index 4c51188..e5b0edd 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -59,6 +59,7 @@ clocks_c_args = [
'-include', 'config.h',
'-DGWEATHER_I_KNOW_THIS_IS_UNSTABLE',
'-DGNOME_DESKTOP_USE_UNSTABLE_API',
+ '-DLIBFEEDBACK_USE_UNSTABLE_API',
]
clocks_dependencies = [
@@ -66,10 +67,10 @@ clocks_dependencies = [
gio,
gobject,
gtk,
- gsound,
gweather,
gnomedesktop,
geocodeglib,
+ libfeedback,
libgeoclue,
libhandy,
math
diff --git a/src/utils.vala b/src/utils.vala
index d5594e7..1b38fba 100644
--- a/src/utils.vala
+++ b/src/utils.vala
@@ -392,44 +392,31 @@ public class Weekdays {
}
public class Bell : Object {
- private GSound.Context? gsound;
private GLib.Cancellable cancellable;
+ private Lfb.Event event;
private string soundtheme;
- private string sound;
+ private string eventname;
- public Bell (string soundid) {
- try {
- gsound = new GSound.Context ();
- } catch (GLib.Error e) {
- warning ("Sound could not be initialized, error: %s", e.message);
- }
-
- var settings = new GLib.Settings ("org.gnome.desktop.sound");
+ public Bell (string eventid) {
+ var settings = new GLib.Settings("org.gnome.desktop.sound");
soundtheme = settings.get_string ("theme-name");
- sound = soundid;
- cancellable = new GLib.Cancellable ();
+ eventname = eventid;
+ cancellable = new GLib.Cancellable();
}
private async void ring_real (bool repeat) {
- if (gsound == null) {
+ if (!Lfb.is_initted())
return;
- }
-
- if (cancellable.is_cancelled ()) {
- cancellable.reset ();
- }
+ event = new Lfb.Event (eventname);
+ if (repeat)
+ event.timeout = 0;
try {
- do {
- yield ((GSound.Context) gsound).play_full (cancellable,
- GSound.Attribute.EVENT_ID, sound,
- GSound.Attribute.CANBERRA_XDG_THEME_NAME, soundtheme,
- GSound.Attribute.MEDIA_ROLE, "alarm");
- } while (repeat);
+ yield event.trigger_feedback_async (cancellable);
} catch (GLib.IOError.CANCELLED e) {
// ignore
} catch (GLib.Error e) {
- warning ("Error playing sound: %s", e.message);
+ warning ("Error triggering feedback for event %s: %s", eventname, e.message);
}
}
@@ -442,7 +429,15 @@ public class Bell : Object {
}
public void stop () {
- cancellable.cancel ();
+ event.end_feedback_async.begin (cancellable, (obj, res) => {
+ try {
+ event.end_feedback_async.end(res);
+ } catch (GLib.IOError.CANCELLED e) {
+ // ignore
+ } catch (GLib.Error e) {
+ warning ("Error ending feedback for event %s: %s", eventname, e.message);
+ }
+ });
}
}
--
2.34.1

View file

@ -0,0 +1,200 @@
From 9a0a5995f58b07bd2a9aedbe34c712b07f801415 Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Thu, 26 Nov 2020 16:45:49 +0100
Subject: [PATCH 03/16] timers: persist running timers
Persist timer state between app starts by storing the remaining
time and the timestamp of when it was started.
---
src/timer-face.vala | 2 ++
src/timer-item.vala | 69 +++++++++++++++++++++++++++++++++++++--------
src/timer-row.vala | 15 ++++++++--
3 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/src/timer-face.vala b/src/timer-face.vala
index 8ee6732..1e8e650 100644
--- a/src/timer-face.vala
+++ b/src/timer-face.vala
@@ -56,6 +56,8 @@ public class Face : Gtk.Stack, Clocks.Clock {
((Item)timer).ring.connect (() => ring ());
((Item)timer).notify["state"].connect (() => {
this.is_running = this.get_total_active_timers () != 0;
+ /* We need to save state changes */
+ save ();
});
return row;
});
diff --git a/src/timer-item.vala b/src/timer-item.vala
index b226d83..e2a55a5 100644
--- a/src/timer-item.vala
+++ b/src/timer-item.vala
@@ -41,6 +41,7 @@ public class Item : Object, ContentItem {
private int stored_minute;
private int stored_second;
+ private GLib.DateTime? start_time;
public signal void ring ();
public signal void countdown_updated (int hours, int minutes, int seconds);
@@ -52,6 +53,12 @@ public class Item : Object, ContentItem {
public void serialize (GLib.VariantBuilder builder) {
builder.open (new GLib.VariantType ("a{sv}"));
builder.add ("{sv}", "duration", new GLib.Variant.int32 (get_total_seconds ()));
+ if (span > 0) {
+ builder.add ("{sv}", "time_left", new GLib.Variant.int32 ((int32) Math.ceil (span)));
+ }
+ if (start_time != null) {
+ builder.add ("{sv}", "start_time", new GLib.Variant.int64 (((!) start_time).to_unix ()));
+ }
if (name != null) {
builder.add ("{sv}", "name", new GLib.Variant.string ((string) name));
}
@@ -63,10 +70,18 @@ public class Item : Object, ContentItem {
Variant val;
int duration = 0;
string? name = null;
+ int span = 0;
+ GLib.DateTime? start_time = null;
var iter = time_variant.iterator ();
while (iter.next ("{sv}", out key, out val)) {
switch (key) {
+ case "time_left":
+ span = (int32) val;
+ break;
+ case "start_time":
+ start_time = new GLib.DateTime.from_unix_local ((int64) val);
+ break;
case "duration":
duration = (int32) val;
break;
@@ -76,33 +91,63 @@ public class Item : Object, ContentItem {
}
}
- return duration != 0 ? (Item?) new Item.from_seconds (duration, name) : null;
+ return duration != 0 ? (Item?) new Item.from_seconds (duration, name, start_time, (double) span) : null;
}
- public Item.from_seconds (int seconds, string? name) {
-
+ public Item.from_seconds (int seconds,
+ string? name,
+ GLib.DateTime? start_time = null,
+ double time_left = 0) {
int rest = 0;
int h = seconds / 3600;
rest = seconds - h * 3600;
int m = rest / 60;
int s = rest - m * 60;
- this (h, m, s, name);
+ this (h, m, s, name, start_time, time_left);
}
- public Item (int h, int m, int s, string? name) {
+ public Item (int h,
+ int m,
+ int s,
+ string? name,
+ GLib.DateTime? start_time = null,
+ double time_left = 0) {
Object (name: name);
hours = h;
minutes = m;
seconds = s;
- span = get_total_seconds ();
timer = new GLib.Timer ();
- timeout_id = 0;
+ if (start_time != null) {
+ this.start_time = start_time;
+ start ();
+ } else if (time_left > 0) {
+ this.span = time_left;
+ state = State.PAUSED;
+ }
+ }
+
+ public void update_countdown () {
+ int h, m, s;
+ if (state == State.STOPPED) {
+ countdown_updated (hours, minutes, seconds);
+ }else {
+ Utils.time_to_hms (span, out h, out m, out s, null);
+ countdown_updated (h, m, s);
+ }
}
public virtual signal void start () {
+ if (start_time == null) {
+ start_time = new GLib.DateTime.now ();
+ if (span == 0)
+ span = get_total_seconds ();
+ } else {
+ span = get_total_seconds () - new GLib.DateTime.now ().difference ((!) start_time) / TimeSpan.SECOND;
+ }
+
state = State.RUNNING;
timeout_id = GLib.Timeout.add (100, () => {
var e = timer.elapsed ();
@@ -134,16 +179,18 @@ public class Item : Object, ContentItem {
}
public virtual signal void pause () {
- state = State.PAUSED;
+ start_time = null;
span -= timer.elapsed ();
timer.stop ();
+ state = State.PAUSED;
}
public virtual signal void reset () {
- state = State.STOPPED;
- span = get_total_seconds ();
+ start_time = null;
+ span = 0;
timer.reset ();
- timeout_id = 0;
+ state = State.STOPPED;
+ update_countdown ();
}
}
diff --git a/src/timer-row.vala b/src/timer-row.vala
index bec09e7..b5d7302 100644
--- a/src/timer-row.vala
+++ b/src/timer-row.vala
@@ -78,7 +78,18 @@ public class Row : Gtk.ListBoxRow {
item.reset.connect (() => this.reset ());
delete_button.clicked.connect (() => deleted ());
- reset ();
+ item.update_countdown ();
+ switch (item.state) {
+ case STOPPED:
+ reset ();
+ break;
+ case RUNNING:
+ this.start ();
+ break;
+ case PAUSED:
+ this.pause ();
+ break;
+ }
}
[GtkCallback]
@@ -105,8 +116,6 @@ public class Row : Gtk.ListBoxRow {
countdown_label.get_style_context ().remove_class ("timer-running");
start_stack.visible_child_name = "start";
name_stack.visible_child_name = "edit";
-
- update_countdown (item.hours, item.minutes, item.seconds);
}
private void start () {
--
2.34.1

View file

@ -0,0 +1,215 @@
From e06420480258cda94e20b482529c788efab83a2f Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Thu, 12 Nov 2020 13:38:07 +0100
Subject: [PATCH 04/16] alarm-item: Make sure that the time property is always
set
The time property for an AlarmItem isn't nullable therefore it needs to
be set during construction.
---
src/alarm-face.vala | 18 +++++++----
src/alarm-item.vala | 12 ++++----
src/alarm-setup-dialog.vala | 59 +++++++++++--------------------------
3 files changed, 36 insertions(+), 53 deletions(-)
diff --git a/src/alarm-face.vala b/src/alarm-face.vala
index 0fe77cb..cf9a592 100644
--- a/src/alarm-face.vala
+++ b/src/alarm-face.vala
@@ -108,7 +108,7 @@ public class Face : Gtk.Stack, Clocks.Clock {
}
internal void edit (Item alarm) {
- var dialog = new SetupDialog ((Gtk.Window) get_toplevel (), alarm, alarms);
+ var dialog = new SetupDialog ((Gtk.Window) get_toplevel (), alarm, alarms, true);
// Disable alarm while editing it and remember the original active state.
alarm.editing = true;
@@ -116,7 +116,7 @@ public class Face : Gtk.Stack, Clocks.Clock {
dialog.response.connect ((dialog, response) => {
alarm.editing = false;
if (response == Gtk.ResponseType.OK) {
- ((SetupDialog) dialog).apply_to_alarm (alarm);
+ ((SetupDialog) dialog).apply_to_alarm ();
save ();
} else if (response == DELETE_ALARM) {
alarms.delete_item (alarm);
@@ -137,11 +137,19 @@ public class Face : Gtk.Stack, Clocks.Clock {
}
public void activate_new () {
- var dialog = new SetupDialog ((Gtk.Window) get_toplevel (), null, alarms);
+ var wc = Utils.WallClock.get_default ();
+ var alarm = new Item ({ wc.date_time.get_hour (), wc.date_time.get_minute () }, false);
+ var dialog = new SetupDialog ((Gtk.Window) get_toplevel (), alarm, alarms);
+
+ // Disable alarm while editing it and remember the original active state.
+ alarm.editing = true;
+
dialog.response.connect ((dialog, response) => {
+ alarm.editing = false;
+ // Enable the newly created alarm
+ alarm.active = true;
if (response == Gtk.ResponseType.OK) {
- var alarm = new Item ();
- ((SetupDialog) dialog).apply_to_alarm (alarm);
+ ((SetupDialog) dialog).apply_to_alarm ();
alarms.add (alarm);
save ();
}
diff --git a/src/alarm-item.vala b/src/alarm-item.vala
index 6103342..26f655f 100644
--- a/src/alarm-item.vala
+++ b/src/alarm-item.vala
@@ -104,9 +104,12 @@ private class Item : Object, ContentItem {
private Utils.Bell bell;
private GLib.Notification notification;
- public Item (string? id = null) {
+ public Item (AlarmTime time, bool active = true, Utils.Weekdays? days = null, string? id = null) {
var guid = id != null ? (string) id : GLib.DBus.generate_guid ();
- Object (id: guid);
+ Object (id: guid,
+ active: active,
+ time: time,
+ days: days);
}
private void setup_bell () {
@@ -271,11 +274,8 @@ private class Item : Object, ContentItem {
}
if (hour >= 0 && minute >= 0) {
- Item alarm = new Item (id);
+ Item alarm = new Item ({ hour, minute }, active, days, id);
alarm.name = name;
- alarm.active = active;
- alarm.time = { hour, minute };
- alarm.days = days;
alarm.ring_minutes = ring_minutes;
alarm.snooze_minutes = snooze_minutes;
alarm.reset ();
diff --git a/src/alarm-setup-dialog.vala b/src/alarm-setup-dialog.vala
index 97cde1f..d20ec61 100644
--- a/src/alarm-setup-dialog.vala
+++ b/src/alarm-setup-dialog.vala
@@ -75,6 +75,7 @@ private class DurationModel : ListModel, Object {
[GtkTemplate (ui = "/org/gnome/clocks/ui/alarm-setup-dialog.ui")]
private class SetupDialog : Gtk.Dialog {
private Utils.WallClock.Format format;
+ public Item alarm { get; set; }
[GtkChild]
private unowned Gtk.Grid time_grid;
[GtkChild]
@@ -103,20 +104,21 @@ private class SetupDialog : Gtk.Dialog {
typeof (DayPickerRow).ensure ();
}
- public SetupDialog (Gtk.Window parent, Item? alarm, ListModel all_alarms) {
+ public SetupDialog (Gtk.Window parent, Item alarm, ListModel all_alarms, bool edit_alarm = false) {
Object (transient_for: parent,
- title: alarm != null ? _("Edit Alarm") : _("New Alarm"),
+ alarm: alarm,
+ title: edit_alarm ? _("Edit Alarm") : _("New Alarm"),
use_header_bar: 1);
add_button (_("Cancel"), Gtk.ResponseType.CANCEL);
- if (alarm != null) {
+ if (edit_alarm) {
add_button (_("Done"), Gtk.ResponseType.OK);
} else {
add_button (_("Add"), Gtk.ResponseType.OK);
}
set_default_response (Gtk.ResponseType.OK);
- delete_button.visible = alarm != null;
+ delete_button.visible = edit_alarm;
other_alarms = new List<Item> ();
var n = all_alarms.get_n_items ();
@@ -158,39 +160,13 @@ private class SetupDialog : Gtk.Dialog {
am_pm_stack.visible_child = am_pm_button;
}
- set_from_alarm (alarm);
+ set_from_alarm ();
}
// Sets up the dialog to show the values of alarm.
- public void set_from_alarm (Item? alarm) {
- string? name;
- bool active;
- int hour;
- int minute;
- int snooze_minutes;
- int ring_minutes;
- unowned Utils.Weekdays? days;
-
- if (alarm == null) {
- var wc = Utils.WallClock.get_default ();
- // Not great but we can't null it
- name = "";
- hour = wc.date_time.get_hour ();
- minute = wc.date_time.get_minute ();
- days = null;
- active = true;
- ring_minutes = 5;
- snooze_minutes = 10;
- } else {
- name = ((Item) alarm).name;
- hour = ((Item) alarm).time.hour;
- minute = ((Item) alarm).time.minute;
- days = ((Item) alarm).days;
- active = ((Item) alarm).active;
- ring_minutes = ((Item) alarm).ring_minutes;
- snooze_minutes = ((Item) alarm).snooze_minutes;
- }
-
+ public void set_from_alarm () {
+ var hour = alarm.time.hour;
+ var minute = alarm.time.minute;
// Set the time.
if (format == Utils.WallClock.Format.TWELVE) {
if (hour < 12) {
@@ -204,22 +180,22 @@ private class SetupDialog : Gtk.Dialog {
hour = 12;
}
}
- ring_duration.set_selected_index (duration_model.find_by_duration (ring_minutes));
- snooze_duration.set_selected_index (duration_model.find_by_duration (snooze_minutes));
+ ring_duration.set_selected_index (duration_model.find_by_duration (alarm.ring_minutes));
+ snooze_duration.set_selected_index (duration_model.find_by_duration (alarm.snooze_minutes));
h_spinbutton.set_value (hour);
m_spinbutton.set_value (minute);
// Set the name.
- name_entry.set_text ((string) name);
+ name_entry.set_text ((string) alarm.name);
- if (days != null) {
- repeats.load ((Utils.Weekdays) days);
+ if (alarm.days != null) {
+ repeats.load ((Utils.Weekdays) alarm.days);
}
}
// Sets alarm according to the current dialog settings.
- public void apply_to_alarm (Item alarm) {
+ public void apply_to_alarm () {
var name = name_entry.get_text ();
var hour = h_spinbutton.get_value_as_int ();
var minute = m_spinbutton.get_value_as_int ();
@@ -254,8 +230,7 @@ private class SetupDialog : Gtk.Dialog {
}
private void avoid_duplicate_alarm () {
- var alarm = new Item ();
- apply_to_alarm (alarm);
+ apply_to_alarm ();
var duplicate = alarm.check_duplicate_alarm (other_alarms);
this.set_response_sensitive (Gtk.ResponseType.OK, !duplicate);
--
2.34.1

View file

@ -0,0 +1,64 @@
From 329dcc1fdc1b620228457fe1544b62661698a044 Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Mon, 16 Nov 2020 11:36:29 +0100
Subject: [PATCH 05/16] alarm: remove edit property
---
src/alarm-face.vala | 8 --------
src/alarm-item.vala | 5 +++--
2 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/src/alarm-face.vala b/src/alarm-face.vala
index cf9a592..9cf1207 100644
--- a/src/alarm-face.vala
+++ b/src/alarm-face.vala
@@ -110,11 +110,7 @@ public class Face : Gtk.Stack, Clocks.Clock {
internal void edit (Item alarm) {
var dialog = new SetupDialog ((Gtk.Window) get_toplevel (), alarm, alarms, true);
- // Disable alarm while editing it and remember the original active state.
- alarm.editing = true;
-
dialog.response.connect ((dialog, response) => {
- alarm.editing = false;
if (response == Gtk.ResponseType.OK) {
((SetupDialog) dialog).apply_to_alarm ();
save ();
@@ -141,11 +137,7 @@ public class Face : Gtk.Stack, Clocks.Clock {
var alarm = new Item ({ wc.date_time.get_hour (), wc.date_time.get_minute () }, false);
var dialog = new SetupDialog ((Gtk.Window) get_toplevel (), alarm, alarms);
- // Disable alarm while editing it and remember the original active state.
- alarm.editing = true;
-
dialog.response.connect ((dialog, response) => {
- alarm.editing = false;
// Enable the newly created alarm
alarm.active = true;
if (response == Gtk.ResponseType.OK) {
diff --git a/src/alarm-item.vala b/src/alarm-item.vala
index 26f655f..9febf63 100644
--- a/src/alarm-item.vala
+++ b/src/alarm-item.vala
@@ -34,7 +34,8 @@ private class Item : Object, ContentItem {
SNOOZING
}
- public bool editing { get; set; default = false; }
+ // Missed can't be a state because we couldn't scheduale next alarms without override missed
+ public bool missed { get; set; default = false; }
public string id { get; construct set; }
@@ -184,7 +185,7 @@ private class Item : Object, ContentItem {
}
private bool compare_with_item (Item i) {
- return (this.alarm_time.compare (i.alarm_time) == 0 && (this.active || this.editing) && i.active);
+ return (this.time.compare (i.time) == 0);
}
public bool check_duplicate_alarm (List<Item> alarms) {
--
2.34.1

View file

@ -0,0 +1,504 @@
From e8584352c152fc891fa82a0d3fceb1810cc6f4e0 Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Fri, 13 Nov 2020 17:59:06 +0100
Subject: [PATCH 06/16] alarms: Make alarms persisted and add missed alarms
notation
This stores the alarm state as well as the alarm and snooze time
to gsettings. This alllows us to tell the user about missed alarms.
A user could miss alarms for two reasons:
- Clocks wasn't running when the alarm went of.
- The user didn't stop the alarm within "ring-time"
This also adds the baseline for starting Clocks via systemd user .timer
units by making Clocks checks at startup if any alarms need to go off.
As a side effect: closing Clocks doesn't stop an alarm and when Clocks
is reopend within "ring-time" after an alarm or snooze the alarm starts
ringing again.
---
src/alarm-face.vala | 5 +-
src/alarm-item.vala | 218 +++++++++++++++++++++++-------------
src/alarm-setup-dialog.vala | 12 +-
src/application.vala | 5 +-
src/window.vala | 3 +
5 files changed, 156 insertions(+), 87 deletions(-)
diff --git a/src/alarm-face.vala b/src/alarm-face.vala
index 9cf1207..8654e76 100644
--- a/src/alarm-face.vala
+++ b/src/alarm-face.vala
@@ -66,7 +66,7 @@ public class Face : Gtk.Stack, Clocks.Clock {
});
listbox.bind_model (alarms, (item) => {
- item.notify["active"].connect (save);
+ item.notify["state"].connect (save);
return new Row ((Item) item, this);
});
@@ -134,12 +134,13 @@ public class Face : Gtk.Stack, Clocks.Clock {
public void activate_new () {
var wc = Utils.WallClock.get_default ();
- var alarm = new Item ({ wc.date_time.get_hour (), wc.date_time.get_minute () }, false);
+ var alarm = new Item (wc.date_time.get_hour (), wc.date_time.get_minute ());
var dialog = new SetupDialog ((Gtk.Window) get_toplevel (), alarm, alarms);
dialog.response.connect ((dialog, response) => {
// Enable the newly created alarm
alarm.active = true;
+
if (response == Gtk.ResponseType.OK) {
((SetupDialog) dialog).apply_to_alarm ();
alarms.add (alarm);
diff --git a/src/alarm-item.vala b/src/alarm-item.vala
index 9febf63..ab9ca9b 100644
--- a/src/alarm-item.vala
+++ b/src/alarm-item.vala
@@ -20,15 +20,9 @@
namespace Clocks {
namespace Alarm {
-private struct AlarmTime {
- public int hour;
- public int minute;
-}
-
private class Item : Object, ContentItem {
- // FIXME: should we add a "MISSED" state where the alarm stopped
- // ringing but we keep showing the ringing panel?
public enum State {
+ DISABLED,
READY,
RINGING,
SNOOZING
@@ -43,6 +37,12 @@ private class Item : Object, ContentItem {
public int ring_minutes { get; set; default = 5; }
+ public bool recurring {
+ get {
+ return days != null && !((!) days).empty;
+ }
+ }
+
public string? name {
get {
return _name;
@@ -54,21 +54,34 @@ private class Item : Object, ContentItem {
}
}
- public AlarmTime time { get; set; }
-
public Utils.Weekdays? days { get; set; }
- public State state { get; private set; }
+ private State _state = State.DISABLED;
+ public State state {
+ get {
+ return _state;
+ }
+ private set {
+ if (_state == value)
+ return;
+
+ _state = value;
+ notify_property ("active");
+ }
+ }
public string time_label {
owned get {
- return Utils.WallClock.get_default ().format_time (alarm_time);
+ return Utils.WallClock.get_default ().format_time (time);
}
}
public string snooze_time_label {
owned get {
- return Utils.WallClock.get_default ().format_time (snooze_time);
+ if (snooze_time == null)
+ return Utils.WallClock.get_default ().format_time (time.add_minutes (snooze_minutes));
+ else
+ return Utils.WallClock.get_default ().format_time ((!) snooze_time);
}
}
@@ -78,37 +91,43 @@ private class Item : Object, ContentItem {
}
}
+ public GLib.DateTime time { get; set; }
+
[CCode (notify = false)]
public bool active {
get {
- return _active && !this.editing;
+ return this.state > State.DISABLED;
}
-
set {
- if (value != _active) {
- _active = value;
- if (_active) {
- reset ();
- } else if (state == State.RINGING) {
- stop ();
- }
+ if (this.state != State.DISABLED && !value) {
+ stop ();
+ this.state = State.DISABLED;
+ notify_property ("active");
+ } else if (this.state == State.DISABLED && value) {
+ this.missed = false;
+ this.time = get_next_alarm_time (time.get_hour (), time.get_minute (), days);
+ this.state = State.READY;
notify_property ("active");
}
}
}
private string _name;
- private bool _active = true;
- private GLib.DateTime alarm_time;
- private GLib.DateTime snooze_time;
- private GLib.DateTime ring_end_time;
+ private GLib.DateTime? snooze_time;
private Utils.Bell bell;
private GLib.Notification notification;
- public Item (AlarmTime time, bool active = true, Utils.Weekdays? days = null, string? id = null) {
+ public Item (int hour, int minute, Utils.Weekdays? days = null, string? id = null) {
+ var guid = id != null ? (string) id : GLib.DBus.generate_guid ();
+ var time = get_next_alarm_time (hour, minute, days);
+ Object (id: guid,
+ time: time,
+ days: days);
+ }
+
+ public Item.for_specific_time (GLib.DateTime time, Utils.Weekdays? days = null, string? id = null) {
var guid = id != null ? (string) id : GLib.DBus.generate_guid ();
Object (id: guid,
- active: active,
time: time,
days: days);
}
@@ -122,24 +141,39 @@ private class Item : Object, ContentItem {
notification.add_button (_("Snooze"), "app.snooze-alarm::".concat (id));
}
- public void reset () {
- update_alarm_time ();
- update_snooze_time (alarm_time);
- state = State.READY;
+ private void show_missed_notification () {
+ var app = (Clocks.Application) GLib.Application.get_default ();
+ var notification = new GLib.Notification (_("Missed alarm"));
+ string label;
+ if (name != null && ((!) name).length > 0) {
+ // Translators: The first %s is the time and the second %s is the title
+ label = _("%s: %s").printf (time_label, (!) name);
+ } else {
+ // Translators: %s is a time
+ label = _("%s").printf (time_label);
+ }
+
+ notification.set_body (label);
+ app.send_notification ("alarm-clock-missed", notification);
+ }
+
+ public void set_alarm_time (int hour, int minute, Utils.Weekdays? days) {
+ this.days = days;
+ this.time = get_next_alarm_time (hour, minute, days);
}
- private void update_alarm_time () {
+ private static GLib.DateTime get_next_alarm_time (int hour, int minute, Utils.Weekdays? days) {
var wallclock = Utils.WallClock.get_default ();
var now = wallclock.date_time;
var dt = new GLib.DateTime (wallclock.timezone,
now.get_year (),
now.get_month (),
now.get_day_of_month (),
- time.hour,
- time.minute,
+ hour,
+ minute,
0);
- if (days == null || ((Utils.Weekdays) days).empty) {
+ if (days == null || ((!) days).empty) {
// Alarm without days.
if (dt.compare (now) <= 0) {
// Time already passed, ring tomorrow.
@@ -148,16 +182,13 @@ private class Item : Object, ContentItem {
} else {
// Alarm with at least one day set.
// Find the next possible day for ringing
- while (dt.compare (now) <= 0 || ! ((Utils.Weekdays) days).get ((Utils.Weekdays.Day) (dt.get_day_of_week () - 1))) {
+ while (dt.compare (now) <= 0 ||
+ ! ((Utils.Weekdays) days).get ((Utils.Weekdays.Day) (dt.get_day_of_week () - 1))) {
dt = dt.add_days (1);
}
}
- alarm_time = dt;
- }
-
- private void update_snooze_time (GLib.DateTime start_time) {
- snooze_time = start_time.add_minutes (snooze_minutes);
+ return dt;
}
public virtual signal void ring () {
@@ -167,30 +198,43 @@ private class Item : Object, ContentItem {
}
private void start_ringing (GLib.DateTime now) {
- update_snooze_time (now);
- ring_end_time = now.add_minutes (ring_minutes);
state = State.RINGING;
ring ();
}
public void snooze () {
bell.stop ();
+ if (snooze_time == null)
+ snooze_time = time.add_minutes (snooze_minutes);
+ else
+ snooze_time = ((!) snooze_time).add_minutes (snooze_minutes);
+
state = State.SNOOZING;
}
public void stop () {
bell.stop ();
- update_snooze_time (alarm_time);
- state = State.READY;
+ snooze_time = null;
+
+ // scheduale the next alarm if recurring
+ if (recurring) {
+ time = get_next_alarm_time (time.get_hour (), time.get_minute (), days);
+ state = State.READY;
+ GLib.Timeout.add_seconds (120, () => {
+ missed = false;
+ return GLib.Source.REMOVE;
+ });
+ } else {
+ state = State.DISABLED;
+ }
}
private bool compare_with_item (Item i) {
- return (this.time.compare (i.time) == 0);
+ return (this.time.get_hour () == i.time.get_hour () &&
+ this.time.get_minute () == i.time.get_minute ());
}
public bool check_duplicate_alarm (List<Item> alarms) {
- update_alarm_time ();
-
foreach (var item in alarms) {
if (this.compare_with_item (item)) {
return true;
@@ -199,11 +243,21 @@ private class Item : Object, ContentItem {
return false;
}
+ private void start_ringing_or_missed (GLib.DateTime now, GLib.DateTime ring_end_time) {
+ if (now.compare (ring_end_time) > 0 ) {
+ missed = true;
+ show_missed_notification ();
+ stop ();
+ } else {
+ start_ringing (now);
+ }
+ }
+
// Update the state and ringing time. Ring or stop
// depending on the current time.
// Returns true if the state changed, false otherwise.
public bool tick () {
- if (!active) {
+ if (state == State.DISABLED) {
return false;
}
@@ -212,17 +266,28 @@ private class Item : Object, ContentItem {
var wallclock = Utils.WallClock.get_default ();
var now = wallclock.date_time;
- if (state == State.RINGING && now.compare (ring_end_time) > 0) {
- stop ();
- }
-
- if (state == State.SNOOZING && now.compare (snooze_time) > 0) {
- start_ringing (now);
- }
-
- if (state == State.READY && now.compare (alarm_time) > 0) {
- start_ringing (now);
- update_alarm_time (); // reschedule for the next repeat
+ GLib.DateTime ring_end_time;
+ if (snooze_time != null)
+ ring_end_time = ((!) snooze_time).add_minutes (ring_minutes);
+ else
+ ring_end_time = time.add_minutes (ring_minutes);
+
+ switch (state) {
+ case State.DISABLED:
+ break;
+ case State.RINGING:
+ // make sure the state changes
+ last_state = State.READY;
+ start_ringing_or_missed (now, ring_end_time);
+ break;
+ case State.SNOOZING:
+ if (snooze_time != null && now.compare ((!) snooze_time) > 0)
+ start_ringing_or_missed (now, ring_end_time);
+ break;
+ case State.READY:
+ if (now.compare (time) > 0)
+ start_ringing_or_missed (now, ring_end_time);
+ break;
}
return state != last_state;
@@ -232,9 +297,10 @@ private class Item : Object, ContentItem {
builder.open (new GLib.VariantType ("a{sv}"));
builder.add ("{sv}", "name", new GLib.Variant.string ((string) name));
builder.add ("{sv}", "id", new GLib.Variant.string (id));
- builder.add ("{sv}", "active", new GLib.Variant.boolean (active));
- builder.add ("{sv}", "hour", new GLib.Variant.int32 (time.hour));
- builder.add ("{sv}", "minute", new GLib.Variant.int32 (time.minute));
+ builder.add ("{sv}", "state", new GLib.Variant.int32 (state));
+ builder.add ("{sv}", "time", new GLib.Variant.int64 (time.to_unix ()));
+ if (snooze_time != null)
+ builder.add ("{sv}", "snooze_time", new GLib.Variant.int64 (((!) snooze_time).to_unix ()));
builder.add ("{sv}", "days", ((Utils.Weekdays) days).serialize ());
builder.add ("{sv}", "snooze_minutes", new GLib.Variant.int32 (snooze_minutes));
builder.add ("{sv}", "ring_minutes", new GLib.Variant.int32 (ring_minutes));
@@ -246,9 +312,9 @@ private class Item : Object, ContentItem {
Variant val;
string? name = null;
string? id = null;
- bool active = true;
- int hour = -1;
- int minute = -1;
+ State state = State.DISABLED;
+ GLib.DateTime? time = null;
+ GLib.DateTime? snooze_time = null;
int snooze_minutes = 10;
int ring_minutes = 5;
Utils.Weekdays? days = null;
@@ -259,12 +325,12 @@ private class Item : Object, ContentItem {
name = (string) val;
} else if (key == "id") {
id = (string) val;
- } else if (key == "active") {
- active = (bool) val;
- } else if (key == "hour") {
- hour = (int32) val;
- } else if (key == "minute") {
- minute = (int32) val;
+ } else if (key == "state") {
+ state = (State) val;
+ } else if (key == "time") {
+ time = new GLib.DateTime.from_unix_local ((int64) val);
+ } else if (key == "snooze_time") {
+ snooze_time = new GLib.DateTime.from_unix_local ((int64) val);
} else if (key == "days") {
days = Utils.Weekdays.deserialize (val);
} else if (key == "snooze_minutes") {
@@ -274,12 +340,14 @@ private class Item : Object, ContentItem {
}
}
- if (hour >= 0 && minute >= 0) {
- Item alarm = new Item ({ hour, minute }, active, days, id);
+ if (time != null) {
+ Item alarm = new Item.for_specific_time ((!) time, days, id);
+ alarm.state = state;
alarm.name = name;
+ if (snooze_time != null)
+ alarm.snooze_time = (!) snooze_time;
alarm.ring_minutes = ring_minutes;
alarm.snooze_minutes = snooze_minutes;
- alarm.reset ();
return alarm;
} else {
warning ("Invalid alarm %s", name != null ? (string) name : "[unnamed]");
diff --git a/src/alarm-setup-dialog.vala b/src/alarm-setup-dialog.vala
index d20ec61..2d826d0 100644
--- a/src/alarm-setup-dialog.vala
+++ b/src/alarm-setup-dialog.vala
@@ -165,8 +165,8 @@ private class SetupDialog : Gtk.Dialog {
// Sets up the dialog to show the values of alarm.
public void set_from_alarm () {
- var hour = alarm.time.hour;
- var minute = alarm.time.minute;
+ var hour = alarm.time.get_hour ();
+ var minute = alarm.time.get_minute ();
// Set the time.
if (format == Utils.WallClock.Format.TWELVE) {
if (hour < 12) {
@@ -211,21 +211,15 @@ private class SetupDialog : Gtk.Dialog {
}
}
- AlarmTime time = { hour, minute };
-
var days = repeats.store ();
alarm.freeze_notify ();
alarm.name = name;
- alarm.time = time;
- alarm.days = days;
+ alarm.set_alarm_time (hour, minute, days);
alarm.snooze_minutes = snooze_item.minutes;
alarm.ring_minutes = ring_item.minutes;
- // Force update of alarm_time before notifying the changes
- alarm.reset ();
-
alarm.thaw_notify ();
}
diff --git a/src/application.vala b/src/application.vala
index 2e67046..92aba34 100644
--- a/src/application.vala
+++ b/src/application.vala
@@ -170,7 +170,10 @@ public class Application : Gtk.Application {
public new void send_notification (string notification_id, GLib.Notification notification) {
base.send_notification (notification_id, notification);
- system_notifications.append (notification_id);
+ // We don't want to withdraw missed notifications
+ if (notification_id != "alarm-clock-missed") {
+ system_notifications.append (notification_id);
+ }
}
private void withdraw_notifications () {
diff --git a/src/window.vala b/src/window.vala
index 55c7f2e..5c35967 100644
--- a/src/window.vala
+++ b/src/window.vala
@@ -158,6 +158,9 @@ public class Window : Hdy.ApplicationWindow {
if (Config.PROFILE == "Devel") {
style.add_class ("devel");
}
+
+ // Immidiatly check if we need to notifiy the user about alarms
+ Utils.WallClock.get_default ().tick ();
}
[Signal (action = true)]
--
2.34.1

View file

@ -0,0 +1,36 @@
From b5b5ad980f72d2b7622d311f31fda5695f49ed8e Mon Sep 17 00:00:00 2001
From: Steve Stevens <steve@heunox.com>
Date: Sun, 9 Jan 2022 12:06:47 -0700
Subject: [PATCH 07/16] Fixed infinite alarming
This issue is caused by the start_ringing() function being called every time
the tick() function is called. Thus causing multiple rings to start happening
if an alarm isn't stopped soon enough all from the same alarm.
Origin: https://gitlab.gnome.org/GNOME/gnome-clocks/-/merge_requests/185
Dependancy: alarms-Make-alarms-persisted-and-add-missed-alarms-n.patch
Applied-Upstream: False
---
src/alarm-item.vala | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/alarm-item.vala b/src/alarm-item.vala
index ab9ca9b..6dcb73d 100644
--- a/src/alarm-item.vala
+++ b/src/alarm-item.vala
@@ -198,8 +198,10 @@ private class Item : Object, ContentItem {
}
private void start_ringing (GLib.DateTime now) {
- state = State.RINGING;
- ring ();
+ if ( state != State.RINGING ) {
+ state = State.RINGING;
+ ring ();
+ }
}
public void snooze () {
--
2.34.1

View file

@ -0,0 +1,50 @@
From bd2fce71df6d3eab84486a445f38e5ed38828f79 Mon Sep 17 00:00:00 2001
From: Steve Stevens <steve@heunox.com>
Date: Sun, 9 Jan 2022 12:07:43 -0700
Subject: [PATCH 08/16] Alarms: Fix wiping edit data
The notifies called when setting up the alarm-setup-dialog would cause
the alarm item to be nulled out when attempting to update the alarm with
the data. Thus this patch suspends those notify actions until the
initial setup of the dialog is complete.
Dependancy: alarms-Make-alarms-persisted-and-add-missed-alarms-n.patch
Applied-Upstream: False
---
src/alarm-setup-dialog.vala | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/alarm-setup-dialog.vala b/src/alarm-setup-dialog.vala
index 2d826d0..85c9d06 100644
--- a/src/alarm-setup-dialog.vala
+++ b/src/alarm-setup-dialog.vala
@@ -99,6 +99,7 @@ private class SetupDialog : Gtk.Dialog {
private unowned Gtk.Button delete_button;
private List<Item> other_alarms;
private DurationModel duration_model;
+ private bool lock_notify = true;
static construct {
typeof (DayPickerRow).ensure ();
@@ -192,6 +193,8 @@ private class SetupDialog : Gtk.Dialog {
if (alarm.days != null) {
repeats.load ((Utils.Weekdays) alarm.days);
}
+ lock_notify = false;
+ avoid_duplicate_alarm ();
}
// Sets alarm according to the current dialog settings.
@@ -224,6 +227,9 @@ private class SetupDialog : Gtk.Dialog {
}
private void avoid_duplicate_alarm () {
+ if (lock_notify) {
+ return;
+ }
apply_to_alarm ();
var duplicate = alarm.check_duplicate_alarm (other_alarms);
--
2.34.1

View file

@ -0,0 +1,44 @@
From 7f0a060e316ceb9e123ec71d74c7a7502d5dfc1b Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Wed, 2 Dec 2020 16:57:31 +0100
Subject: [PATCH 09/16] Don't show numpad when setting a new alarm/timer
Fixes https://source.puri.sm/Librem5/gnome-clocks/-/issues/26
---
src/alarm-setup-dialog.vala | 4 ++++
src/timer-setup.vala | 4 ++++
2 files changed, 8 insertions(+)
diff --git a/src/alarm-setup-dialog.vala b/src/alarm-setup-dialog.vala
index 85c9d06..5831cf3 100644
--- a/src/alarm-setup-dialog.vala
+++ b/src/alarm-setup-dialog.vala
@@ -160,6 +160,10 @@ private class SetupDialog : Gtk.Dialog {
am_pm_stack.add (am_pm_button);
am_pm_stack.visible_child = am_pm_button;
}
+ /* Workaround: To keep the osk closed
+ * https://gitlab.gnome.org/GNOME/gtk/merge_requests/978#note_546576 */
+ h_spinbutton.set ("im-module", "gtk-im-context-none", null);
+ m_spinbutton.set ("im-module", "gtk-im-context-none", null);
set_from_alarm ();
}
diff --git a/src/timer-setup.vala b/src/timer-setup.vala
index 69129f9..4f460ce 100644
--- a/src/timer-setup.vala
+++ b/src/timer-setup.vala
@@ -49,6 +49,10 @@ public class Setup : Gtk.Box {
insert_action_group ("timer-setup", actions);
time_grid.set_direction (Gtk.TextDirection.LTR);
+
+ h_spinbutton.set ("im-module", "gtk-im-context-none", null);
+ m_spinbutton.set ("im-module", "gtk-im-context-none", null);
+ s_spinbutton.set ("im-module", "gtk-im-context-none", null);
}
private int get_duration () {
--
2.34.1

View file

@ -0,0 +1,63 @@
From d09089c22fa81abac887006e1942674bcad736a9 Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Thu, 3 Dec 2020 22:54:42 +0100
Subject: [PATCH 10/16] add option to start hidden
---
src/application.vala | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/application.vala b/src/application.vala
index 92aba34..4bc24c6 100644
--- a/src/application.vala
+++ b/src/application.vala
@@ -21,6 +21,7 @@ namespace Clocks {
public class Application : Gtk.Application {
const OptionEntry[] OPTION_ENTRIES = {
{ "version", 'v', 0, OptionArg.NONE, null, N_("Print version information and exit"), null },
+ { "hidden", 0, 0, OptionArg.NONE, null, N_("Start without showing a window"), null },
{ (string) null }
};
@@ -36,6 +37,7 @@ public class Application : Gtk.Application {
private World.ShellWorldClocks world_clocks;
private uint world_clocks_id = 0;
private Window? window;
+ private bool start_hidden = false;
private List<string> system_notifications;
private Window ensure_window () ensures (window != null) {
@@ -96,7 +98,11 @@ public class Application : Gtk.Application {
base.activate ();
var win = ensure_window ();
- win.present ();
+ if (!start_hidden) {
+ win.present ();
+ } else {
+ start_hidden = false;
+ }
win.focus_in_event.connect (() => {
withdraw_notifications ();
@@ -142,6 +148,9 @@ public class Application : Gtk.Application {
print ("%s %s\n", (string) Environment.get_application_name (), Config.VERSION);
return 0;
}
+ if (options.contains("hidden")) {
+ start_hidden = true;
+ }
return -1;
}
@@ -155,6 +164,7 @@ public class Application : Gtk.Application {
win.show_world ();
win.present ();
+
var world = GWeather.Location.get_world ();
if (world != null) {
// The result is actually nullable
--
2.34.1

View file

@ -0,0 +1,61 @@
From eef891c43eac9bade177f575ca78d867df31dc5c Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Fri, 27 Nov 2020 18:47:34 +0100
Subject: [PATCH 11/16] autostart gnome-clocks
---
data/meson.build | 10 +++++++++-
data/org.gnome.clocks-daemon.desktop.in | 16 ++++++++++++++++
2 files changed, 25 insertions(+), 1 deletion(-)
create mode 100644 data/org.gnome.clocks-daemon.desktop.in
diff --git a/data/meson.build b/data/meson.build
index c0817fd..497b3be 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -46,6 +46,15 @@ if desktop_file_validate.found()
endif
+desktop_daemon_file = i18n.merge_file(
+ input : 'org.gnome.clocks-daemon.desktop.in',
+ output : '@0@-daemon.desktop'.format(app_id),
+ type : 'desktop',
+ po_dir : '../po',
+ install : true,
+ install_dir : join_paths(get_option('sysconfdir'), 'xdg/autostart')
+)
+
dbusconf = configuration_data()
dbusconf.set('bindir', join_paths(get_option('prefix'), get_option('bindir')))
dbusconf.set('name', app_id)
@@ -113,4 +122,3 @@ if glib_compile_schemas.found()
]
)
endif
-
diff --git a/data/org.gnome.clocks-daemon.desktop.in b/data/org.gnome.clocks-daemon.desktop.in
new file mode 100644
index 0000000..49187ca
--- /dev/null
+++ b/data/org.gnome.clocks-daemon.desktop.in
@@ -0,0 +1,16 @@
+[Desktop Entry]
+Name=Clocks
+GenericName=Clocks
+X-GNOME-FullName=GNOME Clocks
+Comment=Clocks for world times, plus alarms, stopwatch and a timer
+# Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
+Keywords=time;timer;alarm;world clock;stopwatch;time zone;
+Exec=gnome-clocks --hidden
+# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
+Icon=@icon@
+Terminal=false
+Type=Application
+Categories=GNOME;GTK;Utility;Clock;
+StartupNotify=false
+NoDisplay=true
+X-GNOME-AutoRestart=true
--
2.34.1

View file

@ -0,0 +1,359 @@
From b7f9d6e3df2d8291194b5b5eacff1386b1b50dea Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Mon, 14 Dec 2020 17:56:13 +0100
Subject: [PATCH 12/16] alarm-setup-dialog: Allow much smaller heights useing a
ScrolledWindow
---
data/ui/alarm-setup-dialog.ui | 298 ++++++++++++++++++----------------
1 file changed, 154 insertions(+), 144 deletions(-)
diff --git a/data/ui/alarm-setup-dialog.ui b/data/ui/alarm-setup-dialog.ui
index f332c4a..2429ce5 100644
--- a/data/ui/alarm-setup-dialog.ui
+++ b/data/ui/alarm-setup-dialog.ui
@@ -17,187 +17,197 @@
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="destroy_with_parent">True</property>
- <property name="default-height">350</property>
- <property name="height-request">350</property>
<property name="type_hint">dialog</property>
<property name="gravity">center</property>
<property name="title" translatable="yes">New Alarm</property>
<child internal-child="vbox">
<object class="GtkBox">
<property name="visible">True</property>
+ <property name="border-width">0</property>
<child>
- <object class="HdyClamp">
+ <object class="GtkScrolledWindow">
<property name="visible">True</property>
- <property name="maximum-size">450</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="propagate-natural-height">True</property>
+ <property name="propagate-natural-width">True</property>
<child>
- <object class="GtkBox">
+ <object class="HdyClamp">
<property name="visible">True</property>
- <property name="spacing">12</property>
- <property name="orientation">vertical</property>
+ <property name="maximum-size">450</property>
<child>
- <object class="GtkGrid" id="time_grid">
+ <object class="GtkBox">
<property name="visible">True</property>
- <property name="halign">center</property>
- <property name="margin_top">12</property>
- <property name="column_spacing">6</property>
+ <property name="orientation">vertical</property>
+ <property name="margin">12</property>
<child>
- <object class="GtkLabel" id="dummy_label1">
+ <object class="GtkGrid" id="time_grid">
<property name="visible">True</property>
- <property name="margin_start">6</property>
- <property name="margin_end">6</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label2">
- <property name="visible">True</property>
- <property name="label"></property>
- </object>
- <packing>
- <property name="left_attach">2</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkSpinButton" id="m_spinbutton">
- <property name="visible">True</property>
- <property name="max_length">2</property>
- <property name="activates_default">False</property>
- <property name="text">0</property>
- <property name="xalign">0.5</property>
- <property name="input_purpose">number</property>
- <property name="orientation">vertical</property>
- <property name="adjustment">m_adjustment</property>
- <property name="numeric">True</property>
- <property name="wrap">True</property>
- <property name="width-request">60</property>
- <signal name="changed" handler="spinbuttons_changed" object="ClocksAlarmSetupDialog" swapped="no"/>
- <signal name="output" handler="show_leading_zeros" object="ClocksAlarmSetupDialog" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">3</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkStack" id="am_pm_stack">
- <property name="visible">True</property>
- <property name="margin_start">6</property>
- <property name="margin_end">6</property>
+ <property name="halign">center</property>
+ <property name="column_spacing">6</property>
<child>
- <object class="GtkLabel" id="dummy_label2">
+ <object class="GtkLabel" id="dummy_label1">
<property name="visible">True</property>
- <property name="can_focus">False</property>
+ <property name="margin_start">6</property>
+ <property name="margin_end">6</property>
</object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label"></property>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="m_spinbutton">
+ <property name="visible">True</property>
+ <property name="max_length">2</property>
+ <property name="activates_default">False</property>
+ <property name="text">0</property>
+ <property name="xalign">0.5</property>
+ <property name="input_purpose">number</property>
+ <property name="orientation">vertical</property>
+ <property name="adjustment">m_adjustment</property>
+ <property name="numeric">True</property>
+ <property name="wrap">True</property>
+ <property name="width-request">60</property>
+ <signal name="changed" handler="spinbuttons_changed" object="ClocksAlarmSetupDialog" swapped="no"/>
+ <signal name="output" handler="show_leading_zeros" object="ClocksAlarmSetupDialog" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">0</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="left_attach">4</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkSpinButton" id="h_spinbutton">
- <property name="visible">True</property>
- <property name="max_length">2</property>
- <property name="activates_default">False</property>
- <property name="text">0</property>
- <property name="xalign">0.5</property>
- <property name="input_purpose">number</property>
- <property name="orientation">vertical</property>
- <property name="adjustment">h_adjustment</property>
- <property name="numeric">True</property>
- <property name="wrap">True</property>
- <property name="width-request">60</property>
- <signal name="changed" handler="spinbuttons_changed" object="ClocksAlarmSetupDialog" swapped="no"/>
- <signal name="output" handler="show_leading_zeros" object="ClocksAlarmSetupDialog" swapped="no"/>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <style>
- <class name="clocks-alarm-setup-time"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkListBox" id="listbox">
- <property name="visible">True</property>
- <property name="selection_mode">none</property>
- <child>
- <object class="ClocksAlarmDayPickerRow" id="repeats">
- <property name="visible">True</property>
- <signal name="days_changed" handler="days_changed" swapped="no" />
- </object>
- </child>
- <child>
- <object class="HdyActionRow">
- <property name="visible">True</property>
- <property name="activatable">False</property>
- <property name="selectable">False</property>
- <property name="title" translatable="yes">Name</property>
- <property name="subtitle" translatable="yes">Optional</property>
<child>
- <object class="GtkEntry" id="name_entry">
+ <object class="GtkStack" id="am_pm_stack">
<property name="visible">True</property>
- <property name="valign">center</property>
- <property name="hexpand">True</property>
- <property name="activates_default">True</property>
- <signal name="changed" handler="entry_changed" object="ClocksAlarmSetupDialog" swapped="no"/>
+ <property name="margin_start">6</property>
+ <property name="margin_end">6</property>
+ <child>
+ <object class="GtkLabel" id="dummy_label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="top_attach">0</property>
+ </packing>
</child>
+ <child>
+ <object class="GtkSpinButton" id="h_spinbutton">
+ <property name="visible">True</property>
+ <property name="max_length">2</property>
+ <property name="activates_default">False</property>
+ <property name="text">0</property>
+ <property name="xalign">0.5</property>
+ <property name="input_purpose">number</property>
+ <property name="orientation">vertical</property>
+ <property name="adjustment">h_adjustment</property>
+ <property name="numeric">True</property>
+ <property name="wrap">True</property>
+ <property name="width-request">60</property>
+ <signal name="changed" handler="spinbuttons_changed" object="ClocksAlarmSetupDialog" swapped="no"/>
+ <signal name="output" handler="show_leading_zeros" object="ClocksAlarmSetupDialog" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <style>
+ <class name="clocks-alarm-setup-time"/>
+ </style>
</object>
</child>
<child>
- <object class="HdyComboRow" id="ring_duration">
+ <object class="GtkListBox" id="listbox">
<property name="visible">True</property>
- <property name="activatable">False</property>
- <property name="selectable">False</property>
- <property name="title" translatable="yes">Ring Duration</property>
+ <property name="selection_mode">none</property>
+ <property name="margin_top">12</property>
+ <child>
+ <object class="ClocksAlarmDayPickerRow" id="repeats">
+ <property name="visible">True</property>
+ <signal name="days_changed" handler="days_changed" swapped="no" />
+ </object>
+ </child>
+ <child>
+ <object class="HdyActionRow">
+ <property name="visible">True</property>
+ <property name="activatable">False</property>
+ <property name="selectable">False</property>
+ <property name="title" translatable="yes">Name</property>
+ <property name="subtitle" translatable="yes">Optional</property>
+ <child>
+ <object class="GtkEntry" id="name_entry">
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="activates_default">True</property>
+ <signal name="changed" handler="entry_changed" object="ClocksAlarmSetupDialog" swapped="no"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="HdyComboRow" id="ring_duration">
+ <property name="visible">True</property>
+ <property name="activatable">False</property>
+ <property name="selectable">False</property>
+ <property name="title" translatable="yes">Ring Duration</property>
+ </object>
+ </child>
+ <child>
+ <object class="HdyComboRow" id="snooze_duration">
+ <property name="visible">True</property>
+ <property name="activatable">False</property>
+ <property name="selectable">False</property>
+ <property name="title" translatable="yes">Snooze Duration</property>
+ </object>
+ </child>
+ <style>
+ <class name="content"/>
+ </style>
</object>
</child>
<child>
- <object class="HdyComboRow" id="snooze_duration">
+ <object class="GtkButton" id="delete_button">
<property name="visible">True</property>
- <property name="activatable">False</property>
- <property name="selectable">False</property>
- <property name="title" translatable="yes">Snooze Duration</property>
+ <property name="label" translatable="yes">R_emove Alarm</property>
+ <property name="use-underline">True</property>
+ <property name="margin_top">12</property>
+ <property name="halign">start</property>
+ <signal name="clicked" handler="delete" swapped="no" />
+ <style>
+ <class name="destructive-action"/>
+ </style>
</object>
</child>
- <style>
- <class name="content"/>
- <class name="clocks-list"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="delete_button">
- <property name="visible">True</property>
- <property name="label" translatable="yes">R_emove Alarm</property>
- <property name="use-underline">True</property>
- <property name="margin">6</property>
- <property name="halign">start</property>
- <signal name="clicked" handler="delete" swapped="no" />
- <style>
- <class name="destructive-action"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkRevealer" id="label_revealer">
- <property name="visible">True</property>
<child>
- <object class="GtkLabel" id="warn_label">
+ <object class="GtkRevealer" id="label_revealer">
<property name="visible">True</property>
- <property name="label" translatable="yes">You already have an alarm for this time.</property>
+ <child>
+ <object class="GtkLabel" id="warn_label">
+ <property name="margin_top">12</property>
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">You already have an alarm for this time.</property>
+ </object>
+ </child>
</object>
</child>
</object>
+
</child>
</object>
</child>
--
2.34.1

View file

@ -0,0 +1,52 @@
From 8828ebc1ddb39ae0730367b38344adc601692946 Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Mon, 14 Dec 2020 18:14:59 +0100
Subject: [PATCH 13/16] timer-setup: remove unused lables
---
data/ui/timer-setup.ui | 22 ----------------------
1 file changed, 22 deletions(-)
diff --git a/data/ui/timer-setup.ui b/data/ui/timer-setup.ui
index 8a2f3b1..588aedb 100644
--- a/data/ui/timer-setup.ui
+++ b/data/ui/timer-setup.ui
@@ -206,17 +206,6 @@
<property name="halign">center</property>
<property name="valign">center</property>
<property name="column_spacing">10</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
<child>
<object class="GtkSpinButton" id="h_spinbutton">
<property name="visible">True</property>
@@ -325,17 +314,6 @@
<property name="top_attach">0</property>
</packing>
</child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- </object>
- <packing>
- <property name="left_attach">6</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
</object>
<packing>
<property name="expand">True</property>
--
2.34.1

View file

@ -0,0 +1,163 @@
From 239add0b868bb338a0eb9998fa2e5d9b23550a99 Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Mon, 14 Dec 2020 18:34:46 +0100
Subject: [PATCH 14/16] timer: Allow much smaller heights useing a
ScrolledWindow
---
data/ui/timer-face.ui | 81 +++++++++++++++++++++----------------
data/ui/timer-setup.ui | 1 -
src/timer-setup-dialog.vala | 13 +++++-
3 files changed, 57 insertions(+), 38 deletions(-)
diff --git a/data/ui/timer-face.ui b/data/ui/timer-face.ui
index 123a8c5..87331ec 100644
--- a/data/ui/timer-face.ui
+++ b/data/ui/timer-face.ui
@@ -7,55 +7,66 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
- <object class="GtkBox" id="no_timer_container">
+ <object class="GtkScrolledWindow">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="orientation">vertical</property>
- <property name="spacing">18</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="propagate-natural-height">True</property>
+ <property name="propagate-natural-width">True</property>
<child>
- <object class="GtkLabel">
+ <object class="GtkBox" id="no_timer_container">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Select Duration</property>
- <style>
- <class name="timer-header"/>
- </style>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="start_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <property name="margin">12</property>
<child>
- <object class="GtkImage">
+ <object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="label" translatable="yes">Select Duration</property>
+ <style>
+ <class name="timer-header"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="start_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
- <property name="icon_name">media-playback-start-symbolic</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon_name">media-playback-start-symbolic</property>
+ </object>
+ </child>
+ <style>
+ <class name="pill-button"/>
+ <class name="large-button"/>
+ <class name="suggested-action"/>
+ </style>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
</child>
- <style>
- <class name="pill-button"/>
- <class name="large-button"/>
- <class name="suggested-action"/>
- </style>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
</child>
</object>
<packing>
diff --git a/data/ui/timer-setup.ui b/data/ui/timer-setup.ui
index 588aedb..37a181d 100644
--- a/data/ui/timer-setup.ui
+++ b/data/ui/timer-setup.ui
@@ -198,7 +198,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">12</property>
- <property name="margin_bottom">12</property>
<child>
<object class="GtkGrid" id="time_grid">
<property name="visible">True</property>
diff --git a/src/timer-setup-dialog.vala b/src/timer-setup-dialog.vala
index e360ad8..6e94b90 100644
--- a/src/timer-setup-dialog.vala
+++ b/src/timer-setup-dialog.vala
@@ -25,14 +25,23 @@ public class SetupDialog: Gtk.Dialog {
public SetupDialog (Gtk.Window parent) {
Object (modal: true, transient_for: parent, title: _("New Timer"), use_header_bar: 1);
- this.set_default_size (640, 360);
add_button (_("Cancel"), Gtk.ResponseType.CANCEL);
var create_button = add_button (_("Add"), Gtk.ResponseType.ACCEPT);
create_button.get_style_context ().add_class ("suggested-action");
timer_setup = new Setup ();
- this.get_content_area ().add (timer_setup);
+ timer_setup.margin = 12;
+ var container = new Gtk.ScrolledWindow (null, null);
+ container.hexpand = true;
+ container.vexpand = true;
+ container.propagate_natural_height = true;
+ container.propagate_natural_width = true;
+ container.hscrollbar_policy = Gtk.PolicyType.NEVER;
+ container.border_width = 0;
+ container.visible = true;
+ container.add (timer_setup);
+ this.get_content_area ().add (container);
timer_setup.duration_changed.connect ((duration) => {
this.set_response_sensitive (Gtk.ResponseType.ACCEPT, duration != 0);
});
--
2.34.1

View file

@ -0,0 +1,226 @@
From 845abcf43c0f86ee9405ef7aeaee63adcc16e1d1 Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Tue, 15 Dec 2020 14:23:43 +0100
Subject: [PATCH 15/16] alarm: make ringing panel fit to small window heights
---
data/ui/alarm-ringing-panel.ui | 181 ++++++++++++++++-----------------
1 file changed, 90 insertions(+), 91 deletions(-)
diff --git a/data/ui/alarm-ringing-panel.ui b/data/ui/alarm-ringing-panel.ui
index df04bc7..76ead33 100644
--- a/data/ui/alarm-ringing-panel.ui
+++ b/data/ui/alarm-ringing-panel.ui
@@ -7,119 +7,118 @@
<object class="HdyWindowHandle">
<property name="visible">True</property>
<child>
- <object class="GtkGrid">
+ <object class="HdyClamp">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="row_spacing">48</property>
- <property name="column_spacing">24</property>
<child>
- <object class="GtkGrid" id="button_grid">
+ <object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="row_spacing">24</property>
<property name="column_spacing">24</property>
- <child>
- <object class="GtkButton" id="stop_button">
- <property name="label" translatable="yes">Stop</property>
- <property name="width_request">200</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <style>
- <class name="pill-button"/>
- <class name="large-button"/>
- <class name="destructive-action"/>
- </style>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="snooze_button">
- <property name="label" translatable="yes">Snooze</property>
- <property name="width_request">200</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <style>
- <class name="pill-button"/>
- <class name="large-button"/>
- </style>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
+ <property name="row_spacing">12</property>
+ <property name="margin">12</property>
<property name="valign">center</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="orientation">vertical</property>
<child>
- <object class="GtkLabel" id="time_label">
+ <object class="GtkFlowBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="justify">center</property>
- <property name="wrap">True</property>
- <property name="xalign">0.5</property>
- <attributes>
- <attribute name="font-features" value="tnum=1"/>
- </attributes>
- <style>
- <class name="clocks-ringing-label"/>
- </style>
+ <property name="row_spacing">24</property>
+ <property name="column_spacing">24</property>
+ <property name="max_children_per_line">2</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkFlowBoxChild">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="stop_button">
+ <property name="label" translatable="yes">Stop</property>
+ <property name="width_request">200</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <style>
+ <class name="pill-button"/>
+ <class name="large-button"/>
+ <class name="destructive-action"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFlowBoxChild">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="snooze_button">
+ <property name="label" translatable="yes">Snooze</property>
+ <property name="width_request">200</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <style>
+ <class name="pill-button"/>
+ <class name="large-button"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="title_label">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="justify">center</property>
- <property name="wrap">True</property>
- <property name="margin_top">24</property>
- <style>
- <class name="clocks-ringing-title"/>
- </style>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="time_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0.5</property>
+ <attributes>
+ <attribute name="font-features" value="tnum=1"/>
+ </attributes>
+ <style>
+ <class name="clocks-ringing-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="title_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <style>
+ <class name="clocks-ringing-title"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
</packing>
</child>
</object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
</child>
</object>
</child>
--
2.34.1

View file

@ -0,0 +1,39 @@
From 7403c9567f2f89fd588ad1796b1a816d5d12bccf Mon Sep 17 00:00:00 2001
From: Julian Sparber <julian@sparber.net>
Date: Tue, 15 Dec 2020 14:31:12 +0100
Subject: [PATCH 16/16] world-standalone: allow smaller window heights
---
data/ui/world-standalone.ui | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/data/ui/world-standalone.ui b/data/ui/world-standalone.ui
index 46667d7..8f7acff 100644
--- a/data/ui/world-standalone.ui
+++ b/data/ui/world-standalone.ui
@@ -38,22 +38,8 @@
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
- <property name="margin_start">34</property>
- <property name="margin_end">34</property>
- <property name="margin_bottom">12</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
- <child>
- <object class="GtkLabel" id="dummy_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label"> </property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
<child>
<object class="GtkLabel" id="time_label">
<property name="visible">True</property>
--
2.34.1

View file

@ -0,0 +1,81 @@
# Maintainer: Danct12 <danct12@disroot.org>
# Contributor: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
pkgname=gnome-clocks-mobile
_pkgname=gnome-clocks
pkgver=41.0
pkgrel=3
pkgdesc="Clocks applications for GNOME"
url="https://wiki.gnome.org/Apps/Clocks"
arch=(x86_64 armv7h aarch64)
license=(GPL)
depends=(gtk3 libgweather gnome-desktop geoclue2 geocode-glib feedbackd libhandy)
makedepends=(vala gobject-introspection yelp-tools git meson)
provides=(gnome-clocks)
conflicts=(gnome-clocks)
_commit=90d36119a5ac0bb86586e261a26562baea4d577c # tags/41.0^0
source=("git+https://gitlab.gnome.org/GNOME/gnome-clocks.git#commit=$_commit"
'0001-timer-Use-name-that-can-be-added-to-the-event-naming.patch'
'0002-Use-libfeedback-in-instead-of-GSound.patch'
'0003-timers-persist-running-timers.patch'
'0004-alarm-item-Make-sure-that-the-time-property-is-alway.patch'
'0005-alarm-remove-edit-property.patch'
'0006-alarms-Make-alarms-persisted-and-add-missed-alarms-n.patch'
'0007-Fixed-infinite-alarming.patch'
'0008-Alarms-Fix-wiping-edit-data.patch'
'0009-Don-t-show-numpad-when-setting-a-new-alarm-timer.patch'
'0010-add-option-to-start-hidden.patch'
'0011-autostart-gnome-clocks.patch'
'0012-alarm-setup-dialog-Allow-much-smaller-heights-useing.patch'
'0013-timer-setup-remove-unused-lables.patch'
'0014-timer-Allow-much-smaller-heights-useing-a-ScrolledWi.patch'
'0015-alarm-make-ringing-panel-fit-to-small-window-heights.patch'
'0016-world-standalone-allow-smaller-window-heights.patch')
sha256sums=('SKIP'
'4aa66ae47df1d970ed6138e3d3cec7eea588af7dfa39f0940c13dfa5164052ad'
'9e692d5e340c81943b7312249054a74ee4f83c756a5bf510102a01f5f9ffc458'
'4d46e7968b54d7f16c89ec2d69a5e06c8952253e589bf58546d2dddf86f4d57a'
'10b5aec1a643e8210e410aed716c136a949aa5eacc2b9589fd81c97d99536b79'
'a22e67d3d580c5291b706048c55410e7cbe2d9e59e57c29357e4bbdd00ceaf5f'
'5ac80e8d2379577e6f5f5b0e7862446d6a017b319401f7bdc2ce523d9ac55da6'
'0ae3d7354a491296c03f4102aace3eaf6f0193efda2311b462cf1afa3f9c7a37'
'73dea007e55d6fec12730fdb1cd7bf319c8b373b337f79e7b91d912ec3d8cc40'
'c242f5fd594cc58ba5dd5b313cb5a057308503c94576bbaa58928181a77cf083'
'1f0a13d25aae7942859decb9167a1e53ce24060cc56ef17a0d0b2c10fb77204f'
'dc9fe50c7b6c902eeeb2e67f4a81b017856f800c98b6ce68627db3e8fc5c39b7'
'8b15b617990827196c7444b4238c562af004dd5d98841e00d8829d12a70b0621'
'437bf6caa21232c7d8ec40d541ebd443e9343197cd21256e4ce8a1cab6045f6a'
'bb0121b34c44b0515a9289704e0562871cd5da1544ca520fb04b80baa5c388fe'
'664515657ee315894be6e1b0b87c9308d9dc1de2eb00aebc29ecf87c133147ac'
'992d8868dc96d5b5742cafa26f119484d461a84ee29ac5cf1985ea7f51942d36')
pkgver() {
cd $_pkgname
git describe --tags | sed 's/-/+/g'
}
prepare() {
cd $_pkgname
local src
for src in "${source[@]}"; do
src="${src%%::*}"
src="${src##*/}"
[[ $src = *.patch ]] || continue
echo "Applying patch $src..."
patch -Np1 < "../$src"
done
}
build() {
arch-meson $_pkgname build
meson compile -C build
}
check() {
meson test -C build --print-errorlogs
}
package() {
meson install -C build --destdir "$pkgdir"
}

View file

@ -0,0 +1,68 @@
From: Julian Sparber <julian@sparber.net>
Date: Wed, 13 Jul 2022 22:03:09 +0400
Subject: contact-sheet: Add call and send sms buttons
This adds a button to make calls via the default handler for tel:
and a button to send sms via the default handler for sms:
The buttons are hidden when no handler is available.
---
src/contacts-contact-sheet.vala | 15 +++++++++++++++
src/contacts-utils.vala | 18 ++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/src/contacts-contact-sheet.vala b/src/contacts-contact-sheet.vala
index e662ee0..c93370d 100644
--- a/src/contacts-contact-sheet.vala
+++ b/src/contacts-contact-sheet.vala
@@ -245,6 +245,21 @@ public class Contacts.ContactSheet : Gtk.Widget {
var row = new ContactSheetRow (chunk,
phone.raw_number,
phone.get_phone_type ().display_name);
+
+ // Show a call button when we have a handler for it
+ if (AppInfo.get_all_for_type ("x-scheme-handler/tel").length () > 0) {
+ var call_button = row.add_button ("call-start-symbolic");
+ call_button.clicked.connect (() => {
+ Utils.start_call (phone.raw_number, get_root () as Gtk.Window);
+ });
+ }
+ if (AppInfo.get_all_for_type ("x-scheme-handler/sms").length () > 0) {
+ var sms_button = row.add_button ("chat-message-new-symbolic");
+ sms_button.clicked.connect (() => {
+ Utils.send_sms (phone.raw_number, get_root () as Gtk.Window);
+ });
+ }
+
group.add (row);
}
diff --git a/src/contacts-utils.vala b/src/contacts-utils.vala
index a457a2e..2e6aeef 100644
--- a/src/contacts-utils.vala
+++ b/src/contacts-utils.vala
@@ -19,6 +19,24 @@ using Folks;
namespace Contacts.Utils {
+ public void start_call (string number, Gtk.Window toplevel) {
+ var uri = "tel:" + Uri.escape_string (number, "+" , false);
+ try {
+ Gtk.show_uri (toplevel, uri, 0);
+ } catch (Error e) {
+ debug ("Couldn't launch URI \"%s\": %s", uri, e.message);
+ }
+ }
+
+ public void send_sms (string number, Gtk.Window toplevel) {
+ var uri = "sms:" + Uri.escape_string (number, "+" , false);
+ try {
+ Gtk.show_uri (toplevel, uri, 0);
+ } catch (Error e) {
+ debug ("Couldn't launch URI \"%s\": %s", uri, e.message);
+ }
+ }
+
public T? get_first<T> (Gee.Collection<T> collection) {
var i = collection.iterator();
if (i.next())

View file

@ -0,0 +1,75 @@
# Maintainer: Danct12 <danct12@disroot.org>
# Contributor: Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
# Contributor: Ionut Biru <ibiru@archlinux.org>
pkgname=gnome-contacts-mobile
_pkgname=gnome-contacts
pkgver=45.1
pkgrel=1
pkgdesc="Contacts Manager for GNOME - Forked for Purism patches"
url="https://wiki.gnome.org/Apps/Contacts"
arch=(x86_64 armv7h aarch64)
license=(GPL-2.0-or-later)
depends=(
cairo
dconf
evolution-data-server
folks
gdk-pixbuf2
glib2
gnome-online-accounts
gtk4
hicolor-icon-theme
libadwaita
libgee
libgoa
libportal
libportal-gtk4
pango
qrencode
)
makedepends=(
appstream-glib
git
gobject-introspection
meson
vala
)
provides=(gnome-contacts)
conflicts=(gnome-contacts)
_commit=aa0456c32a6ec8e766ea090e7f3fb85e0035f506 # tags/45.1^0
source=("git+https://gitlab.gnome.org/GNOME/gnome-contacts.git#commit=$_commit"
'0001-ContactSheet-Add-make-call-and-send-sms-button.patch')
b2sums=('SKIP'
'fa242d8e587486496502cafbb565423752c7f3d49c15bc364a26f64bb81ddbe070f900fa68c8c24d863a894123416ecef7b9b9902d2acbe077523a036d3ccf5c')
pkgver() {
cd $_pkgname
git describe --tags | sed 's/-/+/g'
}
prepare() {
cd $_pkgname
local src
for src in "${source[@]}"; do
src="${src%%::*}"
src="${src##*/}"
[[ $src = *.patch ]] || continue
echo "Applying patch $src..."
patch -Np1 < "../$src"
done
}
build() {
arch-meson $_pkgname build
meson compile -C build
}
check() {
meson test -C build --print-errorlogs
}
package() {
meson install -C build --destdir "$pkgdir"
}

View file

@ -0,0 +1,41 @@
From: Mohammed Sadiq <sadiq@sadiqpk.org>
Date: Fri, 20 Sep 2019 16:11:07 +0530
Subject: [PATCH 1/7] avatar-chooser: Adapt to work on librem5
---
panels/system/users/cc-avatar-chooser.ui | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/panels/system/users/cc-avatar-chooser.ui b/panels/system/users/cc-avatar-chooser.ui
index 0f19c6e..d1ed9ae 100644
--- a/panels/system/users/cc-avatar-chooser.ui
+++ b/panels/system/users/cc-avatar-chooser.ui
@@ -3,6 +3,11 @@
<!-- interface-requires gtk+ 3.8 -->
<template class="CcAvatarChooser" parent="GtkPopover">
<property name="visible">False</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">1</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="min-content-height">380</property>
<child>
<object class="GtkBox">
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
@@ -11,7 +16,7 @@
<object class="GtkFlowBox" id="flowbox">
<property name="selection-mode">none</property>
<property name="homogeneous">True</property>
- <property name="max-children-per-line">5</property>
+ <property name="max-children-per-line">3</property>
<property name="column-spacing">10</property>
</object>
</child>
@@ -29,5 +34,7 @@
</child>
</object>
</child>
+ </object>
+ </child>
</template>
</interface>

View file

@ -0,0 +1,27 @@
From: Arnaud Ferraris <arnaud.ferraris@collabora.com>
Date: Mon, 25 May 2020 21:03:38 +0200
Subject: [PATCH 4/4] power: add more suspend timing options
---
panels/power/cc-power-panel.ui | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/panels/power/cc-power-panel.ui b/panels/power/cc-power-panel.ui
index b6efcd0..4e5bae1 100644
--- a/panels/power/cc-power-panel.ui
+++ b/panels/power/cc-power-panel.ui
@@ -8,6 +8,14 @@
<column type="gint"/>
</columns>
<data>
+ <row>
+ <col id="0" translatable="yes" context="automatic_suspend" comments="Translators: Option for &quot;Delay&quot; in &quot;Automatic suspend&quot; dialog.">5 minutes</col>
+ <col id="1">300</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes" context="automatic_suspend" comments="Translators: Option for &quot;Delay&quot; in &quot;Automatic suspend&quot; dialog.">10 minutes</col>
+ <col id="1">600</col>
+ </row>
<row>
<col id="0" translatable="yes" context="automatic_suspend" comments="Translators: Option for &quot;Delay&quot; in &quot;Automatic suspend&quot; dialog.">15 minutes</col>
<col id="1">900</col>

View file

@ -0,0 +1,37 @@
From: Mohammed Sadiq <sadiq@sadiqpk.org>
Date: Tue, 2 Mar 2021 16:45:32 +0530
Subject: [PATCH 1/8] Add patches to check if phone
---
panels/common/pureos.h | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 panels/common/pureos.h
diff --git a/panels/common/pureos.h b/panels/common/pureos.h
new file mode 100644
index 0000000..2e31d7e
--- /dev/null
+++ b/panels/common/pureos.h
@@ -0,0 +1,22 @@
+#include <gtk/gtk.h>
+
+static inline gboolean
+pureos_get_is_phone (void)
+{
+ GSettingsSchema *schema;
+ GSettings *gsettings;
+ gboolean is_phone;
+
+ schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
+ "org.gtk.Settings.Purism", TRUE);
+
+ if (!schema)
+ return FALSE;
+
+ gsettings = g_settings_new_full (schema, NULL, NULL);
+ is_phone = g_settings_get_boolean (gsettings, "is-phone");
+ g_object_unref (gsettings);
+ g_settings_schema_unref (schema);
+
+ return is_phone;
+}

View file

@ -0,0 +1,152 @@
# Maintainer: Danct12 <danct12@disroot.org>
# Contributor: Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
# Contributor: Jan de Groot <jgc@archlinux.org>
_pkgname=gnome-control-center
pkgname=gnome-control-center-mobile
pkgver=46.0.1
pkgrel=1
pkgdesc="GNOME's main interface to configure various aspects of the desktop - Purism fork"
url="https://gitlab.gnome.org/GNOME/gnome-control-center"
license=(GPL-2.0-or-later)
arch=(x86_64 armv7h aarch64)
depends=(
accountsservice
bolt
cairo
colord-gtk4
cups-pk-helper
dconf
fontconfig
gcc-libs
gcr-4
gdk-pixbuf2
glib2
glibc
gnome-bluetooth-3.0
gnome-color-manager
gnome-desktop-4
gnome-online-accounts
gnome-settings-daemon
gnutls
graphene
gsettings-desktop-schemas
gsound
gtk4
hicolor-icon-theme
json-glib
krb5
libadwaita
libcolord
libcups
libepoxy
libgoa
libgtop
libgudev
libibus
libmm-glib
libnm
libnma-gtk4
libpulse
libpwquality
libsecret
libsoup3
libwacom
libx11
libxi
libxml2
modemmanager
pango
polkit
smbclient
sound-theme-freedesktop
tecla
udisks2
upower
)
makedepends=(
docbook-xsl
git
meson
python
python-packaging
)
checkdepends=(
python-dbusmock
python-gobject
xorg-server-xvfb
)
optdepends=(
'fwupd: device security panel'
'gnome-remote-desktop: screen sharing'
# Cannot be a depend because when gnome-shell checkdepends on
# gnome-control-center depends on gnome-shell depends on libmutter-12.so, it
# makes building gnome-shell against libmutter-13.so impossible
'gnome-shell: multitasking panel'
'gnome-user-share: WebDAV file sharing'
'networkmanager: network settings'
'openssh: remote login'
'power-profiles-daemon: power profiles'
'rygel: media sharing'
'system-config-printer: printer settings'
)
provides=(gnome-control-center)
conflicts=(gnome-control-center)
source=(
"git+https://gitlab.gnome.org/GNOME/gnome-control-center.git?signed#tag=$pkgver"
"git+https://gitlab.gnome.org/GNOME/libgnome-volume-control.git"
# purism
'0001-avatar-chooser-Adapt-to-work-on-librem5.patch'
'Add-patches-to-check-if-phone.patch'
# mobian
'0004-power-add-more-suspend-timing-options.patch'
'resize-connection-editor.patch'
)
sha256sums=('5ee40c5b39544aba9ff36156bc5e5e3258e065e92518a1c150a2936bafe3db0a'
'SKIP'
'c18c1b9fdab8e8b7aad8519a58996267377965dbe3d8d8dc9a9129fe80da01ef'
'09e36b0aa2c40d6b6f5be11fd9617223d5b142ff8b50db6fce0eeebc63007327'
'6f1906d58edfa87658c6396091601cab44f40046aced3a56bf5b4e46c0510fb6'
'c006215f8e8c6ef523708089f246815f845d82d94e5f442460d4a4aafdfb617b')
validpgpkeys=(
9B60FE7947F0A3C58136817F2C2A218742E016BE # Felipe Borges (GNOME) <felipeborges@gnome.org>
)
prepare() {
cd ${_pkgname}
git submodule init subprojects/gvc
git submodule set-url subprojects/gvc "$srcdir/libgnome-volume-control"
git -c protocol.file.allow=always submodule update
local src
for src in "${source[@]}"; do
src="${src%%::*}"
src="${src##*/}"
[[ $src = *.patch ]] || continue
echo "Applying patch $src..."
patch -Np1 < "../$src"
done
}
build() {
local meson_options=(
-D documentation=true
)
arch-meson ${_pkgname} build "${meson_options[@]}"
meson compile -C build
}
check() {
GTK_A11Y=none dbus-run-session xvfb-run -s '-nolisten local +iglx -noreset' \
meson test -C build --print-errorlogs
}
package() {
meson install -C build --destdir "$pkgdir"
echo "X-Purism-FormFactor=Workstation;Mobile;" >> "$pkgdir/usr/share/applications/gnome-control-center.desktop"
}

View file

@ -0,0 +1,614 @@
From: Debian GNOME Maintainers
<pkg-gnome-maintainers@lists.alioth.debian.org>
Date: Thu, 2 Jun 2022 14:36:35 +0200
Subject: resize-connection-editor
===================================================================
---
.../connection-editor/8021x-security-page.ui | 6 +--
.../connection-editor/ce-page-8021x-security.c | 2 +-
panels/network/connection-editor/ce-page-ip4.c | 4 +-
panels/network/connection-editor/ce-page-ip6.c | 4 +-
.../network/connection-editor/ce-page-security.c | 2 +-
.../network/connection-editor/connection-editor.ui | 4 +-
panels/network/connection-editor/details-page.ui | 9 +++--
panels/network/connection-editor/ethernet-page.ui | 36 ++++++++---------
panels/network/connection-editor/ip4-page.ui | 42 ++++++++++----------
panels/network/connection-editor/ip6-page.ui | 46 +++++++++++-----------
panels/network/connection-editor/security-page.ui | 6 +--
panels/network/connection-editor/vpn-page.ui | 6 +--
panels/network/connection-editor/wifi-page.ui | 6 +--
13 files changed, 87 insertions(+), 86 deletions(-)
diff --git a/panels/network/connection-editor/8021x-security-page.ui b/panels/network/connection-editor/8021x-security-page.ui
index 4880d99..2e774a3 100644
--- a/panels/network/connection-editor/8021x-security-page.ui
+++ b/panels/network/connection-editor/8021x-security-page.ui
@@ -8,14 +8,14 @@
<property name="propagate-natural-width">True</property>
<child>
<object class="GtkGrid" id="grid">
- <property name="margin_start">50</property>
- <property name="margin_end">50</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
<property name="margin_top">12</property>
<property name="margin_bottom">12</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="row_spacing">10</property>
- <property name="column_spacing">6</property>
+ <property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="security_label">
<property name="xalign">1</property>
diff --git a/panels/network/connection-editor/ce-page-8021x-security.c b/panels/network/connection-editor/ce-page-8021x-security.c
index 3826946..97cd01a 100644
--- a/panels/network/connection-editor/ce-page-8021x-security.c
+++ b/panels/network/connection-editor/ce-page-8021x-security.c
@@ -68,7 +68,7 @@ finish_setup (CEPage8021xSecurity *self, gpointer unused, GError *error, gpointe
if (error)
return;
- self->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ self->group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
self->security = nma_ws_802_1x_new (self->connection, FALSE, FALSE);
if (!self->security) {
diff --git a/panels/network/connection-editor/ce-page-ip4.c b/panels/network/connection-editor/ce-page-ip4.c
index b7a687d..0aeed7c 100644
--- a/panels/network/connection-editor/ce-page-ip4.c
+++ b/panels/network/connection-editor/ce-page-ip4.c
@@ -247,7 +247,7 @@ add_address_row (CEPageIP4 *self,
row = gtk_list_box_row_new ();
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
- row_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ row_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_add_css_class (row_box, "linked");
widget = GTK_WIDGET (ce_ip_address_entry_new (AF_INET));
@@ -393,7 +393,7 @@ add_route_row (CEPageIP4 *self,
row = gtk_list_box_row_new ();
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
- row_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ row_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_add_css_class (row_box, "linked");
widget = GTK_WIDGET (ce_ip_address_entry_new (AF_INET));
diff --git a/panels/network/connection-editor/ce-page-ip6.c b/panels/network/connection-editor/ce-page-ip6.c
index a5e5dcb..0a02fc0 100644
--- a/panels/network/connection-editor/ce-page-ip6.c
+++ b/panels/network/connection-editor/ce-page-ip6.c
@@ -231,7 +231,7 @@ add_address_row (CEPageIP6 *self,
row = gtk_list_box_row_new ();
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
- row_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ row_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_add_css_class (row_box, "linked");
widget = GTK_WIDGET (ce_ip_address_entry_new (AF_INET6));
@@ -369,7 +369,7 @@ add_route_row (CEPageIP6 *self,
row = gtk_list_box_row_new ();
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
- row_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ row_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_add_css_class (row_box, "linked");
widget = GTK_WIDGET (ce_ip_address_entry_new (AF_INET6));
diff --git a/panels/network/connection-editor/ce-page-security.c b/panels/network/connection-editor/ce-page-security.c
index fbc627a..2a51301 100644
--- a/panels/network/connection-editor/ce-page-security.c
+++ b/panels/network/connection-editor/ce-page-security.c
@@ -234,7 +234,7 @@ finish_setup (CEPageSecurity *self)
sw = nm_connection_get_setting_wireless (self->connection);
g_assert (sw);
- self->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ self->group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
dev_caps = NM_WIFI_DEVICE_CAP_CIPHER_WEP40
| NM_WIFI_DEVICE_CAP_CIPHER_WEP104
diff --git a/panels/network/connection-editor/connection-editor.ui b/panels/network/connection-editor/connection-editor.ui
index 89f8418..0c3b116 100644
--- a/panels/network/connection-editor/connection-editor.ui
+++ b/panels/network/connection-editor/connection-editor.ui
@@ -3,7 +3,7 @@
<template class="NetConnectionEditor" parent="AdwWindow">
<property name="destroy-with-parent">True</property>
<property name="modal">True</property>
- <property name="width_request">360</property>
+ <property name="width_request">320</property>
<property name="height_request">294</property>
<child>
<object class="AdwToolbarView">
@@ -59,7 +59,7 @@
<object class="AdwBin" id="add_connection_frame">
<property name="hexpand">True</property>
<property name="vexpand">True</property>
- <property name="width_request">300</property>
+ <property name="width_request">200</property>
<property name="valign">start</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
diff --git a/panels/network/connection-editor/details-page.ui b/panels/network/connection-editor/details-page.ui
index 8ae94ff..163e8a5 100644
--- a/panels/network/connection-editor/details-page.ui
+++ b/panels/network/connection-editor/details-page.ui
@@ -8,12 +8,12 @@
<property name="propagate-natural-width">True</property>
<child>
<object class="GtkGrid">
- <property name="margin_start">24</property>
- <property name="margin_end">24</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
<property name="margin_top">24</property>
<property name="margin_bottom">24</property>
<property name="row_spacing">12</property>
- <property name="column_spacing">12</property>
+ <property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="strength_heading_label">
<property name="xalign">1</property>
@@ -414,6 +414,7 @@
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="label" translatable="yes">_Metered connection: has data limits or can incur charges</property>
+ <property name="wrap">True</property>
<property name="hexpand">True</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">restrict_data_check</property>
@@ -424,7 +425,7 @@
<property name="xalign">0</property>
<property name="label" translatable="yes">Software updates and other large downloads will not be started automatically.</property>
<property name="wrap">True</property>
- <property name="max_width_chars">60</property>
+ <property name="max_width_chars">30</property>
<style>
<class name="dim-label" />
</style>
diff --git a/panels/network/connection-editor/ethernet-page.ui b/panels/network/connection-editor/ethernet-page.ui
index 89cdf8f..9c7cf3d 100644
--- a/panels/network/connection-editor/ethernet-page.ui
+++ b/panels/network/connection-editor/ethernet-page.ui
@@ -13,14 +13,14 @@
<property name="propagate-natural-width">True</property>
<child>
<object class="GtkGrid">
- <property name="margin_start">50</property>
- <property name="margin_end">50</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
<property name="margin_top">12</property>
<property name="margin_bottom">12</property>
- <property name="hexpand">True</property>
+ <property name="hexpand">False</property>
<property name="vexpand">True</property>
- <property name="row_spacing">10</property>
- <property name="column_spacing">6</property>
+ <property name="row_spacing">5</property>
+ <property name="column_spacing">2</property>
<child>
<object class="GtkLabel">
<property name="xalign">1</property>
@@ -37,8 +37,8 @@
<object class="GtkEntry" id="name_entry">
<property name="invisible_char">●</property>
<layout>
- <property name="column">1</property>
- <property name="row">0</property>
+ <property name="column">0</property>
+ <property name="row">1</property>
</layout>
</object>
</child>
@@ -50,7 +50,7 @@
<property name="mnemonic_widget">mac_combo</property>
<layout>
<property name="column">0</property>
- <property name="row">1</property>
+ <property name="row">2</property>
</layout>
</object>
</child>
@@ -60,8 +60,8 @@
<property name="entry_text_column">0</property>
<property name="id_column">1</property>
<layout>
- <property name="column">1</property>
- <property name="row">1</property>
+ <property name="column">0</property>
+ <property name="row">2</property>
</layout>
</object>
</child>
@@ -71,8 +71,8 @@
<property name="hexpand">True</property>
<property name="active_id">0</property>
<layout>
- <property name="column">1</property>
- <property name="row">2</property>
+ <property name="column">0</property>
+ <property name="row">3</property>
</layout>
<child internal-child="entry">
<object class="GtkEntry">
@@ -88,7 +88,7 @@
<property name="mnemonic_widget">mtu_spin</property>
<layout>
<property name="column">0</property>
- <property name="row">3</property>
+ <property name="row">4</property>
</layout>
</object>
</child>
@@ -101,7 +101,7 @@
<property name="mnemonic_widget">cloned_mac_combo</property>
<layout>
<property name="column">0</property>
- <property name="row">2</property>
+ <property name="row">3</property>
</layout>
</object>
</child>
@@ -109,8 +109,8 @@
<object class="GtkLabel" id="mtu_label">
<property name="label" translatable="yes">bytes</property>
<layout>
- <property name="column">2</property>
- <property name="row">3</property>
+ <property name="column">1</property>
+ <property name="row">4</property>
</layout>
</object>
</child>
@@ -118,8 +118,8 @@
<object class="GtkSpinButton" id="mtu_spin">
<property name="adjustment">mtu_adjustment</property>
<layout>
- <property name="column">1</property>
- <property name="row">3</property>
+ <property name="column">0</property>
+ <property name="row">4</property>
</layout>
</object>
</child>
diff --git a/panels/network/connection-editor/ip4-page.ui b/panels/network/connection-editor/ip4-page.ui
index 31183b4..c988c26 100644
--- a/panels/network/connection-editor/ip4-page.ui
+++ b/panels/network/connection-editor/ip4-page.ui
@@ -10,13 +10,13 @@
<object class="GtkViewport">
<child>
<object class="GtkGrid" id="main_box">
- <property name="margin_start">24</property>
- <property name="margin_end">24</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
<property name="margin_top">24</property>
<property name="margin_bottom">24</property>
<property name="orientation">vertical</property>
- <property name="row-spacing">6</property>
- <property name="column-spacing">6</property>
+ <property name="row-spacing">2</property>
+ <property name="column-spacing">2</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">IPv_4 Method</property>
@@ -38,8 +38,8 @@
<property name="action-name">ip4page.ip4method</property>
<property name="action-target">'automatic'</property>
<layout>
- <property name="row">0</property>
- <property name="column">1</property>
+ <property name="row">1</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -49,8 +49,8 @@
<property name="action-name">ip4page.ip4method</property>
<property name="action-target">'local'</property>
<layout>
- <property name="row">0</property>
- <property name="column">2</property>
+ <property name="row">2</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -60,8 +60,8 @@
<property name="action-name">ip4page.ip4method</property>
<property name="action-target">'manual'</property>
<layout>
- <property name="row">1</property>
- <property name="column">1</property>
+ <property name="row">3</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -71,8 +71,8 @@
<property name="action-name">ip4page.ip4method</property>
<property name="action-target">'disabled'</property>
<layout>
- <property name="row">1</property>
- <property name="column">2</property>
+ <property name="row">4</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -82,8 +82,8 @@
<property name="action-name">ip4page.ip4method</property>
<property name="action-target">'shared'</property>
<layout>
- <property name="row">2</property>
- <property name="column">1</property>
+ <property name="row">5</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -92,9 +92,9 @@
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<layout>
- <property name="row">3</property>
+ <property name="row">6</property>
<property name="column">0</property>
- <property name="column-span">3</property>
+ <property name="column-span">1</property>
</layout>
<child>
<object class="GtkBox" id="address_box">
@@ -112,7 +112,7 @@
</child>
<child>
<object class="GtkBox">
- <property name="orientation">horizontal</property>
+ <property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="address_address_label">
<property name="hexpand">True</property>
@@ -260,7 +260,7 @@
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
- <property name="orientation">horizontal</property>
+ <property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="routes_address_label">
<property name="hexpand">True</property>
@@ -357,19 +357,19 @@
</widgets>
</object>
<object class="GtkSizeGroup" id="routes_metric_sizegroup">
- <property name="mode">horizontal</property>
+ <property name="mode">vertical</property>
<widgets>
<widget name="routes_metric_label" />
</widgets>
</object>
<object class="GtkSizeGroup" id="routes_sizegroup">
- <property name="mode">horizontal</property>
+ <property name="mode">vertical</property>
<widgets>
<widget name="routes_stub_box" />
</widgets>
</object>
<object class="GtkSizeGroup" id="address_sizegroup">
- <property name="mode">horizontal</property>
+ <property name="mode">vertical</property>
<widgets>
<widget name="address_stub_box" />
</widgets>
diff --git a/panels/network/connection-editor/ip6-page.ui b/panels/network/connection-editor/ip6-page.ui
index fc68016..f553bab 100644
--- a/panels/network/connection-editor/ip6-page.ui
+++ b/panels/network/connection-editor/ip6-page.ui
@@ -10,13 +10,13 @@
<object class="GtkViewport">
<child>
<object class="GtkGrid" id="main_box">
- <property name="margin_start">24</property>
- <property name="margin_end">24</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
<property name="margin_top">24</property>
<property name="margin_bottom">24</property>
<property name="orientation">vertical</property>
- <property name="row-spacing">6</property>
- <property name="column-spacing">6</property>
+ <property name="row-spacing">2</property>
+ <property name="column-spacing">2</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">IPv_6 Method</property>
@@ -38,8 +38,8 @@
<property name="action-name">ip6page.ip6method</property>
<property name="action-target">'automatic'</property>
<layout>
- <property name="row">0</property>
- <property name="column">1</property>
+ <property name="row">1</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -49,8 +49,8 @@
<property name="action-name">ip6page.ip6method</property>
<property name="action-target">'dhcp'</property>
<layout>
- <property name="row">0</property>
- <property name="column">2</property>
+ <property name="row">2</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -60,8 +60,8 @@
<property name="action-name">ip6page.ip6method</property>
<property name="action-target">'local'</property>
<layout>
- <property name="row">1</property>
- <property name="column">1</property>
+ <property name="row">3</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -71,8 +71,8 @@
<property name="action-name">ip6page.ip6method</property>
<property name="action-target">'manual'</property>
<layout>
- <property name="row">1</property>
- <property name="column">2</property>
+ <property name="row">4</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -82,8 +82,8 @@
<property name="action-name">ip6page.ip6method</property>
<property name="action-target">'disabled'</property>
<layout>
- <property name="row">2</property>
- <property name="column">1</property>
+ <property name="row">5</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -93,8 +93,8 @@
<property name="action-name">ip6page.ip6method</property>
<property name="action-target">'shared'</property>
<layout>
- <property name="row">2</property>
- <property name="column">2</property>
+ <property name="row">6</property>
+ <property name="column">0</property>
</layout>
</object>
</child>
@@ -103,9 +103,9 @@
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<layout>
- <property name="row">3</property>
+ <property name="row">7</property>
<property name="column">0</property>
- <property name="column-span">3</property>
+ <property name="column-span">1</property>
</layout>
<child>
<object class="GtkBox" id="address_box">
@@ -123,7 +123,7 @@
</child>
<child>
<object class="GtkBox">
- <property name="orientation">horizontal</property>
+ <property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="address_address_label">
<property name="hexpand">True</property>
@@ -271,7 +271,7 @@
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
- <property name="orientation">horizontal</property>
+ <property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="routes_address_label">
<property name="hexpand">True</property>
@@ -368,19 +368,19 @@
</widgets>
</object>
<object class="GtkSizeGroup" id="routes_metric_sizegroup">
- <property name="mode">horizontal</property>
+ <property name="mode">vertical </property>
<widgets>
<widget name="routes_metric_label" />
</widgets>
</object>
<object class="GtkSizeGroup" id="routes_sizegroup">
- <property name="mode">horizontal</property>
+ <property name="mode">vertical </property>
<widgets>
<widget name="routes_stub_box" />
</widgets>
</object>
<object class="GtkSizeGroup" id="address_sizegroup">
- <property name="mode">horizontal</property>
+ <property name="mode">vertical </property>
<widgets>
<widget name="address_stub_box" />
</widgets>
diff --git a/panels/network/connection-editor/security-page.ui b/panels/network/connection-editor/security-page.ui
index affba83..ef8723a 100644
--- a/panels/network/connection-editor/security-page.ui
+++ b/panels/network/connection-editor/security-page.ui
@@ -8,14 +8,14 @@
<property name="propagate-natural-width">True</property>
<child>
<object class="GtkGrid">
- <property name="margin_start">50</property>
- <property name="margin_end">50</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
<property name="margin_top">12</property>
<property name="margin_bottom">12</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="row_spacing">10</property>
- <property name="column_spacing">6</property>
+ <property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="security_label">
<property name="xalign">1</property>
diff --git a/panels/network/connection-editor/vpn-page.ui b/panels/network/connection-editor/vpn-page.ui
index d087e5e..8ce453b 100644
--- a/panels/network/connection-editor/vpn-page.ui
+++ b/panels/network/connection-editor/vpn-page.ui
@@ -8,12 +8,12 @@
<property name="propagate-natural-width">True</property>
<child>
<object class="GtkBox" id="box">
- <property name="margin_start">50</property>
- <property name="margin_end">50</property>
+ <property name="margin_start">12</property>
+ <property name="margin_end">12</property>
<property name="margin_top">12</property>
<property name="margin_bottom">12</property>
<property name="orientation">vertical</property>
- <property name="spacing">10</property>
+ <property name="spacing">2</property>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
diff --git a/panels/network/connection-editor/wifi-page.ui b/panels/network/connection-editor/wifi-page.ui
index daf0ea6..eae877f 100644
--- a/panels/network/connection-editor/wifi-page.ui
+++ b/panels/network/connection-editor/wifi-page.ui
@@ -8,14 +8,14 @@
<property name="propagate-natural-width">True</property>
<child>
<object class="GtkGrid">
- <property name="margin_start">50</property>
- <property name="margin_end">50</property>
+ <property name="margin_start">10</property>
+ <property name="margin_end">10</property>
<property name="margin_top">12</property>
<property name="margin_bottom">12</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="row_spacing">10</property>
- <property name="column_spacing">6</property>
+ <property name="column_spacing">2</property>
<child>
<object class="GtkLabel">
<property name="xalign">1</property>

View file

@ -0,0 +1,117 @@
From 792b2465d27c4cbc851ef1675f6661cb741fc987 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Guido=20G=C3=BCnther?= <agx@sigxcpu.org>
Date: Thu, 2 Jul 2020 20:43:33 +0200
Subject: [PATCH 1/2] Add libgtherm dependency
This will be used by the thermal view
---
.gitignore | 3 ++-
meson.build | 22 ++++++++++++++++++++++
org.gnome.Usage.json | 13 +++++++++++++
src/meson.build | 1 +
subprojects/libgtherm.wrap | 5 +++++
5 files changed, 43 insertions(+), 1 deletion(-)
create mode 100644 subprojects/libgtherm.wrap
diff --git a/.gitignore b/.gitignore
index 870c299..bd7f5b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,4 +7,5 @@ build
.ccls-cache
.gdb_history
compile_commands.json
-*~
\ No newline at end of file
+subprojects/gtherm/
+*~
diff --git a/meson.build b/meson.build
index d2f40ac..25e11fa 100644
--- a/meson.build
+++ b/meson.build
@@ -8,6 +8,7 @@ project(
cc = meson.get_compiler('c')
valac = meson.get_compiler('vala')
+libgtherm_dep = dependency('libgtherm-0.0', required: false)
glib_dep = dependency('glib-2.0', version : '>=2.38')
gobject_dep = dependency('gobject-2.0')
gio_dep = dependency('gio-2.0')
@@ -41,6 +42,27 @@ else
libhandy_vapidir = ''
endif
+if not libgtherm_dep.found()
+ libgtherm_subproj = subproject(
+ 'libgtherm',
+ default_options: [
+ 'gtk_doc=false',
+ ]
+ )
+
+ # When using libgtherm as subproject, make sure we get the VAPI file
+ libgtherm_dep = declare_dependency(
+ dependencies: [
+ libgtherm_subproj.get_variable('libgtherm_dep'),
+ libgtherm_subproj.get_variable('libgtherm_vapi'),
+ ]
+ )
+
+ libgtherm_vapidir = join_paths(meson.build_root(), 'subprojects', 'libgtherm', 'src')
+else
+ libgtherm_vapidir = ''
+endif
+
gnome = import('gnome')
i18n = import('i18n')
diff --git a/org.gnome.Usage.json b/org.gnome.Usage.json
index b8de5b2..ed7f9bb 100644
--- a/org.gnome.Usage.json
+++ b/org.gnome.Usage.json
@@ -39,6 +39,19 @@
}
]
},
+ {
+ "name" : "libgtherm",
+ "buildsystem" : "meson",
+ "config-opts" : [
+ "-Dgtk_doc=false"
+ ],
+ "sources" : [
+ {
+ "type" : "git",
+ "url" : "https://source.puri.sm/Librem5/gtherm.git"
+ }
+ ]
+ },
{
"name" : "libhandy",
"buildsystem" : "meson",
diff --git a/src/meson.build b/src/meson.build
index 935e2d6..0c29986 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -56,6 +56,7 @@ deps = [
libgtop_dep,
tracker_dep,
libdazzle_dep,
+ libgtherm_dep,
libhandy_dep,
cc.find_library('m'),
valac.find_library('config', dirs: vapi_dir),
diff --git a/subprojects/libgtherm.wrap b/subprojects/libgtherm.wrap
new file mode 100644
index 0000000..79b76f4
--- /dev/null
+++ b/subprojects/libgtherm.wrap
@@ -0,0 +1,5 @@
+[wrap-git]
+directory=gtherm
+url=https://source.puri.sm/Librem5/gtherm.git
+revision=origin/master
+
--
2.30.0

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,55 @@
# Maintainer: Philip Müller <philm at manjaro dot org>
# Contributor: Balló György <ballogyor+arch at gmail dot com>
pkgname=gnome-usage-mobile
_pkgname=gnome-usage
pkgver=3.38.1
pkgrel=2
pkgdesc="GNOME application to view information about use of system resources"
arch=(armv7h aarch64)
url="https://wiki.gnome.org/Apps/Usage"
license=(GPL3)
depends=(gtk3 libgtop libdazzle tracker3 libhandy gtherm xdg-user-dirs)
makedepends=(git meson vala accountsservice gamemode)
optdepends=('accountsservice: show user tags for processes'
'gamemode: show processes requesting game mode')
provides=("$_pkgname=$pkgver")
conflicts=("$_pkgname")
_commit=4745bb5e8f2a44a35cb410020dcf6e54e73bd6e1 # tags/3.38.1^0
source=("git+https://gitlab.gnome.org/GNOME/gnome-usage.git#commit=$_commit"
'0001-Add-libgtherm-dependency.patch'
'0002-Add-initial-thermal-view.patch')
sha256sums=('SKIP'
'b7845a5717334e043171401188165bd5050f672fac3c73b9624b750217a6d377'
'0caa915c6d9044d57af44e9723efcfb6be1052e8b360b2c3f35dc2ef8499f38c')
pkgver() {
cd $_pkgname
git describe --tags | sed 's/^v//;s/-/+/g'
}
prepare() {
cd $_pkgname
local src
for src in "${source[@]}"; do
src="${src%%::*}"
src="${src##*/}"
[[ $src = *.patch ]] || continue
msg2 "Applying patch $src..."
patch -Np1 < "../$src"
done
}
build() {
arch-meson $_pkgname build
meson compile -C build
}
check() {
meson test -C build --print-errorlogs
}
package() {
meson install -C build --destdir "$pkgdir"
}

27
gtherm/PKGBUILD Normal file
View file

@ -0,0 +1,27 @@
# Maintainer: Danct12 <danct12@disroot.org>
# Contributor: Dan Johansen <strit@manjaro.org>
# Contributor: Philip Müller <philm@manjaro.org>
pkgname=gtherm
pkgver=0.0.3
pkgrel=1
pkgdesc="A simple daemon to monitor thermal zones and cooling devices"
url="https://source.puri.sm/Librem5/gtherm"
license=('GPL')
arch=('x86_64' 'armv7h' 'aarch64')
depends=('glib2' 'gobject-introspection')
makedepends=('meson' 'vala')
source=("https://source.puri.sm/Librem5/gtherm/-/archive/v$pkgver/gtherm-v$pkgver.tar.gz")
sha256sums=('a0bb7e3c8b5446e98acdd2a6c07567c88032a0c5b3e459317de6761a5bacf35f')
build() {
arch-meson $pkgname-v$pkgver build
ninja -C build
}
package() {
DESTDIR="$pkgdir" ninja -C build install
mkdir -p $pkgdir/usr/lib/systemd/user/default.target.wants
install -Dm644 $pkgname-v$pkgver/debian/gthd.user.service $pkgdir/usr/lib/systemd/user/gthd.service
ln -sfv /usr/lib/systemd/user/gthd.service $pkgdir/usr/lib/systemd/user/default.target.wants/gthd.service
}

View file

@ -0,0 +1,104 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Jan Alexander Steffens (heftig)" <heftig@archlinux.org>
Date: Mon, 18 Mar 2024 02:14:24 +0100
Subject: [PATCH] Allow disabling legacy Tracker search
---
docs/reference/gtk/meson.build | 2 --
gtk/gtksearchengine.c | 5 ++---
gtk/meson.build | 5 ++++-
meson.build | 5 +++++
meson_options.txt | 2 ++
5 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/docs/reference/gtk/meson.build b/docs/reference/gtk/meson.build
index 9fa282d38cb5..b2f977363a5a 100644
--- a/docs/reference/gtk/meson.build
+++ b/docs/reference/gtk/meson.build
@@ -129,7 +129,6 @@ private_headers = [
'gtksearchenginemodel.h',
'gtksearchenginequartz.h',
'gtksearchenginesimple.h',
- 'gtksearchenginetracker.h',
'gtksearchentryprivate.h',
'gtkselectionprivate.h',
'gtksettingsprivate.h',
@@ -208,7 +207,6 @@ private_headers = [
'gtkrecentchooserdefault.h',
'gtkrecentchooserutils.h',
'gtksearchengine.h',
- 'gtksearchenginetracker.h',
'gtksearchenginesimple.h',
'gtksearchenginequartz.h',
'gtksequence.h',
diff --git a/gtk/gtksearchengine.c b/gtk/gtksearchengine.c
index 1910cc0ad337..dd4022c2cc4d 100644
--- a/gtk/gtksearchengine.c
+++ b/gtk/gtksearchengine.c
@@ -29,9 +29,8 @@
#if defined(HAVE_TRACKER3)
#include "gtksearchenginetracker3.h"
#endif
-#if !defined G_OS_WIN32 /* No tracker on windows */
+#if defined(HAVE_TRACKER)
#include "gtksearchenginetracker.h"
-#define HAVE_TRACKER 1
#endif
#include <gdk/gdk.h> /* for GDK_WINDOWING_QUARTZ */
@@ -388,7 +387,7 @@ _gtk_search_engine_new (void)
}
#endif
-#ifdef HAVE_TRACKER
+#if defined(HAVE_TRACKER)
if (!engine->priv->native)
{
engine->priv->native = _gtk_search_engine_tracker_new ();
diff --git a/gtk/meson.build b/gtk/meson.build
index ea866d8231c2..03677b120f60 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -652,9 +652,12 @@ gtk_unix_sources = files(
'gtkprintoperation-portal.c',
'gtkprintunixdialog.c',
'gtkprintbackend.c',
- 'gtksearchenginetracker.c',
)
+if os_unix and tracker_enabled
+ gtk_unix_sources += 'gtksearchenginetracker.c'
+endif
+
if os_unix and tracker3_enabled
gtk_unix_sources += 'gtksearchenginetracker3.c'
endif
diff --git a/meson.build b/meson.build
index 24785bfe4dd8..1999f526d987 100644
--- a/meson.build
+++ b/meson.build
@@ -466,6 +466,11 @@ if require_harfbuzz and not harfbuzz_dep.found()
fallback: ['harfbuzz', 'libharfbuzz_dep'])
endif
+tracker_enabled = get_option('tracker')
+if tracker_enabled
+ cdata.set('HAVE_TRACKER', true)
+endif
+
tracker3_enabled = get_option('tracker3')
if tracker3_enabled
tracker3_dep = dependency('tracker-sparql-3.0', required: false)
diff --git a/meson_options.txt b/meson_options.txt
index 94099aa01eb3..3b5485a88f74 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -17,6 +17,8 @@ option('cloudproviders', type: 'boolean', value: false,
description : 'Enable the cloudproviders support')
option('profiler', type: 'boolean', value: false,
description : 'Enable profiler support')
+option('tracker', type: 'boolean', value: true,
+ description : 'Enable Tracker filechooser search')
option('tracker3', type: 'boolean', value: false,
description : 'Enable Tracker3 filechooser search')

View file

@ -0,0 +1,348 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Wed, 16 Dec 2020 18:54:47 +0500
Subject: Add GtkHdyAnimation
This is imported from HdyAnimation from libhandy 1.0.2.
---
gtk/hdy-animation-private.h | 53 ++++++++++
gtk/hdy-animation.c | 250 ++++++++++++++++++++++++++++++++++++++++++++
gtk/meson.build | 2 +
3 files changed, 305 insertions(+)
create mode 100644 gtk/hdy-animation-private.h
create mode 100644 gtk/hdy-animation.c
diff --git a/gtk/hdy-animation-private.h b/gtk/hdy-animation-private.h
new file mode 100644
index 0000000..6816f6e
--- /dev/null
+++ b/gtk/hdy-animation-private.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include "gtkwidget.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_HDY_ANIMATION (gtk_hdy_animation_get_type())
+
+typedef struct _GtkHdyAnimation GtkHdyAnimation;
+
+typedef void (*GtkHdyAnimationValueCallback) (gdouble value,
+ gpointer user_data);
+typedef void (*GtkHdyAnimationDoneCallback) (gpointer user_data);
+typedef double (*GtkHdyAnimationEasingFunc) (gdouble t);
+
+GType gtk_hdy_animation_get_type (void) G_GNUC_CONST;
+
+GtkHdyAnimation *gtk_hdy_animation_new (GtkWidget *widget,
+ gdouble from,
+ gdouble to,
+ gint64 duration,
+ GtkHdyAnimationEasingFunc easing_func,
+ GtkHdyAnimationValueCallback value_cb,
+ GtkHdyAnimationDoneCallback done_cb,
+ gpointer user_data);
+
+GtkHdyAnimation *gtk_hdy_animation_ref (GtkHdyAnimation *self);
+void gtk_hdy_animation_unref (GtkHdyAnimation *self);
+
+void gtk_hdy_animation_start (GtkHdyAnimation *self);
+void gtk_hdy_animation_stop (GtkHdyAnimation *self);
+
+gdouble gtk_hdy_animation_get_value (GtkHdyAnimation *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GtkHdyAnimation, gtk_hdy_animation_unref)
+
+gboolean gtk_hdy_get_enable_animations (GtkWidget *widget);
+
+gdouble gtk_hdy_lerp (gdouble a, gdouble b, gdouble t);
+
+gdouble gtk_hdy_ease_out_cubic (gdouble t);
+
+G_END_DECLS
diff --git a/gtk/hdy-animation.c b/gtk/hdy-animation.c
new file mode 100644
index 0000000..0de1128
--- /dev/null
+++ b/gtk/hdy-animation.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2019-2020 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "hdy-animation-private.h"
+
+/**
+ * SECTION:hdy-animation
+ * @short_description: Animation helpers
+ * @title: Animation Helpers
+ *
+ * Animation helpers.
+ *
+ * Since: 0.0.11
+ */
+
+G_DEFINE_BOXED_TYPE (GtkHdyAnimation, gtk_hdy_animation, gtk_hdy_animation_ref, gtk_hdy_animation_unref)
+
+struct _GtkHdyAnimation
+{
+ gatomicrefcount ref_count;
+
+ GtkWidget *widget;
+
+ gdouble value;
+
+ gdouble value_from;
+ gdouble value_to;
+ gint64 duration; /* ms */
+
+ gint64 start_time; /* ms */
+ guint tick_cb_id;
+
+ GtkHdyAnimationEasingFunc easing_func;
+ GtkHdyAnimationValueCallback value_cb;
+ GtkHdyAnimationDoneCallback done_cb;
+ gpointer user_data;
+};
+
+static void
+set_value (GtkHdyAnimation *self,
+ gdouble value)
+{
+ self->value = value;
+ self->value_cb (value, self->user_data);
+}
+
+static gboolean
+tick_cb (GtkWidget *widget,
+ GdkFrameClock *frame_clock,
+ GtkHdyAnimation *self)
+{
+ gint64 frame_time = gdk_frame_clock_get_frame_time (frame_clock) / 1000; /* ms */
+ gdouble t = (gdouble) (frame_time - self->start_time) / self->duration;
+
+ if (t >= 1) {
+ self->tick_cb_id = 0;
+
+ set_value (self, self->value_to);
+
+ g_signal_handlers_disconnect_by_func (self->widget, gtk_hdy_animation_stop, self);
+
+ self->done_cb (self->user_data);
+
+ return G_SOURCE_REMOVE;
+ }
+
+ set_value (self, gtk_hdy_lerp (self->value_from, self->value_to, self->easing_func (t)));
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+gtk_hdy_animation_free (GtkHdyAnimation *self)
+{
+ gtk_hdy_animation_stop (self);
+
+ g_slice_free (GtkHdyAnimation, self);
+}
+
+GtkHdyAnimation *
+gtk_hdy_animation_new (GtkWidget *widget,
+ gdouble from,
+ gdouble to,
+ gint64 duration,
+ GtkHdyAnimationEasingFunc easing_func,
+ GtkHdyAnimationValueCallback value_cb,
+ GtkHdyAnimationDoneCallback done_cb,
+ gpointer user_data)
+{
+ GtkHdyAnimation *self;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (easing_func != NULL, NULL);
+ g_return_val_if_fail (value_cb != NULL, NULL);
+ g_return_val_if_fail (done_cb != NULL, NULL);
+
+ self = g_slice_new0 (GtkHdyAnimation);
+
+ g_atomic_ref_count_init (&self->ref_count);
+
+ self->widget = widget;
+ self->value_from = from;
+ self->value_to = to;
+ self->duration = duration;
+ self->easing_func = easing_func;
+ self->value_cb = value_cb;
+ self->done_cb = done_cb;
+ self->user_data = user_data;
+
+ self->value = from;
+
+ return self;
+}
+
+GtkHdyAnimation *
+gtk_hdy_animation_ref (GtkHdyAnimation *self)
+{
+ g_return_val_if_fail (self != NULL, NULL);
+
+ g_atomic_ref_count_inc (&self->ref_count);
+
+ return self;
+}
+
+void
+gtk_hdy_animation_unref (GtkHdyAnimation *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (g_atomic_ref_count_dec (&self->ref_count))
+ gtk_hdy_animation_free (self);
+}
+
+void
+gtk_hdy_animation_start (GtkHdyAnimation *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (!gtk_hdy_get_enable_animations (self->widget) ||
+ !gtk_widget_get_mapped (self->widget) ||
+ self->duration <= 0) {
+ set_value (self, self->value_to);
+
+ self->done_cb (self->user_data);
+
+ return;
+ }
+
+ self->start_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (self->widget)) / 1000;
+
+ if (self->tick_cb_id)
+ return;
+
+ g_signal_connect_swapped (self->widget, "unmap",
+ G_CALLBACK (gtk_hdy_animation_stop), self);
+ self->tick_cb_id = gtk_widget_add_tick_callback (self->widget, (GtkTickCallback) tick_cb, self, NULL);
+}
+
+void
+gtk_hdy_animation_stop (GtkHdyAnimation *self)
+{
+ g_return_if_fail (self != NULL);
+
+ if (!self->tick_cb_id)
+ return;
+
+ gtk_widget_remove_tick_callback (self->widget, self->tick_cb_id);
+ self->tick_cb_id = 0;
+
+ g_signal_handlers_disconnect_by_func (self->widget, gtk_hdy_animation_stop, self);
+
+ self->done_cb (self->user_data);
+}
+
+gdouble
+gtk_hdy_animation_get_value (GtkHdyAnimation *self)
+{
+ g_return_val_if_fail (self != NULL, 0.0);
+
+ return self->value;
+}
+
+/**
+ * gtk_hdy_get_enable_animations:
+ * @widget: a #GtkWidget
+ *
+ * Returns whether animations are enabled for that widget. This should be used
+ * when implementing an animated widget to know whether to animate it or not.
+ *
+ * Returns: %TRUE if animations are enabled for @widget.
+ *
+ * Since: 0.0.11
+ */
+gboolean
+gtk_hdy_get_enable_animations (GtkWidget *widget)
+{
+ gboolean enable_animations = TRUE;
+
+ g_assert (GTK_IS_WIDGET (widget));
+
+ g_object_get (gtk_widget_get_settings (widget),
+ "gtk-enable-animations", &enable_animations,
+ NULL);
+
+ return enable_animations;
+}
+
+/**
+ * gtk_hdy_lerp: (skip)
+ * @a: the start
+ * @b: the end
+ * @t: the interpolation rate
+ *
+ * Computes the linear interpolation between @a and @b for @t.
+ *
+ * Returns: the linear interpolation between @a and @b for @t.
+ *
+ * Since: 0.0.11
+ */
+gdouble
+gtk_hdy_lerp (gdouble a, gdouble b, gdouble t)
+{
+ return a * (1.0 - t) + b * t;
+}
+
+/* From clutter-easing.c, based on Robert Penner's
+ * infamous easing equations, MIT license.
+ */
+
+/**
+ * gtk_hdy_ease_out_cubic:
+ * @t: the term
+ *
+ * Computes the ease out for @t.
+ *
+ * Returns: the ease out for @t.
+ *
+ * Since: 0.0.11
+ */
+gdouble
+gtk_hdy_ease_out_cubic (gdouble t)
+{
+ gdouble p = t - 1;
+ return p * p * p + 1;
+}
diff --git a/gtk/meson.build b/gtk/meson.build
index 1d35e83..9fe7c4d 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -383,6 +383,7 @@ gtk_sources = files(
'gtkwin32draw.c',
'gtkwin32theme.c',
'gdkpixbufutils.c',
+ 'hdy-animation.c',
'hdy-css.c',
'hdy-view-switcher-bar.c',
'hdy-view-switcher-button.c',
@@ -394,6 +395,7 @@ gtk_sources = files(
gtk_private_type_headers = files(
'gtkcsstypesprivate.h',
'gtktexthandleprivate.h',
+ 'hdy-animation-private.h',
'hdy-css-private.h',
'hdy-view-switcher-bar-private.h',
'hdy-view-switcher-button-private.h',

View file

@ -0,0 +1,642 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Wed, 14 Oct 2020 19:27:32 +0500
Subject: Add GtkHdyClamp
This is imported from HdyLeaflet from libhandy 1.0.0.
---
gtk/hdy-clamp-private.h | 31 +++
gtk/hdy-clamp.c | 566 ++++++++++++++++++++++++++++++++++++++++++++++++
gtk/meson.build | 2 +
3 files changed, 599 insertions(+)
create mode 100644 gtk/hdy-clamp-private.h
create mode 100644 gtk/hdy-clamp.c
diff --git a/gtk/hdy-clamp-private.h b/gtk/hdy-clamp-private.h
new file mode 100644
index 0000000..b41278f
--- /dev/null
+++ b/gtk/hdy-clamp-private.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include "gtkbin.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_HDY_CLAMP (gtk_hdy_clamp_get_type())
+
+G_DECLARE_FINAL_TYPE (GtkHdyClamp, gtk_hdy_clamp, GTK, HDY_CLAMP, GtkBin)
+
+GtkWidget *gtk_hdy_clamp_new (void);
+
+gint gtk_hdy_clamp_get_maximum_size (GtkHdyClamp *self);
+void gtk_hdy_clamp_set_maximum_size (GtkHdyClamp *self,
+ gint maximum_size);
+
+gint gtk_hdy_clamp_get_tightening_threshold (GtkHdyClamp *self);
+void gtk_hdy_clamp_set_tightening_threshold (GtkHdyClamp *self,
+ gint tightening_threshold);
+
+G_END_DECLS
diff --git a/gtk/hdy-clamp.c b/gtk/hdy-clamp.c
new file mode 100644
index 0000000..8b287dc
--- /dev/null
+++ b/gtk/hdy-clamp.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2018 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "gtkorientable.h"
+#include "gtkstylecontext.h"
+#include "gtktypebuiltins.h"
+#include "hdy-clamp-private.h"
+#include "hdy-animation-private.h"
+
+#include <math.h>
+
+/**
+ * SECTION:hdy-clamp
+ * @short_description: A container constraining its child to a given size.
+ * @Title: GtkHdyClamp
+ *
+ * The #GtkHdyClamp widget constraints the size of the widget it contains to a
+ * given maximum size. It will constrain the width if it is horizontal, or the
+ * height if it is vertical. The expansion of the child from its minimum to its
+ * maximum size is eased out for a smooth transition.
+ *
+ * If the child requires more than the requested maximum size, it will be
+ * allocated the minimum size it can fit in instead.
+ *
+ * # CSS nodes
+ *
+ * #GtkHdyClamp has a single CSS node with name clamp. The node will get the style
+ * classes .large when its child reached its maximum size, .small when the clamp
+ * allocates its full size to its child, .medium in-between, or none if it
+ * didn't compute its size yet.
+ *
+ * Since: 1.0
+ */
+
+#define GTK_HDY_EASE_OUT_TAN_CUBIC 3
+
+enum {
+ PROP_0,
+ PROP_MAXIMUM_SIZE,
+ PROP_TIGHTENING_THRESHOLD,
+
+ /* Overridden properties */
+ PROP_ORIENTATION,
+
+ LAST_PROP = PROP_TIGHTENING_THRESHOLD + 1,
+};
+
+struct _GtkHdyClamp
+{
+ GtkBin parent_instance;
+
+ gint maximum_size;
+ gint tightening_threshold;
+
+ GtkOrientation orientation;
+};
+
+static GParamSpec *props[LAST_PROP];
+
+G_DEFINE_TYPE_WITH_CODE (GtkHdyClamp, gtk_hdy_clamp, GTK_TYPE_BIN,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
+
+static void
+set_orientation (GtkHdyClamp *self,
+ GtkOrientation orientation)
+{
+ if (self->orientation == orientation)
+ return;
+
+ self->orientation = orientation;
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+ g_object_notify (G_OBJECT (self), "orientation");
+}
+
+static void
+gtk_hdy_clamp_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyClamp *self = GTK_HDY_CLAMP (object);
+
+ switch (prop_id) {
+ case PROP_MAXIMUM_SIZE:
+ g_value_set_int (value, gtk_hdy_clamp_get_maximum_size (self));
+ break;
+ case PROP_TIGHTENING_THRESHOLD:
+ g_value_set_int (value, gtk_hdy_clamp_get_tightening_threshold (self));
+ break;
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, self->orientation);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_hdy_clamp_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyClamp *self = GTK_HDY_CLAMP (object);
+
+ switch (prop_id) {
+ case PROP_MAXIMUM_SIZE:
+ gtk_hdy_clamp_set_maximum_size (self, g_value_get_int (value));
+ break;
+ case PROP_TIGHTENING_THRESHOLD:
+ gtk_hdy_clamp_set_tightening_threshold (self, g_value_get_int (value));
+ break;
+ case PROP_ORIENTATION:
+ set_orientation (self, g_value_get_enum (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+/**
+ * get_child_size:
+ * @self: a #GtkHdyClamp
+ * @for_size: the size of the clamp
+ * @child_minimum: the minimum size reachable by the child, and hence by @self
+ * @child_maximum: the maximum size @self will ever allocate its child
+ * @lower_threshold: the threshold below which @self will allocate its full size to its child
+ * @upper_threshold: the threshold up from which @self will allocate its maximum size to its child
+ *
+ * Measures the child's extremes, the clamp's thresholds, and returns size to
+ * allocate to the child.
+ *
+ * If the clamp is horizontal, all values are widths, otherwise they are
+ * heights.
+ */
+static gint
+get_child_size (GtkHdyClamp *self,
+ gint for_size,
+ gint *child_minimum,
+ gint *child_maximum,
+ gint *lower_threshold,
+ gint *upper_threshold)
+{
+ GtkBin *bin = GTK_BIN (self);
+ GtkWidget *child;
+ gint min = 0, max = 0, lower = 0, upper = 0;
+ gdouble amplitude, progress;
+
+ child = gtk_bin_get_child (bin);
+ if (child == NULL)
+ return 0;
+
+ if (gtk_widget_get_visible (child)) {
+ if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
+ gtk_widget_get_preferred_width (child, &min, NULL);
+ else
+ gtk_widget_get_preferred_height (child, &min, NULL);
+ }
+
+ lower = MAX (MIN (self->tightening_threshold, self->maximum_size), min);
+ max = MAX (lower, self->maximum_size);
+ amplitude = max - lower;
+ upper = GTK_HDY_EASE_OUT_TAN_CUBIC * amplitude + lower;
+
+ if (child_minimum)
+ *child_minimum = min;
+ if (child_maximum)
+ *child_maximum = max;
+ if (lower_threshold)
+ *lower_threshold = lower;
+ if (upper_threshold)
+ *upper_threshold = upper;
+
+ if (for_size < 0)
+ return 0;
+
+ if (for_size <= lower)
+ return for_size;
+
+ if (for_size >= upper)
+ return max;
+
+ progress = (double) (for_size - lower) / (double) (upper - lower);
+
+ return gtk_hdy_ease_out_cubic (progress) * amplitude + lower;
+}
+
+/* This private method is prefixed by the call name because it will be a virtual
+ * method in GTK 4.
+ */
+static void
+gtk_hdy_clamp_measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ int for_size,
+ int *minimum,
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
+{
+ GtkHdyClamp *self = GTK_HDY_CLAMP (widget);
+ GtkBin *bin = GTK_BIN (widget);
+ GtkWidget *child;
+ gint child_size;
+
+ if (minimum)
+ *minimum = 0;
+ if (natural)
+ *natural = 0;
+ if (minimum_baseline)
+ *minimum_baseline = -1;
+ if (natural_baseline)
+ *natural_baseline = -1;
+
+ child = gtk_bin_get_child (bin);
+ if (!(child && gtk_widget_get_visible (child)))
+ return;
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL) {
+ if (self->orientation == orientation) {
+ gtk_widget_get_preferred_width (child, minimum, natural);
+
+ return;
+ }
+
+ child_size = get_child_size (GTK_HDY_CLAMP (widget), for_size, NULL, NULL, NULL, NULL);
+
+ gtk_widget_get_preferred_width_for_height (child,
+ child_size,
+ minimum,
+ natural);
+ } else {
+ if (self->orientation == orientation) {
+ gtk_widget_get_preferred_height (child, minimum, natural);
+
+ return;
+ }
+
+ child_size = get_child_size (GTK_HDY_CLAMP (widget), for_size, NULL, NULL, NULL, NULL);
+
+ gtk_widget_get_preferred_height_and_baseline_for_width (child,
+ child_size,
+ minimum,
+ natural,
+ minimum_baseline,
+ natural_baseline);
+ }
+}
+
+static GtkSizeRequestMode
+gtk_hdy_clamp_get_request_mode (GtkWidget *widget)
+{
+ GtkHdyClamp *self = GTK_HDY_CLAMP (widget);
+
+ return self->orientation == GTK_ORIENTATION_HORIZONTAL ?
+ GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH :
+ GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
+}
+
+static void
+gtk_hdy_clamp_get_preferred_width_for_height (GtkWidget *widget,
+ gint height,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_hdy_clamp_measure (widget, GTK_ORIENTATION_HORIZONTAL, height,
+ minimum, natural, NULL, NULL);
+}
+
+static void
+gtk_hdy_clamp_get_preferred_width (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_hdy_clamp_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1,
+ minimum, natural, NULL, NULL);
+}
+
+static void
+gtk_hdy_clamp_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum,
+ gint *natural,
+ gint *minimum_baseline,
+ gint *natural_baseline)
+{
+ gtk_hdy_clamp_measure (widget, GTK_ORIENTATION_VERTICAL, width,
+ minimum, natural, minimum_baseline, natural_baseline);
+}
+
+static void
+gtk_hdy_clamp_get_preferred_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_hdy_clamp_measure (widget, GTK_ORIENTATION_VERTICAL, width,
+ minimum, natural, NULL, NULL);
+}
+
+static void
+gtk_hdy_clamp_get_preferred_height (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_hdy_clamp_measure (widget, GTK_ORIENTATION_VERTICAL, -1,
+ minimum, natural, NULL, NULL);
+}
+
+static void
+gtk_hdy_clamp_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkHdyClamp *self = GTK_HDY_CLAMP (widget);
+ GtkBin *bin = GTK_BIN (widget);
+ GtkAllocation child_allocation;
+ gint baseline;
+ GtkWidget *child;
+ GtkStyleContext *context = gtk_widget_get_style_context (widget);
+ gint child_maximum = 0, lower_threshold = 0;
+ gint child_clamped_size;
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ child = gtk_bin_get_child (bin);
+ if (!(child && gtk_widget_get_visible (child))) {
+ gtk_style_context_remove_class (context, "small");
+ gtk_style_context_remove_class (context, "medium");
+ gtk_style_context_remove_class (context, "large");
+
+ return;
+ }
+
+ if (self->orientation == GTK_ORIENTATION_HORIZONTAL) {
+ child_allocation.width = get_child_size (self, allocation->width, NULL, &child_maximum, &lower_threshold, NULL);
+ child_allocation.height = allocation->height;
+
+ child_clamped_size = child_allocation.width;
+ }
+ else {
+ child_allocation.width = allocation->width;
+ child_allocation.height = get_child_size (self, allocation->height, NULL, &child_maximum, &lower_threshold, NULL);
+
+ child_clamped_size = child_allocation.height;
+ }
+
+ if (child_clamped_size >= child_maximum) {
+ gtk_style_context_remove_class (context, "small");
+ gtk_style_context_remove_class (context, "medium");
+ gtk_style_context_add_class (context, "large");
+ } else if (child_clamped_size <= lower_threshold) {
+ gtk_style_context_add_class (context, "small");
+ gtk_style_context_remove_class (context, "medium");
+ gtk_style_context_remove_class (context, "large");
+ } else {
+ gtk_style_context_remove_class (context, "small");
+ gtk_style_context_add_class (context, "medium");
+ gtk_style_context_remove_class (context, "large");
+ }
+
+ if (!gtk_widget_get_has_window (widget)) {
+ /* This always center the child on the side of the orientation. */
+
+ if (self->orientation == GTK_ORIENTATION_HORIZONTAL) {
+ child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2;
+ child_allocation.y = allocation->y;
+ } else {
+ child_allocation.x = allocation->x;
+ child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2;
+ }
+ }
+ else {
+ child_allocation.x = 0;
+ child_allocation.y = 0;
+ }
+
+ baseline = gtk_widget_get_allocated_baseline (widget);
+ gtk_widget_size_allocate_with_baseline (child, &child_allocation, baseline);
+}
+
+static void
+gtk_hdy_clamp_class_init (GtkHdyClampClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ object_class->get_property = gtk_hdy_clamp_get_property;
+ object_class->set_property = gtk_hdy_clamp_set_property;
+
+ widget_class->get_request_mode = gtk_hdy_clamp_get_request_mode;
+ widget_class->get_preferred_width = gtk_hdy_clamp_get_preferred_width;
+ widget_class->get_preferred_width_for_height = gtk_hdy_clamp_get_preferred_width_for_height;
+ widget_class->get_preferred_height = gtk_hdy_clamp_get_preferred_height;
+ widget_class->get_preferred_height_for_width = gtk_hdy_clamp_get_preferred_height_for_width;
+ widget_class->get_preferred_height_and_baseline_for_width = gtk_hdy_clamp_get_preferred_height_and_baseline_for_width;
+ widget_class->size_allocate = gtk_hdy_clamp_size_allocate;
+
+ gtk_container_class_handle_border_width (container_class);
+
+ g_object_class_override_property (object_class,
+ PROP_ORIENTATION,
+ "orientation");
+
+ /**
+ * GtkHdyClamp:maximum-size:
+ *
+ * The maximum size to allocate to the child. It is the width if the clamp is
+ * horizontal, or the height if it is vertical.
+ *
+ * Since: 1.0
+ */
+ props[PROP_MAXIMUM_SIZE] =
+ g_param_spec_int ("maximum-size",
+ _("Maximum size"),
+ _("The maximum size allocated to the child"),
+ 0, G_MAXINT, 600,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * GtkHdyClamp:tightening-threshold:
+ *
+ * The size starting from which the clamp will tighten its grip on the child,
+ * slowly allocating less and less of the available size up to the maximum
+ * allocated size. Below that threshold and below the maximum width, the child
+ * will be allocated all the available size.
+ *
+ * If the threshold is greater than the maximum size to allocate to the child,
+ * the child will be allocated all the width up to the maximum.
+ * If the threshold is lower than the minimum size to allocate to the child,
+ * that size will be used as the tightening threshold.
+ *
+ * Effectively, tightening the grip on the child before it reaches its maximum
+ * size makes transitions to and from the maximum size smoother when resizing.
+ *
+ * Since: 1.0
+ */
+ props[PROP_TIGHTENING_THRESHOLD] =
+ g_param_spec_int ("tightening-threshold",
+ _("Tightening threshold"),
+ _("The size from which the clamp will tighten its grip on the child"),
+ 0, G_MAXINT, 400,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+
+ gtk_widget_class_set_css_name (widget_class, "clamp");
+}
+
+static void
+gtk_hdy_clamp_init (GtkHdyClamp *self)
+{
+ self->maximum_size = 600;
+ self->tightening_threshold = 400;
+}
+
+/**
+ * gtk_hdy_clamp_new:
+ *
+ * Creates a new #GtkHdyClamp.
+ *
+ * Returns: a new #GtkHdyClamp
+ *
+ * Since: 1.0
+ */
+GtkWidget *
+gtk_hdy_clamp_new (void)
+{
+ return g_object_new (GTK_TYPE_HDY_CLAMP, NULL);
+}
+
+/**
+ * gtk_hdy_clamp_get_maximum_size:
+ * @self: a #GtkHdyClamp
+ *
+ * Gets the maximum size to allocate to the contained child. It is the width if
+ * @self is horizontal, or the height if it is vertical.
+ *
+ * Returns: the maximum width to allocate to the contained child.
+ *
+ * Since: 1.0
+ */
+gint
+gtk_hdy_clamp_get_maximum_size (GtkHdyClamp *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_CLAMP (self), 0);
+
+ return self->maximum_size;
+}
+
+/**
+ * gtk_hdy_clamp_set_maximum_size:
+ * @self: a #GtkHdyClamp
+ * @maximum_size: the maximum size
+ *
+ * Sets the maximum size to allocate to the contained child. It is the width if
+ * @self is horizontal, or the height if it is vertical.
+ *
+ * Since: 1.0
+ */
+void
+gtk_hdy_clamp_set_maximum_size (GtkHdyClamp *self,
+ gint maximum_size)
+{
+ g_return_if_fail (GTK_IS_HDY_CLAMP (self));
+
+ if (self->maximum_size == maximum_size)
+ return;
+
+ self->maximum_size = maximum_size;
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MAXIMUM_SIZE]);
+}
+
+/**
+ * gtk_hdy_clamp_get_tightening_threshold:
+ * @self: a #GtkHdyClamp
+ *
+ * Gets the size starting from which the clamp will tighten its grip on the
+ * child.
+ *
+ * Returns: the size starting from which the clamp will tighten its grip on the
+ * child.
+ *
+ * Since: 1.0
+ */
+gint
+gtk_hdy_clamp_get_tightening_threshold (GtkHdyClamp *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_CLAMP (self), 0);
+
+ return self->tightening_threshold;
+}
+
+/**
+ * gtk_hdy_clamp_set_tightening_threshold:
+ * @self: a #GtkHdyClamp
+ * @tightening_threshold: the tightening threshold
+ *
+ * Sets the size starting from which the clamp will tighten its grip on the
+ * child.
+ *
+ * Since: 1.0
+ */
+void
+gtk_hdy_clamp_set_tightening_threshold (GtkHdyClamp *self,
+ gint tightening_threshold)
+{
+ g_return_if_fail (GTK_IS_HDY_CLAMP (self));
+
+ if (self->tightening_threshold == tightening_threshold)
+ return;
+
+ self->tightening_threshold = tightening_threshold;
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TIGHTENING_THRESHOLD]);
+}
diff --git a/gtk/meson.build b/gtk/meson.build
index ae63ff0..c66ad0c 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -384,6 +384,7 @@ gtk_sources = files(
'gtkwin32theme.c',
'gdkpixbufutils.c',
'hdy-animation.c',
+ 'hdy-clamp.c',
'hdy-css.c',
'hdy-navigation-direction.c',
'hdy-shadow-helper.c',
@@ -403,6 +404,7 @@ gtk_private_type_headers = files(
'gtktexthandleprivate.h',
'hdy-animation-private.h',
'hdy-cairo-private.h',
+ 'hdy-clamp-private.h',
'hdy-css-private.h',
'hdy-navigation-direction-private.h',
'hdy-shadow-helper-private.h',

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Wed, 14 Oct 2020 16:29:45 +0500
Subject: Add GtkHdyNavigationDirection
This is imported from HdyNavigationDirection from libhandy 1.0.0.
---
gtk/gtkprivate.h | 1 +
gtk/hdy-navigation-direction-private.h | 22 ++++++++++++++++++++++
gtk/hdy-navigation-direction.c | 26 ++++++++++++++++++++++++++
gtk/meson.build | 2 ++
4 files changed, 51 insertions(+)
create mode 100644 gtk/hdy-navigation-direction-private.h
create mode 100644 gtk/hdy-navigation-direction.c
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index 68f0f8d..8c6eded 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -30,6 +30,7 @@
#include "gtkcsstypesprivate.h"
#include "gtktexthandleprivate.h"
+#include "hdy-navigation-direction-private.h"
#include "hdy-squeezer-private.h"
#include "hdy-view-switcher-private.h"
diff --git a/gtk/hdy-navigation-direction-private.h b/gtk/hdy-navigation-direction-private.h
new file mode 100644
index 0000000..2f2f184
--- /dev/null
+++ b/gtk/hdy-navigation-direction-private.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 Alexander Mikhaylenko <exalm7659@gmail.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GTK_HDY_NAVIGATION_DIRECTION_BACK,
+ GTK_HDY_NAVIGATION_DIRECTION_FORWARD,
+} GtkHdyNavigationDirection;
+
+G_END_DECLS
diff --git a/gtk/hdy-navigation-direction.c b/gtk/hdy-navigation-direction.c
new file mode 100644
index 0000000..35b9ab4
--- /dev/null
+++ b/gtk/hdy-navigation-direction.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 Alexander Mikhaylenko <exalm7659@gmail.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+#include "hdy-navigation-direction-private.h"
+
+/**
+ * SECTION:gtk-hdy-navigation-direction
+ * @short_description: Swipe navigation directions.
+ * @title: GtkHdyNavigationDirection
+ * @See_also: #GtkHdyDeck, #GtkHdyLeaflet
+ */
+
+/**
+ * GtkHdyNavigationDirection:
+ * @GTK_HDY_NAVIGATION_DIRECTION_BACK: Corresponds to start or top, depending on orientation and text direction
+ * @GTK_HDY_NAVIGATION_DIRECTION_FORWARD: Corresponds to end or bottom, depending on orientation and text direction
+ *
+ * Represents direction of a swipe navigation gesture in #GtkHdyDeck and
+ * #GtkHdyLeaflet.
+ *
+ * Since: 1.0
+ */
diff --git a/gtk/meson.build b/gtk/meson.build
index ae3dc94..7407f5b 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -385,6 +385,7 @@ gtk_sources = files(
'gdkpixbufutils.c',
'hdy-animation.c',
'hdy-css.c',
+ 'hdy-navigation-direction.c',
'hdy-shadow-helper.c',
'hdy-squeezer.c',
'hdy-view-switcher-bar.c',
@@ -401,6 +402,7 @@ gtk_private_type_headers = files(
'hdy-animation-private.h',
'hdy-cairo-private.h',
'hdy-css-private.h',
+ 'hdy-navigation-direction-private.h',
'hdy-shadow-helper-private.h',
'hdy-squeezer-private.h',
'hdy-view-switcher-bar-private.h',

View file

@ -0,0 +1,535 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Wed, 14 Oct 2020 16:05:39 +0500
Subject: Add GtkHdyShadowHelper
This is imported from HdyShadowHelper from libhandy 1.0.2.
---
gtk/hdy-shadow-helper-private.h | 37 ++++
gtk/hdy-shadow-helper.c | 453 ++++++++++++++++++++++++++++++++++++++++
gtk/meson.build | 2 +
3 files changed, 492 insertions(+)
create mode 100644 gtk/hdy-shadow-helper-private.h
create mode 100644 gtk/hdy-shadow-helper.c
diff --git a/gtk/hdy-shadow-helper-private.h b/gtk/hdy-shadow-helper-private.h
new file mode 100644
index 0000000..1b34ddb
--- /dev/null
+++ b/gtk/hdy-shadow-helper-private.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 Alexander Mikhaylenko <exalm7659@gmail.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include "gtkenums.h"
+#include "gtkwidget.h"
+#include "gtkwidgetpath.h"
+
+G_BEGIN_DECLS
+
+#define GTK_HDY_TYPE_SHADOW_HELPER (gtk_hdy_shadow_helper_get_type())
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkStyleContext, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWidgetPath, gtk_widget_path_unref)
+
+G_DECLARE_FINAL_TYPE (GtkHdyShadowHelper, gtk_hdy_shadow_helper, GTK, HDY_SHADOW_HELPER, GObject)
+
+GtkHdyShadowHelper * gtk_hdy_shadow_helper_new (GtkWidget *widget);
+
+void gtk_hdy_shadow_helper_clear_cache (GtkHdyShadowHelper *self);
+
+void gtk_hdy_shadow_helper_draw_shadow (GtkHdyShadowHelper *self,
+ cairo_t *cr,
+ gint width,
+ gint height,
+ gdouble progress,
+ GtkPanDirection direction);
+
+G_END_DECLS
diff --git a/gtk/hdy-shadow-helper.c b/gtk/hdy-shadow-helper.c
new file mode 100644
index 0000000..69583c4
--- /dev/null
+++ b/gtk/hdy-shadow-helper.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2019 Alexander Mikhaylenko <exalm7659@gmail.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "hdy-shadow-helper-private.h"
+
+#include "gtkrender.h"
+#include "gtkstylecontext.h"
+#include "gtktypebuiltins.h"
+#include "gtkwidgetpath.h"
+#include "hdy-cairo-private.h"
+
+#include <math.h>
+
+/**
+ * PRIVATE:gtk-hdy-shadow-helper
+ * @short_description: Shadow helper used in #GtkHdyLeaflet
+ * @title: GtkHdyShadowHelper
+ * @See_also: #GtkHdyLeaflet
+ * @stability: Private
+ *
+ * A helper class for drawing #GtkHdyLeaflet transition shadow.
+ *
+ * Since: 0.0.12
+ */
+
+struct _GtkHdyShadowHelper
+{
+ GObject parent_instance;
+
+ GtkWidget *widget;
+
+ gboolean is_cache_valid;
+
+ cairo_pattern_t *dimming_pattern;
+ cairo_pattern_t *shadow_pattern;
+ cairo_pattern_t *border_pattern;
+ cairo_pattern_t *outline_pattern;
+ gint shadow_size;
+ gint border_size;
+ gint outline_size;
+
+ GtkPanDirection last_direction;
+ gint last_width;
+ gint last_height;
+ gint last_scale;
+};
+
+G_DEFINE_TYPE (GtkHdyShadowHelper, gtk_hdy_shadow_helper, G_TYPE_OBJECT);
+
+enum {
+ PROP_0,
+ PROP_WIDGET,
+ LAST_PROP,
+};
+
+static GParamSpec *props[LAST_PROP];
+
+
+static GtkStyleContext *
+create_context (GtkHdyShadowHelper *self,
+ const gchar *name,
+ GtkPanDirection direction)
+{
+ g_autoptr(GtkWidgetPath) path = NULL;
+ GtkStyleContext *context;
+ gint pos;
+ const gchar *direction_name;
+ GEnumClass *enum_class;
+
+ enum_class = g_type_class_ref (GTK_TYPE_PAN_DIRECTION);
+ direction_name = g_enum_get_value (enum_class, direction)->value_nick;
+
+ path = gtk_widget_path_copy (gtk_widget_get_path (self->widget));
+
+ pos = gtk_widget_path_append_type (path, GTK_TYPE_WIDGET);
+ gtk_widget_path_iter_set_object_name (path, pos, name);
+
+ gtk_widget_path_iter_add_class (path, pos, direction_name);
+
+ context = gtk_style_context_new ();
+ gtk_style_context_set_path (context, path);
+
+ g_type_class_unref (enum_class);
+
+ return context;
+}
+
+static gint
+get_element_size (GtkStyleContext *context,
+ GtkPanDirection direction)
+{
+ gint width, height;
+
+ gtk_style_context_get (context,
+ gtk_style_context_get_state (context),
+ "min-width", &width,
+ "min-height", &height,
+ NULL);
+
+ switch (direction) {
+ case GTK_PAN_DIRECTION_LEFT:
+ case GTK_PAN_DIRECTION_RIGHT:
+ return width;
+ case GTK_PAN_DIRECTION_UP:
+ case GTK_PAN_DIRECTION_DOWN:
+ return height;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return 0;
+}
+
+static cairo_pattern_t *
+create_element_pattern (GtkStyleContext *context,
+ gint width,
+ gint height,
+ gint scale)
+{
+ g_autoptr (cairo_surface_t) surface =
+ cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width * scale, height * scale);
+ g_autoptr (cairo_t) cr = cairo_create (surface);
+ cairo_pattern_t *pattern;
+
+ cairo_surface_set_device_scale (surface, scale, scale);
+
+ gtk_render_background (context, cr, 0, 0, width, height);
+ gtk_render_frame (context, cr, 0, 0, width, height);
+
+ pattern = cairo_pattern_create_for_surface (surface);
+
+ return pattern;
+}
+
+static void
+cache_shadow (GtkHdyShadowHelper *self,
+ gint width,
+ gint height,
+ GtkPanDirection direction)
+{
+ g_autoptr(GtkStyleContext) dim_context = NULL;
+ g_autoptr(GtkStyleContext) shadow_context = NULL;
+ g_autoptr(GtkStyleContext) border_context = NULL;
+ g_autoptr(GtkStyleContext) outline_context = NULL;
+ gint shadow_size, border_size, outline_size, scale;
+
+ scale = gtk_widget_get_scale_factor (self->widget);
+
+ if (self->last_direction == direction &&
+ self->last_width == width &&
+ self->last_height == height &&
+ self->last_scale == scale &&
+ self->is_cache_valid)
+ return;
+
+ gtk_hdy_shadow_helper_clear_cache (self);
+
+ dim_context = create_context (self, "dimming", direction);
+ shadow_context = create_context (self, "shadow", direction);
+ border_context = create_context (self, "border", direction);
+ outline_context = create_context (self, "outline", direction);
+
+ shadow_size = get_element_size (shadow_context, direction);
+ border_size = get_element_size (border_context, direction);
+ outline_size = get_element_size (outline_context, direction);
+
+ self->dimming_pattern = create_element_pattern (dim_context, width, height, scale);
+ if (direction == GTK_PAN_DIRECTION_LEFT || direction == GTK_PAN_DIRECTION_RIGHT) {
+ self->shadow_pattern = create_element_pattern (shadow_context, shadow_size, height, scale);
+ self->border_pattern = create_element_pattern (border_context, border_size, height, scale);
+ self->outline_pattern = create_element_pattern (outline_context, outline_size, height, scale);
+ } else {
+ self->shadow_pattern = create_element_pattern (shadow_context, width, shadow_size, scale);
+ self->border_pattern = create_element_pattern (border_context, width, border_size, scale);
+ self->outline_pattern = create_element_pattern (outline_context, width, outline_size, scale);
+ }
+
+ self->border_size = border_size;
+ self->shadow_size = shadow_size;
+ self->outline_size = outline_size;
+
+ self->is_cache_valid = TRUE;
+ self->last_direction = direction;
+ self->last_width = width;
+ self->last_height = height;
+ self->last_scale = scale;
+}
+
+static void
+gtk_hdy_shadow_helper_dispose (GObject *object)
+{
+ GtkHdyShadowHelper *self = GTK_HDY_SHADOW_HELPER (object);
+
+ gtk_hdy_shadow_helper_clear_cache (self);
+
+ if (self->widget)
+ g_clear_object (&self->widget);
+
+ G_OBJECT_CLASS (gtk_hdy_shadow_helper_parent_class)->dispose (object);
+}
+
+static void
+gtk_hdy_shadow_helper_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyShadowHelper *self = GTK_HDY_SHADOW_HELPER (object);
+
+ switch (prop_id) {
+ case PROP_WIDGET:
+ g_value_set_object (value, self->widget);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_hdy_shadow_helper_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyShadowHelper *self = GTK_HDY_SHADOW_HELPER (object);
+
+ switch (prop_id) {
+ case PROP_WIDGET:
+ self->widget = GTK_WIDGET (g_object_ref (g_value_get_object (value)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_hdy_shadow_helper_class_init (GtkHdyShadowHelperClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gtk_hdy_shadow_helper_dispose;
+ object_class->get_property = gtk_hdy_shadow_helper_get_property;
+ object_class->set_property = gtk_hdy_shadow_helper_set_property;
+
+ /**
+ * GtkHdyShadowHelper:widget:
+ *
+ * The widget the shadow will be drawn for. Must not be %NULL
+ *
+ * Since: 0.0.11
+ */
+ props[PROP_WIDGET] =
+ g_param_spec_object ("widget",
+ _("Widget"),
+ _("The widget the shadow will be drawn for"),
+ GTK_TYPE_WIDGET,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+}
+
+static void
+gtk_hdy_shadow_helper_init (GtkHdyShadowHelper *self)
+{
+}
+
+/**
+ * gtk_hdy_shadow_helper_new:
+ *
+ * Creates a new #GtkHdyShadowHelper object.
+ *
+ * Returns: The newly created #GtkHdyShadowHelper object
+ *
+ * Since: 0.0.12
+ */
+GtkHdyShadowHelper *
+gtk_hdy_shadow_helper_new (GtkWidget *widget)
+{
+ return g_object_new (GTK_HDY_TYPE_SHADOW_HELPER,
+ "widget", widget,
+ NULL);
+}
+
+/**
+ * gtk_hdy_shadow_helper_clear_cache:
+ * @self: a #GtkHdyShadowHelper
+ *
+ * Clears shadow cache. This should be used after a transition is done.
+ *
+ * Since: 0.0.12
+ */
+void
+gtk_hdy_shadow_helper_clear_cache (GtkHdyShadowHelper *self)
+{
+ if (!self->is_cache_valid)
+ return;
+
+ cairo_pattern_destroy (self->dimming_pattern);
+ cairo_pattern_destroy (self->shadow_pattern);
+ cairo_pattern_destroy (self->border_pattern);
+ cairo_pattern_destroy (self->outline_pattern);
+ self->border_size = 0;
+ self->shadow_size = 0;
+ self->outline_size = 0;
+
+ self->last_direction = 0;
+ self->last_width = 0;
+ self->last_height = 0;
+ self->last_scale = 0;
+
+ self->is_cache_valid = FALSE;
+}
+
+/**
+ * gtk_hdy_shadow_helper_draw_shadow:
+ * @self: a #GtkHdyShadowHelper
+ * @cr: a Cairo context to draw to
+ * @width: the width of the shadow rectangle
+ * @height: the height of the shadow rectangle
+ * @progress: transition progress, changes from 0 to 1
+ * @direction: shadow direction
+ *
+ * Draws a transition shadow. For caching to work, @width, @height and
+ * @direction shouldn't change between calls.
+ *
+ * Since: 0.0.12
+ */
+void
+gtk_hdy_shadow_helper_draw_shadow (GtkHdyShadowHelper *self,
+ cairo_t *cr,
+ gint width,
+ gint height,
+ gdouble progress,
+ GtkPanDirection direction)
+{
+ gdouble remaining_distance, shadow_opacity;
+ gint shadow_size, border_size, outline_size, distance;
+
+ if (progress >= 1)
+ return;
+
+ cache_shadow (self, width, height, direction);
+
+ shadow_size = self->shadow_size;
+ border_size = self->border_size;
+ outline_size = self->outline_size;
+
+ switch (direction) {
+ case GTK_PAN_DIRECTION_LEFT:
+ case GTK_PAN_DIRECTION_RIGHT:
+ distance = width;
+ break;
+ case GTK_PAN_DIRECTION_UP:
+ case GTK_PAN_DIRECTION_DOWN:
+ distance = height;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ remaining_distance = (1 - progress) * (gdouble) distance;
+ shadow_opacity = 1;
+ if (remaining_distance < shadow_size)
+ shadow_opacity = (remaining_distance / shadow_size);
+
+ cairo_save (cr);
+
+ switch (direction) {
+ case GTK_PAN_DIRECTION_LEFT:
+ cairo_rectangle (cr, -outline_size, 0, width + outline_size, height);
+ break;
+ case GTK_PAN_DIRECTION_RIGHT:
+ cairo_rectangle (cr, 0, 0, width + outline_size, height);
+ break;
+ case GTK_PAN_DIRECTION_UP:
+ cairo_rectangle (cr, 0, -outline_size, width, height + outline_size);
+ break;
+ case GTK_PAN_DIRECTION_DOWN:
+ cairo_rectangle (cr, 0, 0, width, height + outline_size);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ cairo_clip (cr);
+ gdk_window_mark_paint_from_clip (gtk_widget_get_window (self->widget), cr);
+
+ cairo_set_source (cr, self->dimming_pattern);
+ cairo_paint_with_alpha (cr, 1 - progress);
+
+ switch (direction) {
+ case GTK_PAN_DIRECTION_RIGHT:
+ cairo_translate (cr, width - shadow_size, 0);
+ break;
+ case GTK_PAN_DIRECTION_DOWN:
+ cairo_translate (cr, 0, height - shadow_size);
+ break;
+ case GTK_PAN_DIRECTION_LEFT:
+ case GTK_PAN_DIRECTION_UP:
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ cairo_set_source (cr, self->shadow_pattern);
+ cairo_paint_with_alpha (cr, shadow_opacity);
+
+ switch (direction) {
+ case GTK_PAN_DIRECTION_RIGHT:
+ cairo_translate (cr, shadow_size - border_size, 0);
+ break;
+ case GTK_PAN_DIRECTION_DOWN:
+ cairo_translate (cr, 0, shadow_size - border_size);
+ break;
+ case GTK_PAN_DIRECTION_LEFT:
+ case GTK_PAN_DIRECTION_UP:
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ cairo_set_source (cr, self->border_pattern);
+ cairo_paint (cr);
+
+ switch (direction) {
+ case GTK_PAN_DIRECTION_RIGHT:
+ cairo_translate (cr, border_size, 0);
+ break;
+ case GTK_PAN_DIRECTION_DOWN:
+ cairo_translate (cr, 0, border_size);
+ break;
+ case GTK_PAN_DIRECTION_LEFT:
+ cairo_translate (cr, -outline_size, 0);
+ break;
+ case GTK_PAN_DIRECTION_UP:
+ cairo_translate (cr, 0, -outline_size);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ cairo_set_source (cr, self->outline_pattern);
+ cairo_paint (cr);
+
+ cairo_restore (cr);
+}
diff --git a/gtk/meson.build b/gtk/meson.build
index 4b3e871..ae3dc94 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -385,6 +385,7 @@ gtk_sources = files(
'gdkpixbufutils.c',
'hdy-animation.c',
'hdy-css.c',
+ 'hdy-shadow-helper.c',
'hdy-squeezer.c',
'hdy-view-switcher-bar.c',
'hdy-view-switcher-button.c',
@@ -400,6 +401,7 @@ gtk_private_type_headers = files(
'hdy-animation-private.h',
'hdy-cairo-private.h',
'hdy-css-private.h',
+ 'hdy-shadow-helper-private.h',
'hdy-squeezer-private.h',
'hdy-view-switcher-bar-private.h',
'hdy-view-switcher-button-private.h',

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,953 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Mon, 31 Aug 2020 10:40:08 +0200
Subject: Add GtkHdyViewSwitcher
This is imported from HdyViewSwitcher from libhandy 1.0.1.
---
gtk/gtkprivate.h | 1 +
gtk/hdy-css-private.h | 25 ++
gtk/hdy-css.c | 74 ++++
gtk/hdy-view-switcher-private.h | 43 +++
gtk/hdy-view-switcher.c | 733 ++++++++++++++++++++++++++++++++++++++++
gtk/meson.build | 4 +
6 files changed, 880 insertions(+)
create mode 100644 gtk/hdy-css-private.h
create mode 100644 gtk/hdy-css.c
create mode 100644 gtk/hdy-view-switcher-private.h
create mode 100644 gtk/hdy-view-switcher.c
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index dcab28d..473bb99 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -30,6 +30,7 @@
#include "gtkcsstypesprivate.h"
#include "gtktexthandleprivate.h"
+#include "hdy-view-switcher-private.h"
G_BEGIN_DECLS
diff --git a/gtk/hdy-css-private.h b/gtk/hdy-css-private.h
new file mode 100644
index 0000000..3f5fca8
--- /dev/null
+++ b/gtk/hdy-css-private.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include "gtkwidget.h"
+
+G_BEGIN_DECLS
+
+void gtk_hdy_css_measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ gint *minimum,
+ gint *natural);
+
+void gtk_hdy_css_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+
+G_END_DECLS
diff --git a/gtk/hdy-css.c b/gtk/hdy-css.c
new file mode 100644
index 0000000..16cbc01
--- /dev/null
+++ b/gtk/hdy-css.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "hdy-css-private.h"
+#include "gtkstylecontext.h"
+
+void
+gtk_hdy_css_measure (GtkWidget *widget,
+ GtkOrientation orientation,
+ gint *minimum,
+ gint *natural)
+{
+ GtkStyleContext *style_context = gtk_widget_get_style_context (widget);
+ GtkStateFlags state_flags = gtk_widget_get_state_flags (widget);
+ GtkBorder border, margin, padding;
+ gint css_width, css_height;
+
+ /* Manually apply minimum sizes, the border, the padding and the margin as we
+ * can't use the private GtkGagdet.
+ */
+ gtk_style_context_get (style_context, state_flags,
+ "min-width", &css_width,
+ "min-height", &css_height,
+ NULL);
+ gtk_style_context_get_border (style_context, state_flags, &border);
+ gtk_style_context_get_margin (style_context, state_flags, &margin);
+ gtk_style_context_get_padding (style_context, state_flags, &padding);
+ if (orientation == GTK_ORIENTATION_VERTICAL) {
+ *minimum = MAX (*minimum, css_height) +
+ border.top + margin.top + padding.top +
+ border.bottom + margin.bottom + padding.bottom;
+ *natural = MAX (*natural, css_height) +
+ border.top + margin.top + padding.top +
+ border.bottom + margin.bottom + padding.bottom;
+ } else {
+ *minimum = MAX (*minimum, css_width) +
+ border.left + margin.left + padding.left +
+ border.right + margin.right + padding.right;
+ *natural = MAX (*natural, css_width) +
+ border.left + margin.left + padding.left +
+ border.right + margin.right + padding.right;
+ }
+}
+
+void
+gtk_hdy_css_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkStyleContext *style_context;
+ GtkStateFlags state_flags;
+ GtkBorder border, margin, padding;
+
+ /* Manually apply the border, the padding and the margin as we can't use the
+ * private GtkGagdet.
+ */
+ style_context = gtk_widget_get_style_context (widget);
+ state_flags = gtk_widget_get_state_flags (widget);
+ gtk_style_context_get_border (style_context, state_flags, &border);
+ gtk_style_context_get_margin (style_context, state_flags, &margin);
+ gtk_style_context_get_padding (style_context, state_flags, &padding);
+ allocation->width -= border.left + border.right +
+ margin.left + margin.right +
+ padding.left + padding.right;
+ allocation->height -= border.top + border.bottom +
+ margin.top + margin.bottom +
+ padding.top + padding.bottom;
+ allocation->x += border.left + margin.left + padding.left;
+ allocation->y += border.top + margin.top + padding.top;
+}
diff --git a/gtk/hdy-view-switcher-private.h b/gtk/hdy-view-switcher-private.h
new file mode 100644
index 0000000..6267afd
--- /dev/null
+++ b/gtk/hdy-view-switcher-private.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 Zander Brown <zbrown@gnome.org>
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include "gtkbin.h"
+#include "gtkstack.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_HDY_VIEW_SWITCHER (gtk_hdy_view_switcher_get_type())
+
+typedef enum {
+ GTK_HDY_VIEW_SWITCHER_POLICY_AUTO,
+ GTK_HDY_VIEW_SWITCHER_POLICY_NARROW,
+ GTK_HDY_VIEW_SWITCHER_POLICY_WIDE,
+} GtkHdyViewSwitcherPolicy;
+
+G_DECLARE_FINAL_TYPE (GtkHdyViewSwitcher, gtk_hdy_view_switcher, GTK, HDY_VIEW_SWITCHER, GtkBin)
+
+GtkWidget *hdy_view_switcher_new (void);
+
+GtkHdyViewSwitcherPolicy gtk_hdy_view_switcher_get_policy (GtkHdyViewSwitcher *self);
+void gtk_hdy_view_switcher_set_policy (GtkHdyViewSwitcher *self,
+ GtkHdyViewSwitcherPolicy policy);
+
+PangoEllipsizeMode gtk_hdy_view_switcher_get_narrow_ellipsize (GtkHdyViewSwitcher *self);
+void gtk_hdy_view_switcher_set_narrow_ellipsize (GtkHdyViewSwitcher *self,
+ PangoEllipsizeMode mode);
+
+GtkStack *gtk_hdy_view_switcher_get_stack (GtkHdyViewSwitcher *self);
+void gtk_hdy_view_switcher_set_stack (GtkHdyViewSwitcher *self,
+ GtkStack *stack);
+
+G_END_DECLS
diff --git a/gtk/hdy-view-switcher.c b/gtk/hdy-view-switcher.c
new file mode 100644
index 0000000..2664b3e
--- /dev/null
+++ b/gtk/hdy-view-switcher.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) 2019 Zander Brown <zbrown@gnome.org>
+ * Copyright (C) 2019 Purism SPC
+ *
+ * Based on gtkstackswitcher.c, Copyright (c) 2013 Red Hat, Inc.
+ * https://gitlab.gnome.org/GNOME/gtk/blob/a0129f556b1fd655215165739d0277d7f7a2c1a8/gtk/gtkstackswitcher.c
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "gtkbox.h"
+#include "gtkdragdest.h"
+#include "gtkorientable.h"
+#include "gtkprivatetypebuiltins.h"
+#include "hdy-css-private.h"
+#include "hdy-view-switcher-button-private.h"
+#include "hdy-view-switcher-private.h"
+
+/**
+ * SECTION:gtk-hdy-view-switcher
+ * @short_description: An adaptive view switcher.
+ * @title: GtkHdyViewSwitcher
+ *
+ * An adaptive view switcher, designed to switch between multiple views in a
+ * similar fashion than a #GtkStackSwitcher.
+ *
+ * Depending on the available width, the view switcher can adapt from a wide
+ * mode showing the view's icon and title side by side, to a narrow mode showing
+ * the view's icon and title one on top of the other, in a more compact way.
+ * This can be controlled via the policy property.
+ *
+ * To look good in a header bar, an #GtkHdyViewSwitcher requires to fill its full
+ * height. Contrary to #GtkHeaderBar, #GtkHdyHeaderBar doesn't force a vertical
+ * alignment on its title widget, so we recommend it over #GtkHeaderBar.
+ *
+ * # CSS nodes
+ *
+ * #GtkHdyViewSwitcher has a single CSS node with name viewswitcher.
+ *
+ * Since: 0.0.10
+ */
+
+#define MIN_NAT_BUTTON_WIDTH 100
+#define TIMEOUT_EXPAND 500
+
+enum {
+ PROP_0,
+ PROP_POLICY,
+ PROP_NARROW_ELLIPSIZE,
+ PROP_STACK,
+ LAST_PROP,
+};
+
+struct _GtkHdyViewSwitcher
+{
+ GtkBin parent_instance;
+
+ GtkWidget *box;
+ GHashTable *buttons;
+ gboolean in_child_changed;
+ GtkWidget *switch_button;
+ guint switch_timer;
+
+ GtkHdyViewSwitcherPolicy policy;
+ PangoEllipsizeMode narrow_ellipsize;
+ GtkStack *stack;
+};
+
+static GParamSpec *props[LAST_PROP];
+
+G_DEFINE_TYPE (GtkHdyViewSwitcher, gtk_hdy_view_switcher, GTK_TYPE_BIN)
+
+static void
+set_visible_stack_child_for_button (GtkHdyViewSwitcher *self,
+ GtkHdyViewSwitcherButton *button)
+{
+ if (self->in_child_changed)
+ return;
+
+ gtk_stack_set_visible_child (self->stack, GTK_WIDGET (g_object_get_data (G_OBJECT (button), "stack-child")));
+}
+
+static void
+update_button (GtkHdyViewSwitcher *self,
+ GtkWidget *widget,
+ GtkHdyViewSwitcherButton *button)
+{
+ g_autofree gchar *title = NULL;
+ g_autofree gchar *icon_name = NULL;
+ gboolean needs_attention;
+
+ gtk_container_child_get (GTK_CONTAINER (self->stack), widget,
+ "title", &title,
+ "icon-name", &icon_name,
+ "needs-attention", &needs_attention,
+ NULL);
+
+ g_object_set (G_OBJECT (button),
+ "icon-name", icon_name,
+ "icon-size", GTK_ICON_SIZE_BUTTON,
+ "label", title,
+ "needs-attention", needs_attention,
+ NULL);
+
+ gtk_widget_set_visible (GTK_WIDGET (button),
+ gtk_widget_get_visible (widget) && (title != NULL || icon_name != NULL));
+}
+
+static void
+on_stack_child_updated (GtkWidget *widget,
+ GParamSpec *pspec,
+ GtkHdyViewSwitcher *self)
+{
+ update_button (self, widget, g_hash_table_lookup (self->buttons, widget));
+}
+
+static void
+on_position_updated (GtkWidget *widget,
+ GParamSpec *pspec,
+ GtkHdyViewSwitcher *self)
+{
+ GtkWidget *button = g_hash_table_lookup (self->buttons, widget);
+ gint position;
+
+ gtk_container_child_get (GTK_CONTAINER (self->stack), widget,
+ "position", &position,
+ NULL);
+ gtk_box_reorder_child (GTK_BOX (self->box), button, position);
+}
+
+static void
+remove_switch_timer (GtkHdyViewSwitcher *self)
+{
+ if (!self->switch_timer)
+ return;
+
+ g_source_remove (self->switch_timer);
+ self->switch_timer = 0;
+}
+
+static gboolean
+gtk_hdy_view_switcher_switch_timeout (gpointer data)
+{
+ GtkHdyViewSwitcher *self = GTK_HDY_VIEW_SWITCHER (data);
+ GtkWidget *button = self->switch_button;
+
+ self->switch_timer = 0;
+ self->switch_button = NULL;
+
+ if (button)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean
+gtk_hdy_view_switcher_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ GtkHdyViewSwitcher *self = GTK_HDY_VIEW_SWITCHER (widget);
+ GtkAllocation allocation;
+ GtkWidget *button;
+ GHashTableIter iter;
+ gpointer value;
+ gboolean retval = FALSE;
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ x += allocation.x;
+ y += allocation.y;
+
+ button = NULL;
+ g_hash_table_iter_init (&iter, self->buttons);
+ while (g_hash_table_iter_next (&iter, NULL, &value)) {
+ gtk_widget_get_allocation (GTK_WIDGET (value), &allocation);
+ if (x >= allocation.x && x <= allocation.x + allocation.width &&
+ y >= allocation.y && y <= allocation.y + allocation.height) {
+ button = GTK_WIDGET (value);
+ retval = TRUE;
+
+ break;
+ }
+ }
+
+ if (button != self->switch_button)
+ remove_switch_timer (self);
+
+ self->switch_button = button;
+
+ if (button && !self->switch_timer) {
+ self->switch_timer = gdk_threads_add_timeout (TIMEOUT_EXPAND,
+ gtk_hdy_view_switcher_switch_timeout,
+ self);
+ g_source_set_name_by_id (self->switch_timer, "[gtk+] gtk_hdy_view_switcher_switch_timeout");
+ }
+
+ return retval;
+}
+
+static void
+gtk_hdy_view_switcher_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time)
+{
+ GtkHdyViewSwitcher *self = GTK_HDY_VIEW_SWITCHER (widget);
+
+ remove_switch_timer (self);
+}
+
+static void
+add_button_for_stack_child (GtkHdyViewSwitcher *self,
+ GtkWidget *stack_child)
+{
+ g_autoptr (GList) children = gtk_container_get_children (GTK_CONTAINER (self->box));
+ GtkHdyViewSwitcherButton *button = GTK_HDY_VIEW_SWITCHER_BUTTON (gtk_hdy_view_switcher_button_new ());
+
+ g_object_set_data (G_OBJECT (button), "stack-child", stack_child);
+ gtk_hdy_view_switcher_button_set_narrow_ellipsize (button, self->narrow_ellipsize);
+
+ update_button (self, stack_child, button);
+
+ if (children != NULL)
+ gtk_radio_button_join_group (GTK_RADIO_BUTTON (button), GTK_RADIO_BUTTON (children->data));
+
+ gtk_container_add (GTK_CONTAINER (self->box), GTK_WIDGET (button));
+
+ g_signal_connect_swapped (button, "clicked", G_CALLBACK (set_visible_stack_child_for_button), self);
+ g_signal_connect (stack_child, "notify::visible", G_CALLBACK (on_stack_child_updated), self);
+ g_signal_connect (stack_child, "child-notify::title", G_CALLBACK (on_stack_child_updated), self);
+ g_signal_connect (stack_child, "child-notify::icon-name", G_CALLBACK (on_stack_child_updated), self);
+ g_signal_connect (stack_child, "child-notify::needs-attention", G_CALLBACK (on_stack_child_updated), self);
+ g_signal_connect (stack_child, "child-notify::position", G_CALLBACK (on_position_updated), self);
+
+ g_hash_table_insert (self->buttons, stack_child, button);
+}
+
+static void
+add_button_for_stack_child_cb (GtkWidget *stack_child,
+ GtkHdyViewSwitcher *self)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER (self));
+ g_return_if_fail (GTK_IS_WIDGET (stack_child));
+
+ add_button_for_stack_child (self, stack_child);
+}
+
+static void
+remove_button_for_stack_child (GtkHdyViewSwitcher *self,
+ GtkWidget *stack_child)
+{
+ g_signal_handlers_disconnect_by_func (stack_child, on_stack_child_updated, self);
+ g_signal_handlers_disconnect_by_func (stack_child, on_position_updated, self);
+ gtk_container_remove (GTK_CONTAINER (self->box), g_hash_table_lookup (self->buttons, stack_child));
+ g_hash_table_remove (self->buttons, stack_child);
+}
+
+static void
+remove_button_for_stack_child_cb (GtkWidget *stack_child,
+ GtkHdyViewSwitcher *self)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER (self));
+ g_return_if_fail (GTK_IS_WIDGET (stack_child));
+
+ remove_button_for_stack_child (self, stack_child);
+}
+
+static void
+update_active_button_for_visible_stack_child (GtkHdyViewSwitcher *self)
+{
+ GtkWidget *visible_stack_child = gtk_stack_get_visible_child (self->stack);
+ GtkWidget *button = g_hash_table_lookup (self->buttons, visible_stack_child);
+
+ if (button == NULL)
+ return;
+
+ self->in_child_changed = TRUE;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+ self->in_child_changed = FALSE;
+}
+
+static void
+disconnect_stack_signals (GtkHdyViewSwitcher *self)
+{
+ g_signal_handlers_disconnect_by_func (self->stack, add_button_for_stack_child, self);
+ g_signal_handlers_disconnect_by_func (self->stack, remove_button_for_stack_child, self);
+ g_signal_handlers_disconnect_by_func (self->stack, update_active_button_for_visible_stack_child, self);
+ g_signal_handlers_disconnect_by_func (self->stack, disconnect_stack_signals, self);
+}
+
+static void
+connect_stack_signals (GtkHdyViewSwitcher *self)
+{
+ g_signal_connect_object (self->stack, "add",
+ G_CALLBACK (add_button_for_stack_child), self,
+ G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+ g_signal_connect_object (self->stack, "remove",
+ G_CALLBACK (remove_button_for_stack_child), self,
+ G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+ g_signal_connect_object (self->stack, "notify::visible-child",
+ G_CALLBACK (update_active_button_for_visible_stack_child), self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (self->stack, "destroy",
+ G_CALLBACK (disconnect_stack_signals), self,
+ G_CONNECT_SWAPPED);
+}
+
+static void
+gtk_hdy_view_switcher_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyViewSwitcher *self = GTK_HDY_VIEW_SWITCHER (object);
+
+ switch (prop_id) {
+ case PROP_POLICY:
+ g_value_set_enum (value, gtk_hdy_view_switcher_get_policy (self));
+ break;
+ case PROP_NARROW_ELLIPSIZE:
+ g_value_set_enum (value, gtk_hdy_view_switcher_get_narrow_ellipsize (self));
+ break;
+ case PROP_STACK:
+ g_value_set_object (value, gtk_hdy_view_switcher_get_stack (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_hdy_view_switcher_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyViewSwitcher *self = GTK_HDY_VIEW_SWITCHER (object);
+
+ switch (prop_id) {
+ case PROP_POLICY:
+ gtk_hdy_view_switcher_set_policy (self, g_value_get_enum (value));
+ break;
+ case PROP_NARROW_ELLIPSIZE:
+ gtk_hdy_view_switcher_set_narrow_ellipsize (self, g_value_get_enum (value));
+ break;
+ case PROP_STACK:
+ gtk_hdy_view_switcher_set_stack (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_hdy_view_switcher_dispose (GObject *object)
+{
+ GtkHdyViewSwitcher *self = GTK_HDY_VIEW_SWITCHER (object);
+
+ remove_switch_timer (self);
+ gtk_hdy_view_switcher_set_stack (self, NULL);
+
+ G_OBJECT_CLASS (gtk_hdy_view_switcher_parent_class)->dispose (object);
+}
+
+static void
+gtk_hdy_view_switcher_finalize (GObject *object)
+{
+ GtkHdyViewSwitcher *self = GTK_HDY_VIEW_SWITCHER (object);
+
+ g_hash_table_destroy (self->buttons);
+
+ G_OBJECT_CLASS (gtk_hdy_view_switcher_parent_class)->finalize (object);
+}
+
+static void
+gtk_hdy_view_switcher_get_preferred_width (GtkWidget *widget,
+ gint *min,
+ gint *nat)
+{
+ GtkHdyViewSwitcher *self = GTK_HDY_VIEW_SWITCHER (widget);
+ g_autoptr (GList) children = gtk_container_get_children (GTK_CONTAINER (self->box));
+ gint max_h_min = 0, max_h_nat = 0, max_v_min = 0, max_v_nat = 0;
+ gint n_children = 0;
+
+ for (GList *l = children; l != NULL; l = g_list_next (l)) {
+ gint h_min = 0, h_nat = 0, v_min = 0, v_nat = 0;
+
+ if (!gtk_widget_get_visible (l->data))
+ continue;
+
+ gtk_hdy_view_switcher_button_get_size (GTK_HDY_VIEW_SWITCHER_BUTTON (l->data), &h_min, &h_nat, &v_min, &v_nat);
+ max_h_min = MAX (h_min, max_h_min);
+ max_h_nat = MAX (h_nat, max_h_nat);
+ max_v_min = MAX (v_min, max_v_min);
+ max_v_nat = MAX (v_nat, max_v_nat);
+
+ n_children++;
+ }
+
+ /* Make the buttons ask at least a minimum arbitrary size for their natural
+ * width. This prevents them from looking terribly narrow in a very wide bar.
+ */
+ max_h_nat = MAX (max_h_nat, MIN_NAT_BUTTON_WIDTH);
+ max_v_nat = MAX (max_v_nat, MIN_NAT_BUTTON_WIDTH);
+
+ switch (self->policy) {
+ case GTK_HDY_VIEW_SWITCHER_POLICY_NARROW:
+ *min = max_v_min * n_children;
+ *nat = max_v_nat * n_children;
+ break;
+ case GTK_HDY_VIEW_SWITCHER_POLICY_WIDE:
+ *min = max_h_min * n_children;
+ *nat = max_h_nat * n_children;
+ break;
+ case GTK_HDY_VIEW_SWITCHER_POLICY_AUTO:
+ default:
+ *min = max_v_min * n_children;
+ *nat = max_h_nat * n_children;
+ break;
+ }
+
+ gtk_hdy_css_measure (widget, GTK_ORIENTATION_HORIZONTAL, min, nat);
+}
+
+static gint
+is_narrow (GtkHdyViewSwitcher *self,
+ gint width)
+{
+ g_autoptr (GList) children = gtk_container_get_children (GTK_CONTAINER (self->box));
+ gint max_h_min = 0;
+ gint n_children = 0;
+
+ if (self->policy == GTK_HDY_VIEW_SWITCHER_POLICY_NARROW)
+ return TRUE;
+
+ if (self->policy == GTK_HDY_VIEW_SWITCHER_POLICY_WIDE)
+ return FALSE;
+
+ for (GList *l = children; l != NULL; l = g_list_next (l)) {
+ gint h_min = 0;
+
+ if (!gtk_widget_get_visible (l->data))
+ continue;
+
+ gtk_hdy_view_switcher_button_get_size (GTK_HDY_VIEW_SWITCHER_BUTTON (l->data), &h_min, NULL, NULL, NULL);
+ max_h_min = MAX (max_h_min, h_min);
+
+ n_children++;
+ }
+
+ return (max_h_min * n_children) > width;
+}
+
+static void
+gtk_hdy_view_switcher_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkHdyViewSwitcher *self = GTK_HDY_VIEW_SWITCHER (widget);
+
+ g_autoptr (GList) children = gtk_container_get_children (GTK_CONTAINER (self->box));
+ GtkOrientation orientation;
+
+ gtk_hdy_css_size_allocate (widget, allocation);
+
+ orientation = is_narrow (GTK_HDY_VIEW_SWITCHER (widget), allocation->width) ?
+ GTK_ORIENTATION_VERTICAL :
+ GTK_ORIENTATION_HORIZONTAL;
+
+ for (GList *l = children; l != NULL; l = g_list_next (l))
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (l->data), orientation);
+
+ GTK_WIDGET_CLASS (gtk_hdy_view_switcher_parent_class)->size_allocate (widget, allocation);
+}
+
+static void
+gtk_hdy_view_switcher_class_init (GtkHdyViewSwitcherClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->get_property = gtk_hdy_view_switcher_get_property;
+ object_class->set_property = gtk_hdy_view_switcher_set_property;
+ object_class->dispose = gtk_hdy_view_switcher_dispose;
+ object_class->finalize = gtk_hdy_view_switcher_finalize;
+
+ widget_class->size_allocate = gtk_hdy_view_switcher_size_allocate;
+ widget_class->get_preferred_width = gtk_hdy_view_switcher_get_preferred_width;
+ widget_class->drag_motion = gtk_hdy_view_switcher_drag_motion;
+ widget_class->drag_leave = gtk_hdy_view_switcher_drag_leave;
+
+ /**
+ * GtkHdyViewSwitcher:policy:
+ *
+ * The #GtkHdyViewSwitcherPolicy the view switcher should use to determine which
+ * mode to use.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_POLICY] =
+ g_param_spec_enum ("policy",
+ _("Policy"),
+ _("The policy to determine the mode to use"),
+ GTK_TYPE_HDY_VIEW_SWITCHER_POLICY, GTK_HDY_VIEW_SWITCHER_POLICY_AUTO,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkHdyViewSwitcher:narrow-ellipsize:
+ *
+ * The preferred place to ellipsize the string, if the narrow mode label does
+ * not have enough room to display the entire string, specified as a
+ * #PangoEllipsizeMode.
+ *
+ * Note that setting this property to a value other than %PANGO_ELLIPSIZE_NONE
+ * has the side-effect that the label requests only enough space to display
+ * the ellipsis.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_NARROW_ELLIPSIZE] =
+ g_param_spec_enum ("narrow-ellipsize",
+ _("Narrow ellipsize"),
+ _("The preferred place to ellipsize the string, if the narrow mode label does not have enough room to display the entire string"),
+ PANGO_TYPE_ELLIPSIZE_MODE,
+ PANGO_ELLIPSIZE_NONE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * GtkHdyViewSwitcher:stack:
+ *
+ * The #GtkStack the view switcher controls.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_STACK] =
+ g_param_spec_object ("stack",
+ _("Stack"),
+ _("Stack"),
+ GTK_TYPE_STACK,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+
+ gtk_widget_class_set_css_name (widget_class, "viewswitcher");
+}
+
+static void
+gtk_hdy_view_switcher_init (GtkHdyViewSwitcher *self)
+{
+ self->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_widget_show (self->box);
+ gtk_box_set_homogeneous (GTK_BOX (self->box), TRUE);
+ gtk_container_add (GTK_CONTAINER (self), self->box);
+
+ self->buttons = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ gtk_widget_set_valign (GTK_WIDGET (self), GTK_ALIGN_FILL);
+
+ gtk_drag_dest_set (GTK_WIDGET (self), 0, NULL, 0, 0);
+ gtk_drag_dest_set_track_motion (GTK_WIDGET (self), TRUE);
+}
+
+/**
+ * gtk_hdy_view_switcher_new:
+ *
+ * Creates a new #GtkHdyViewSwitcher widget.
+ *
+ * Returns: a new #GtkHdyViewSwitcher
+ *
+ * Since: 0.0.10
+ */
+GtkWidget *
+gtk_hdy_view_switcher_new (void)
+{
+ return g_object_new (GTK_TYPE_HDY_VIEW_SWITCHER, NULL);
+}
+
+/**
+ * gtk_hdy_view_switcher_get_policy:
+ * @self: a #GtkHdyViewSwitcher
+ *
+ * Gets the policy of @self.
+ *
+ * Returns: the policy of @self
+ *
+ * Since: 0.0.10
+ */
+GtkHdyViewSwitcherPolicy
+gtk_hdy_view_switcher_get_policy (GtkHdyViewSwitcher *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER (self), GTK_HDY_VIEW_SWITCHER_POLICY_AUTO);
+
+ return self->policy;
+}
+
+/**
+ * gtk_hdy_view_switcher_set_policy:
+ * @self: a #GtkHdyViewSwitcher
+ * @policy: the new policy
+ *
+ * Sets the policy of @self.
+ *
+ * Since: 0.0.10
+ */
+void
+gtk_hdy_view_switcher_set_policy (GtkHdyViewSwitcher *self,
+ GtkHdyViewSwitcherPolicy policy)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER (self));
+
+ if (self->policy == policy)
+ return;
+
+ self->policy = policy;
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_POLICY]);
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+/**
+ * gtk_hdy_view_switcher_get_narrow_ellipsize:
+ * @self: a #GtkHdyViewSwitcher
+ *
+ * Get the ellipsizing position of the narrow mode label. See
+ * gtk_hdy_view_switcher_set_narrow_ellipsize().
+ *
+ * Returns: #PangoEllipsizeMode
+ *
+ * Since: 0.0.10
+ **/
+PangoEllipsizeMode
+gtk_hdy_view_switcher_get_narrow_ellipsize (GtkHdyViewSwitcher *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER (self), PANGO_ELLIPSIZE_NONE);
+
+ return self->narrow_ellipsize;
+}
+
+/**
+ * gtk_hdy_view_switcher_set_narrow_ellipsize:
+ * @self: a #GtkHdyViewSwitcher
+ * @mode: a #PangoEllipsizeMode
+ *
+ * Set the mode used to ellipsize the text in narrow mode if there is not
+ * enough space to render the entire string.
+ *
+ * Since: 0.0.10
+ **/
+void
+gtk_hdy_view_switcher_set_narrow_ellipsize (GtkHdyViewSwitcher *self,
+ PangoEllipsizeMode mode)
+{
+ GHashTableIter iter;
+ gpointer button;
+
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER (self));
+ g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END);
+
+ if ((PangoEllipsizeMode) self->narrow_ellipsize == mode)
+ return;
+
+ self->narrow_ellipsize = mode;
+
+ g_hash_table_iter_init (&iter, self->buttons);
+ while (g_hash_table_iter_next (&iter, NULL, &button))
+ gtk_hdy_view_switcher_button_set_narrow_ellipsize (GTK_HDY_VIEW_SWITCHER_BUTTON (button), mode);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NARROW_ELLIPSIZE]);
+}
+
+/**
+ * gtk_hdy_view_switcher_get_stack:
+ * @self: a #GtkHdyViewSwitcher
+ *
+ * Get the #GtkStack being controlled by the #GtkHdyViewSwitcher.
+ *
+ * See: gtk_hdy_view_switcher_set_stack()
+ *
+ * Returns: (nullable) (transfer none): the #GtkStack, or %NULL if none has been set
+ *
+ * Since: 0.0.10
+ */
+GtkStack *
+gtk_hdy_view_switcher_get_stack (GtkHdyViewSwitcher *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER (self), NULL);
+
+ return self->stack;
+}
+
+/**
+ * gtk_hdy_view_switcher_set_stack:
+ * @self: a #GtkHdyViewSwitcher
+ * @stack: (nullable): a #GtkStack
+ *
+ * Sets the #GtkStack to control.
+ *
+ * Since: 0.0.10
+ */
+void
+gtk_hdy_view_switcher_set_stack (GtkHdyViewSwitcher *self,
+ GtkStack *stack)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER (self));
+ g_return_if_fail (stack == NULL || GTK_IS_STACK (stack));
+
+ if (self->stack == stack)
+ return;
+
+ if (self->stack) {
+ disconnect_stack_signals (self);
+ gtk_container_foreach (GTK_CONTAINER (self->stack), (GtkCallback) remove_button_for_stack_child_cb, self);
+ }
+
+ g_set_object (&self->stack, stack);
+
+ if (self->stack) {
+ gtk_container_foreach (GTK_CONTAINER (self->stack), (GtkCallback) add_button_for_stack_child_cb, self);
+ update_active_button_for_visible_stack_child (self);
+ connect_stack_signals (self);
+ }
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STACK]);
+}
diff --git a/gtk/meson.build b/gtk/meson.build
index 38b810c..1054e29 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -383,7 +383,9 @@ gtk_sources = files(
'gtkwin32draw.c',
'gtkwin32theme.c',
'gdkpixbufutils.c',
+ 'hdy-css.c',
'hdy-view-switcher-button.c',
+ 'hdy-view-switcher.c',
'language-names.c',
'script-names.c',
)
@@ -391,7 +393,9 @@ gtk_sources = files(
gtk_private_type_headers = files(
'gtkcsstypesprivate.h',
'gtktexthandleprivate.h',
+ 'hdy-css-private.h',
'hdy-view-switcher-button-private.h',
+ 'hdy-view-switcher-private.h',
)
gtk_gir_public_headers = files(

View file

@ -0,0 +1,509 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Mon, 31 Aug 2020 10:40:14 +0200
Subject: Add GtkHdyViewSwitcherBar
This is imported from HdyViewSwitcherBar from libhandy 1.0.0.
---
gtk/hdy-view-switcher-bar-private.h | 38 ++++
gtk/hdy-view-switcher-bar.c | 398 ++++++++++++++++++++++++++++++++++++
gtk/meson.build | 2 +
gtk/ui/hdy-view-switcher-bar.ui | 20 ++
4 files changed, 458 insertions(+)
create mode 100644 gtk/hdy-view-switcher-bar-private.h
create mode 100644 gtk/hdy-view-switcher-bar.c
create mode 100644 gtk/ui/hdy-view-switcher-bar.ui
diff --git a/gtk/hdy-view-switcher-bar-private.h b/gtk/hdy-view-switcher-bar-private.h
new file mode 100644
index 0000000..a1d942a
--- /dev/null
+++ b/gtk/hdy-view-switcher-bar-private.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 Zander Brown <zbrown@gnome.org>
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include "gtkbin.h"
+#include "gtkstack.h"
+#include "hdy-view-switcher-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_HDY_VIEW_SWITCHER_BAR (gtk_hdy_view_switcher_bar_get_type())
+
+G_DECLARE_FINAL_TYPE (GtkHdyViewSwitcherBar, gtk_hdy_view_switcher_bar, GTK, HDY_VIEW_SWITCHER_BAR, GtkBin)
+
+GtkWidget *gtk_hdy_view_switcher_bar_new (void);
+
+GtkHdyViewSwitcherPolicy gtk_hdy_view_switcher_bar_get_policy (GtkHdyViewSwitcherBar *self);
+void gtk_hdy_view_switcher_bar_set_policy (GtkHdyViewSwitcherBar *self,
+ GtkHdyViewSwitcherPolicy policy);
+
+GtkStack *gtk_hdy_view_switcher_bar_get_stack (GtkHdyViewSwitcherBar *self);
+void gtk_hdy_view_switcher_bar_set_stack (GtkHdyViewSwitcherBar *self,
+ GtkStack *stack);
+
+gboolean gtk_hdy_view_switcher_bar_get_reveal (GtkHdyViewSwitcherBar *self);
+void gtk_hdy_view_switcher_bar_set_reveal (GtkHdyViewSwitcherBar *self,
+ gboolean reveal);
+
+G_END_DECLS
diff --git a/gtk/hdy-view-switcher-bar.c b/gtk/hdy-view-switcher-bar.c
new file mode 100644
index 0000000..39d2aa4
--- /dev/null
+++ b/gtk/hdy-view-switcher-bar.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2019 Zander Brown <zbrown@gnome.org>
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "gtkactionbar.h"
+#include "gtkrevealer.h"
+#include "gtkprivatetypebuiltins.h"
+#include "hdy-view-switcher-bar-private.h"
+#include "hdy-view-switcher-private.h"
+
+/**
+ * SECTION:hdy-view-switcher-bar
+ * @short_description: A view switcher action bar.
+ * @title: GtkHdyViewSwitcherBar
+ * @See_also: #GtkHdyViewSwitcher, #GtkHdyViewSwitcherTitle
+ *
+ * An action bar letting you switch between multiple views offered by a
+ * #GtkStack, via an #GtkHdyViewSwitcher. It is designed to be put at the bottom of
+ * a window and to be revealed only on really narrow windows e.g. on mobile
+ * phones. It can't be revealed if there are less than two pages.
+ *
+ * You can conveniently bind the #GtkHdyViewSwitcherBar:reveal property to
+ * #GtkHdyViewSwitcherTitle:title-visible to automatically reveal the view switcher
+ * bar when the title label is displayed in place of the view switcher.
+ *
+ * An example of the UI definition for a common use case:
+ * |[
+ * <object class="GtkWindow"/>
+ * <child type="titlebar">
+ * <object class="HdyHeaderBar">
+ * <property name="centering-policy">strict</property>
+ * <child type="title">
+ * <object class="GtkHdyViewSwitcherTitle"
+ * id="view_switcher_title">
+ * <property name="stack">stack</property>
+ * </object>
+ * </child>
+ * </object>
+ * </child>
+ * <child>
+ * <object class="GtkBox">
+ * <child>
+ * <object class="GtkStack" id="stack"/>
+ * </child>
+ * <child>
+ * <object class="GtkHdyViewSwitcherBar">
+ * <property name="stack">stack</property>
+ * <property name="reveal"
+ * bind-source="view_switcher_title"
+ * bind-property="title-visible"
+ * bind-flags="sync-create"/>
+ * </object>
+ * </child>
+ * </object>
+ * </child>
+ * </object>
+ * ]|
+ *
+ * # CSS nodes
+ *
+ * #GtkHdyViewSwitcherBar has a single CSS node with name viewswitcherbar.
+ *
+ * Since: 0.0.10
+ */
+
+enum {
+ PROP_0,
+ PROP_POLICY,
+ PROP_STACK,
+ PROP_REVEAL,
+ LAST_PROP,
+};
+
+struct _GtkHdyViewSwitcherBar
+{
+ GtkBin parent_instance;
+
+ GtkActionBar *action_bar;
+ GtkRevealer *revealer;
+ GtkHdyViewSwitcher *view_switcher;
+
+ GtkHdyViewSwitcherPolicy policy;
+ gboolean reveal;
+};
+
+static GParamSpec *props[LAST_PROP];
+
+G_DEFINE_TYPE (GtkHdyViewSwitcherBar, gtk_hdy_view_switcher_bar, GTK_TYPE_BIN)
+
+static void
+count_children_cb (GtkWidget *widget,
+ gint *count)
+{
+ (*count)++;
+}
+
+static void
+update_bar_revealed (GtkHdyViewSwitcherBar *self)
+{
+ GtkStack *stack = gtk_hdy_view_switcher_get_stack (self->view_switcher);
+ gint count = 0;
+
+ if (self->reveal && stack)
+ gtk_container_foreach (GTK_CONTAINER (stack), (GtkCallback) count_children_cb, &count);
+
+ gtk_revealer_set_reveal_child (self->revealer, count > 1);
+}
+
+static void
+gtk_hdy_view_switcher_bar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyViewSwitcherBar *self = GTK_HDY_VIEW_SWITCHER_BAR (object);
+
+ switch (prop_id) {
+ case PROP_POLICY:
+ g_value_set_enum (value, gtk_hdy_view_switcher_bar_get_policy (self));
+ break;
+ case PROP_STACK:
+ g_value_set_object (value, gtk_hdy_view_switcher_bar_get_stack (self));
+ break;
+ case PROP_REVEAL:
+ g_value_set_boolean (value, gtk_hdy_view_switcher_bar_get_reveal (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_hdy_view_switcher_bar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyViewSwitcherBar *self = GTK_HDY_VIEW_SWITCHER_BAR (object);
+
+ switch (prop_id) {
+ case PROP_POLICY:
+ gtk_hdy_view_switcher_bar_set_policy (self, g_value_get_enum (value));
+ break;
+ case PROP_STACK:
+ gtk_hdy_view_switcher_bar_set_stack (self, g_value_get_object (value));
+ break;
+ case PROP_REVEAL:
+ gtk_hdy_view_switcher_bar_set_reveal (self, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_hdy_view_switcher_bar_class_init (GtkHdyViewSwitcherBarClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->get_property = gtk_hdy_view_switcher_bar_get_property;
+ object_class->set_property = gtk_hdy_view_switcher_bar_set_property;
+
+ /**
+ * GtkHdyViewSwitcherBar:policy:
+ *
+ * The #GtkHdyViewSwitcherPolicy the #GtkHdyViewSwitcher should use to determine
+ * which mode to use.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_POLICY] =
+ g_param_spec_enum ("policy",
+ _("Policy"),
+ _("The policy to determine the mode to use"),
+ GTK_TYPE_HDY_VIEW_SWITCHER_POLICY, GTK_HDY_VIEW_SWITCHER_POLICY_NARROW,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkHdyViewSwitcherBar:stack:
+ *
+ * The #GtkStack the #GtkHdyViewSwitcher controls.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_STACK] =
+ g_param_spec_object ("stack",
+ _("Stack"),
+ _("Stack"),
+ GTK_TYPE_STACK,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkHdyViewSwitcherBar:reveal:
+ *
+ * Whether the bar should be revealed or hidden.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_REVEAL] =
+ g_param_spec_boolean ("reveal",
+ _("Reveal"),
+ _("Whether the view switcher is revealed"),
+ FALSE,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+
+ gtk_widget_class_set_css_name (widget_class, "viewswitcherbar");
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gtk/libgtk/ui/hdy-view-switcher-bar.ui");
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherBar, action_bar);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherBar, view_switcher);
+}
+
+static void
+gtk_hdy_view_switcher_bar_init (GtkHdyViewSwitcherBar *self)
+{
+ /* This must be initialized before the template so the embedded view switcher
+ * can pick up the correct default value.
+ */
+ self->policy = GTK_HDY_VIEW_SWITCHER_POLICY_NARROW;
+
+ g_type_ensure (GTK_TYPE_HDY_VIEW_SWITCHER);
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ self->revealer = GTK_REVEALER (gtk_bin_get_child (GTK_BIN (self->action_bar)));
+ update_bar_revealed (self);
+ gtk_revealer_set_transition_type (self->revealer, GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
+}
+
+/**
+ * gtk_hdy_view_switcher_bar_new:
+ *
+ * Creates a new #GtkHdyViewSwitcherBar widget.
+ *
+ * Returns: a new #GtkHdyViewSwitcherBar
+ *
+ * Since: 0.0.10
+ */
+GtkWidget *
+gtk_hdy_view_switcher_bar_new (void)
+{
+ return g_object_new (GTK_TYPE_HDY_VIEW_SWITCHER_BAR, NULL);
+}
+
+/**
+ * gtk_hdy_view_switcher_bar_get_policy:
+ * @self: a #GtkHdyViewSwitcherBar
+ *
+ * Gets the policy of @self.
+ *
+ * Returns: the policy of @self
+ *
+ * Since: 0.0.10
+ */
+GtkHdyViewSwitcherPolicy
+gtk_hdy_view_switcher_bar_get_policy (GtkHdyViewSwitcherBar *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BAR (self), GTK_HDY_VIEW_SWITCHER_POLICY_NARROW);
+
+ return self->policy;
+}
+
+/**
+ * gtk_hdy_view_switcher_bar_set_policy:
+ * @self: a #GtkHdyViewSwitcherBar
+ * @policy: the new policy
+ *
+ * Sets the policy of @self.
+ *
+ * Since: 0.0.10
+ */
+void
+gtk_hdy_view_switcher_bar_set_policy (GtkHdyViewSwitcherBar *self,
+ GtkHdyViewSwitcherPolicy policy)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BAR (self));
+
+ if (self->policy == policy)
+ return;
+
+ self->policy = policy;
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_POLICY]);
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+/**
+ * gtk_hdy_view_switcher_bar_get_stack:
+ * @self: a #GtkHdyViewSwitcherBar
+ *
+ * Get the #GtkStack being controlled by the #GtkHdyViewSwitcher.
+ *
+ * Returns: (nullable) (transfer none): the #GtkStack, or %NULL if none has been set
+ *
+ * Since: 0.0.10
+ */
+GtkStack *
+gtk_hdy_view_switcher_bar_get_stack (GtkHdyViewSwitcherBar *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BAR (self), NULL);
+
+ return gtk_hdy_view_switcher_get_stack (self->view_switcher);
+}
+
+/**
+ * gtk_hdy_view_switcher_bar_set_stack:
+ * @self: a #GtkHdyViewSwitcherBar
+ * @stack: (nullable): a #GtkStack
+ *
+ * Sets the #GtkStack to control.
+ *
+ * Since: 0.0.10
+ */
+void
+gtk_hdy_view_switcher_bar_set_stack (GtkHdyViewSwitcherBar *self,
+ GtkStack *stack)
+{
+ GtkStack *previous_stack;
+
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BAR (self));
+ g_return_if_fail (stack == NULL || GTK_IS_STACK (stack));
+
+ previous_stack = gtk_hdy_view_switcher_get_stack (self->view_switcher);
+
+ if (previous_stack == stack)
+ return;
+
+ if (previous_stack)
+ g_signal_handlers_disconnect_by_func (previous_stack, G_CALLBACK (update_bar_revealed), self);
+
+ gtk_hdy_view_switcher_set_stack (self->view_switcher, stack);
+
+ if (stack) {
+ g_signal_connect_swapped (stack, "add", G_CALLBACK (update_bar_revealed), self);
+ g_signal_connect_swapped (stack, "remove", G_CALLBACK (update_bar_revealed), self);
+ }
+
+ update_bar_revealed (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STACK]);
+}
+
+/**
+ * gtk_hdy_view_switcher_bar_get_reveal:
+ * @self: a #GtkHdyViewSwitcherBar
+ *
+ * Gets whether @self should be revealed or not.
+ *
+ * Returns: %TRUE if @self is revealed, %FALSE if not.
+ *
+ * Since: 0.0.10
+ */
+gboolean
+gtk_hdy_view_switcher_bar_get_reveal (GtkHdyViewSwitcherBar *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BAR (self), FALSE);
+
+ return self->reveal;
+}
+
+/**
+ * gtk_hdy_view_switcher_bar_set_reveal:
+ * @self: a #GtkHdyViewSwitcherBar
+ * @reveal: %TRUE to reveal @self
+ *
+ * Sets whether @self should be revealed or not.
+ *
+ * Since: 0.0.10
+ */
+void
+gtk_hdy_view_switcher_bar_set_reveal (GtkHdyViewSwitcherBar *self,
+ gboolean reveal)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BAR (self));
+
+ reveal = !!reveal;
+
+ if (self->reveal == reveal)
+ return;
+
+ self->reveal = reveal;
+ update_bar_revealed (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_REVEAL]);
+}
diff --git a/gtk/meson.build b/gtk/meson.build
index 1054e29..1d35e83 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -384,6 +384,7 @@ gtk_sources = files(
'gtkwin32theme.c',
'gdkpixbufutils.c',
'hdy-css.c',
+ 'hdy-view-switcher-bar.c',
'hdy-view-switcher-button.c',
'hdy-view-switcher.c',
'language-names.c',
@@ -394,6 +395,7 @@ gtk_private_type_headers = files(
'gtkcsstypesprivate.h',
'gtktexthandleprivate.h',
'hdy-css-private.h',
+ 'hdy-view-switcher-bar-private.h',
'hdy-view-switcher-button-private.h',
'hdy-view-switcher-private.h',
)
diff --git a/gtk/ui/hdy-view-switcher-bar.ui b/gtk/ui/hdy-view-switcher-bar.ui
new file mode 100644
index 0000000..42246e8
--- /dev/null
+++ b/gtk/ui/hdy-view-switcher-bar.ui
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <template class="GtkHdyViewSwitcherBar" parent="GtkBin">
+ <child>
+ <object class="GtkActionBar" id="action_bar">
+ <property name="visible">True</property>
+ <child type="center">
+ <object class="GtkHdyViewSwitcher" id="view_switcher">
+ <property name="margin-start">10</property>
+ <property name="margin-end">10</property>
+ <property name="narrow-ellipsize">end</property>
+ <property name="policy" bind-source="GtkHdyViewSwitcherBar" bind-property="policy" bind-flags="sync-create|bidirectional" />
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>

View file

@ -0,0 +1,753 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Mon, 31 Aug 2020 10:40:01 +0200
Subject: Add GtkHdyViewSwitcherButton
This is imported from HdyViewSwitcherButton from libhandy 1.0.0.
---
gtk/hdy-view-switcher-button-private.h | 51 ++++
gtk/hdy-view-switcher-button.c | 544 +++++++++++++++++++++++++++++++++
gtk/meson.build | 2 +
gtk/ui/hdy-view-switcher-button.ui | 105 +++++++
4 files changed, 702 insertions(+)
create mode 100644 gtk/hdy-view-switcher-button-private.h
create mode 100644 gtk/hdy-view-switcher-button.c
create mode 100644 gtk/ui/hdy-view-switcher-button.ui
diff --git a/gtk/hdy-view-switcher-button-private.h b/gtk/hdy-view-switcher-button-private.h
new file mode 100644
index 0000000..a37add6
--- /dev/null
+++ b/gtk/hdy-view-switcher-button-private.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 Zander Brown <zbrown@gnome.org>
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include "gtkradiobutton.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_HDY_VIEW_SWITCHER_BUTTON (gtk_hdy_view_switcher_button_get_type())
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkRadioButton, g_object_unref)
+
+G_DECLARE_FINAL_TYPE (GtkHdyViewSwitcherButton, gtk_hdy_view_switcher_button, GTK, HDY_VIEW_SWITCHER_BUTTON, GtkRadioButton)
+
+GtkWidget *gtk_hdy_view_switcher_button_new (void);
+
+const gchar *gtk_hdy_view_switcher_button_get_icon_name (GtkHdyViewSwitcherButton *self);
+void gtk_hdy_view_switcher_button_set_icon_name (GtkHdyViewSwitcherButton *self,
+ const gchar *icon_name);
+
+GtkIconSize gtk_hdy_view_switcher_button_get_icon_size (GtkHdyViewSwitcherButton *self);
+void gtk_hdy_view_switcher_button_set_icon_size (GtkHdyViewSwitcherButton *self,
+ GtkIconSize icon_size);
+
+gboolean gtk_hdy_view_switcher_button_get_needs_attention (GtkHdyViewSwitcherButton *self);
+void gtk_hdy_view_switcher_button_set_needs_attention (GtkHdyViewSwitcherButton *self,
+ gboolean needs_attention);
+
+const gchar *gtk_hdy_view_switcher_button_get_label (GtkHdyViewSwitcherButton *self);
+void gtk_hdy_view_switcher_button_set_label (GtkHdyViewSwitcherButton *self,
+ const gchar *label);
+
+void gtk_hdy_view_switcher_button_set_narrow_ellipsize (GtkHdyViewSwitcherButton *self,
+ PangoEllipsizeMode mode);
+
+void gtk_hdy_view_switcher_button_get_size (GtkHdyViewSwitcherButton *self,
+ gint *h_min_width,
+ gint *h_nat_width,
+ gint *v_min_width,
+ gint *v_nat_width);
+
+G_END_DECLS
diff --git a/gtk/hdy-view-switcher-button.c b/gtk/hdy-view-switcher-button.c
new file mode 100644
index 0000000..875ca7d
--- /dev/null
+++ b/gtk/hdy-view-switcher-button.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2019 Zander Brown <zbrown@gnome.org>
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "gtkbox.h"
+#include "gtkimage.h"
+#include "gtklabel.h"
+#include "gtkorientable.h"
+#include "gtkstack.h"
+#include "gtkstylecontext.h"
+#include "gtkstyleprovider.h"
+#include "hdy-view-switcher-button-private.h"
+
+
+/**
+ * PRIVATE:gtk-hdy-view-switcher-button
+ * @short_description: Button used in #GtkHdyViewSwitcher.
+ * @title: GtkHdyViewSwitcherButton
+ * @See_also: #GtkHdyViewSwitcher
+ * @stability: Private
+ *
+ * #GtkHdyViewSwitcherButton represents an application's view. It is designed to be
+ * used exclusively internally by #GtkHdyViewSwitcher.
+ *
+ * Since: 0.0.10
+ */
+
+enum {
+ PROP_0,
+ PROP_ICON_SIZE,
+ PROP_ICON_NAME,
+ PROP_NEEDS_ATTENTION,
+
+ /* Overridden properties */
+ PROP_LABEL,
+ PROP_ORIENTATION,
+
+ LAST_PROP = PROP_NEEDS_ATTENTION + 1,
+};
+
+struct _GtkHdyViewSwitcherButton
+{
+ GtkRadioButton parent_instance;
+
+ GtkBox *horizontal_box;
+ GtkImage *horizontal_image;
+ GtkLabel *horizontal_label_active;
+ GtkLabel *horizontal_label_inactive;
+ GtkStack *horizontal_label_stack;
+ GtkStack *stack;
+ GtkBox *vertical_box;
+ GtkImage *vertical_image;
+ GtkLabel *vertical_label_active;
+ GtkLabel *vertical_label_inactive;
+ GtkStack *vertical_label_stack;
+
+ gchar *icon_name;
+ GtkIconSize icon_size;
+ gchar *label;
+ GtkOrientation orientation;
+};
+
+static GParamSpec *props[LAST_PROP];
+
+G_DEFINE_TYPE_WITH_CODE (GtkHdyViewSwitcherButton, gtk_hdy_view_switcher_button, GTK_TYPE_RADIO_BUTTON,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
+
+static void
+on_active_changed (GtkHdyViewSwitcherButton *self)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self));
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self))) {
+ gtk_stack_set_visible_child (self->horizontal_label_stack, GTK_WIDGET (self->horizontal_label_active));
+ gtk_stack_set_visible_child (self->vertical_label_stack, GTK_WIDGET (self->vertical_label_active));
+ } else {
+ gtk_stack_set_visible_child (self->horizontal_label_stack, GTK_WIDGET (self->horizontal_label_inactive));
+ gtk_stack_set_visible_child (self->vertical_label_stack, GTK_WIDGET (self->vertical_label_inactive));
+ }
+}
+
+static GtkOrientation
+get_orientation (GtkHdyViewSwitcherButton *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self), GTK_ORIENTATION_HORIZONTAL);
+
+ return self->orientation;
+}
+
+static void
+set_orientation (GtkHdyViewSwitcherButton *self,
+ GtkOrientation orientation)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self));
+
+ if (self->orientation == orientation)
+ return;
+
+ self->orientation = orientation;
+
+ gtk_stack_set_visible_child (self->stack,
+ GTK_WIDGET (self->orientation == GTK_ORIENTATION_VERTICAL ?
+ self->vertical_box :
+ self->horizontal_box));
+}
+
+static void
+gtk_hdy_view_switcher_button_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyViewSwitcherButton *self = GTK_HDY_VIEW_SWITCHER_BUTTON (object);
+
+ switch (prop_id) {
+ case PROP_ICON_NAME:
+ g_value_set_string (value, gtk_hdy_view_switcher_button_get_icon_name (self));
+ break;
+ case PROP_ICON_SIZE:
+ g_value_set_int (value, gtk_hdy_view_switcher_button_get_icon_size (self));
+ break;
+ case PROP_NEEDS_ATTENTION:
+ g_value_set_boolean (value, gtk_hdy_view_switcher_button_get_needs_attention (self));
+ break;
+ case PROP_LABEL:
+ g_value_set_string (value, gtk_hdy_view_switcher_button_get_label (self));
+ break;
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, get_orientation (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_hdy_view_switcher_button_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyViewSwitcherButton *self = GTK_HDY_VIEW_SWITCHER_BUTTON (object);
+
+ switch (prop_id) {
+ case PROP_ICON_NAME:
+ gtk_hdy_view_switcher_button_set_icon_name (self, g_value_get_string (value));
+ break;
+ case PROP_ICON_SIZE:
+ gtk_hdy_view_switcher_button_set_icon_size (self, g_value_get_int (value));
+ break;
+ case PROP_NEEDS_ATTENTION:
+ gtk_hdy_view_switcher_button_set_needs_attention (self, g_value_get_boolean (value));
+ break;
+ case PROP_LABEL:
+ gtk_hdy_view_switcher_button_set_label (self, g_value_get_string (value));
+ break;
+ case PROP_ORIENTATION:
+ set_orientation (self, g_value_get_enum (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_hdy_view_switcher_button_finalize (GObject *object)
+{
+ GtkHdyViewSwitcherButton *self = GTK_HDY_VIEW_SWITCHER_BUTTON (object);
+
+ g_free (self->icon_name);
+ g_free (self->label);
+
+ G_OBJECT_CLASS (gtk_hdy_view_switcher_button_parent_class)->finalize (object);
+}
+
+static void
+gtk_hdy_view_switcher_button_class_init (GtkHdyViewSwitcherButtonClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->get_property = gtk_hdy_view_switcher_button_get_property;
+ object_class->set_property = gtk_hdy_view_switcher_button_set_property;
+ object_class->finalize = gtk_hdy_view_switcher_button_finalize;
+
+ g_object_class_override_property (object_class,
+ PROP_LABEL,
+ "label");
+
+ g_object_class_override_property (object_class,
+ PROP_ORIENTATION,
+ "orientation");
+
+ /**
+ * GtkHdyViewSwitcherButton:icon-name:
+ *
+ * The icon name representing the view, or %NULL for no icon.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_ICON_NAME] =
+ g_param_spec_string ("icon-name",
+ _("Icon Name"),
+ _("Icon name for image"),
+ "text-x-generic-symbolic",
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE);
+
+ /**
+ * GtkHdyViewSwitcherButton:icon-size:
+ *
+ * The icon size.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_ICON_SIZE] =
+ g_param_spec_int ("icon-size",
+ _("Icon Size"),
+ _("Symbolic size to use for named icon"),
+ 0, G_MAXINT, GTK_ICON_SIZE_BUTTON,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE);
+
+ /**
+ * GtkHdyViewSwitcherButton:needs-attention:
+ *
+ * Sets a flag specifying whether the view requires the user attention. This
+ * is used by the GtkHdyViewSwitcher to change the appearance of the
+ * corresponding button when a view needs attention and it is not the current
+ * one.
+ *
+ * Since: 0.0.10
+ */
+ props[PROP_NEEDS_ATTENTION] =
+ g_param_spec_boolean ("needs-attention",
+ _("Needs attention"),
+ _("Hint the view needs attention"),
+ FALSE,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+
+ /* We probably should set the class's CSS name to "viewswitcherbutton"
+ * here, but it doesn't work because GtkCheckButton hardcodes it to "button"
+ * on instantiation, and the functions required to override it are private.
+ * In the meantime, we can use the "viewswitcher > button" CSS selector as
+ * a fairly safe fallback.
+ */
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gtk/libgtk/ui/hdy-view-switcher-button.ui");
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, horizontal_box);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, horizontal_image);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, horizontal_label_active);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, horizontal_label_inactive);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, horizontal_label_stack);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, stack);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, vertical_box);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, vertical_image);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, vertical_label_active);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, vertical_label_inactive);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherButton, vertical_label_stack);
+ gtk_widget_class_bind_template_callback (widget_class, on_active_changed);
+}
+
+static void
+gtk_hdy_view_switcher_button_init (GtkHdyViewSwitcherButton *self)
+{
+ self->icon_size = GTK_ICON_SIZE_BUTTON;
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ gtk_stack_set_visible_child (GTK_STACK (self->stack), GTK_WIDGET (self->horizontal_box));
+
+ gtk_widget_set_focus_on_click (GTK_WIDGET (self), FALSE);
+ /* Make the button look like a regular button and not a radio button. */
+ gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (self), FALSE);
+
+ on_active_changed (self);
+}
+
+/**
+ * gtk_hdy_view_switcher_button_new:
+ *
+ * Creates a new #GtkHdyViewSwitcherButton widget.
+ *
+ * Returns: a new #GtkHdyViewSwitcherButton
+ *
+ * Since: 0.0.10
+ */
+GtkWidget *
+gtk_hdy_view_switcher_button_new (void)
+{
+ return g_object_new (GTK_TYPE_HDY_VIEW_SWITCHER_BUTTON, NULL);
+}
+
+/**
+ * gtk_hdy_view_switcher_button_get_icon_name:
+ * @self: a #GtkHdyViewSwitcherButton
+ *
+ * Gets the icon name representing the view, or %NULL is no icon is set.
+ *
+ * Returns: (transfer none) (nullable): the icon name, or %NULL
+ *
+ * Since: 0.0.10
+ **/
+const gchar *
+gtk_hdy_view_switcher_button_get_icon_name (GtkHdyViewSwitcherButton *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self), NULL);
+
+ return self->icon_name;
+}
+
+/**
+ * gtk_hdy_view_switcher_button_set_icon_name:
+ * @self: a #GtkHdyViewSwitcherButton
+ * @icon_name: (nullable): an icon name or %NULL
+ *
+ * Sets the icon name representing the view, or %NULL to disable the icon.
+ *
+ * Since: 0.0.10
+ **/
+void
+gtk_hdy_view_switcher_button_set_icon_name (GtkHdyViewSwitcherButton *self,
+ const gchar *icon_name)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self));
+
+ if (!g_strcmp0 (self->icon_name, icon_name))
+ return;
+
+ g_free (self->icon_name);
+ self->icon_name = g_strdup (icon_name);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ICON_NAME]);
+}
+
+/**
+ * gtk_hdy_view_switcher_button_get_icon_size:
+ * @self: a #GtkHdyViewSwitcherButton
+ *
+ * Gets the icon size used by @self.
+ *
+ * Returns: the icon size used by @self
+ *
+ * Since: 0.0.10
+ **/
+GtkIconSize
+gtk_hdy_view_switcher_button_get_icon_size (GtkHdyViewSwitcherButton *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self), GTK_ICON_SIZE_INVALID);
+
+ return self->icon_size;
+}
+
+/**
+ * gtk_hdy_view_switcher_button_set_icon_size:
+ * @self: a #GtkHdyViewSwitcherButton
+ * @icon_size: the new icon size
+ *
+ * Sets the icon size used by @self.
+ *
+ * Since: 0.0.10
+ */
+void
+gtk_hdy_view_switcher_button_set_icon_size (GtkHdyViewSwitcherButton *self,
+ GtkIconSize icon_size)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self));
+
+ if (self->icon_size == icon_size)
+ return;
+
+ self->icon_size = icon_size;
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ICON_SIZE]);
+}
+
+/**
+ * gtk_hdy_view_switcher_button_get_needs_attention:
+ * @self: a #GtkHdyViewSwitcherButton
+ *
+ * Gets whether the view represented by @self requires the user attention.
+ *
+ * Returns: %TRUE if the view represented by @self requires the user attention, %FALSE otherwise
+ *
+ * Since: 0.0.10
+ **/
+gboolean
+gtk_hdy_view_switcher_button_get_needs_attention (GtkHdyViewSwitcherButton *self)
+{
+ GtkStyleContext *context;
+
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self), FALSE);
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (self));
+
+ return gtk_style_context_has_class (context, GTK_STYLE_CLASS_NEEDS_ATTENTION);
+}
+
+/**
+ * gtk_hdy_view_switcher_button_set_needs_attention:
+ * @self: a #GtkHdyViewSwitcherButton
+ * @needs_attention: the new icon size
+ *
+ * Sets whether the view represented by @self requires the user attention.
+ *
+ * Since: 0.0.10
+ */
+void
+gtk_hdy_view_switcher_button_set_needs_attention (GtkHdyViewSwitcherButton *self,
+ gboolean needs_attention)
+{
+ GtkStyleContext *context;
+
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self));
+
+ needs_attention = !!needs_attention;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (self));
+ if (gtk_style_context_has_class (context, GTK_STYLE_CLASS_NEEDS_ATTENTION) == needs_attention)
+ return;
+
+ if (needs_attention)
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_NEEDS_ATTENTION);
+ else
+ gtk_style_context_remove_class (context, GTK_STYLE_CLASS_NEEDS_ATTENTION);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NEEDS_ATTENTION]);
+}
+
+/**
+ * gtk_hdy_view_switcher_button_get_label:
+ * @self: a #GtkHdyViewSwitcherButton
+ *
+ * Gets the label representing the view.
+ *
+ * Returns: (transfer none) (nullable): the label, or %NULL
+ *
+ * Since: 0.0.10
+ **/
+const gchar *
+gtk_hdy_view_switcher_button_get_label (GtkHdyViewSwitcherButton *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self), NULL);
+
+ return self->label;
+}
+
+/**
+ * gtk_hdy_view_switcher_button_set_label:
+ * @self: a #GtkHdyViewSwitcherButton
+ * @label: (nullable): a label or %NULL
+ *
+ * Sets the label representing the view.
+ *
+ * Since: 0.0.10
+ **/
+void
+gtk_hdy_view_switcher_button_set_label (GtkHdyViewSwitcherButton *self,
+ const gchar *label)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self));
+
+ if (!g_strcmp0 (self->label, label))
+ return;
+
+ g_free (self->label);
+ self->label = g_strdup (label);
+
+ g_object_notify (G_OBJECT (self), "label");
+}
+
+/**
+ * gtk_hdy_view_switcher_button_set_narrow_ellipsize:
+ * @self: a #GtkHdyViewSwitcherButton
+ * @mode: a #PangoEllipsizeMode
+ *
+ * Set the mode used to ellipsize the text in narrow mode if there is not
+ * enough space to render the entire string.
+ *
+ * Since: 0.0.10
+ **/
+void
+gtk_hdy_view_switcher_button_set_narrow_ellipsize (GtkHdyViewSwitcherButton *self,
+ PangoEllipsizeMode mode)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_BUTTON (self));
+ g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && mode <= PANGO_ELLIPSIZE_END);
+
+ gtk_label_set_ellipsize (self->vertical_label_active, mode);
+ gtk_label_set_ellipsize (self->vertical_label_inactive, mode);
+}
+
+/**
+ * gtk_hdy_view_switcher_button_get_size:
+ * @self: a #GtkHdyViewSwitcherButton
+ * @h_min_width: (out) (nullable): the minimum width when horizontal
+ * @h_nat_width: (out) (nullable): the natural width when horizontal
+ * @v_min_width: (out) (nullable): the minimum width when vertical
+ * @v_nat_width: (out) (nullable): the natural width when vertical
+ *
+ * Measure the size requests in both horizontal and vertical modes.
+ *
+ * Since: 0.0.10
+ */
+void
+gtk_hdy_view_switcher_button_get_size (GtkHdyViewSwitcherButton *self,
+ gint *h_min_width,
+ gint *h_nat_width,
+ gint *v_min_width,
+ gint *v_nat_width)
+{
+ GtkStyleContext *context;
+ GtkStateFlags state;
+ GtkBorder border;
+
+ /* gtk_widget_get_preferred_width() doesn't accept both its out parameters to
+ * be NULL, so we must have guards.
+ */
+ if (h_min_width != NULL || h_nat_width != NULL)
+ gtk_widget_get_preferred_width (GTK_WIDGET (self->horizontal_box), h_min_width, h_nat_width);
+ if (v_min_width != NULL || v_nat_width != NULL)
+ gtk_widget_get_preferred_width (GTK_WIDGET (self->vertical_box), v_min_width, v_nat_width);
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (self));
+ state = gtk_style_context_get_state (context);
+ gtk_style_context_get_border (context, state, &border);
+ if (h_min_width != NULL)
+ *h_min_width += border.left + border.right;
+ if (h_nat_width != NULL)
+ *h_nat_width += border.left + border.right;
+ if (v_min_width != NULL)
+ *v_min_width += border.left + border.right;
+ if (v_nat_width != NULL)
+ *v_nat_width += border.left + border.right;
+}
diff --git a/gtk/meson.build b/gtk/meson.build
index 4b7a453..38b810c 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -383,6 +383,7 @@ gtk_sources = files(
'gtkwin32draw.c',
'gtkwin32theme.c',
'gdkpixbufutils.c',
+ 'hdy-view-switcher-button.c',
'language-names.c',
'script-names.c',
)
@@ -390,6 +391,7 @@ gtk_sources = files(
gtk_private_type_headers = files(
'gtkcsstypesprivate.h',
'gtktexthandleprivate.h',
+ 'hdy-view-switcher-button-private.h',
)
gtk_gir_public_headers = files(
diff --git a/gtk/ui/hdy-view-switcher-button.ui b/gtk/ui/hdy-view-switcher-button.ui
new file mode 100644
index 0000000..6e437dc
--- /dev/null
+++ b/gtk/ui/hdy-view-switcher-button.ui
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <template class="GtkHdyViewSwitcherButton" parent="GtkRadioButton">
+ <signal name="notify::active" handler="on_active_changed" after="yes"/>
+ <child>
+ <object class="GtkStack" id="stack">
+ <property name="hhomogeneous">False</property>
+ <property name="transition-type">crossfade</property>
+ <property name="vhomogeneous">True</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkBox" id="horizontal_box">
+ <property name="halign">center</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">8</property>
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ <style>
+ <class name="wide"/>
+ </style>
+ <child>
+ <object class="GtkImage" id="horizontal_image">
+ <property name="icon-name" bind-source="GtkHdyViewSwitcherButton" bind-property="icon-name" bind-flags="sync-create" />
+ <property name="icon-size" bind-source="GtkHdyViewSwitcherButton" bind-property="icon-size" bind-flags="sync-create" />
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="horizontal_label_stack">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="horizontal_label_inactive">
+ <property name="label" bind-source="GtkHdyViewSwitcherButton" bind-property="label" bind-flags="sync-create|bidirectional" />
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="name">inactive</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="horizontal_label_active">
+ <property name="label" bind-source="GtkHdyViewSwitcherButton" bind-property="label" bind-flags="sync-create|bidirectional" />
+ <property name="visible">True</property>
+ <style>
+ <class name="active"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">active</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="vertical_box">
+ <property name="halign">center</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">4</property>
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ <style>
+ <class name="narrow"/>
+ </style>
+ <child>
+ <object class="GtkImage" id="vertical_image">
+ <property name="icon-name" bind-source="GtkHdyViewSwitcherButton" bind-property="icon-name" bind-flags="sync-create" />
+ <property name="icon-size" bind-source="GtkHdyViewSwitcherButton" bind-property="icon-size" bind-flags="sync-create" />
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="vertical_label_stack">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="vertical_label_inactive">
+ <property name="label" bind-source="GtkHdyViewSwitcherButton" bind-property="label" bind-flags="sync-create|bidirectional" />
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="name">inactive</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="vertical_label_active">
+ <property name="label" bind-source="GtkHdyViewSwitcherButton" bind-property="label" bind-flags="sync-create|bidirectional" />
+ <property name="visible">True</property>
+ <style>
+ <class name="active"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">active</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>

View file

@ -0,0 +1,757 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Thu, 10 Sep 2020 14:26:18 +0200
Subject: Add GtkHdyViewSwitcherTitle
This is imported from HdyViewSwitcherTitle from libhandy 1.0.0.
---
gtk/hdy-view-switcher-title-private.h | 46 +++
gtk/hdy-view-switcher-title.c | 606 ++++++++++++++++++++++++++++++++++
gtk/meson.build | 2 +
gtk/ui/hdy-view-switcher-title.ui | 52 +++
4 files changed, 706 insertions(+)
create mode 100644 gtk/hdy-view-switcher-title-private.h
create mode 100644 gtk/hdy-view-switcher-title.c
create mode 100644 gtk/ui/hdy-view-switcher-title.ui
diff --git a/gtk/hdy-view-switcher-title-private.h b/gtk/hdy-view-switcher-title-private.h
new file mode 100644
index 0000000..6bc8fdf
--- /dev/null
+++ b/gtk/hdy-view-switcher-title-private.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 Zander Brown <zbrown@gnome.org>
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include "hdy-view-switcher-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_HDY_VIEW_SWITCHER_TITLE (gtk_hdy_view_switcher_title_get_type())
+
+G_DECLARE_FINAL_TYPE (GtkHdyViewSwitcherTitle, gtk_hdy_view_switcher_title, GTK, HDY_VIEW_SWITCHER_TITLE, GtkBin)
+
+GtkHdyViewSwitcherTitle *gtk_hdy_view_switcher_title_new (void);
+
+GtkHdyViewSwitcherPolicy gtk_hdy_view_switcher_title_get_policy (GtkHdyViewSwitcherTitle *self);
+void gtk_hdy_view_switcher_title_set_policy (GtkHdyViewSwitcherTitle *self,
+ GtkHdyViewSwitcherPolicy policy);
+
+GtkStack *gtk_hdy_view_switcher_title_get_stack (GtkHdyViewSwitcherTitle *self);
+void gtk_hdy_view_switcher_title_set_stack (GtkHdyViewSwitcherTitle *self,
+ GtkStack *stack);
+
+const gchar *gtk_hdy_view_switcher_title_get_title (GtkHdyViewSwitcherTitle *self);
+void gtk_hdy_view_switcher_title_set_title (GtkHdyViewSwitcherTitle *self,
+ const gchar *title);
+
+const gchar *gtk_hdy_view_switcher_title_get_subtitle (GtkHdyViewSwitcherTitle *self);
+void gtk_hdy_view_switcher_title_set_subtitle (GtkHdyViewSwitcherTitle *self,
+ const gchar *subtitle);
+
+gboolean gtk_hdy_view_switcher_title_get_view_switcher_enabled (GtkHdyViewSwitcherTitle *self);
+void gtk_hdy_view_switcher_title_set_view_switcher_enabled (GtkHdyViewSwitcherTitle *self,
+ gboolean enabled);
+
+gboolean gtk_hdy_view_switcher_title_get_title_visible (GtkHdyViewSwitcherTitle *self);
+
+G_END_DECLS
diff --git a/gtk/hdy-view-switcher-title.c b/gtk/hdy-view-switcher-title.c
new file mode 100644
index 0000000..4cb815b
--- /dev/null
+++ b/gtk/hdy-view-switcher-title.c
@@ -0,0 +1,606 @@
+/*
+ * Copyright (C) 2019 Zander Brown <zbrown@gnome.org>
+ * Copyright (C) 2019 Purism SPC
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include "gtkbox.h"
+#include "gtklabel.h"
+#include "gtkprivatetypebuiltins.h"
+#include "hdy-view-switcher-title-private.h"
+#include "hdy-squeezer-private.h"
+
+/**
+ * SECTION:gtk-hdy-view-switcher-title
+ * @short_description: A view switcher title.
+ * @title: GtkHdyViewSwitcherTitle
+ * @See_also: #GtkHdyHeaderBar, #GtkHdyViewSwitcher, #GtkHdyViewSwitcherBar
+ *
+ * A widget letting you switch between multiple views offered by a #GtkStack,
+ * via an #GtkHdyViewSwitcher. It is designed to be used as the title widget of a
+ * #GtkHdyHeaderBar, and will display the window's title when the window is too
+ * narrow to fit the view switcher e.g. on mobile phones, or if there are less
+ * than two views.
+ *
+ * You can conveniently bind the #GtkHdyViewSwitcherBar:reveal property to
+ * #GtkHdyViewSwitcherTitle:title-visible to automatically reveal the view switcher
+ * bar when the title label is displayed in place of the view switcher.
+ *
+ * An example of the UI definition for a common use case:
+ * |[
+ * <object class="GtkWindow"/>
+ * <child type="titlebar">
+ * <object class="GtkHdyHeaderBar">
+ * <property name="centering-policy">strict</property>
+ * <child type="title">
+ * <object class="GtkHdyViewSwitcherTitle"
+ * id="view_switcher_title">
+ * <property name="stack">stack</property>
+ * </object>
+ * </child>
+ * </object>
+ * </child>
+ * <child>
+ * <object class="GtkBox">
+ * <child>
+ * <object class="GtkStack" id="stack"/>
+ * </child>
+ * <child>
+ * <object class="GtkHdyViewSwitcherBar">
+ * <property name="stack">stack</property>
+ * <property name="reveal"
+ * bind-source="view_switcher_title"
+ * bind-property="title-visible"
+ * bind-flags="sync-create"/>
+ * </object>
+ * </child>
+ * </object>
+ * </child>
+ * </object>
+ * ]|
+ *
+ * # CSS nodes
+ *
+ * #GtkHdyViewSwitcherTitle has a single CSS node with name viewswitchertitle.
+ *
+ * Since: 1.0
+ */
+
+enum {
+ PROP_0,
+ PROP_POLICY,
+ PROP_STACK,
+ PROP_TITLE,
+ PROP_SUBTITLE,
+ PROP_VIEW_SWITCHER_ENABLED,
+ PROP_TITLE_VISIBLE,
+ LAST_PROP,
+};
+
+struct _GtkHdyViewSwitcherTitle
+{
+ GtkBin parent_instance;
+
+ GtkHdySqueezer *squeezer;
+ GtkLabel *subtitle_label;
+ GtkBox *title_box;
+ GtkLabel *title_label;
+ GtkHdyViewSwitcher *view_switcher;
+
+ gboolean view_switcher_enabled;
+};
+
+static GParamSpec *props[LAST_PROP];
+
+G_DEFINE_TYPE (GtkHdyViewSwitcherTitle, gtk_hdy_view_switcher_title, GTK_TYPE_BIN)
+
+static void
+update_subtitle_label (GtkHdyViewSwitcherTitle *self)
+{
+ const gchar *subtitle = gtk_label_get_label (self->subtitle_label);
+
+ gtk_widget_set_visible (GTK_WIDGET (self->subtitle_label), subtitle && subtitle[0]);
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+static void
+count_children_cb (GtkWidget *widget,
+ gint *count)
+{
+ (*count)++;
+}
+
+static void
+update_view_switcher_visible (GtkHdyViewSwitcherTitle *self)
+{
+ GtkStack *stack = gtk_hdy_view_switcher_get_stack (self->view_switcher);
+ gint count = 0;
+
+ if (self->view_switcher_enabled && stack)
+ gtk_container_foreach (GTK_CONTAINER (stack), (GtkCallback) count_children_cb, &count);
+
+ gtk_hdy_squeezer_set_child_enabled (self->squeezer, GTK_WIDGET (self->view_switcher), count > 1);
+}
+
+static void
+notify_squeezer_visible_child_cb (GObject *self)
+{
+ g_object_notify_by_pspec (self, props[PROP_TITLE_VISIBLE]);
+}
+
+static void
+gtk_hdy_view_switcher_title_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyViewSwitcherTitle *self = GTK_HDY_VIEW_SWITCHER_TITLE (object);
+
+ switch (prop_id) {
+ case PROP_POLICY:
+ g_value_set_enum (value, gtk_hdy_view_switcher_title_get_policy (self));
+ break;
+ case PROP_STACK:
+ g_value_set_object (value, gtk_hdy_view_switcher_title_get_stack (self));
+ break;
+ case PROP_TITLE:
+ g_value_set_string (value, gtk_hdy_view_switcher_title_get_title (self));
+ break;
+ case PROP_SUBTITLE:
+ g_value_set_string (value, gtk_hdy_view_switcher_title_get_subtitle (self));
+ break;
+ case PROP_VIEW_SWITCHER_ENABLED:
+ g_value_set_boolean (value, gtk_hdy_view_switcher_title_get_view_switcher_enabled (self));
+ break;
+ case PROP_TITLE_VISIBLE:
+ g_value_set_boolean (value, gtk_hdy_view_switcher_title_get_title_visible (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_hdy_view_switcher_title_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkHdyViewSwitcherTitle *self = GTK_HDY_VIEW_SWITCHER_TITLE (object);
+
+ switch (prop_id) {
+ case PROP_POLICY:
+ gtk_hdy_view_switcher_title_set_policy (self, g_value_get_enum (value));
+ break;
+ case PROP_STACK:
+ gtk_hdy_view_switcher_title_set_stack (self, g_value_get_object (value));
+ break;
+ case PROP_TITLE:
+ gtk_hdy_view_switcher_title_set_title (self, g_value_get_string (value));
+ break;
+ case PROP_SUBTITLE:
+ gtk_hdy_view_switcher_title_set_subtitle (self, g_value_get_string (value));
+ break;
+ case PROP_VIEW_SWITCHER_ENABLED:
+ gtk_hdy_view_switcher_title_set_view_switcher_enabled (self, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_hdy_view_switcher_title_dispose (GObject *object) {
+ GtkHdyViewSwitcherTitle *self = (GtkHdyViewSwitcherTitle *)object;
+
+ if (self->view_switcher) {
+ GtkStack *stack = gtk_hdy_view_switcher_get_stack (self->view_switcher);
+
+ if (stack)
+ g_signal_handlers_disconnect_by_func (stack, G_CALLBACK (update_view_switcher_visible), self);
+ }
+
+ G_OBJECT_CLASS (gtk_hdy_view_switcher_title_parent_class)->dispose (object);
+}
+
+static void
+gtk_hdy_view_switcher_title_class_init (GtkHdyViewSwitcherTitleClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = gtk_hdy_view_switcher_title_dispose;
+ object_class->get_property = gtk_hdy_view_switcher_title_get_property;
+ object_class->set_property = gtk_hdy_view_switcher_title_set_property;
+
+ /**
+ * GtkHdyViewSwitcherTitle:policy:
+ *
+ * The #GtkHdyViewSwitcherPolicy the #GtkHdyViewSwitcher should use to determine
+ * which mode to use.
+ *
+ * Since: 1.0
+ */
+ props[PROP_POLICY] =
+ g_param_spec_enum ("policy",
+ _("Policy"),
+ _("The policy to determine the mode to use"),
+ GTK_TYPE_HDY_VIEW_SWITCHER_POLICY, GTK_HDY_VIEW_SWITCHER_POLICY_AUTO,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkHdyViewSwitcherTitle:stack:
+ *
+ * The #GtkStack the #GtkHdyViewSwitcher controls.
+ *
+ * Since: 1.0
+ */
+ props[PROP_STACK] =
+ g_param_spec_object ("stack",
+ _("Stack"),
+ _("Stack"),
+ GTK_TYPE_STACK,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkHdyViewSwitcherTitle:title:
+ *
+ * The title of the #GtkHdyViewSwitcher.
+ *
+ * Since: 1.0
+ */
+ props[PROP_TITLE] =
+ g_param_spec_string ("title",
+ _("Title"),
+ _("The title to display"),
+ NULL,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkHdyViewSwitcherTitle:subtitle:
+ *
+ * The subtitle of the #GtkHdyViewSwitcher.
+ *
+ * Since: 1.0
+ */
+ props[PROP_SUBTITLE] =
+ g_param_spec_string ("subtitle",
+ _("Subtitle"),
+ _("The subtitle to display"),
+ NULL,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkHdyViewSwitcherTitle:view-switcher-enabled:
+ *
+ * Whether the bar should be revealed or hidden.
+ *
+ * Since: 1.0
+ */
+ props[PROP_VIEW_SWITCHER_ENABLED] =
+ g_param_spec_boolean ("view-switcher-enabled",
+ _("View switcher enabled"),
+ _("Whether the view switcher is enabled"),
+ TRUE,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GtkHdyViewSwitcherTitle:title-visible:
+ *
+ * Whether the bar should be revealed or hidden.
+ *
+ * Since: 1.0
+ */
+ props[PROP_TITLE_VISIBLE] =
+ g_param_spec_boolean ("title-visible",
+ _("Title visible"),
+ _("Whether the title label is visible"),
+ TRUE,
+ G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+
+ gtk_widget_class_set_css_name (widget_class, "viewswitchertitle");
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gtk/libgtk/ui/hdy-view-switcher-title.ui");
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherTitle, squeezer);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherTitle, subtitle_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherTitle, title_box);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherTitle, title_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkHdyViewSwitcherTitle, view_switcher);
+ gtk_widget_class_bind_template_callback (widget_class, notify_squeezer_visible_child_cb);
+}
+
+static void
+gtk_hdy_view_switcher_title_init (GtkHdyViewSwitcherTitle *self)
+{
+ /* This must be initialized before the template so the embedded view switcher
+ * can pick up the correct default value.
+ */
+ self->view_switcher_enabled = TRUE;
+
+ g_type_ensure (GTK_TYPE_HDY_SQUEEZER);
+ g_type_ensure (GTK_TYPE_HDY_VIEW_SWITCHER);
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ update_subtitle_label (self);
+ update_view_switcher_visible (self);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_new:
+ *
+ * Creates a new #GtkHdyViewSwitcherTitle widget.
+ *
+ * Returns: a new #GtkHdyViewSwitcherTitle
+ *
+ * Since: 1.0
+ */
+GtkHdyViewSwitcherTitle *
+gtk_hdy_view_switcher_title_new (void)
+{
+ return g_object_new (GTK_TYPE_HDY_VIEW_SWITCHER_TITLE, NULL);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_get_policy:
+ * @self: a #GtkHdyViewSwitcherTitle
+ *
+ * Gets the policy of @self.
+ *
+ * Returns: the policy of @self
+ *
+ * Since: 1.0
+ */
+GtkHdyViewSwitcherPolicy
+gtk_hdy_view_switcher_title_get_policy (GtkHdyViewSwitcherTitle *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self), GTK_HDY_VIEW_SWITCHER_POLICY_NARROW);
+
+ return gtk_hdy_view_switcher_get_policy (self->view_switcher);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_set_policy:
+ * @self: a #GtkHdyViewSwitcherTitle
+ * @policy: the new policy
+ *
+ * Sets the policy of @self.
+ *
+ * Since: 1.0
+ */
+void
+gtk_hdy_view_switcher_title_set_policy (GtkHdyViewSwitcherTitle *self,
+ GtkHdyViewSwitcherPolicy policy)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self));
+
+ if (gtk_hdy_view_switcher_get_policy (self->view_switcher) == policy)
+ return;
+
+ gtk_hdy_view_switcher_set_policy (self->view_switcher, policy);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_POLICY]);
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+/**
+ * gtk_hdy_view_switcher_title_get_stack:
+ * @self: a #GtkHdyViewSwitcherTitle
+ *
+ * Get the #GtkStack being controlled by the #GtkHdyViewSwitcher.
+ *
+ * Returns: (nullable) (transfer none): the #GtkStack, or %NULL if none has been set
+ *
+ * Since: 1.0
+ */
+GtkStack *
+gtk_hdy_view_switcher_title_get_stack (GtkHdyViewSwitcherTitle *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self), NULL);
+
+ return gtk_hdy_view_switcher_get_stack (self->view_switcher);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_set_stack:
+ * @self: a #GtkHdyViewSwitcherTitle
+ * @stack: (nullable): a #GtkStack
+ *
+ * Sets the #GtkStack to control.
+ *
+ * Since: 1.0
+ */
+void
+gtk_hdy_view_switcher_title_set_stack (GtkHdyViewSwitcherTitle *self,
+ GtkStack *stack)
+{
+ GtkStack *previous_stack;
+
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self));
+ g_return_if_fail (stack == NULL || GTK_IS_STACK (stack));
+
+ previous_stack = gtk_hdy_view_switcher_get_stack (self->view_switcher);
+
+ if (previous_stack == stack)
+ return;
+
+ if (previous_stack)
+ g_signal_handlers_disconnect_by_func (previous_stack, G_CALLBACK (update_view_switcher_visible), self);
+
+ gtk_hdy_view_switcher_set_stack (self->view_switcher, stack);
+
+ if (stack) {
+ g_signal_connect_swapped (stack, "add", G_CALLBACK (update_view_switcher_visible), self);
+ g_signal_connect_swapped (stack, "remove", G_CALLBACK (update_view_switcher_visible), self);
+ }
+
+ update_view_switcher_visible (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STACK]);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_get_title:
+ * @self: a #GtkHdyViewSwitcherTitle
+ *
+ * Gets the title of @self. See gtk_hdy_view_switcher_title_set_title().
+ *
+ * Returns: (transfer none) (nullable): the title of @self, or %NULL.
+ *
+ * Since: 1.0
+ */
+const gchar *
+gtk_hdy_view_switcher_title_get_title (GtkHdyViewSwitcherTitle *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self), NULL);
+
+ return gtk_label_get_label (self->title_label);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_set_title:
+ * @self: a #GtkHdyViewSwitcherTitle
+ * @title: (nullable): a title, or %NULL
+ *
+ * Sets the title of @self. The title should give a user additional details. A
+ * good title should not include the application name.
+ *
+ * Since: 1.0
+ */
+void
+gtk_hdy_view_switcher_title_set_title (GtkHdyViewSwitcherTitle *self,
+ const gchar *title)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self));
+
+ if (g_strcmp0 (gtk_label_get_label (self->title_label), title) == 0)
+ return;
+
+ gtk_label_set_label (self->title_label, title);
+ gtk_widget_set_visible (GTK_WIDGET (self->title_label), title && title[0]);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TITLE]);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_get_subtitle:
+ * @self: a #GtkHdyViewSwitcherTitle
+ *
+ * Gets the subtitle of @self. See gtk_hdy_view_switcher_title_set_subtitle().
+ *
+ * Returns: (transfer none) (nullable): the subtitle of @self, or %NULL.
+ *
+ * Since: 1.0
+ */
+const gchar *
+gtk_hdy_view_switcher_title_get_subtitle (GtkHdyViewSwitcherTitle *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self), NULL);
+
+ return gtk_label_get_label (self->subtitle_label);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_set_subtitle:
+ * @self: a #GtkHdyViewSwitcherTitle
+ * @subtitle: (nullable): a subtitle, or %NULL
+ *
+ * Sets the subtitle of @self. The subtitle should give a user additional
+ * details.
+ *
+ * Since: 1.0
+ */
+void
+gtk_hdy_view_switcher_title_set_subtitle (GtkHdyViewSwitcherTitle *self,
+ const gchar *subtitle)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self));
+
+ if (g_strcmp0 (gtk_label_get_label (self->subtitle_label), subtitle) == 0)
+ return;
+
+ gtk_label_set_label (self->subtitle_label, subtitle);
+ update_subtitle_label (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SUBTITLE]);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_get_view_switcher_enabled:
+ * @self: a #GtkHdyViewSwitcherTitle
+ *
+ * Gets whether @self's view switcher is enabled.
+ *
+ * See gtk_hdy_view_switcher_title_set_view_switcher_enabled().
+ *
+ * Returns: %TRUE if the view switcher is enabled, %FALSE otherwise.
+ *
+ * Since: 1.0
+ */
+gboolean
+gtk_hdy_view_switcher_title_get_view_switcher_enabled (GtkHdyViewSwitcherTitle *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self), FALSE);
+
+ return self->view_switcher_enabled;
+}
+
+/**
+ * gtk_hdy_view_switcher_title_set_view_switcher_enabled:
+ * @self: a #GtkHdyViewSwitcherTitle
+ * @enabled: %TRUE to enable the view switcher, %FALSE to disable it
+ *
+ * Make @self enable or disable its view switcher. If it is disabled, the title
+ * will be displayed instead. This allows to programmatically and prematurely
+ * hide the view switcher of @self even if it fits in the available space.
+ *
+ * This can be used e.g. to ensure the view switcher is hidden below a certain
+ * window width, or any other constraint you find suitable.
+ *
+ * Since: 1.0
+ */
+void
+gtk_hdy_view_switcher_title_set_view_switcher_enabled (GtkHdyViewSwitcherTitle *self,
+ gboolean enabled)
+{
+ g_return_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self));
+
+ enabled = !!enabled;
+
+ if (self->view_switcher_enabled == enabled)
+ return;
+
+ self->view_switcher_enabled = enabled;
+ update_view_switcher_visible (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), props[PROP_VIEW_SWITCHER_ENABLED]);
+}
+
+/**
+ * gtk_hdy_view_switcher_title_get_title_visible:
+ * @self: a #GtkHdyViewSwitcherTitle
+ *
+ * Get whether the title label of @self is visible.
+ *
+ * Returns: %TRUE if the title label of @self is visible, %FALSE if not.
+ *
+ * Since: 1.0
+ */
+gboolean
+gtk_hdy_view_switcher_title_get_title_visible (GtkHdyViewSwitcherTitle *self)
+{
+ g_return_val_if_fail (GTK_IS_HDY_VIEW_SWITCHER_TITLE (self), FALSE);
+
+ return gtk_hdy_squeezer_get_visible_child (self->squeezer) == (GtkWidget *) self->title_box;
+}
diff --git a/gtk/meson.build b/gtk/meson.build
index 80ae1bf..4b3e871 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -389,6 +389,7 @@ gtk_sources = files(
'hdy-view-switcher-bar.c',
'hdy-view-switcher-button.c',
'hdy-view-switcher.c',
+ 'hdy-view-switcher-title.c',
'language-names.c',
'script-names.c',
)
@@ -403,6 +404,7 @@ gtk_private_type_headers = files(
'hdy-view-switcher-bar-private.h',
'hdy-view-switcher-button-private.h',
'hdy-view-switcher-private.h',
+ 'hdy-view-switcher-title-private.h',
)
gtk_gir_public_headers = files(
diff --git a/gtk/ui/hdy-view-switcher-title.ui b/gtk/ui/hdy-view-switcher-title.ui
new file mode 100644
index 0000000..3e16d1f
--- /dev/null
+++ b/gtk/ui/hdy-view-switcher-title.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <template class="GtkHdyViewSwitcherTitle" parent="GtkBin">
+ <child>
+ <object class="GtkHdySqueezer" id="squeezer">
+ <property name="transition-type">crossfade</property>
+ <property name="visible">True</property>
+ <property name="no-show-all">True</property>
+ <signal name="notify::visible-child" handler="notify_squeezer_visible_child_cb" swapped="yes"/>
+ <child>
+ <object class="GtkHdyViewSwitcher" id="view_switcher">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="title_box">
+ <property name="orientation">vertical</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="title_label">
+ <property name="ellipsize">end</property>
+ <property name="halign">center</property>
+ <property name="wrap">False</property>
+ <property name="single-line-mode">True</property>
+ <property name="visible">True</property>
+ <property name="width-chars">5</property>
+ <style>
+ <class name="title"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="subtitle_label">
+ <property name="ellipsize">end</property>
+ <property name="halign">center</property>
+ <property name="wrap">False</property>
+ <property name="single-line-mode">True</property>
+ <property name="visible">True</property>
+ <style>
+ <class name="subtitle"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>

View file

@ -0,0 +1,46 @@
From: Mohammed Sadiq <sadiq@sadiqpk.org>
Date: Thu, 27 Aug 2020 14:45:07 +0530
Subject: Add org.gtk.Settings.Purism
---
gtk/meson.build | 1 +
gtk/org.gtk.Settings.Purism.gschema.xml | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
create mode 100644 gtk/org.gtk.Settings.Purism.gschema.xml
diff --git a/gtk/meson.build b/gtk/meson.build
index 40feabc..e50a4bc 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -964,6 +964,7 @@ gtk_settings_schemas = [
'org.gtk.Settings.ColorChooser.gschema.xml',
'org.gtk.Settings.EmojiChooser.gschema.xml',
'org.gtk.Settings.Debug.gschema.xml',
+ 'org.gtk.Settings.Purism.gschema.xml',
]
install_data(gtk_settings_schemas, install_dir: gtk_schemasdir)
gnome.compile_schemas(depend_files: files(gtk_settings_schemas),
diff --git a/gtk/org.gtk.Settings.Purism.gschema.xml b/gtk/org.gtk.Settings.Purism.gschema.xml
new file mode 100644
index 0000000..f5637dd
--- /dev/null
+++ b/gtk/org.gtk.Settings.Purism.gschema.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schemalist>
+
+ <schema id='org.gtk.Settings.Purism' path='/org/gtk/settings/purism/'>
+ <key name='is-phone' type='b'>
+ <default>false</default>
+ <summary>Enable hacks for small screens</summary>
+ <description>
+ If this setting is true, GTK enables various tweaks to let it
+ work on small screens.
+
+ This is a temporary workaround until automatic adaptive UIs
+ are implemented based on the workarea size.
+ </description>
+ </key>
+ </schema>
+
+</schemalist>

View file

@ -0,0 +1,81 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Tue, 13 Oct 2020 18:54:49 +0500
Subject: Add padding for HdyViewSwitcherTitle
Make sure it moves to the bottom on narrow sizes.
---
gtk/theme/Adwaita/_common.scss | 5 +++++
gtk/theme/Adwaita/gtk-contained-dark.css | 2 ++
gtk/theme/Adwaita/gtk-contained.css | 2 ++
gtk/theme/HighContrast/gtk-contained-inverse.css | 2 ++
gtk/theme/HighContrast/gtk-contained.css | 2 ++
5 files changed, 13 insertions(+)
diff --git a/gtk/theme/Adwaita/_common.scss b/gtk/theme/Adwaita/_common.scss
index 19b6f38..e40e429 100644
--- a/gtk/theme/Adwaita/_common.scss
+++ b/gtk/theme/Adwaita/_common.scss
@@ -4868,6 +4868,11 @@ viewswitcher {
padding: 0;
}
+ headerbar & {
+ padding-left: 70px;
+ padding-right: 70px;
+ }
+
button {
border-radius: 0;
border-top: 0;
diff --git a/gtk/theme/Adwaita/gtk-contained-dark.css b/gtk/theme/Adwaita/gtk-contained-dark.css
index 9797b3a..3cd917d 100644
--- a/gtk/theme/Adwaita/gtk-contained-dark.css
+++ b/gtk/theme/Adwaita/gtk-contained-dark.css
@@ -1958,6 +1958,8 @@ popover.emoji-completion .emoji:hover { background: #424242; }
/************ libhandy * */
viewswitcher, viewswitcher button { margin: 0; padding: 0; }
+headerbar viewswitcher { padding-left: 70px; padding-right: 70px; }
+
viewswitcher button { border-radius: 0; border-top: 0; border-bottom: 0; box-shadow: none; font-size: 1rem; }
viewswitcher button:not(:checked):not(:hover) { background: transparent; }
diff --git a/gtk/theme/Adwaita/gtk-contained.css b/gtk/theme/Adwaita/gtk-contained.css
index 72946ec..4eff74f 100644
--- a/gtk/theme/Adwaita/gtk-contained.css
+++ b/gtk/theme/Adwaita/gtk-contained.css
@@ -1974,6 +1974,8 @@ popover.emoji-completion .emoji:hover { background: white; }
/************ libhandy * */
viewswitcher, viewswitcher button { margin: 0; padding: 0; }
+headerbar viewswitcher { padding-left: 70px; padding-right: 70px; }
+
viewswitcher button { border-radius: 0; border-top: 0; border-bottom: 0; box-shadow: none; font-size: 1rem; }
viewswitcher button:not(:checked):not(:hover) { background: transparent; }
diff --git a/gtk/theme/HighContrast/gtk-contained-inverse.css b/gtk/theme/HighContrast/gtk-contained-inverse.css
index eb633dc..5a2cf09 100644
--- a/gtk/theme/HighContrast/gtk-contained-inverse.css
+++ b/gtk/theme/HighContrast/gtk-contained-inverse.css
@@ -2038,6 +2038,8 @@ popover.emoji-completion .emoji:hover { background: #424242; }
/************ libhandy * */
viewswitcher, viewswitcher button { margin: 0; padding: 0; }
+headerbar viewswitcher { padding-left: 70px; padding-right: 70px; }
+
viewswitcher button { border-radius: 0; border-top: 0; border-bottom: 0; box-shadow: none; font-size: 1rem; }
viewswitcher button:not(:checked):not(:hover) { background: transparent; }
diff --git a/gtk/theme/HighContrast/gtk-contained.css b/gtk/theme/HighContrast/gtk-contained.css
index 95d09e5..ba598cc 100644
--- a/gtk/theme/HighContrast/gtk-contained.css
+++ b/gtk/theme/HighContrast/gtk-contained.css
@@ -2054,6 +2054,8 @@ popover.emoji-completion .emoji:hover { background: white; }
/************ libhandy * */
viewswitcher, viewswitcher button { margin: 0; padding: 0; }
+headerbar viewswitcher { padding-left: 70px; padding-right: 70px; }
+
viewswitcher button { border-radius: 0; border-top: 0; border-bottom: 0; box-shadow: none; font-size: 1rem; }
viewswitcher button:not(:checked):not(:hover) { background: transparent; }

View file

@ -0,0 +1,112 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Mon, 1 Jul 2019 13:28:48 +0200
Subject: Add the view-sidebar-symbolic icon
This will be used to reveal/conceal the file chooser sidebar.
---
gtk/gen-gtk-gresources-xml.py | 6 ++
.../scalable/actions/view-sidebar-symbolic.svg | 78 ++++++++++++++++++++++
2 files changed, 84 insertions(+)
create mode 100644 gtk/icons/scalable/actions/view-sidebar-symbolic.svg
diff --git a/gtk/gen-gtk-gresources-xml.py b/gtk/gen-gtk-gresources-xml.py
index 91cbaa3..4816205 100644
--- a/gtk/gen-gtk-gresources-xml.py
+++ b/gtk/gen-gtk-gresources-xml.py
@@ -71,6 +71,12 @@ for s in ['16x16', '22x22', '24x24', '32x32', '48x48']:
for f in get_files(icons_dir, '.png'):
xml += ' <file>icons/{0}/{1}/{2}</file>\n'.format(s,c,f)
+for c in ['actions', 'status']:
+ icons_dir = 'icons/scalable/{0}'.format(c)
+ if os.path.exists(os.path.join(srcdir,icons_dir)):
+ for f in get_files(icons_dir, '.svg'):
+ xml += ' <file>icons/scalable/{0}/{1}</file>\n'.format(c,f)
+
for f in get_files('inspector', '.ui'):
xml += ' <file compressed=\'true\' preprocess=\'xml-stripblanks\'>inspector/{0}</file>\n'.format(f)
diff --git a/gtk/icons/scalable/actions/view-sidebar-symbolic.svg b/gtk/icons/scalable/actions/view-sidebar-symbolic.svg
new file mode 100644
index 0000000..559e11f
--- /dev/null
+++ b/gtk/icons/scalable/actions/view-sidebar-symbolic.svg
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="4.2333331mm"
+ height="4.2333331mm"
+ viewBox="0 0 4.2333331 4.2333331"
+ version="1.1"
+ id="svg10539"
+ inkscape:version="0.92.2 2405546, 2018-03-11"
+ sodipodi:docname="view-sidebar-symbolic.svg">
+ <defs
+ id="defs10533" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#e8e8e7"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="44.8"
+ inkscape:cx="3.9955133"
+ inkscape:cy="6.9472436"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="3440"
+ inkscape:window-height="1376"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid11109" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata10536">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(45.205952,-342.50834)">
+ <path
+ style="color:#bebebe;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.99999994;marker:none"
+ d="M 3 2 C 1.9093002 2 1 2.9093039 1 4 L 1 12 L 1 14 L 15 14 L 15 12 L 15 4 C 15 2.9093039 14.090704 2 13 2 L 3 2 z M 3 4 L 6 4 L 6 12 L 3 12 L 3 4 z M 7 4 L 13 4 L 13 12 L 7 12 L 7 4 z "
+ transform="matrix(0.26458333,0,0,0.26458333,-45.205952,342.50834)"
+ id="rect10509" />
+ <rect
+ transform="matrix(0,-1,-1,0,0,0)"
+ style="color:#bebebe;display:inline;overflow:visible;visibility:visible;opacity:0.35;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:0.26458332;marker:none"
+ id="rect10511"
+ width="2.1166327"
+ height="0.79374611"
+ x="-345.68332"
+ y="43.618412" />
+ </g>
+</svg>

209
gtk3-mobile/PKGBUILD Normal file
View file

@ -0,0 +1,209 @@
# Maintainer: Danct12 <danct12@disroot.org>
# Contributor Jan Alexander Steffens (heftig) <jan.steffens@gmail.com>
# Contributor: Ionut Biru <ibiru@archlinux.org>
pkgname=gtk3-mobile
pkgver=3.24.43
pkgrel=1
pkgdesc="GObject-based multi-platform GUI toolkit (Built with Purism patches)"
url="https://www.gtk.org/"
arch=('x86_64' 'armv7h' 'aarch64')
license=(LGPL-2.1-or-later)
depends=(
adwaita-icon-theme
at-spi2-core
cairo
cantarell-fonts
dconf
desktop-file-utils
fontconfig
fribidi
gdk-pixbuf2
glib2
glibc
gtk-update-icon-cache
harfbuzz
iso-codes
libcloudproviders
libcolord
libcups
libegl
libepoxy
libgl
librsvg
libx11
libxcomposite
libxcursor
libxdamage
libxext
libxfixes
libxi
libxinerama
libxkbcommon
libxrandr
libxrender
pango
shared-mime-info
tracker3
wayland
)
makedepends=(
git
glib2-devel
gobject-introspection
gtk-doc
hicolor-icon-theme
meson
sassc
wayland-protocols
)
optdepends=('evince: Default print preview command')
provides=(
gtk3
gtk3-print-backends
libgailutil-3.so
libgdk-3.so
libgtk-3.so
)
conflicts=(
gtk3
gtk3-print-backends
)
install=gtk3.install
source=(
"git+https://gitlab.gnome.org/GNOME/gtk.git#tag=$pkgver"
gtk-query-immodules-3.0.hook
0001-Allow-disabling-legacy-Tracker-search.patch
# Purism patches
Add-GtkHdyViewSwitcherButton.patch
Add-GtkHdyViewSwitcher.patch
Add-GtkHdyViewSwitcherBar.patch
Add-GtkHdyAnimation.patch
Add-GtkHdySqueezer.patch
Add-GtkHdyViewSwitcherTitle.patch
Add-GtkHdyShadowHelper.patch
Add-GtkHdyNavigationDirection.patch
Add-GtkHdySwipeable-and-GtkHdySwipeTracker.patch
Add-GtkHdyClamp.patch
Add-GtkHdyFlap.patch
theme-Add-libhandy-styles.patch
Add-padding-for-HdyViewSwitcherTitle.patch
hdy-flap-Use-natural-size-for-folding-instead-of-minimum.patch
Add-org.gtk.Settings.Purism.patch
gtkprivate-Add-an-API-to-check-if-phone.patch
aboutdialog-Port-to-phones.patch
Add-the-view-sidebar-symbolic-icon.patch
Port-file-chooser-to-phones.patch
messagedialog-Set-orientation-based-on-device.patch
dialog-Maximize-resizable-dialogs-on-phones.patch
window-Maximize-resizable-pseudo-dialogs-on-mobile.patch
headerbar-Use-a-back-button-in-dialogs-on-mobile.patch
infobar-Move-the-action-area-below-on-the-phone.patch
Reduce-the-font-chooser-minimum-size.patch
printunixdialog-Adapt-for-phones.patch
window-Disable-window-dragging-on-phones.patch
librem5-Make-GtkShortcutsWindow-adaptive.patch
scrolledwindow-Set-deceleration-value-based-on-the-device.patch
events-Compress-touch-update-events.patch
gdk-wayland-Track-last-touch-serial-on-seat.patch
)
sha256sums=('2d447a2ecf41d2616e413263b495a8f410a43dda1c74cf3e05a740c98f98f9ff'
'de46e5514ff39a7a65e01e485e874775ab1c0ad20b8e94ada43f4a6af1370845'
'f102ea1987b9b8370882d5c7f6aa577bfa3adade834b179c6352c39388ab9b3e'
'5d741bf9ef9071f1a78cf8b1b8f0ffa62d67e1144628093e66a0e22ac06d5d3d'
'4d8c9deaa13619eb813e399413bb8e4a77b825e843e80efe9580f0c70317dbae'
'23cff79de2a818b58e8dc76551d32b67642c5031253350285dbec5d7f160a7a0'
'd3af6e355ce1508fcf021ab46dfed389f914e3f9cf1bbf11b2eec131d5b76427'
'8b40ce6feb86b09c30e08280b8a7cd7fb1a79eea1d5de827706411c629687c8d'
'115a79dceb93715bb729e351b5964003f1bf725044619f28a5a8c76adf5fb22b'
'd43e2eda22eea205f55ff452e6ebc6b844463c258885a1ea4beae908034d82dc'
'c8e849707874e5da7610ca69da5f4451fddd3182b2e6a9c4d4531bb0fce70636'
'a972aa3b1dfe1aa46365d595ab0011154fcb37dede6fd281494872b390181049'
'257d65205e783107115676c6fb193bed7554ca8eac5249c6053b1fddadbe0164'
'5d0234ef479c71b654432f70c004ea203d5d739a91eb2501c1b16c15d6ecf0eb'
'b92313d8fdb6552cbd30bdd287dac4cd5ebb275b3adc16f9a7ca69aac1de7269'
'59a5f0ebd8b7edbac6383d0c5493524b1e6083fe18feff269122ae90fa00984e'
'dd45a31922dd3f991510231db2b6bba177b6bba87391359cb3c0f952efe35e8d'
'623071a08e6f11605fcf2715b912f247c136c32cf4606ff4cd6fbf5dcea8cb13'
'4090a682251701822354b9234e56731696e29c5a18d9f784ace4acec48a289e0'
'f5a46311e324a21ba84378f7afcf84a6b63bf30863f87819082abaf69e07ffea'
'37c03f07e3dfd4797897bc763ab16584329dda38eb669ff0134e5c5bf8c1fee9'
'22907025b7eff0e8df69320b5e8c677ee36f492bfc28ecb216cba5a7a3d23fab'
'd2cacebfa98032fbe0b4cf8d5f57715701d2b27a6e3b419480a239ee7e88c248'
'e9990ef0b19f76c34538afca009e3133d382d95ba04d73c7fa3c376bf24f775c'
'93059974c72ac6975b75bf014a5d1e9e4dee0af91c714e54efde9549ae7abe1d'
'5a1bd1b7a6398f941a2c5a2f106f8e58ba94ff7f0dba8f96fb9e74551e821177'
'84af604adc392c5e8e4b721219694f0a7c3d7f1c507ec6ffe4cb3349c6bd2d51'
'2e6b997431443c53449af401bc5d4a3645c55ba3268809cf5c28cdfbe98e379c'
'f81d536f84b589fa2bdf516c7f7a07083da5a0729467203a918fb8f715b366a7'
'2c1ab430785c1d3ac2622db66aa531a165d592d997e7f445c8512786217955c8'
'7b6d71ac78967c7bcf45c3f9b458874373dcf5ac7b8df451df9dbe7d42e07a6d'
'308db49020bae14b42de494e72216c0b9b222f59d1e18d1e4c04dda45e060e54'
'5b9194b11f214fc7033265ef0f1ed085485318b6fd3028074c8c58115a59a868'
'3568421c2ac4434ccc340add69520bce021b52f90ff2ef3bf065ff2e249e5903')
pkgver() {
cd gtk
git describe --tags | sed 's/[^-]*-g/r&/;s/-/+/g'
}
prepare() {
cd gtk
local src
for src in "${source[@]}"; do
src="${src%%::*}"
src="${src##*/}"
[[ $src = *.patch ]] || continue
msg2 "Applying patch $src..."
patch -Np1 < "../$src"
done
}
build() {
local meson_options=(
-D broadway_backend=true
-D cloudproviders=true
-D colord=yes
-D gtk_doc=true
-D introspection=true
-D man=true
-D tracker=false
-D tracker3=true
)
CFLAGS+=" -DG_DISABLE_CAST_CHECKS"
arch-meson gtk build "${meson_options[@]}"
meson compile -C build
}
package() {
meson install -C build --destdir "$pkgdir"
install -Dm644 /dev/stdin "$pkgdir/usr/share/gtk-3.0/settings.ini" <<END
[Settings]
gtk-icon-theme-name = Adwaita
gtk-theme-name = Adwaita
gtk-font-name = Cantarell 11
END
install -Dt "$pkgdir/usr/share/libalpm/hooks" -m644 gtk-query-immodules-3.0.hook
cd "$pkgdir"
# Built by GTK 4, shared with GTK 3
rm usr/bin/gtk-update-icon-cache
rm usr/share/man/man1/gtk-update-icon-cache.1
# provided by gtk3-docs
rm -r usr/share/gtk-doc
# provided by gtk3-demos
rm -r usr/bin/gtk3-{demo,demo-application,icon-browser,widget-factory}
rm -r usr/share/applications/gtk3-{demo,icon-browser,widget-factory}.desktop
rm -r usr/share/glib-2.0/schemas/org.gtk.{Demo,exampleapp}.gschema.xml
rm -r usr/share/icons/hicolor/*/apps/gtk3-{demo,widget-factory}[-.]*
rm -r usr/share/man/man1/gtk3-{demo,demo-application,icon-browser,widget-factory}.1
}
# vim:set ts=2 sw=2 et:

View file

@ -0,0 +1,728 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Mon, 24 Jun 2019 15:52:36 +0200
Subject: Port file chooser to phones
Fixes https://source.puri.sm/Librem5/Apps_Issues/issues/99.
---
gtk/gtkfilechooserdialog.c | 2 +-
gtk/gtkfilechooserwidget.c | 165 ++++++++++++++++++++++++++++++++++-------
gtk/gtkplacesview.c | 24 ++++++
gtk/ui/gtkfilechooserwidget.ui | 87 ++++++++++++++++------
gtk/ui/gtkplacesview.ui | 3 +-
5 files changed, 226 insertions(+), 55 deletions(-)
diff --git a/gtk/gtkfilechooserdialog.c b/gtk/gtkfilechooserdialog.c
index db1d8f6..cf4229a 100644
--- a/gtk/gtkfilechooserdialog.c
+++ b/gtk/gtkfilechooserdialog.c
@@ -532,7 +532,7 @@ setup_save_entry (GtkFileChooserDialog *dialog)
need_entry = action == GTK_FILE_CHOOSER_ACTION_SAVE ||
action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
- if (need_entry && !dialog->priv->has_entry)
+ if (need_entry && !dialog->priv->has_entry && FALSE)
{
GtkWidget *box;
GtkWidget *label;
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 0496fd2..32a32aa 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -31,6 +31,7 @@
#include "gtkcheckmenuitem.h"
#include "gtkclipboard.h"
#include "gtkcomboboxtext.h"
+#include "gtkcssprovider.h"
#include "gtkdragsource.h"
#include "gtkdragdest.h"
#include "gtkentry.h"
@@ -80,6 +81,8 @@
#include "gtkseparator.h"
#include "gtkmodelbutton.h"
#include "gtkgesturelongpress.h"
+#include "hdy-clamp-private.h"
+#include "hdy-flap-private.h"
#include <cairo-gobject.h>
@@ -225,7 +228,8 @@ struct _GtkFileChooserWidgetPrivate {
GtkWidget *save_widgets_table;
/* The file browsing widgets */
- GtkWidget *browse_widgets_hpaned;
+ GtkWidget *flap;
+ GtkWidget *browse_box;
GtkWidget *browse_header_revealer;
GtkWidget *browse_header_stack;
GtkWidget *browse_files_stack;
@@ -379,6 +383,7 @@ struct _GtkFileChooserWidgetPrivate {
guint create_folders : 1;
guint auto_selecting_first_row : 1;
guint browse_files_interaction_frozen : 1;
+ guint location_visible : 1;
};
#define MAX_LOADING_TIME 500
@@ -426,6 +431,7 @@ enum {
MODEL_COL_TIME_TEXT,
MODEL_COL_LOCATION_TEXT,
MODEL_COL_ELLIPSIZE,
+ MODEL_COL_DISPLAY,
MODEL_COL_NUM_COLUMNS
};
@@ -445,7 +451,8 @@ enum {
G_TYPE_STRING, /* MODEL_COL_DATE_TEXT */ \
G_TYPE_STRING, /* MODEL_COL_TIME_TEXT */ \
G_TYPE_STRING, /* MODEL_COL_LOCATION_TEXT */ \
- PANGO_TYPE_ELLIPSIZE_MODE /* MODEL_COL_ELLIPSIZE */
+ PANGO_TYPE_ELLIPSIZE_MODE, /* MODEL_COL_ELLIPSIZE */ \
+ G_TYPE_STRING /* MODEL_COL_DISPLAY */
#define DEFAULT_RECENT_FILES_LIMIT 50
@@ -1289,6 +1296,9 @@ places_sidebar_open_location_cb (GtkPlacesSidebar *sidebar,
operation_mode_set (impl, OPERATION_MODE_RECENT);
else
change_folder_and_display_error (impl, location, clear_entry);
+
+ if (gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap)))
+ gtk_hdy_flap_set_reveal_flap (GTK_HDY_FLAP (priv->flap), FALSE);
}
/* Callback used when the places sidebar needs us to display an error message */
@@ -1846,6 +1856,24 @@ open_folder_cb (GSimpleAction *action,
}
G_GNUC_END_IGNORE_DEPRECATIONS
+static void
+update_show_columns (GtkFileChooserWidget *impl)
+{
+ GtkFileChooserWidgetPrivate *priv = impl->priv;
+ gboolean folded = gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap));
+
+ gtk_tree_view_column_set_visible (priv->list_size_column,
+ priv->show_size_column && !folded);
+ gtk_tree_view_column_set_visible (priv->list_type_column,
+ priv->show_type_column && !folded);
+ gtk_tree_view_column_set_visible (priv->list_time_column, !folded);
+ g_object_set (priv->list_time_renderer,
+ "visible", priv->show_time && !folded,
+ NULL);
+
+ clear_model_cache (impl, MODEL_COL_DISPLAY);
+}
+
/* callback used when the "Show Hidden Files" menu item is toggled */
static void
change_show_hidden_state (GSimpleAction *action,
@@ -1870,8 +1898,7 @@ change_show_size_state (GSimpleAction *action,
g_simple_action_set_state (action, state);
priv->show_size_column = g_variant_get_boolean (state);
- gtk_tree_view_column_set_visible (priv->list_size_column,
- priv->show_size_column);
+ update_show_columns (impl);
}
/* Callback used when the "Show Type Column" menu item is toggled */
@@ -1886,8 +1913,8 @@ change_show_type_state (GSimpleAction *action,
g_simple_action_set_state (action, state);
priv->show_type_column = g_variant_get_boolean (state);
- gtk_tree_view_column_set_visible (priv->list_type_column,
- priv->show_type_column);
+ update_show_columns (impl);
+
}
static void
@@ -1952,11 +1979,9 @@ update_time_renderer_visible (GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
- g_object_set (priv->list_time_renderer,
- "visible", priv->show_time,
- NULL);
clear_model_cache (impl, MODEL_COL_DATE_TEXT);
clear_model_cache (impl, MODEL_COL_TIME_TEXT);
+ update_show_columns (impl);
gtk_widget_queue_draw (priv->browse_files_tree_view);
}
@@ -2637,7 +2662,7 @@ location_entry_setup (GtkFileChooserWidget *impl)
_gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (priv->location_entry), priv->action);
_gtk_file_chooser_entry_set_file_filter (GTK_FILE_CHOOSER_ENTRY (priv->location_entry),
priv->current_filter);
- gtk_entry_set_width_chars (GTK_ENTRY (priv->location_entry), 45);
+
gtk_entry_set_activates_default (GTK_ENTRY (priv->location_entry), TRUE);
}
@@ -2684,6 +2709,8 @@ save_widgets_create (GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
GtkWidget *vbox;
+ GtkWidget *clamp;
+ GtkWidget *separator;
GtkWidget *widget;
if (priv->save_widgets != NULL ||
@@ -2705,14 +2732,19 @@ save_widgets_create (GtkFileChooserWidget *impl)
return;
}
- vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- gtk_style_context_add_class (gtk_widget_get_style_context (vbox), "search-bar");
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 0);
+ clamp = gtk_hdy_clamp_new ();
+ gtk_widget_show (clamp);
+ gtk_container_add (GTK_CONTAINER (vbox), clamp);
+
+ separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_widget_show (separator);
+ gtk_container_add (GTK_CONTAINER (vbox), separator);
priv->save_widgets_table = gtk_grid_new ();
- gtk_container_set_border_width (GTK_CONTAINER (priv->save_widgets_table), 10);
- gtk_box_pack_start (GTK_BOX (vbox), priv->save_widgets_table, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (priv->save_widgets_table), 6);
+ gtk_container_add (GTK_CONTAINER (clamp), priv->save_widgets_table);
gtk_widget_show (priv->save_widgets_table);
gtk_grid_set_row_spacing (GTK_GRID (priv->save_widgets_table), 12);
gtk_grid_set_column_spacing (GTK_GRID (priv->save_widgets_table), 12);
@@ -2878,6 +2910,9 @@ places_sidebar_show_other_locations_with_flags_cb (GtkPlacesSidebar *sidebar
update_preview_widget_visibility (impl);
operation_mode_set (impl, OPERATION_MODE_OTHER_LOCATIONS);
+
+ if (gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap)))
+ gtk_hdy_flap_set_reveal_flap (GTK_HDY_FLAP (priv->flap), FALSE);
}
static void
@@ -2940,7 +2975,8 @@ update_extra_and_filters (GtkFileChooserWidget *impl)
{
gtk_widget_set_visible (impl->priv->extra_and_filters,
gtk_widget_get_visible (impl->priv->extra_align) ||
- gtk_widget_get_visible (impl->priv->filter_combo_hbox));
+ gtk_widget_get_visible (impl->priv->filter_combo_hbox) ||
+ gtk_hdy_flap_get_folded (GTK_HDY_FLAP (impl->priv->flap)));
}
/* Sets the extra_widget by packing it in the appropriate place */
@@ -3755,7 +3791,7 @@ change_icon_theme (GtkFileChooserWidget *impl)
profile_start ("start", NULL);
- if (gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height))
+ if (gtk_icon_size_lookup (GTK_ICON_SIZE_DND, &width, &height))
priv->icon_size = MAX (width, height);
else
priv->icon_size = FALLBACK_ICON_SIZE;
@@ -3888,7 +3924,6 @@ settings_load (GtkFileChooserWidget *impl)
gint sort_column;
GtkSortType sort_order;
StartupMode startup_mode;
- gint sidebar_width;
GSettings *settings;
settings = _gtk_file_chooser_get_settings_for_widget (GTK_WIDGET (impl));
@@ -3898,7 +3933,6 @@ settings_load (GtkFileChooserWidget *impl)
show_type_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_TYPE_COLUMN);
sort_column = g_settings_get_enum (settings, SETTINGS_KEY_SORT_COLUMN);
sort_order = g_settings_get_enum (settings, SETTINGS_KEY_SORT_ORDER);
- sidebar_width = g_settings_get_int (settings, SETTINGS_KEY_SIDEBAR_WIDTH);
startup_mode = g_settings_get_enum (settings, SETTINGS_KEY_STARTUP_MODE);
sort_directories_first = g_settings_get_boolean (settings, SETTINGS_KEY_SORT_DIRECTORIES_FIRST);
date_format = g_settings_get_enum (settings, SETTINGS_KEY_DATE_FORMAT);
@@ -3907,9 +3941,8 @@ settings_load (GtkFileChooserWidget *impl)
if (!priv->show_hidden_set)
set_show_hidden (impl, show_hidden);
priv->show_size_column = show_size_column;
- gtk_tree_view_column_set_visible (priv->list_size_column, show_size_column);
priv->show_type_column = show_type_column;
- gtk_tree_view_column_set_visible (priv->list_type_column, show_type_column);
+ update_show_columns (impl);
priv->sort_column = sort_column;
priv->sort_order = sort_order;
@@ -3924,7 +3957,6 @@ settings_load (GtkFileChooserWidget *impl)
*/
update_time_renderer_visible (impl);
- gtk_paned_set_position (GTK_PANED (priv->browse_widgets_hpaned), sidebar_width);
}
static void
@@ -3945,8 +3977,6 @@ settings_save (GtkFileChooserWidget *impl)
g_settings_set_boolean (settings, SETTINGS_KEY_SORT_DIRECTORIES_FIRST, priv->sort_directories_first);
g_settings_set_enum (settings, SETTINGS_KEY_SORT_COLUMN, priv->sort_column);
g_settings_set_enum (settings, SETTINGS_KEY_SORT_ORDER, priv->sort_order);
- g_settings_set_int (settings, SETTINGS_KEY_SIDEBAR_WIDTH,
- gtk_paned_get_position (GTK_PANED (priv->browse_widgets_hpaned)));
g_settings_set_enum (settings, SETTINGS_KEY_DATE_FORMAT, priv->show_time ? DATE_FORMAT_WITH_TIME : DATE_FORMAT_REGULAR);
g_settings_set_enum (settings, SETTINGS_KEY_TYPE_FORMAT, priv->type_format);
@@ -4416,13 +4446,18 @@ update_columns (GtkFileChooserWidget *impl,
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
gboolean need_resize = FALSE;
+ gboolean folded = gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap));
+
+ priv->location_visible = location_visible;
- if (gtk_tree_view_column_get_visible (priv->list_location_column) != location_visible)
+ if (gtk_tree_view_column_get_visible (priv->list_location_column) != (location_visible && !folded))
{
- gtk_tree_view_column_set_visible (priv->list_location_column, location_visible);
+ gtk_tree_view_column_set_visible (priv->list_location_column, location_visible && !folded);
need_resize = TRUE;
}
+ clear_model_cache (impl, MODEL_COL_DISPLAY);
+
if (g_strcmp0 (gtk_tree_view_column_get_title (priv->list_time_column), time_title) != 0)
{
gtk_tree_view_column_set_title (priv->list_time_column, time_title);
@@ -5303,6 +5338,47 @@ file_system_model_set (GtkFileSystemModel *model,
g_object_unref (home_location);
}
break;
+ case MODEL_COL_DISPLAY:
+ {
+ gchar *metadata_str;
+ gchar* metadata[7];
+ int i = 0;
+
+ #define APPEND_COLUMN(column) {\
+ GValue val = { 0, }; \
+ gchar *ret; \
+ g_value_init (&val, G_TYPE_STRING); \
+ file_system_model_set (model, file, info, column, &val, data); \
+ ret = g_value_get_string (&val); \
+ if (ret && *ret) \
+ metadata[i++] = g_markup_escape_text (ret, -1); \
+ g_value_unset (&val); \
+ }
+
+ APPEND_COLUMN(MODEL_COL_NAME)
+ APPEND_COLUMN(MODEL_COL_DATE_TEXT)
+
+ if (priv->show_time)
+ APPEND_COLUMN(MODEL_COL_TIME_TEXT)
+
+ if (priv->show_type_column)
+ APPEND_COLUMN(MODEL_COL_TYPE)
+
+ if (priv->show_size_column)
+ APPEND_COLUMN(MODEL_COL_SIZE_TEXT)
+
+ if (priv->operation_mode == OPERATION_MODE_RECENT)
+ APPEND_COLUMN(MODEL_COL_LOCATION_TEXT)
+
+ metadata[i] = NULL;
+ metadata_str = g_strjoinv (" · ", &metadata[1]);
+ g_value_take_string (value, g_strdup_printf ("%s\n<span size=\"smaller\" alpha=\"55%%\">%s</span>", metadata[0], metadata_str));
+
+ while (i > 0)
+ g_free (metadata[--i]);
+ g_free (metadata_str);
+ }
+ break;
default:
g_assert_not_reached ();
break;
@@ -8106,6 +8182,7 @@ static void
update_cell_renderer_attributes (GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
+ gboolean folded = gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap));
gtk_tree_view_column_set_attributes (priv->list_name_column,
priv->list_pixbuf_renderer,
@@ -8114,7 +8191,8 @@ update_cell_renderer_attributes (GtkFileChooserWidget *impl)
NULL);
gtk_tree_view_column_set_attributes (priv->list_name_column,
priv->list_name_renderer,
- "text", MODEL_COL_NAME,
+ folded ? "markup" : "text",
+ folded ? MODEL_COL_DISPLAY : MODEL_COL_NAME,
"ellipsize", MODEL_COL_ELLIPSIZE,
"sensitive", MODEL_COL_IS_SENSITIVE,
NULL);
@@ -8152,6 +8230,20 @@ update_cell_renderer_attributes (GtkFileChooserWidget *impl)
update_time_renderer_visible (impl);
}
+static void
+flap_folded_cb (GtkFileChooserWidget *impl)
+{
+ GtkFileChooserWidgetPrivate *priv = impl->priv;
+ gboolean folded = gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap));
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->browse_files_tree_view), !folded);
+
+ update_show_columns (impl);
+ update_cell_renderer_attributes (impl);
+ update_extra_and_filters (impl);
+ update_columns (impl, priv->location_visible, gtk_tree_view_column_get_title (priv->list_time_column));
+}
+
static void
location_set_user_text (GtkFileChooserWidget *impl,
const gchar *path)
@@ -8688,12 +8780,13 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
"/org/gtk/libgtk/ui/gtkfilechooserwidget.ui");
/* A *lot* of widgets that we need to handle .... */
- gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_widgets_hpaned);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_stack);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_sidebar);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_view);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_tree_view);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_swin);
+ gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, flap);
+ gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_box);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_header_revealer);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_header_stack);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_new_folder_button);
@@ -8755,6 +8848,7 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
gtk_widget_class_bind_template_callback (widget_class, rename_file_name_changed);
gtk_widget_class_bind_template_callback (widget_class, rename_file_rename_clicked);
gtk_widget_class_bind_template_callback (widget_class, rename_file_end);
+ gtk_widget_class_bind_template_callback (widget_class, flap_folded_cb);
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_FILE_CHOOSER_WIDGET_ACCESSIBLE);
gtk_widget_class_set_css_name (widget_class, "filechooser");
@@ -8831,6 +8925,19 @@ post_process_ui (GtkFileChooserWidget *impl)
gtk_popover_set_relative_to (GTK_POPOVER (impl->priv->rename_file_popover), impl->priv->browse_files_tree_view);
add_actions (impl);
+
+ {
+ GtkCssProvider *provider;
+
+ provider = gtk_css_provider_new ();
+ gtk_css_provider_load_from_data (provider, "placessidebar { border: none; }", -1, NULL);
+
+ gtk_style_context_add_provider (gtk_widget_get_style_context (impl->priv->places_sidebar),
+ GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ }
+
+ update_extra_and_filters (impl);
}
void
@@ -8888,6 +8995,8 @@ gtk_file_chooser_widget_init (GtkFileChooserWidget *impl)
/* Ensure GTK+ private types used by the template
* definition before calling gtk_widget_init_template()
*/
+ g_type_ensure (GTK_TYPE_HDY_CLAMP);
+ g_type_ensure (GTK_TYPE_HDY_FLAP);
g_type_ensure (GTK_TYPE_PATH_BAR);
g_type_ensure (GTK_TYPE_PLACES_VIEW);
diff --git a/gtk/gtkplacesview.c b/gtk/gtkplacesview.c
index 89f7ace..fd17820 100644
--- a/gtk/gtkplacesview.c
+++ b/gtk/gtkplacesview.c
@@ -26,6 +26,7 @@
#include "gtkmarshalers.h"
#include "gtkplacesviewprivate.h"
#include "gtkplacesviewrowprivate.h"
+#include "gtkprivate.h"
#include "gtktypebuiltins.h"
/**
@@ -94,6 +95,9 @@ struct _GtkPlacesViewPrivate
guint fetching_networks : 1;
guint loading : 1;
guint destroyed : 1;
+
+ GtkWidget *connect_label;
+ GSettings *settings;
};
static void mount_volume (GtkPlacesView *view,
@@ -409,6 +413,8 @@ gtk_places_view_destroy (GtkWidget *widget)
g_cancellable_cancel (priv->cancellable);
g_cancellable_cancel (priv->networks_fetching_cancellable);
+ g_clear_object (&priv->settings);
+
GTK_WIDGET_CLASS (gtk_places_view_parent_class)->destroy (widget);
}
@@ -2211,6 +2217,14 @@ listbox_sort_func (GtkListBoxRow *row1,
return retval;
}
+static void
+update_connect_label (GtkPlacesView *self)
+{
+ GtkPlacesViewPrivate *priv = gtk_places_view_get_instance_private (self);
+
+ gtk_widget_set_visible (priv->connect_label, !_gtk_get_is_phone ());
+}
+
static void
gtk_places_view_constructed (GObject *object)
{
@@ -2260,6 +2274,15 @@ gtk_places_view_constructed (GObject *object)
"volume-removed",
G_CALLBACK (update_places),
object);
+
+ priv->settings = _gtk_get_purism_settings ();
+
+ if (priv->settings)
+ g_signal_connect_object (priv->settings, "changed::is-phone",
+ G_CALLBACK (update_connect_label), object,
+ G_CONNECT_SWAPPED);
+
+ update_connect_label (GTK_PLACES_VIEW (object));
}
static void
@@ -2386,6 +2409,7 @@ gtk_places_view_class_init (GtkPlacesViewClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, stack);
gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, server_adresses_popover);
gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, available_protocols_grid);
+ gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, connect_label);
gtk_widget_class_bind_template_callback (widget_class, on_address_entry_text_changed);
gtk_widget_class_bind_template_callback (widget_class, on_address_entry_show_help_pressed);
diff --git a/gtk/ui/gtkfilechooserwidget.ui b/gtk/ui/gtkfilechooserwidget.ui
index 6e7c21d..89f891c 100644
--- a/gtk/ui/gtkfilechooserwidget.ui
+++ b/gtk/ui/gtkfilechooserwidget.ui
@@ -9,14 +9,20 @@
<property name="visible">1</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkPaned" id="browse_widgets_hpaned">
+ <object class="GtkHdyFlap" id="flap">
<property name="visible">1</property>
- <child>
+ <property name="swipe-to-open">0</property>
+ <property name="swipe-to-close" bind-source="flap" bind-property="folded" bind-flags="sync-create"/>
+ <signal name="notify::folded" handler="flap_folded_cb" swapped="yes"/>
+ <child type="flap">
<object class="GtkPlacesSidebar" id="places_sidebar">
<property name="visible">1</property>
+ <property name="hexpand-set">1</property>
<property name="hscrollbar-policy">never</property>
<property name="local-only">1</property>
<property name="show-other-locations">1</property>
+ <property name="propagate-natural-width">1</property>
+ <property name="width-request">200</property>
<child internal-child="accessible">
<object class="AtkObject">
<property name="AtkObject::accessible-name" translatable="yes">Places</property>
@@ -29,13 +35,17 @@
<signal name="show-error-message" handler="places_sidebar_show_error_message_cb" swapped="no"/>
<signal name="show-other-locations-with-flags" handler="places_sidebar_show_other_locations_with_flags_cb" swapped="no"/>
</object>
- <packing>
- <property name="resize">0</property>
- <property name="shrink">0</property>
- </packing>
+ </child>
+ <child type="separator">
+ <object class="GtkSeparator">
+ <property name="visible">1</property>
+ <style>
+ <class name="sidebar"/>
+ </style>
+ </object>
</child>
<child>
- <object class="GtkBox">
+ <object class="GtkBox" id="browse_box">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<child>
@@ -110,6 +120,9 @@
<property name="name">pathbar</property>
</packing>
</child>
+ <child>
+ <object class="GtkHdyClamp">
+ <property name="visible">1</property>
<child>
<object class="GtkBox" id="location_entry_box">
<property name="visible">1</property>
@@ -122,10 +135,15 @@
</object>
</child>
</object>
+ </child>
+ </object>
<packing>
<property name="name">location</property>
</packing>
</child>
+ <child>
+ <object class="GtkHdyClamp">
+ <property name="visible">1</property>
<child>
<object class="GtkBox" id="search_entry_box">
<property name="visible">1</property>
@@ -137,10 +155,10 @@
<property name="AtkObject::accessible-name" translatable="yes">Search Layer</property>
</object>
</child>
- <child type="center">
+ <child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">1</property>
- <property name="width-chars">45</property>
+ <property name="hexpand">True</property>
<signal name="search-changed" handler="search_entry_activate_cb" swapped="yes"/>
<signal name="stop-search" handler="search_entry_stop_cb" swapped="yes"/>
</object>
@@ -154,6 +172,8 @@
</packing>
</child>
</object>
+ </child>
+ </object>
<packing>
<property name="name">search</property>
</packing>
@@ -171,9 +191,15 @@
</packing>
</child>
<child>
- <object class="GtkBox" id="list_and_preview_box">
+ <object class="GtkHdyFlap" id="list_and_preview_box">
<property name="visible">1</property>
- <property name="spacing">12</property>
+ <property name="flap-position">end</property>
+ <property name="fold-policy">never</property>
+ <property name="modal">False</property>
+ <property name="swipe-to-open">False</property>
+ <property name="swipe-to-close">False</property>
+ <property name="transition-type">slide</property>
+ <property name="reveal-flap" bind-source="flap" bind-property="folded" bind-flags="invert-boolean|sync-create"/>
<child>
<object class="GtkStack" id="browse_files_stack">
<property name="visible">1</property>
@@ -223,6 +249,7 @@
<child>
<object class="GtkCellRendererPixbuf" id="list_pixbuf_renderer">
<property name="xpad">6</property>
+ <property name="stock-size">5</property>
</object>
</child>
<child>
@@ -351,6 +378,8 @@
<object class="GtkLabel">
<property name="visible">1</property>
<property name="label" translatable="yes">No Results Found</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.44"/>
@@ -365,6 +394,8 @@
<object class="GtkLabel">
<property name="visible">1</property>
<property name="label" translatable="yes">Try a different search</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
<style>
<class name="dim-label"/>
</style>
@@ -380,19 +411,15 @@
</packing>
</child>
</object>
- <packing>
- <property name="expand">1</property>
- </packing>
</child>
- <child>
+ <child type="flap">
<object class="GtkBox" id="preview_box">
<property name="orientation">vertical</property>
<property name="spacing">12</property>
+ <style>
+ <class name="background"/>
+ </style>
</object>
- <packing>
- <property name="fill">0</property>
- <property name="position">1</property>
- </packing>
</child>
</object>
<packing>
@@ -401,9 +428,6 @@
</packing>
</child>
</object>
- <packing>
- <property name="shrink">0</property>
- </packing>
</child>
</object>
<packing>
@@ -419,15 +443,30 @@
<child>
<object class="GtkActionBar" id="extra_and_filters">
<property name="no-show-all">1</property>
+ <child>
+ <object class="GtkToggleButton" id="reveal_sidebar_button">
+ <property name="visible" bind-source="flap" bind-property="folded" bind-flags="sync-create"/>
+ <property name="active" bind-source="flap" bind-property="reveal-flap" bind-flags="sync-create|bidirectional"/>
+ <property name="tooltip-text" translatable="yes">Show locations</property>
+ <property name="use-underline">1</property>
+ <property name="can-default">1</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">1</property>
+ <property name="icon-name">view-sidebar-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
<child>
<object class="GtkBox" id="extra_align">
- <property name="visible">1</property>
+ <property name="no-show-all">1</property>
<property name="spacing">12</property>
</object>
</child>
<child>
<object class="GtkBox" id="filter_combo_hbox">
- <property name="visible">1</property>
+ <property name="no-show-all">1</property>
<property name="spacing">12</property>
<child>
<object class="GtkComboBoxText" id="filter_combo">
diff --git a/gtk/ui/gtkplacesview.ui b/gtk/ui/gtkplacesview.ui
index 5ede590..d68aab0 100644
--- a/gtk/ui/gtkplacesview.ui
+++ b/gtk/ui/gtkplacesview.ui
@@ -300,7 +300,7 @@
<class name="background"/>
</style>
<child>
- <object class="GtkLabel">
+ <object class="GtkLabel" id="connect_label">
<property name="visible">1</property>
<property name="hexpand">1</property>
<property name="xalign">0</property>
@@ -336,7 +336,6 @@
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="hexpand">1</property>
- <property name="width-chars">20</property>
<property name="placeholder-text" translatable="yes">Enter server address…</property>
<property name="secondary-icon-name">dialog-question-symbolic</property>
<property name="completion">address_entry_completion</property>

View file

@ -0,0 +1,38 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Sun, 25 Aug 2019 10:20:31 +0200
Subject: Reduce the font chooser minimum size
This helps GtkfontChooserDialog fitting in mobile phone screens.
---
gtk/ui/gtkfontchooserdialog.ui | 2 ++
gtk/ui/gtkfontchooserwidget.ui | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/gtk/ui/gtkfontchooserdialog.ui b/gtk/ui/gtkfontchooserdialog.ui
index 1067096..f787ee6 100644
--- a/gtk/ui/gtkfontchooserdialog.ui
+++ b/gtk/ui/gtkfontchooserdialog.ui
@@ -5,6 +5,8 @@
<property name="border-width">5</property>
<property name="title" translatable="yes">Select Font</property>
<property name="type-hint">dialog</property>
+ <property name="default-width">400</property>
+ <property name="default-height">500</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="orientation">vertical</property>
diff --git a/gtk/ui/gtkfontchooserwidget.ui b/gtk/ui/gtkfontchooserwidget.ui
index 2d39200..074f233 100644
--- a/gtk/ui/gtkfontchooserwidget.ui
+++ b/gtk/ui/gtkfontchooserwidget.ui
@@ -70,8 +70,8 @@
<child>
<object class="GtkScrolledWindow" id="list_scrolled_window">
<property name="visible">1</property>
- <property name="width-request">400</property>
- <property name="height-request">300</property>
+ <property name="width-request">300</property>
+ <property name="height-request">50</property>
<property name="can-focus">1</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>

View file

@ -0,0 +1,186 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Mon, 28 Jan 2019 18:52:40 +0100
Subject: aboutdialog: Port to phones
---
gtk/gtkaboutdialog.c | 22 ++++++++++++++++------
gtk/ui/gtkaboutdialog.ui | 30 +++++++++++++++++++++++++-----
2 files changed, 41 insertions(+), 11 deletions(-)
diff --git a/gtk/gtkaboutdialog.c b/gtk/gtkaboutdialog.c
index adb0515..a1967b0 100644
--- a/gtk/gtkaboutdialog.c
+++ b/gtk/gtkaboutdialog.c
@@ -51,12 +51,13 @@
#include "gtktogglebutton.h"
#include "gtktypebuiltins.h"
#include "gtkstack.h"
-#include "gtkstackswitcher.h"
#include "gtksettings.h"
#include "gtkheaderbar.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkdialogprivate.h"
+#include "hdy-view-switcher-bar-private.h"
+#include "hdy-view-switcher-title-private.h"
/**
@@ -162,6 +163,7 @@ struct _GtkAboutDialogPrivate
GtkWidget *stack;
GtkWidget *stack_switcher;
+ GtkWidget *stack_switcher_mobile;
GtkWidget *credits_button;
GtkWidget *license_button;
@@ -591,6 +593,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, stack);
gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, stack_switcher);
+ gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, stack_switcher_mobile);
gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, logo_image);
gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, name_label);
gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, version_label);
@@ -625,12 +628,13 @@ static void
update_stack_switcher_visibility (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv = about->priv;
+ gboolean show;
- if (gtk_widget_get_visible (priv->credits_page) ||
- gtk_widget_get_visible (priv->license_page))
- gtk_widget_show (priv->stack_switcher);
- else
- gtk_widget_hide (priv->stack_switcher);
+ show = gtk_widget_get_visible (priv->credits_page) ||
+ gtk_widget_get_visible (priv->license_page);
+
+ gtk_widget_set_visible (priv->stack_switcher, show);
+ gtk_widget_set_visible (priv->stack_switcher_mobile, show);
}
static void
@@ -749,6 +753,9 @@ gtk_about_dialog_init (GtkAboutDialog *about)
gtk_dialog_set_default_response (GTK_DIALOG (about), GTK_RESPONSE_CANCEL);
+ g_type_ensure (GTK_TYPE_HDY_VIEW_SWITCHER_BAR);
+ g_type_ensure (GTK_TYPE_HDY_VIEW_SWITCHER_TITLE);
+
gtk_widget_init_template (GTK_WIDGET (about));
gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (about));
@@ -2197,6 +2204,9 @@ add_credits_section (GtkAboutDialog *about,
markup = g_strdup_printf ("<span size=\"small\">%s</span>", title);
label = gtk_label_new (markup);
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_line_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD_CHAR);
+
g_free (markup);
gtk_widget_set_halign (label, GTK_ALIGN_END);
gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
diff --git a/gtk/ui/gtkaboutdialog.ui b/gtk/ui/gtkaboutdialog.ui
index 31bb628..7d3d2a5 100644
--- a/gtk/ui/gtkaboutdialog.ui
+++ b/gtk/ui/gtkaboutdialog.ui
@@ -6,29 +6,32 @@
<property name="icon-name">help-about</property>
</object>
<template class="GtkAboutDialog" parent="GtkDialog">
- <property name="border-width">5</property>
- <property name="resizable">0</property>
<property name="type-hint">dialog</property>
+ <property name="default-width">420</property>
<child internal-child="headerbar">
<object class="GtkHeaderBar" id="headerbar1">
<property name="visible">1</property>
<property name="show-close-button">1</property>
<child type="title">
- <object class="GtkStackSwitcher" id="stack_switcher">
+ <object class="GtkHdyViewSwitcherTitle" id="stack_switcher">
+ <property name="visible">1</property>
<property name="stack">stack</property>
<property name="no-show-all">1</property>
+ <property name="policy">wide</property>
+ <property name="title" bind-source="GtkAboutDialog" bind-property="title" bind-flags="sync-create"/>
</object>
</child>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
+ <property name="border-width">0</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkBox" id="box">
<property name="visible">1</property>
- <property name="border-width">5</property>
+ <property name="border-width">12</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
@@ -57,12 +60,16 @@
</child>
<child>
<object class="GtkStack" id="stack">
- <property name="width-request">400</property>
+ <property name="width-request">300</property>
<property name="height-request">100</property>
<property name="visible">1</property>
<property name="transition-type">over-up-down</property>
<property name="transition-duration">600</property>
<signal name="notify::visible-child" handler="stack_visible_child_notify" swapped="no"/>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="visible">1</property>
+ <property name="propagate-natural-height">1</property>
<child>
<object class="GtkBox" id="page_vbox">
<property name="visible">1</property>
@@ -131,9 +138,12 @@
<property name="fill">0</property>
</packing>
</child>
+ </object>
+ </child>
</object>
<packing>
<property name="name">main</property>
+ <property name="icon-name">help-about-symbolic</property>
<property name="title" translatable="yes">About</property>
</packing>
</child>
@@ -174,6 +184,7 @@
</object>
<packing>
<property name="name">credits</property>
+ <property name="icon-name">system-users-symbolic</property>
<property name="title" translatable="yes">Credits</property>
</packing>
</child>
@@ -207,6 +218,7 @@
</object>
<packing>
<property name="name">license</property>
+ <property name="icon-name">accessories-dictionary-symbolic</property>
<property name="title" translatable="yes">License</property>
</packing>
</child>
@@ -222,6 +234,14 @@
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkHdyViewSwitcherBar" id="stack_switcher_mobile">
+ <property name="stack">stack</property>
+ <property name="no-show-all">1</property>
+ <property name="visible">1</property>
+ <property name="reveal" bind-source="stack_switcher" bind-property="title-visible" bind-flags="sync-create"/>
+ </object>
+ </child>
</object>
</child>
</template>

View file

@ -0,0 +1,23 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Thu, 11 Jul 2019 10:26:16 +0200
Subject: dialog: Maximize resizable dialogs on phones
This will make them look better on phone screens.
---
gtk/gtkdialog.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/gtk/gtkdialog.c b/gtk/gtkdialog.c
index 0e58ac4..84e1413 100644
--- a/gtk/gtkdialog.c
+++ b/gtk/gtkdialog.c
@@ -779,6 +779,9 @@ gtk_dialog_map (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_dialog_parent_class)->map (widget);
+ if (gtk_window_get_resizable (window) && _gtk_get_is_phone ())
+ gtk_window_maximize (window);
+
focus = gtk_window_get_focus (window);
if (!focus)
{

View file

@ -0,0 +1,67 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Thu, 3 Dec 2020 14:42:23 +0500
Subject: events: Compress touch update events
GTK3 often moves child windows around in response to touch gestures, such
as scrolling or swipes. This leads to a problem when a frame has multiple
events whose coordinates are relative to the window: the first event moves
the window, then the second event has wrong coordinates. This leads to a
severe jumping when scrolling or swiping when the system slows down.
GTK4 fixes this by getting rid of child windows completely, but for GTK3
we have to work around this by compressing touch update events. This isn't
really suitable for upstream, but wouldn't be the worst patch we have
downstream.
See https://source.puri.sm/Librem5/debs/gtk/-/issues/8
---
gdk/gdkevents.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index 087178e..40ef45d 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -268,30 +268,36 @@ _gdk_event_queue_handle_motion_compression (GdkDisplay *display)
while (tmp_list)
{
GdkEventPrivate *event = tmp_list->data;
+ GdkWindow *window;
+ GdkDevice *device;
if (event->flags & GDK_EVENT_PENDING)
break;
- if (event->event.type != GDK_MOTION_NOTIFY)
+ if (event->event.type != GDK_MOTION_NOTIFY &&
+ event->event.type != GDK_TOUCH_UPDATE)
break;
+ window = gdk_event_get_window (&event->event);
+ device = gdk_event_get_device (&event->event);
+
if (pending_motion_window != NULL &&
- pending_motion_window != event->event.motion.window)
+ pending_motion_window != window)
break;
if (pending_motion_device != NULL &&
- pending_motion_device != event->event.motion.device)
+ pending_motion_device != device)
break;
- pending_motion_window = event->event.motion.window;
+ pending_motion_window = window;
- if (!event->event.motion.window->event_compression)
+ if (!window->event_compression)
{
uncompressed_motion = TRUE;
break;
}
- pending_motion_device = event->event.motion.device;
+ pending_motion_device = device;
pending_motions = tmp_list;
tmp_list = tmp_list->prev;

View file

@ -0,0 +1,46 @@
From: =?utf-8?q?Guido_G=C3=BCnther?= <agx@sigxcpu.org>
Date: Fri, 10 Mar 2023 12:25:13 +0100
Subject: gdk/wayland: Track last touch serial on seat
Since the touch data is released on touch up
_gdk_wayland_seat_get_last_implicit_grab_serial will return 0 serial
most of the time for touch only devices. This breaks xdg activation as
the compositor will reject tokens that have a 0 serial set via
xdg_activation_token_v1_set_serial.
Avoid that by tracking touch serials on the seat itself too.
---
gdk/wayland/gdkdevice-wayland.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index 9dc86a3..9570e82 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -212,6 +212,7 @@ struct _GdkWaylandSeat
GdkKeymap *keymap;
GHashTable *touches;
+ guint32 last_touch_down_serial;
GList *tablets;
GList *tablet_tools;
GList *tablet_pads;
@@ -2514,7 +2515,7 @@ touch_handle_down (void *data,
touch = gdk_wayland_seat_add_touch (seat, id, wl_surface);
touch->x = wl_fixed_to_double (x);
touch->y = wl_fixed_to_double (y);
- touch->touch_down_serial = serial;
+ seat->last_touch_down_serial = touch->touch_down_serial = serial;
event = _create_touch_event (seat, touch, GDK_TOUCH_BEGIN, time);
@@ -5398,6 +5399,9 @@ _gdk_wayland_seat_get_last_implicit_grab_serial (GdkSeat *seat,
}
}
+ if (wayland_seat->last_touch_down_serial > serial)
+ serial = wayland_seat->last_touch_down_serial;
+
return serial;
}

View file

@ -0,0 +1,11 @@
[Trigger]
Type = File
Operation = Install
Operation = Upgrade
Operation = Remove
Target = usr/lib/gtk-3.0/3.0.0/immodules/*.so
[Action]
Description = Probing GTK3 input method modules...
When = PostTransaction
Exec = /usr/bin/gtk-query-immodules-3.0 --update-cache

3
gtk3-mobile/gtk3.install Normal file
View file

@ -0,0 +1,3 @@
pre_remove() {
rm -f /usr/lib/gtk-3.0/3.0.0/immodules.cache
}

View file

@ -0,0 +1,53 @@
From: Mohammed Sadiq <sadiq@sadiqpk.org>
Date: Thu, 27 Aug 2020 14:48:11 +0530
Subject: gtkprivate: Add an API to check if phone
---
gtk/gtkprivate.h | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index aca24fd..635b247 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -127,6 +127,40 @@ GBytes *get_emoji_data (void);
#endif /* G_ENABLE_DEBUG */
+static inline GSettings *
+_gtk_get_purism_settings (void)
+{
+ GSettings *gsettings;
+ GSettingsSchema *schema;
+
+ schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
+ "org.gtk.Settings.Purism", TRUE);
+
+ if (!schema)
+ return NULL;
+
+ gsettings = g_settings_new_full (schema, NULL, NULL);
+
+ g_settings_schema_unref (schema);
+
+ return gsettings;
+}
+
+static inline gboolean
+_gtk_get_is_phone (void)
+{
+ GSettings *gsettings = _gtk_get_purism_settings ();
+ gboolean is_phone;
+
+ if (!gsettings)
+ return FALSE;
+
+ is_phone = g_settings_get_boolean (gsettings, "is-phone");
+ g_object_unref (gsettings);
+
+ return is_phone;
+}
+
G_END_DECLS
#endif /* __GTK_PRIVATE_H__ */

View file

@ -0,0 +1,51 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Wed, 23 Dec 2020 16:33:24 +0500
Subject: hdy-flap: Use natural size for folding instead of minimum
See https://gitlab.gnome.org/GNOME/libhandy/-/issues/390#note_991319
---
gtk/hdy-flap.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/gtk/hdy-flap.c b/gtk/hdy-flap.c
index 8735ad9..1b4504d 100644
--- a/gtk/hdy-flap.c
+++ b/gtk/hdy-flap.c
@@ -962,21 +962,29 @@ gtk_hdy_flap_size_allocate (GtkWidget *widget,
alloc->x, alloc->y, alloc->width, alloc->height);
if (self->fold_policy == GTK_HDY_FLAP_FOLD_POLICY_AUTO) {
- GtkRequisition flap_min = { 0, 0 };
- GtkRequisition content_min = { 0, 0 };
- GtkRequisition separator_min = { 0, 0 };
+ GtkRequisition flap_size = { 0, 0 };
+ GtkRequisition content_size = { 0, 0 };
+ GtkRequisition separator_size = { 0, 0 };
+ gboolean flap_expand, content_expand;
+
+ flap_expand = gtk_widget_compute_expand (self->flap.widget, self->orientation);
+ content_expand = gtk_widget_compute_expand (self->content.widget, self->orientation);
if (self->flap.widget)
- gtk_widget_get_preferred_size (self->flap.widget, &flap_min, NULL);
+ gtk_widget_get_preferred_size (self->flap.widget,
+ content_expand ? &flap_size : NULL,
+ content_expand ? NULL : &flap_size);
if (self->content.widget)
- gtk_widget_get_preferred_size (self->content.widget, &content_min, NULL);
+ gtk_widget_get_preferred_size (self->content.widget,
+ flap_expand ? &content_size : NULL,
+ flap_expand ? NULL : &content_size);
if (self->separator.widget)
- gtk_widget_get_preferred_size (self->separator.widget, &separator_min, NULL);
+ gtk_widget_get_preferred_size (self->separator.widget, &separator_size, NULL);
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
- set_folded (self, alloc->width < content_min.width + flap_min.width + separator_min.width);
+ set_folded (self, alloc->width < content_size.width + flap_size.width + separator_size.width);
else
- set_folded (self, alloc->height < content_min.height + flap_min.height + separator_min.height);
+ set_folded (self, alloc->height < content_size.height + flap_size.height + separator_size.height);
}
compute_allocation (self,

View file

@ -0,0 +1,101 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Thu, 11 Jul 2019 10:44:14 +0200
Subject: headerbar: Use a back button in dialogs on mobile
This will allow to drop the close buttons and make the dialogs and
transient windows look like proper mobile dialogs.
---
gtk/gtkheaderbar.c | 38 +++++++++++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c
index 0ef94e3..9a4833a 100644
--- a/gtk/gtkheaderbar.c
+++ b/gtk/gtkheaderbar.c
@@ -30,6 +30,7 @@
#include "gtkwindowprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkcontainerprivate.h"
+#include "gtkdialog.h"
#include "a11y/gtkheaderbaraccessible.h"
#include <string.h>
@@ -88,6 +89,7 @@ struct _GtkHeaderBarPrivate
GtkWidget *titlebar_icon;
GtkCssGadget *gadget;
+ GSettings *settings;
};
typedef struct _Child Child;
@@ -280,6 +282,7 @@ _gtk_header_bar_update_window_buttons (GtkHeaderBar *bar)
GMenuModel *menu;
gboolean shown_by_shell;
gboolean is_sovereign_window;
+ gboolean is_mobile_dialog;
toplevel = gtk_widget_get_toplevel (widget);
if (!gtk_widget_is_toplevel (toplevel))
@@ -310,7 +313,15 @@ _gtk_header_bar_update_window_buttons (GtkHeaderBar *bar)
"gtk-decoration-layout", &layout_desc,
NULL);
- if (priv->decoration_layout_set)
+ is_mobile_dialog = GTK_IS_DIALOG (toplevel) ||
+ (GTK_IS_WINDOW (toplevel) && !!gtk_window_get_transient_for (GTK_WINDOW (toplevel)));
+
+ if (is_mobile_dialog && _gtk_get_is_phone ())
+ {
+ g_free (layout_desc);
+ layout_desc = g_strdup ("back:");
+ }
+ else if (priv->decoration_layout_set)
{
g_free (layout_desc);
layout_desc = g_strdup (priv->decoration_layout);
@@ -457,6 +468,23 @@ _gtk_header_bar_update_window_buttons (GtkHeaderBar *bar)
if (GTK_IS_ACCESSIBLE (accessible))
atk_object_set_name (accessible, _("Close"));
}
+ else if (strcmp (t[j], "back") == 0 &&
+ gtk_window_get_deletable (window))
+ {
+ button = gtk_button_new ();
+ gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
+ image = gtk_image_new_from_icon_name ("go-previous-symbolic", GTK_ICON_SIZE_BUTTON);
+ g_object_set (image, "use-fallback", TRUE, NULL);
+ gtk_container_add (GTK_CONTAINER (button), image);
+ gtk_widget_set_can_focus (button, TRUE);
+ gtk_widget_show_all (button);
+ g_signal_connect_swapped (button, "clicked",
+ G_CALLBACK (gtk_window_close), window);
+
+ accessible = gtk_widget_get_accessible (button);
+ if (GTK_IS_ACCESSIBLE (accessible))
+ atk_object_set_name (accessible, _("Back"));
+ }
if (button)
{
@@ -1514,6 +1542,8 @@ gtk_header_bar_destroy (GtkWidget *widget)
priv->titlebar_end_separator = NULL;
}
+ g_clear_object (&priv->settings);
+
GTK_WIDGET_CLASS (gtk_header_bar_parent_class)->destroy (widget);
}
@@ -2154,6 +2184,12 @@ gtk_header_bar_init (GtkHeaderBar *bar)
NULL,
NULL);
+ priv->settings = _gtk_get_purism_settings ();
+
+ if (priv->settings)
+ g_signal_connect_object (priv->settings, "changed::is-phone",
+ G_CALLBACK (_gtk_header_bar_update_window_buttons), bar,
+ G_CONNECT_SWAPPED);
}
static void

View file

@ -0,0 +1,162 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Sat, 13 Jul 2019 10:39:21 +0200
Subject: infobar: Move the action area below on the phone
This will help the infobars fit on phone screens.
Because of how GtkInfoBar API works, this cannot really be made adaptive
and will have to use the is-phone setting.
---
gtk/gtkinfobar.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
gtk/ui/gtkinfobar.ui | 14 +++++---------
2 files changed, 59 insertions(+), 9 deletions(-)
diff --git a/gtk/gtkinfobar.c b/gtk/gtkinfobar.c
index 8eb89ff..c6777c9 100644
--- a/gtk/gtkinfobar.c
+++ b/gtk/gtkinfobar.c
@@ -141,6 +141,7 @@ enum
struct _GtkInfoBarPrivate
{
+ GtkWidget *grid;
GtkWidget *content_area;
GtkWidget *action_area;
GtkWidget *close_button;
@@ -152,6 +153,7 @@ struct _GtkInfoBarPrivate
gboolean default_response_sensitive;
GtkGesture *gesture;
+ GSettings *settings;
};
typedef struct _ResponseData ResponseData;
@@ -412,6 +414,8 @@ gtk_info_bar_finalize (GObject *object)
g_object_unref (info_bar->priv->gesture);
+ g_clear_object (&info_bar->priv->settings);
+
G_OBJECT_CLASS (gtk_info_bar_parent_class)->finalize (object);
}
@@ -595,6 +599,7 @@ gtk_info_bar_class_init (GtkInfoBarClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkinfobar.ui");
gtk_widget_class_bind_template_child_internal_private (widget_class, GtkInfoBar, content_area);
gtk_widget_class_bind_template_child_internal_private (widget_class, GtkInfoBar, action_area);
+ gtk_widget_class_bind_template_child_private (widget_class, GtkInfoBar, grid);
gtk_widget_class_bind_template_child_private (widget_class, GtkInfoBar, close_button);
gtk_widget_class_bind_template_child_private (widget_class, GtkInfoBar, revealer);
@@ -622,6 +627,46 @@ click_pressed_cb (GtkGestureMultiPress *gesture,
gtk_info_bar_response (info_bar, priv->default_response);
}
+static void
+update_layout (GtkInfoBar *info_bar)
+{
+ GtkInfoBarPrivate *priv = info_bar->priv;
+
+ if (_gtk_get_is_phone ()) {
+ gtk_container_child_set (GTK_CONTAINER (priv->grid), priv->action_area,
+ "left-attach", 0,
+ "top-attach", 1,
+ "width", 2,
+ NULL);
+ gtk_container_child_set (GTK_CONTAINER (priv->grid), priv->close_button,
+ "left-attach", 1,
+ NULL);
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->action_area),
+ GTK_ORIENTATION_VERTICAL);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (priv->action_area),
+ GTK_BUTTONBOX_EXPAND);
+ gtk_style_context_remove_class (gtk_widget_get_style_context (priv->action_area),
+ "linked");
+ } else {
+ gtk_container_child_set (GTK_CONTAINER (priv->grid), priv->action_area,
+ "left-attach", 1,
+ "top-attach", 0,
+ "width", 1,
+ NULL);
+ gtk_container_child_set (GTK_CONTAINER (priv->grid), priv->close_button,
+ "left-attach", 2,
+ NULL);
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->action_area),
+ GTK_ORIENTATION_HORIZONTAL);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (priv->action_area),
+ GTK_BUTTONBOX_END);
+ }
+
+ gtk_box_set_spacing (GTK_BOX (priv->action_area), 6);
+}
+
static void
gtk_info_bar_init (GtkInfoBar *info_bar)
{
@@ -645,6 +690,15 @@ gtk_info_bar_init (GtkInfoBar *info_bar)
priv->gesture = gtk_gesture_multi_press_new (widget);
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->gesture), GDK_BUTTON_PRIMARY);
g_signal_connect (priv->gesture, "pressed", G_CALLBACK (click_pressed_cb), widget);
+
+ update_layout (info_bar);
+
+ priv->settings = _gtk_get_purism_settings ();
+
+ if (priv->settings)
+ g_signal_connect_object (priv->settings, "changed::is-phone",
+ G_CALLBACK (update_layout), info_bar,
+ G_CONNECT_SWAPPED);
}
static GtkBuildableIface *parent_buildable_iface;
diff --git a/gtk/ui/gtkinfobar.ui b/gtk/ui/gtkinfobar.ui
index 0b0eaf1..e7a8068 100644
--- a/gtk/ui/gtkinfobar.ui
+++ b/gtk/ui/gtkinfobar.ui
@@ -9,6 +9,9 @@
<child>
<object class="GtkBox" id="content">
<property name="visible">1</property>
+ <child>
+ <object class="GtkGrid" id="grid">
+ <property name="visible">1</property>
<child>
<object class="GtkBox" id="content_area">
<property name="visible">1</property>
@@ -16,9 +19,6 @@
<property name="spacing">16</property>
<property name="hexpand">1</property>
</object>
- <packing>
- <property name="expand">1</property>
- </packing>
</child>
<child>
<object class="GtkButtonBox" id="action_area">
@@ -27,9 +27,6 @@
<property name="spacing">6</property>
<property name="layout-style">end</property>
</object>
- <packing>
- <property name="position">1</property>
- </packing>
</child>
<child>
<object class="GtkButton" id="close_button">
@@ -47,12 +44,11 @@
</object>
</child>
</object>
- <packing>
- <property name="position">2</property>
- </packing>
</child>
</object>
</child>
+ </object>
+ </child>
</object>
</child>
</template>

View file

@ -0,0 +1,219 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Thu, 18 Mar 2021 17:42:00 +0500
Subject: librem5: Make GtkShortcutsWindow adaptive
Fixes https://source.puri.sm/Librem5/debs/gtk/-/issues/30
---
gtk/gtkshortcutssection.c | 65 +++++++++++++++++++++++++++++++++++++++++------
gtk/gtkshortcutswindow.c | 5 ++--
2 files changed, 60 insertions(+), 10 deletions(-)
diff --git a/gtk/gtkshortcutssection.c b/gtk/gtkshortcutssection.c
index 9a61765..a3d4e85 100644
--- a/gtk/gtkshortcutssection.c
+++ b/gtk/gtkshortcutssection.c
@@ -27,6 +27,7 @@
#include "gtkstackswitcher.h"
#include "gtkstylecontext.h"
#include "gtkorientable.h"
+#include "gtkscrolledwindow.h"
#include "gtksizegroup.h"
#include "gtkwidget.h"
#include "gtkbindings.h"
@@ -62,7 +63,8 @@ struct _GtkShortcutsSection
gchar *view_name;
guint max_height;
- GtkStack *stack;
+ GtkWidget *column;
+ GtkWidget *stack;
GtkStackSwitcher *switcher;
GtkWidget *show_all;
GtkWidget *footer;
@@ -117,10 +119,12 @@ static void gtk_shortcuts_section_maybe_reflow (GtkShortcutsSection *self);
static gboolean gtk_shortcuts_section_change_current_page (GtkShortcutsSection *self,
gint offset);
+/*
static void gtk_shortcuts_section_pan_gesture_pan (GtkGesturePan *gesture,
GtkPanDirection direction,
gdouble offset,
GtkShortcutsSection *self);
+*/
static void
gtk_shortcuts_section_add (GtkContainer *container,
@@ -424,11 +428,14 @@ gtk_shortcuts_section_class_init (GtkShortcutsSectionClass *klass)
static void
gtk_shortcuts_section_init (GtkShortcutsSection *self)
{
+ GtkSizeGroup *group;
+
self->max_height = 15;
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
gtk_box_set_homogeneous (GTK_BOX (self), FALSE);
gtk_box_set_spacing (GTK_BOX (self), 22);
+/*
gtk_container_set_border_width (GTK_CONTAINER (self), 24);
self->stack = g_object_new (GTK_TYPE_STACK,
@@ -447,8 +454,38 @@ gtk_shortcuts_section_init (GtkShortcutsSection *self)
NULL);
gtk_style_context_remove_class (gtk_widget_get_style_context (GTK_WIDGET (self->switcher)), GTK_STYLE_CLASS_LINKED);
+*/
+
+ self->stack = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+ "propagate-natural-width", TRUE,
+ "vexpand", TRUE,
+ "visible", TRUE,
+ NULL);
+ GTK_CONTAINER_CLASS (gtk_shortcuts_section_parent_class)->add (GTK_CONTAINER (self), GTK_WIDGET (self->stack));
+
+ self->column = g_object_new (GTK_TYPE_BOX,
+ "orientation", GTK_ORIENTATION_VERTICAL,
+ "spacing", 24,
+ "margin", 24,
+ "halign", GTK_ALIGN_CENTER,
+ "visible", TRUE,
+ NULL);
+ gtk_container_add (GTK_CONTAINER (self->stack), self->column);
+
+ group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ gtk_size_group_set_ignore_hidden (group, TRUE);
+G_GNUC_END_IGNORE_DEPRECATIONS
+ g_object_set_data_full (G_OBJECT (self->column), "accel-size-group", group, g_object_unref);
+
+ group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ gtk_size_group_set_ignore_hidden (group, TRUE);
+G_GNUC_END_IGNORE_DEPRECATIONS
+ g_object_set_data_full (G_OBJECT (self->column), "title-size-group", group, g_object_unref);
self->show_all = gtk_button_new_with_mnemonic (_("_Show All"));
+ g_object_set (self->show_all, "margin", 24, "margin-top", 0, NULL);
gtk_widget_set_no_show_all (self->show_all, TRUE);
g_signal_connect_swapped (self->show_all, "clicked",
G_CALLBACK (gtk_shortcuts_section_show_all), self);
@@ -456,13 +493,8 @@ gtk_shortcuts_section_init (GtkShortcutsSection *self)
self->footer = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 20);
GTK_CONTAINER_CLASS (gtk_shortcuts_section_parent_class)->add (GTK_CONTAINER (self), self->footer);
- gtk_box_set_center_widget (GTK_BOX (self->footer), GTK_WIDGET (self->switcher));
gtk_box_pack_end (GTK_BOX (self->footer), self->show_all, TRUE, TRUE, 0);
gtk_widget_set_halign (self->show_all, GTK_ALIGN_END);
-
- self->pan_gesture = gtk_gesture_pan_new (GTK_WIDGET (self->stack), GTK_ORIENTATION_HORIZONTAL);
- g_signal_connect (self->pan_gesture, "pan",
- G_CALLBACK (gtk_shortcuts_section_pan_gesture_pan), self);
}
static void
@@ -499,6 +531,7 @@ static void
gtk_shortcuts_section_add_group (GtkShortcutsSection *self,
GtkShortcutsGroup *group)
{
+/*
GList *children;
GtkWidget *page, *column;
@@ -523,6 +556,14 @@ gtk_shortcuts_section_add_group (GtkShortcutsSection *self,
g_list_free (children);
gtk_container_add (GTK_CONTAINER (column), GTK_WIDGET (group));
+*/
+ gtk_container_add (GTK_CONTAINER (self->column), GTK_WIDGET (group));
+
+ g_object_set (group,
+ "accel-size-group", g_object_get_data (G_OBJECT (self->column), "accel-size-group"),
+ "title-size-group", g_object_get_data (G_OBJECT (self->column), "title-size-group"),
+ NULL);
+
self->groups = g_list_append (self->groups, group);
gtk_shortcuts_section_maybe_reflow (self);
@@ -570,7 +611,7 @@ gtk_shortcuts_section_filter_groups (GtkShortcutsSection *self)
gtk_widget_set_visible (GTK_WIDGET (self->show_all), self->has_filtered_group);
gtk_widget_set_visible (gtk_widget_get_parent (GTK_WIDGET (self->show_all)),
gtk_widget_get_visible (GTK_WIDGET (self->show_all)) ||
- gtk_widget_get_visible (GTK_WIDGET (self->switcher)));
+ TRUE);
}
static void
@@ -606,6 +647,9 @@ gtk_shortcuts_section_reflow_groups (GtkShortcutsSection *self)
guint n_pages;
GtkWidget *current_page, *current_column;
+ self->need_reflow = FALSE;
+ return;
+
/* collect all groups from the current pages */
groups = NULL;
pages = gtk_container_get_children (GTK_CONTAINER (self->stack));
@@ -768,7 +812,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
gchar *title;
title = g_strdup_printf ("_%u", n_pages + 1);
- gtk_stack_add_titled (self->stack, page, title, title);
+ gtk_stack_add_titled (GTK_STACK (self->stack), page, title, title);
g_free (title);
}
@@ -790,6 +834,7 @@ static gboolean
gtk_shortcuts_section_change_current_page (GtkShortcutsSection *self,
gint offset)
{
+/*
GtkWidget *child;
GList *children, *l;
@@ -812,8 +857,11 @@ gtk_shortcuts_section_change_current_page (GtkShortcutsSection *self,
g_list_free (children);
return TRUE;
+*/
+ return FALSE;
}
+/*
static void
gtk_shortcuts_section_pan_gesture_pan (GtkGesturePan *gesture,
GtkPanDirection direction,
@@ -832,3 +880,4 @@ gtk_shortcuts_section_pan_gesture_pan (GtkGesturePan *gesture,
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
}
+*/
diff --git a/gtk/gtkshortcutswindow.c b/gtk/gtkshortcutswindow.c
index 36f55f6..803b5d3 100644
--- a/gtk/gtkshortcutswindow.c
+++ b/gtk/gtkshortcutswindow.c
@@ -871,7 +871,7 @@ gtk_shortcuts_window_init (GtkShortcutsWindow *self)
GtkWidget *empty;
PangoAttrList *attributes;
- gtk_window_set_resizable (GTK_WINDOW (self), FALSE);
+ gtk_window_set_default_size (GTK_WINDOW (self), -1, 600);
gtk_window_set_type_hint (GTK_WINDOW (self), GDK_WINDOW_TYPE_HINT_DIALOG);
g_signal_connect (self, "key-press-event",
@@ -952,6 +952,7 @@ gtk_shortcuts_window_init (GtkShortcutsWindow *self)
priv->menu_label = g_object_new (GTK_TYPE_LABEL,
"visible", TRUE,
+ "ellipsize", PANGO_ELLIPSIZE_END,
NULL);
gtk_container_add (GTK_CONTAINER (menu_box), GTK_WIDGET (priv->menu_label));
@@ -986,7 +987,7 @@ gtk_shortcuts_window_init (GtkShortcutsWindow *self)
gtk_container_add (GTK_CONTAINER (priv->search_bar), GTK_WIDGET (priv->search_entry));
g_object_set (priv->search_entry,
"placeholder-text", _("Search Shortcuts"),
- "width-chars", 40,
+ "width-chars", 30,
NULL);
g_signal_connect_object (priv->search_entry,
"search-changed",

View file

@ -0,0 +1,234 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Mon, 24 Jun 2019 14:49:07 +0200
Subject: messagedialog: Set orientation based on device
This makes the dialog work better with horizontally constrained screens.
---
gtk/gtkmessagedialog.c | 39 ++++++++++++++++++++++++
gtk/theme/Adwaita/_common.scss | 22 +++++++++++--
gtk/theme/Adwaita/gtk-contained-dark.css | 12 ++++++--
gtk/theme/Adwaita/gtk-contained.css | 12 ++++++--
gtk/theme/HighContrast/gtk-contained-inverse.css | 12 ++++++--
gtk/theme/HighContrast/gtk-contained.css | 12 ++++++--
6 files changed, 95 insertions(+), 14 deletions(-)
diff --git a/gtk/gtkmessagedialog.c b/gtk/gtkmessagedialog.c
index e70c820..e3a6659 100644
--- a/gtk/gtkmessagedialog.c
+++ b/gtk/gtkmessagedialog.c
@@ -36,6 +36,7 @@
#include "gtkimage.h"
#include "gtkintl.h"
#include "gtkprivate.h"
+#include "gtkorientable.h"
#include "gtktypebuiltins.h"
/**
@@ -108,6 +109,8 @@ struct _GtkMessageDialogPrivate
guint has_primary_markup : 1;
guint has_secondary_text : 1;
guint message_type : 3;
+
+ GSettings *settings;
};
static void gtk_message_dialog_style_updated (GtkWidget *widget);
@@ -144,6 +147,31 @@ G_DEFINE_TYPE_WITH_CODE (GtkMessageDialog, gtk_message_dialog, GTK_TYPE_DIALOG,
static GtkBuildableIface *parent_buildable_iface;
+static void
+update_orientation (GtkMessageDialog *dialog)
+{
+ GtkWidget *action_area;
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+ if (_gtk_get_is_phone ())
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (action_area), GTK_ORIENTATION_VERTICAL);
+ else
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (action_area), GTK_ORIENTATION_HORIZONTAL);
+}
+
+static void
+gtk_message_dialog_destroy (GtkWidget *widget)
+{
+ GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (widget);
+
+ g_clear_object (&dialog->priv->settings);
+
+ GTK_WIDGET_CLASS (gtk_message_dialog_parent_class)->destroy (widget);
+}
+
static void
gtk_message_dialog_buildable_interface_init (GtkBuildableIface *iface)
{
@@ -162,6 +190,7 @@ gtk_message_dialog_class_init (GtkMessageDialogClass *class)
gobject_class = G_OBJECT_CLASS (class);
widget_class->style_updated = gtk_message_dialog_style_updated;
+ widget_class->destroy = gtk_message_dialog_destroy;
gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_ALERT);
@@ -327,6 +356,16 @@ gtk_message_dialog_init (GtkMessageDialog *dialog)
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
G_GNUC_END_IGNORE_DEPRECATIONS
+
+ priv->settings = _gtk_get_purism_settings ();
+
+ if (priv->settings)
+ g_signal_connect_object (priv->settings, "changed::is-phone",
+ G_CALLBACK (update_orientation), dialog,
+ G_CONNECT_SWAPPED);
+
+ update_orientation (dialog);
+
gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area), GTK_BUTTONBOX_EXPAND);
settings = gtk_widget_get_settings (GTK_WIDGET (dialog));
diff --git a/gtk/theme/Adwaita/_common.scss b/gtk/theme/Adwaita/_common.scss
index e40e429..b6609f9 100644
--- a/gtk/theme/Adwaita/_common.scss
+++ b/gtk/theme/Adwaita/_common.scss
@@ -3987,10 +3987,13 @@ messagedialog { // Message Dialog styling
.dialog-action-area button {
padding: 10px 14px; // labels are not vertically centered on message dialog, this is a workaround
- border-right-style: none;
- border-bottom-style: none;
border-radius: 0;
-gtk-outline-radius: 0;
+ }
+
+ .dialog-action-area.horizontal button {
+ border-right-style: none;
+ border-bottom-style: none;
&:first-child {
border-left-style: none;
@@ -4003,6 +4006,21 @@ messagedialog { // Message Dialog styling
-gtk-outline-bottom-right-radius: $button_radius + 2;
}
}
+
+ .dialog-action-area.vertical button {
+ border-right-style: none;
+ border-left-style: none;
+ border-radius: 0;
+ -gtk-outline-radius: 0;
+
+ &:last-child {
+ border-bottom-style: none;
+ border-bottom-left-radius: $button_radius + 2;
+ border-bottom-right-radius: $button_radius + 2;
+ -gtk-outline-bottom-left-radius: $button_radius + 2;
+ -gtk-outline-bottom-right-radius: $button_radius + 2;
+ }
+ }
}
}
diff --git a/gtk/theme/Adwaita/gtk-contained-dark.css b/gtk/theme/Adwaita/gtk-contained-dark.css
index 3cd917d..76e816b 100644
--- a/gtk/theme/Adwaita/gtk-contained-dark.css
+++ b/gtk/theme/Adwaita/gtk-contained-dark.css
@@ -1602,11 +1602,17 @@ messagedialog .titlebar { min-height: 20px; background-image: none; background-c
messagedialog.csd.background { border-bottom-left-radius: 9px; border-bottom-right-radius: 9px; }
-messagedialog.csd .dialog-action-area button { padding: 10px 14px; border-right-style: none; border-bottom-style: none; border-radius: 0; -gtk-outline-radius: 0; }
+messagedialog.csd .dialog-action-area button { padding: 10px 14px; border-radius: 0; -gtk-outline-radius: 0; }
-messagedialog.csd .dialog-action-area button:first-child { border-left-style: none; border-bottom-left-radius: 7px; -gtk-outline-bottom-left-radius: 7px; }
+messagedialog.csd .dialog-action-area.horizontal button { border-right-style: none; border-bottom-style: none; }
-messagedialog.csd .dialog-action-area button:last-child { border-bottom-right-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
+messagedialog.csd .dialog-action-area.horizontal button:first-child { border-left-style: none; border-bottom-left-radius: 7px; -gtk-outline-bottom-left-radius: 7px; }
+
+messagedialog.csd .dialog-action-area.horizontal button:last-child { border-bottom-right-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
+
+messagedialog.csd .dialog-action-area.vertical button { border-right-style: none; border-left-style: none; border-radius: 0; -gtk-outline-radius: 0; }
+
+messagedialog.csd .dialog-action-area.vertical button:last-child { border-bottom-style: none; border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; -gtk-outline-bottom-left-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
filechooser .dialog-action-box { border-top: 1px solid #1b1b1b; }
diff --git a/gtk/theme/Adwaita/gtk-contained.css b/gtk/theme/Adwaita/gtk-contained.css
index 4eff74f..ffbd2ae 100644
--- a/gtk/theme/Adwaita/gtk-contained.css
+++ b/gtk/theme/Adwaita/gtk-contained.css
@@ -1618,11 +1618,17 @@ messagedialog .titlebar { min-height: 20px; background-image: none; background-c
messagedialog.csd.background { border-bottom-left-radius: 9px; border-bottom-right-radius: 9px; }
-messagedialog.csd .dialog-action-area button { padding: 10px 14px; border-right-style: none; border-bottom-style: none; border-radius: 0; -gtk-outline-radius: 0; }
+messagedialog.csd .dialog-action-area button { padding: 10px 14px; border-radius: 0; -gtk-outline-radius: 0; }
-messagedialog.csd .dialog-action-area button:first-child { border-left-style: none; border-bottom-left-radius: 7px; -gtk-outline-bottom-left-radius: 7px; }
+messagedialog.csd .dialog-action-area.horizontal button { border-right-style: none; border-bottom-style: none; }
-messagedialog.csd .dialog-action-area button:last-child { border-bottom-right-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
+messagedialog.csd .dialog-action-area.horizontal button:first-child { border-left-style: none; border-bottom-left-radius: 7px; -gtk-outline-bottom-left-radius: 7px; }
+
+messagedialog.csd .dialog-action-area.horizontal button:last-child { border-bottom-right-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
+
+messagedialog.csd .dialog-action-area.vertical button { border-right-style: none; border-left-style: none; border-radius: 0; -gtk-outline-radius: 0; }
+
+messagedialog.csd .dialog-action-area.vertical button:last-child { border-bottom-style: none; border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; -gtk-outline-bottom-left-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
filechooser .dialog-action-box { border-top: 1px solid #cdc7c2; }
diff --git a/gtk/theme/HighContrast/gtk-contained-inverse.css b/gtk/theme/HighContrast/gtk-contained-inverse.css
index 5a2cf09..7e9f8ec 100644
--- a/gtk/theme/HighContrast/gtk-contained-inverse.css
+++ b/gtk/theme/HighContrast/gtk-contained-inverse.css
@@ -1682,11 +1682,17 @@ messagedialog .titlebar { min-height: 20px; background-image: none; background-c
messagedialog.csd.background { border-bottom-left-radius: 9px; border-bottom-right-radius: 9px; }
-messagedialog.csd .dialog-action-area button { padding: 10px 14px; border-right-style: none; border-bottom-style: none; border-radius: 0; -gtk-outline-radius: 0; }
+messagedialog.csd .dialog-action-area button { padding: 10px 14px; border-radius: 0; -gtk-outline-radius: 0; }
-messagedialog.csd .dialog-action-area button:first-child { border-left-style: none; border-bottom-left-radius: 7px; -gtk-outline-bottom-left-radius: 7px; }
+messagedialog.csd .dialog-action-area.horizontal button { border-right-style: none; border-bottom-style: none; }
-messagedialog.csd .dialog-action-area button:last-child { border-bottom-right-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
+messagedialog.csd .dialog-action-area.horizontal button:first-child { border-left-style: none; border-bottom-left-radius: 7px; -gtk-outline-bottom-left-radius: 7px; }
+
+messagedialog.csd .dialog-action-area.horizontal button:last-child { border-bottom-right-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
+
+messagedialog.csd .dialog-action-area.vertical button { border-right-style: none; border-left-style: none; border-radius: 0; -gtk-outline-radius: 0; }
+
+messagedialog.csd .dialog-action-area.vertical button:last-child { border-bottom-style: none; border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; -gtk-outline-bottom-left-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
filechooser .dialog-action-box { border-top: 1px solid #686868; }
diff --git a/gtk/theme/HighContrast/gtk-contained.css b/gtk/theme/HighContrast/gtk-contained.css
index ba598cc..20fbd2c 100644
--- a/gtk/theme/HighContrast/gtk-contained.css
+++ b/gtk/theme/HighContrast/gtk-contained.css
@@ -1698,11 +1698,17 @@ messagedialog .titlebar { min-height: 20px; background-image: none; background-c
messagedialog.csd.background { border-bottom-left-radius: 9px; border-bottom-right-radius: 9px; }
-messagedialog.csd .dialog-action-area button { padding: 10px 14px; border-right-style: none; border-bottom-style: none; border-radius: 0; -gtk-outline-radius: 0; }
+messagedialog.csd .dialog-action-area button { padding: 10px 14px; border-radius: 0; -gtk-outline-radius: 0; }
-messagedialog.csd .dialog-action-area button:first-child { border-left-style: none; border-bottom-left-radius: 7px; -gtk-outline-bottom-left-radius: 7px; }
+messagedialog.csd .dialog-action-area.horizontal button { border-right-style: none; border-bottom-style: none; }
-messagedialog.csd .dialog-action-area button:last-child { border-bottom-right-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
+messagedialog.csd .dialog-action-area.horizontal button:first-child { border-left-style: none; border-bottom-left-radius: 7px; -gtk-outline-bottom-left-radius: 7px; }
+
+messagedialog.csd .dialog-action-area.horizontal button:last-child { border-bottom-right-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
+
+messagedialog.csd .dialog-action-area.vertical button { border-right-style: none; border-left-style: none; border-radius: 0; -gtk-outline-radius: 0; }
+
+messagedialog.csd .dialog-action-area.vertical button:last-child { border-bottom-style: none; border-bottom-left-radius: 7px; border-bottom-right-radius: 7px; -gtk-outline-bottom-left-radius: 7px; -gtk-outline-bottom-right-radius: 7px; }
filechooser .dialog-action-box { border-top: 1px solid #877b6e; }

View file

@ -0,0 +1,492 @@
From: Alexander Mikhaylenko <alexm@gnome.org>
Date: Mon, 12 Oct 2020 18:07:07 +0500
Subject: printunixdialog: Adapt for phones
This makes the dialog work better with horizontally constrained screens.
---
gtk/gtkprinteroptionwidget.c | 40 ++++++++++++++++
gtk/gtkprintunixdialog.c | 76 +++++++++++++++++++++++++++--
gtk/ui/gtkprintunixdialog.ui | 111 +++++++++++++++++++++++++++++--------------
3 files changed, 186 insertions(+), 41 deletions(-)
diff --git a/gtk/gtkprinteroptionwidget.c b/gtk/gtkprinteroptionwidget.c
index e4bf137..2465581 100644
--- a/gtk/gtkprinteroptionwidget.c
+++ b/gtk/gtkprinteroptionwidget.c
@@ -69,6 +69,8 @@ struct GtkPrinterOptionWidgetPrivate
/* the last location for save to file, that the user selected */
gchar *last_location;
+
+ GSettings *settings;
};
enum {
@@ -96,6 +98,17 @@ static void gtk_printer_option_widget_get_property (GObject *object,
static gboolean gtk_printer_option_widget_mnemonic_activate (GtkWidget *widget,
gboolean group_cycling);
+static void
+gtk_printer_option_widget_destroy (GtkWidget *widget)
+{
+ GtkPrinterOptionWidget *powidget = GTK_PRINTER_OPTION_WIDGET (widget);
+ GtkPrinterOptionWidgetPrivate *priv = powidget->priv;
+
+ g_clear_object (&priv->settings);
+
+ GTK_WIDGET_CLASS (gtk_printer_option_widget_parent_class)->destroy (widget);
+}
+
static void
gtk_printer_option_widget_class_init (GtkPrinterOptionWidgetClass *class)
{
@@ -109,6 +122,7 @@ gtk_printer_option_widget_class_init (GtkPrinterOptionWidgetClass *class)
object_class->set_property = gtk_printer_option_widget_set_property;
object_class->get_property = gtk_printer_option_widget_get_property;
+ widget_class->destroy = gtk_printer_option_widget_destroy;
widget_class->mnemonic_activate = gtk_printer_option_widget_mnemonic_activate;
signals[CHANGED] =
@@ -748,6 +762,22 @@ alternative_append (GtkWidget *box,
return gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
}
+static void
+update_is_phone (GtkPrinterOptionWidget *widget)
+{
+ GtkPrinterOptionWidgetPrivate *priv = widget->priv;
+ gboolean is_phone;
+
+ if (!priv->box)
+ return;
+
+ is_phone = _gtk_get_is_phone ();
+
+ gtk_box_set_spacing (GTK_BOX (priv->box), is_phone ? 6 : 12);
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->box),
+ is_phone ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL);
+}
+
static void
construct_widgets (GtkPrinterOptionWidget *widget)
{
@@ -822,6 +852,16 @@ construct_widgets (GtkPrinterOptionWidget *widget)
case GTK_PRINTER_OPTION_TYPE_ALTERNATIVE:
group = NULL;
priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+
+ priv->settings = _gtk_get_purism_settings ();
+
+ if (priv->settings)
+ g_signal_connect_object (priv->settings, "changed::is-phone",
+ G_CALLBACK (update_is_phone), widget,
+ G_CONNECT_SWAPPED);
+
+ update_is_phone (widget);
+
gtk_widget_set_valign (priv->box, GTK_ALIGN_BASELINE);
gtk_widget_show (priv->box);
gtk_box_pack_start (GTK_BOX (widget), priv->box, TRUE, TRUE, 0);
diff --git a/gtk/gtkprintunixdialog.c b/gtk/gtkprintunixdialog.c
index 936bbef..f2eaec4 100644
--- a/gtk/gtkprintunixdialog.c
+++ b/gtk/gtkprintunixdialog.c
@@ -263,6 +263,7 @@ struct GtkPrintUnixDialogPrivate
{
GtkWidget *notebook;
+ GtkWidget *printer_swin;
GtkWidget *printer_treeview;
GtkTreeViewColumn *printer_icon_column;
GtkTreeViewColumn *printer_name_column;
@@ -368,6 +369,8 @@ struct GtkPrintUnixDialogPrivate
gchar *format_for_printer;
gint current_page;
+
+ GSettings *settings;
};
G_DEFINE_TYPE_WITH_CODE (GtkPrintUnixDialog, gtk_print_unix_dialog, GTK_TYPE_DIALOG,
@@ -480,6 +483,7 @@ gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
"/org/gtk/libgtk/ui/gtkprintunixdialog.ui");
/* GtkTreeView / GtkTreeModel */
+ gtk_widget_class_bind_template_child_private (widget_class, GtkPrintUnixDialog, printer_swin);
gtk_widget_class_bind_template_child_private (widget_class, GtkPrintUnixDialog, printer_treeview);
gtk_widget_class_bind_template_child_private (widget_class, GtkPrintUnixDialog, printer_list);
gtk_widget_class_bind_template_child_private (widget_class, GtkPrintUnixDialog, printer_list_filter);
@@ -712,6 +716,44 @@ G_GNUC_END_IGNORE_DEPRECATIONS
return FALSE;
}
+static void
+update_is_phone (GtkPrintUnixDialog *dialog)
+{
+ GtkPrintUnixDialogPrivate *priv = gtk_print_unix_dialog_get_instance_private (dialog);
+ gboolean is_phone = _gtk_get_is_phone ();
+ GtkPrintCapabilities caps;
+ GtkWidget *button;
+ GList *children, *l;
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (priv->extension_point),
+ is_phone ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL);
+
+ caps = priv->manual_capabilities | priv->printer_capabilities;
+ button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_APPLY);
+ gtk_widget_set_visible (button, (caps & GTK_PRINT_CAPABILITY_PREVIEW) != 0 && !is_phone);
+
+ children = gtk_container_get_children (GTK_CONTAINER (priv->extension_point));
+ l = g_list_last (children);
+ if (l && l != children)
+ gtk_widget_set_halign (GTK_WIDGET (l->data),
+ is_phone ? GTK_ALIGN_FILL : GTK_ALIGN_END);
+
+ for (l = children; l && l->data; l = l->next)
+ {
+ GtkWidget *hbox = l->data;
+ GtkWidget *widget = g_object_get_data (G_OBJECT (l->data), "gtk-external-label");
+
+ if (!widget)
+ continue;
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
+ is_phone ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL);
+ gtk_widget_set_margin_start (widget, is_phone ? 12 : 0);
+ }
+
+ g_list_free (children);
+}
+
static void
gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
{
@@ -805,6 +847,15 @@ gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
gtk_css_node_set_name (gtk_widget_get_css_node (priv->collate_image), I_("paper"));
gtk_css_node_set_name (gtk_widget_get_css_node (priv->page_layout_preview), I_("paper"));
+
+ priv->settings = _gtk_get_purism_settings ();
+
+ if (priv->settings)
+ g_signal_connect_object (priv->settings, "changed::is-phone",
+ G_CALLBACK (update_is_phone), dialog,
+ G_CONNECT_SWAPPED);
+
+ update_is_phone (dialog);
}
static void
@@ -838,6 +889,8 @@ gtk_print_unix_dialog_destroy (GtkWidget *widget)
/* Make sure we don't destroy custom widgets owned by the backends */
clear_per_printer_ui (dialog);
+ g_clear_object (&dialog->priv->settings);
+
GTK_WIDGET_CLASS (gtk_print_unix_dialog_parent_class)->destroy (widget);
}
@@ -1359,6 +1412,15 @@ add_option_to_extension_point (GtkPrinterOption *option,
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
gtk_widget_show (hbox);
+ g_object_set_data (G_OBJECT (hbox), "gtk-external-label", widget);
+
+ if (_gtk_get_is_phone ())
+ {
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
+ GTK_ORIENTATION_VERTICAL);
+ gtk_widget_set_margin_start (widget, 12);
+ }
+
gtk_box_pack_start (GTK_BOX (extension_point), hbox, TRUE, TRUE, 0);
}
else
@@ -1600,7 +1662,7 @@ update_dialog_from_settings (GtkPrintUnixDialog *dialog)
*/
children = gtk_container_get_children (GTK_CONTAINER (priv->extension_point));
l = g_list_last (children);
- if (l && l != children)
+ if (l && l != children && !_gtk_get_is_phone ())
gtk_widget_set_halign (GTK_WIDGET (l->data), GTK_ALIGN_END);
g_list_free (children);
@@ -1660,7 +1722,6 @@ update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
GtkPrintUnixDialogPrivate *priv = dialog->priv;
gboolean can_collate;
const gchar *copies;
- GtkWidget *button;
copies = gtk_entry_get_text (GTK_ENTRY (priv->copies_spin));
can_collate = (*copies != '\0' && atoi (copies) > 1);
@@ -1681,9 +1742,7 @@ update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
gtk_widget_set_sensitive (GTK_WIDGET (priv->pages_per_sheet),
caps & GTK_PRINT_CAPABILITY_NUMBER_UP);
- button = gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_APPLY);
- gtk_widget_set_visible (button, (caps & GTK_PRINT_CAPABILITY_PREVIEW) != 0);
-
+ update_is_phone (dialog);
update_collate_icon (NULL, dialog);
gtk_tree_model_filter_refilter (priv->printer_list_filter);
@@ -3749,6 +3808,13 @@ gtk_print_unix_dialog_add_custom_tab (GtkPrintUnixDialog *dialog,
GtkWidget *child,
GtkWidget *tab_label)
{
+ GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+
+ gtk_container_add (GTK_CONTAINER (scrolled_window), child);
+ gtk_widget_show (child);
+
+ child = scrolled_window;
+
gtk_notebook_insert_page (GTK_NOTEBOOK (dialog->priv->notebook),
child, tab_label, 2);
gtk_widget_show (child);
diff --git a/gtk/ui/gtkprintunixdialog.ui b/gtk/ui/gtkprintunixdialog.ui
index e4e552a..e2ba70b 100644
--- a/gtk/ui/gtkprintunixdialog.ui
+++ b/gtk/ui/gtkprintunixdialog.ui
@@ -50,6 +50,8 @@
<template class="GtkPrintUnixDialog" parent="GtkDialog">
<property name="can-focus">False</property>
<property name="type-hint">dialog</property>
+ <property name="default-width">660</property>
+ <property name="default-height">480</property>
<signal name="notify::page-setup" handler="redraw_page_layout_preview" swapped="no"/>
<signal name="response" handler="error_dialogs" swapped="no"/>
<child internal-child="vbox">
@@ -69,6 +71,11 @@
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="show-border">0</property>
+ <property name="scrollable">1</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">1</property>
+ <property name="hscrollbar-policy">never</property>
<child>
<object class="GtkBox" id="general_main_box">
<property name="visible">1</property>
@@ -85,6 +92,7 @@
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="shadow-type">in</property>
+ <property name="vscrollbar-policy">never</property>
<child>
<object class="GtkTreeView" id="printer_treeview">
<property name="visible">1</property>
@@ -165,9 +173,16 @@
</packing>
</child>
<child>
- <object class="GtkBox" id="box3">
+ <object class="GtkFlowBox">
<property name="visible">1</property>
- <property name="spacing">18</property>
+ <property name="row-spacing">18</property>
+ <property name="column-spacing">18</property>
+ <property name="max-children-per-line">2</property>
+ <property name="selection-mode">none</property>
+ <child>
+ <object class="GtkFlowBoxChild">
+ <property name="visible">1</property>
+ <property name="can-focus">0</property>
<child>
<object class="GtkBox" id="frame_template1">
<property name="visible">1</property>
@@ -294,10 +309,13 @@
</packing>
</child>
</object>
- <packing>
- <property name="expand">1</property>
- </packing>
</child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFlowBoxChild">
+ <property name="visible">1</property>
+ <property name="can-focus">0</property>
<child>
<object class="GtkBox" id="frame_template2">
<property name="visible">1</property>
@@ -407,10 +425,8 @@
</packing>
</child>
</object>
- <packing>
- <property name="expand">1</property>
- <property name="position">1</property>
- </packing>
+ </child>
+ </object>
</child>
</object>
<packing>
@@ -419,6 +435,8 @@
</packing>
</child>
</object>
+ </child>
+ </object>
</child>
<child type="tab">
<object class="GtkLabel" id="label1">
@@ -429,6 +447,10 @@
<property name="tab-fill">0</property>
</packing>
</child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">1</property>
+ <property name="hscrollbar-policy">never</property>
<child>
<object class="GtkBox" id="page_setup_main_box">
<property name="visible">1</property>
@@ -436,9 +458,16 @@
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
- <object class="GtkBox" id="box4">
+ <object class="GtkFlowBox">
<property name="visible">1</property>
- <property name="spacing">18</property>
+ <property name="row-spacing">18</property>
+ <property name="column-spacing">18</property>
+ <property name="max-children-per-line">2</property>
+ <property name="selection-mode">none</property>
+ <child>
+ <object class="GtkFlowBoxChild">
+ <property name="visible">1</property>
+ <property name="can-focus">0</property>
<child>
<object class="GtkBox" id="frame_template3">
<property name="visible">1</property>
@@ -632,10 +661,13 @@
</packing>
</child>
</object>
- <packing>
- <property name="expand">1</property>
- </packing>
+ </child>
+ </object>
</child>
+ <child>
+ <object class="GtkFlowBoxChild">
+ <property name="visible">1</property>
+ <property name="can-focus">0</property>
<child>
<object class="GtkBox" id="frame_template4">
<property name="visible">1</property>
@@ -760,7 +792,9 @@
<property name="model">page_setup_list</property>
<property name="valign">baseline</property>
<child>
- <object class="GtkCellRendererText" id="paper_size_renderer"/>
+ <object class="GtkCellRendererText" id="paper_size_renderer">
+ <property name="ellipsize">end</property>
+ </object>
</child>
</object>
<packing>
@@ -812,16 +846,10 @@
</packing>
</child>
</object>
- <packing>
- <property name="expand">1</property>
- <property name="padding">6</property>
- <property name="position">1</property>
- </packing>
</child>
</object>
- <packing>
- <property name="fill">0</property>
- </packing>
+ </child>
+ </object>
</child>
<child>
<object class="GtkBox" id="box6">
@@ -847,6 +875,8 @@
<packing>
<property name="position">1</property>
</packing>
+ </child>
+ </object>
</child>
<child type="tab">
<object class="GtkLabel" id="label2">
@@ -859,10 +889,17 @@
</packing>
</child>
<child>
- <object class="GtkGrid" id="job_page">
+ <object class="GtkFlowBox" id="job_page">
<property name="border-width">12</property>
<property name="row-spacing">18</property>
<property name="column-spacing">18</property>
+ <property name="max-children-per-line">2</property>
+ <property name="selection-mode">none</property>
+ <property name="valign">start</property>
+ <child>
+ <object class="GtkFlowBoxChild">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
<child>
<object class="GtkBox" id="frame_template5">
<property name="visible">1</property>
@@ -949,11 +986,13 @@
</packing>
</child>
</object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">0</property>
- </packing>
</child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFlowBoxChild">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
<child>
<object class="GtkBox" id="frame_template6">
<property name="visible">1</property>
@@ -1074,11 +1113,13 @@
</packing>
</child>
</object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">1</property>
- </packing>
+ </child>
+ </object>
</child>
+ <child>
+ <object class="GtkFlowBoxChild">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
<child>
<object class="GtkBox" id="frame_template7">
<property name="visible">1</property>
@@ -1165,10 +1206,8 @@
</packing>
</child>
</object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">0</property>
- </packing>
+ </child>
+ </object>
</child>
</object>
<packing>

View file

@ -0,0 +1,122 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Sat, 6 Jul 2019 11:05:24 +0200
Subject: scrolledwindow: Set deceleration value based on the device
This makes it nicer on phones by avoiding having to scroll too much on a
touch screen and it makes it match the changes we applied to WebKitGTK
for the same reasons.
---
gtk/gtkscrolledwindow.c | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index a931d2b..e173e57 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -177,6 +177,7 @@
/* Kinetic scrolling */
#define MAX_OVERSHOOT_DISTANCE 100
#define DECELERATION_FRICTION 4
+#define DECELERATION_FRICTION_TOUCH 1
#define OVERSHOOT_FRICTION 20
#define SCROLL_CAPTURE_THRESHOLD_MS 150
#define VELOCITY_ACCUMULATION_FLOOR 0.33
@@ -396,7 +397,8 @@ static gboolean _gtk_scrolled_window_get_overshoot (GtkScrolledWindow *scrolled_
gint *overshoot_x,
gint *overshoot_y);
-static void gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window);
+static void gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window,
+ gboolean is_dragging);
static gint _gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window);
static void gtk_scrolled_window_update_use_indicators (GtkScrolledWindow *scrolled_window);
@@ -1051,7 +1053,8 @@ scrolled_window_drag_end_cb (GtkScrolledWindow *scrolled_window,
static void
gtk_scrolled_window_decelerate (GtkScrolledWindow *scrolled_window,
gdouble x_velocity,
- gdouble y_velocity)
+ gdouble y_velocity,
+ gboolean is_dragging)
{
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
gboolean overshoot;
@@ -1068,7 +1071,7 @@ gtk_scrolled_window_decelerate (GtkScrolledWindow *scrolled_window,
if (priv->x_velocity != 0 || priv->y_velocity != 0 || overshoot)
{
- gtk_scrolled_window_start_deceleration (scrolled_window);
+ gtk_scrolled_window_start_deceleration (scrolled_window, is_dragging);
priv->x_velocity = priv->y_velocity = 0;
}
}
@@ -1078,7 +1081,7 @@ scrolled_window_swipe_cb (GtkScrolledWindow *scrolled_window,
gdouble x_velocity,
gdouble y_velocity)
{
- gtk_scrolled_window_decelerate (scrolled_window, -x_velocity, -y_velocity);
+ gtk_scrolled_window_decelerate (scrolled_window, -x_velocity, -y_velocity, TRUE);
}
static void
@@ -3490,7 +3493,7 @@ start_scroll_deceleration_cb (gpointer user_data)
if (!priv->deceleration_id)
{
uninstall_scroll_cursor (scrolled_window);
- gtk_scrolled_window_start_deceleration (scrolled_window);
+ gtk_scrolled_window_start_deceleration (scrolled_window, FALSE);
}
return FALSE;
@@ -3638,7 +3641,7 @@ gtk_scrolled_window_scroll_event (GtkWidget *widget,
if (start_deceleration &&
scroll_history_finish (scrolled_window, &vel_x, &vel_y))
- gtk_scrolled_window_decelerate (scrolled_window, vel_x, vel_y);
+ gtk_scrolled_window_decelerate (scrolled_window, vel_x, vel_y, FALSE);
else if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
{
priv->scroll_events_overshoot_id =
@@ -3790,12 +3793,14 @@ gtk_scrolled_window_accumulate_velocity (GtkKineticScrolling **scrolling, double
}
static void
-gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
+gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window,
+ gboolean is_deceleration)
{
GtkScrolledWindowPrivate *priv = scrolled_window->priv;
GdkFrameClock *frame_clock;
gint64 current_time;
double elapsed;
+ gdouble friction = is_deceleration ? DECELERATION_FRICTION_TOUCH : DECELERATION_FRICTION;
g_return_if_fail (priv->deceleration_id == 0);
@@ -3820,7 +3825,7 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
gtk_kinetic_scrolling_new (lower,
upper,
MAX_OVERSHOOT_DISTANCE,
- DECELERATION_FRICTION,
+ friction,
OVERSHOOT_FRICTION,
priv->unclamped_hadj_value,
priv->x_velocity);
@@ -3843,7 +3848,7 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
gtk_kinetic_scrolling_new (lower,
upper,
MAX_OVERSHOOT_DISTANCE,
- DECELERATION_FRICTION,
+ friction,
OVERSHOOT_FRICTION,
priv->unclamped_vadj_value,
priv->y_velocity);
@@ -4666,7 +4671,7 @@ gtk_scrolled_window_grab_notify (GtkWidget *widget,
priv->drag_device))
{
if (_gtk_scrolled_window_get_overshoot (scrolled_window, NULL, NULL))
- gtk_scrolled_window_start_deceleration (scrolled_window);
+ gtk_scrolled_window_start_deceleration (scrolled_window, FALSE);
else
gtk_scrolled_window_cancel_deceleration (scrolled_window);
}

View file

@ -0,0 +1,543 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Mon, 31 Aug 2020 10:40:20 +0200
Subject: theme: Add libhandy styles
This is imported from libhandy 1.0.0.
---
gtk/theme/Adwaita/_colors.scss | 6 +
gtk/theme/Adwaita/_common.scss | 187 +++++++++++++++++++++++
gtk/theme/Adwaita/gtk-contained-dark.css | 67 ++++++++
gtk/theme/Adwaita/gtk-contained.css | 67 ++++++++
gtk/theme/HighContrast/_colors-hc.scss | 5 +
gtk/theme/HighContrast/gtk-contained-inverse.css | 67 ++++++++
gtk/theme/HighContrast/gtk-contained.css | 67 ++++++++
7 files changed, 466 insertions(+)
diff --git a/gtk/theme/Adwaita/_colors.scss b/gtk/theme/Adwaita/_colors.scss
index 32dd762..79ef3ca 100644
--- a/gtk/theme/Adwaita/_colors.scss
+++ b/gtk/theme/Adwaita/_colors.scss
@@ -75,3 +75,9 @@ $progress_border_color: $selected_borders_color;
$checkradio_bg_color: if($variant == 'light', $selected_bg_color, lighten($selected_bg_color,10%));
$checkradio_fg_color: $selected_fg_color;
$checkradio_borders_color: if($variant == 'light', darken($checkradio_bg_color,20%), darken($checkradio_bg_color,40%));
+
+// HdyFlap
+
+$flap_dimming: rgba(0, 0, 0, if($variant == 'light', 0.12, 0.24));
+$flap_border: rgba(0, 0, 0, if($variant == 'light', 0.05, 0.2));
+$flap_outline: rgba(255, 255, 255, if($variant == 'light', 0.2, 0.05));
diff --git a/gtk/theme/Adwaita/_common.scss b/gtk/theme/Adwaita/_common.scss
index dc02b49..19b6f38 100644
--- a/gtk/theme/Adwaita/_common.scss
+++ b/gtk/theme/Adwaita/_common.scss
@@ -4855,3 +4855,190 @@ popover.emoji-completion contents row box {
popover.emoji-completion .emoji:hover {
background: $popover_hover_color;
}
+
+/************
+ * libhandy *
+ ************/
+
+// HdyViewSwitcher
+
+viewswitcher {
+ &, & button {
+ margin: 0;
+ padding: 0;
+ }
+
+ button {
+ border-radius: 0;
+ border-top: 0;
+ border-bottom: 0;
+ box-shadow: none;
+ font-size: 1rem;
+
+ &:not(:checked):not(:hover) {
+ background: transparent;
+ }
+
+ &:not(:only-child):not(:last-child) {
+ border-right-width: 0px;
+ }
+
+ &:not(only-child):first-child:not(:checked):not(:hover),
+ &:not(:checked):not(:hover) + button:not(:checked):not(:hover) {
+ border-left-color: transparent;
+ }
+
+ &:not(only-child):last-child:not(:checked):not(:hover) {
+ border-right-color: transparent;
+ }
+
+ &:not(:checked):hover:not(:backdrop) {
+ background-image: image(lighter($bg_color));
+ }
+
+ &:not(only-child):first-child:not(:checked):hover,
+ &:not(:checked):hover + button:not(:checked):not(:hover),
+ &:not(:checked):not(:hover) + button:not(:checked):hover {
+ border-left-color: shade($borders_color, 1.15);
+ }
+
+ &:not(only-child):last-child:not(:checked):hover {
+ border-right-color: shade($borders_color, 1.15);
+ }
+
+ &:not(:checked):hover:backdrop {
+ background-image: image($bg_color);
+ }
+
+ // View switcher in a header bar
+ headerbar &:not(:checked) {
+ &:hover:not(:backdrop) {
+ // Reimplementation of $button_fill from Adwaita. The colors are made
+ // only 70% visible to avoid the highlight to be too strong.
+ $c: gtkalpha($bg_color, 0.7);
+ $button_fill: if($variant == 'light', linear-gradient(to top, shade($c, 0.96) 2px, $c),
+ linear-gradient(to top, shade($c, 0.99) 2px, $c)) !global;
+ background-image: $button_fill;
+ }
+
+ &:not(only-child):first-child:hover,
+ &:hover + button:not(:checked):not(:hover),
+ &:not(:hover) + button:not(:checked):hover {
+ border-left-color: $borders_color;
+ }
+
+ &:not(only-child):last-child:hover {
+ border-right-color: $borders_color;
+ }
+
+ &:hover:backdrop {
+ background-image: image($bg_color);
+ }
+ }
+
+ // View switcher button
+ > stack > box {
+ &.narrow {
+ font-size: 0.75rem;
+ padding-top: 7px;
+ padding-bottom: 5px;
+
+ image,
+ label {
+ padding-left: 8px;
+ padding-right: 8px;
+ }
+ }
+
+ &.wide {
+ padding: 8px 12px;
+
+ label {
+ &:dir(ltr) {
+ padding-right: 7px;
+ }
+
+ &:dir(rtl) {
+ padding-left: 7px;
+ }
+ }
+ }
+
+ label.active {
+ font-weight: bold;
+ }
+ }
+
+ &.needs-attention {
+ &:active > stack > box label,
+ &:checked > stack > box label {
+ animation: none;
+ background-image: none;
+ }
+
+ > stack > box label {
+ animation: needs_attention 150ms ease-in;
+ background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(#3584e4), to(transparent)), -gtk-gradient(radial, center center, 0, center center, 0.5, to(rgba(255, 255, 255, 0.769231)), to(transparent));
+ background-size: 6px 6px, 6px 6px;
+ background-repeat: no-repeat;
+ background-position: right 0px, right 1px;
+
+ &:backdrop {
+ background-size: 6px 6px, 0 0;
+ }
+
+ &:dir(rtl) {
+ background-position: left 0px, left 1px;
+ }
+ }
+ }
+ }
+}
+
+// HdyViewSwitcherBar
+
+viewswitcherbar actionbar > revealer > box {
+ padding: 0;
+}
+
+// HdyFlap
+
+@mixin background-shadow($direction) {
+ background-image:
+ linear-gradient($direction,
+ rgba(0, 0, 0, if($variant == 'light', 0.05, 0.1)),
+ rgba(0, 0, 0, if($variant == 'light', 0.01, 0.02)) 40px,
+ rgba(0, 0, 0, 0) 56px),
+ linear-gradient($direction,
+ rgba(0, 0, 0, if($variant == 'light', 0.03, 0.06)),
+ rgba(0, 0, 0, if($variant == 'light', 0.01, 0.02)) 7px,
+ rgba(0, 0, 0, 0) 24px);
+}
+
+flap {
+ > dimming {
+ background: $flap_dimming;
+ }
+
+ > border {
+ min-width: 1px;
+ min-height: 1px;
+ background: $flap_border;
+ }
+
+ > shadow {
+ min-width: 56px;
+ min-height: 56px;
+
+ &.left { @include background-shadow(to right); }
+ &.right { @include background-shadow(to left); }
+ &.up { @include background-shadow(to bottom); }
+ &.down { @include background-shadow(to top); }
+ }
+
+ > outline {
+ min-width: 1px;
+ min-height: 1px;
+ background: $flap_outline;
+ }
+}
diff --git a/gtk/theme/Adwaita/gtk-contained-dark.css b/gtk/theme/Adwaita/gtk-contained-dark.css
index 32b7fb9..9797b3a 100644
--- a/gtk/theme/Adwaita/gtk-contained-dark.css
+++ b/gtk/theme/Adwaita/gtk-contained-dark.css
@@ -1955,6 +1955,73 @@ popover.emoji-completion contents row box { padding: 2px 10px; }
popover.emoji-completion .emoji:hover { background: #424242; }
+/************ libhandy * */
+viewswitcher, viewswitcher button { margin: 0; padding: 0; }
+
+viewswitcher button { border-radius: 0; border-top: 0; border-bottom: 0; box-shadow: none; font-size: 1rem; }
+
+viewswitcher button:not(:checked):not(:hover) { background: transparent; }
+
+viewswitcher button:not(:only-child):not(:last-child) { border-right-width: 0px; }
+
+viewswitcher button:not(only-child):first-child:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):not(:hover) { border-left-color: transparent; }
+
+viewswitcher button:not(only-child):last-child:not(:checked):not(:hover) { border-right-color: transparent; }
+
+viewswitcher button:not(:checked):hover:not(:backdrop) { background-image: image(lighter(#353535)); }
+
+viewswitcher button:not(only-child):first-child:not(:checked):hover, viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { border-left-color: shade(#1b1b1b, 1.15); }
+
+viewswitcher button:not(only-child):last-child:not(:checked):hover { border-right-color: shade(#1b1b1b, 1.15); }
+
+viewswitcher button:not(:checked):hover:backdrop { background-image: image(#353535); }
+
+headerbar viewswitcher button:not(:checked):hover:not(:backdrop) { background-image: linear-gradient(to top, shade(alpha(#353535,0.7), 0.99) 2px, alpha(#353535,0.7)); }
+
+headerbar viewswitcher button:not(:checked):not(only-child):first-child:hover, headerbar viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), headerbar viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { border-left-color: #1b1b1b; }
+
+headerbar viewswitcher button:not(:checked):not(only-child):last-child:hover { border-right-color: #1b1b1b; }
+
+headerbar viewswitcher button:not(:checked):hover:backdrop { background-image: image(#353535); }
+
+viewswitcher button > stack > box.narrow { font-size: 0.75rem; padding-top: 7px; padding-bottom: 5px; }
+
+viewswitcher button > stack > box.narrow image, viewswitcher button > stack > box.narrow label { padding-left: 8px; padding-right: 8px; }
+
+viewswitcher button > stack > box.wide { padding: 8px 12px; }
+
+viewswitcher button > stack > box.wide label:dir(ltr) { padding-right: 7px; }
+
+viewswitcher button > stack > box.wide label:dir(rtl) { padding-left: 7px; }
+
+viewswitcher button > stack > box label.active { font-weight: bold; }
+
+viewswitcher button.needs-attention:active > stack > box label, viewswitcher button.needs-attention:checked > stack > box label { animation: none; background-image: none; }
+
+viewswitcher button.needs-attention > stack > box label { animation: needs_attention 150ms ease-in; background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(#3584e4), to(transparent)), -gtk-gradient(radial, center center, 0, center center, 0.5, to(rgba(255, 255, 255, 0.769231)), to(transparent)); background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; background-position: right 0px, right 1px; }
+
+viewswitcher button.needs-attention > stack > box label:backdrop { background-size: 6px 6px, 0 0; }
+
+viewswitcher button.needs-attention > stack > box label:dir(rtl) { background-position: left 0px, left 1px; }
+
+viewswitcherbar actionbar > revealer > box { padding: 0; }
+
+flap > dimming { background: rgba(0, 0, 0, 0.24); }
+
+flap > border { min-width: 1px; min-height: 1px; background: rgba(0, 0, 0, 0.2); }
+
+flap > shadow { min-width: 56px; min-height: 56px; }
+
+flap > shadow.left { background-image: linear-gradient(to right, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.02) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to right, rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.02) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.right { background-image: linear-gradient(to left, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.02) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to left, rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.02) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.up { background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.02) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to bottom, rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.02) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.down { background-image: linear-gradient(to top, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.02) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to top, rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.02) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > outline { min-width: 1px; min-height: 1px; background: rgba(255, 255, 255, 0.05); }
+
/* GTK NAMED COLORS ---------------- use responsibly! */
/*
widget text/foreground color */
diff --git a/gtk/theme/Adwaita/gtk-contained.css b/gtk/theme/Adwaita/gtk-contained.css
index 729b1fc..72946ec 100644
--- a/gtk/theme/Adwaita/gtk-contained.css
+++ b/gtk/theme/Adwaita/gtk-contained.css
@@ -1971,6 +1971,73 @@ popover.emoji-completion contents row box { padding: 2px 10px; }
popover.emoji-completion .emoji:hover { background: white; }
+/************ libhandy * */
+viewswitcher, viewswitcher button { margin: 0; padding: 0; }
+
+viewswitcher button { border-radius: 0; border-top: 0; border-bottom: 0; box-shadow: none; font-size: 1rem; }
+
+viewswitcher button:not(:checked):not(:hover) { background: transparent; }
+
+viewswitcher button:not(:only-child):not(:last-child) { border-right-width: 0px; }
+
+viewswitcher button:not(only-child):first-child:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):not(:hover) { border-left-color: transparent; }
+
+viewswitcher button:not(only-child):last-child:not(:checked):not(:hover) { border-right-color: transparent; }
+
+viewswitcher button:not(:checked):hover:not(:backdrop) { background-image: image(lighter(#f6f5f4)); }
+
+viewswitcher button:not(only-child):first-child:not(:checked):hover, viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { border-left-color: shade(#cdc7c2, 1.15); }
+
+viewswitcher button:not(only-child):last-child:not(:checked):hover { border-right-color: shade(#cdc7c2, 1.15); }
+
+viewswitcher button:not(:checked):hover:backdrop { background-image: image(#f6f5f4); }
+
+headerbar viewswitcher button:not(:checked):hover:not(:backdrop) { background-image: linear-gradient(to top, shade(alpha(#f6f5f4,0.7), 0.96) 2px, alpha(#f6f5f4,0.7)); }
+
+headerbar viewswitcher button:not(:checked):not(only-child):first-child:hover, headerbar viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), headerbar viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { border-left-color: #cdc7c2; }
+
+headerbar viewswitcher button:not(:checked):not(only-child):last-child:hover { border-right-color: #cdc7c2; }
+
+headerbar viewswitcher button:not(:checked):hover:backdrop { background-image: image(#f6f5f4); }
+
+viewswitcher button > stack > box.narrow { font-size: 0.75rem; padding-top: 7px; padding-bottom: 5px; }
+
+viewswitcher button > stack > box.narrow image, viewswitcher button > stack > box.narrow label { padding-left: 8px; padding-right: 8px; }
+
+viewswitcher button > stack > box.wide { padding: 8px 12px; }
+
+viewswitcher button > stack > box.wide label:dir(ltr) { padding-right: 7px; }
+
+viewswitcher button > stack > box.wide label:dir(rtl) { padding-left: 7px; }
+
+viewswitcher button > stack > box label.active { font-weight: bold; }
+
+viewswitcher button.needs-attention:active > stack > box label, viewswitcher button.needs-attention:checked > stack > box label { animation: none; background-image: none; }
+
+viewswitcher button.needs-attention > stack > box label { animation: needs_attention 150ms ease-in; background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(#3584e4), to(transparent)), -gtk-gradient(radial, center center, 0, center center, 0.5, to(rgba(255, 255, 255, 0.769231)), to(transparent)); background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; background-position: right 0px, right 1px; }
+
+viewswitcher button.needs-attention > stack > box label:backdrop { background-size: 6px 6px, 0 0; }
+
+viewswitcher button.needs-attention > stack > box label:dir(rtl) { background-position: left 0px, left 1px; }
+
+viewswitcherbar actionbar > revealer > box { padding: 0; }
+
+flap > dimming { background: rgba(0, 0, 0, 0.12); }
+
+flap > border { min-width: 1px; min-height: 1px; background: rgba(0, 0, 0, 0.05); }
+
+flap > shadow { min-width: 56px; min-height: 56px; }
+
+flap > shadow.left { background-image: linear-gradient(to right, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to right, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.right { background-image: linear-gradient(to left, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to left, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.up { background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to bottom, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.down { background-image: linear-gradient(to top, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to top, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > outline { min-width: 1px; min-height: 1px; background: rgba(255, 255, 255, 0.2); }
+
/* GTK NAMED COLORS ---------------- use responsibly! */
/*
widget text/foreground color */
diff --git a/gtk/theme/HighContrast/_colors-hc.scss b/gtk/theme/HighContrast/_colors-hc.scss
index f9c038b..1ce6f24 100644
--- a/gtk/theme/HighContrast/_colors-hc.scss
+++ b/gtk/theme/HighContrast/_colors-hc.scss
@@ -14,3 +14,8 @@ $alt_borders_color: if($variant == 'light', darken($alt_borders_color, 33%), lig
$insensitive_fg_color: mix($fg_color, $bg_color, 50%);
$insensitive_bg_color: mix($bg_color, $base_color, 60%);
$insensitive_borders_color: mix($borders_color, $bg_color, 80%);
+
+// HdyFlap
+
+$flap_border: $borders_color;
+$flap_outline: transparent;
diff --git a/gtk/theme/HighContrast/gtk-contained-inverse.css b/gtk/theme/HighContrast/gtk-contained-inverse.css
index e35c276..eb633dc 100644
--- a/gtk/theme/HighContrast/gtk-contained-inverse.css
+++ b/gtk/theme/HighContrast/gtk-contained-inverse.css
@@ -2034,3 +2034,70 @@ popover.emoji-completion arrow { border: none; background: none; }
popover.emoji-completion contents row box { padding: 2px 10px; }
popover.emoji-completion .emoji:hover { background: #424242; }
+
+/************ libhandy * */
+viewswitcher, viewswitcher button { margin: 0; padding: 0; }
+
+viewswitcher button { border-radius: 0; border-top: 0; border-bottom: 0; box-shadow: none; font-size: 1rem; }
+
+viewswitcher button:not(:checked):not(:hover) { background: transparent; }
+
+viewswitcher button:not(:only-child):not(:last-child) { border-right-width: 0px; }
+
+viewswitcher button:not(only-child):first-child:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):not(:hover) { border-left-color: transparent; }
+
+viewswitcher button:not(only-child):last-child:not(:checked):not(:hover) { border-right-color: transparent; }
+
+viewswitcher button:not(:checked):hover:not(:backdrop) { background-image: image(lighter(#303030)); }
+
+viewswitcher button:not(only-child):first-child:not(:checked):hover, viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { border-left-color: shade(#686868, 1.15); }
+
+viewswitcher button:not(only-child):last-child:not(:checked):hover { border-right-color: shade(#686868, 1.15); }
+
+viewswitcher button:not(:checked):hover:backdrop { background-image: image(#303030); }
+
+headerbar viewswitcher button:not(:checked):hover:not(:backdrop) { background-image: linear-gradient(to top, shade(alpha(#303030,0.7), 0.99) 2px, alpha(#303030,0.7)); }
+
+headerbar viewswitcher button:not(:checked):not(only-child):first-child:hover, headerbar viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), headerbar viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { border-left-color: #686868; }
+
+headerbar viewswitcher button:not(:checked):not(only-child):last-child:hover { border-right-color: #686868; }
+
+headerbar viewswitcher button:not(:checked):hover:backdrop { background-image: image(#303030); }
+
+viewswitcher button > stack > box.narrow { font-size: 0.75rem; padding-top: 7px; padding-bottom: 5px; }
+
+viewswitcher button > stack > box.narrow image, viewswitcher button > stack > box.narrow label { padding-left: 8px; padding-right: 8px; }
+
+viewswitcher button > stack > box.wide { padding: 8px 12px; }
+
+viewswitcher button > stack > box.wide label:dir(ltr) { padding-right: 7px; }
+
+viewswitcher button > stack > box.wide label:dir(rtl) { padding-left: 7px; }
+
+viewswitcher button > stack > box label.active { font-weight: bold; }
+
+viewswitcher button.needs-attention:active > stack > box label, viewswitcher button.needs-attention:checked > stack > box label { animation: none; background-image: none; }
+
+viewswitcher button.needs-attention > stack > box label { animation: needs_attention 150ms ease-in; background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(#3584e4), to(transparent)), -gtk-gradient(radial, center center, 0, center center, 0.5, to(rgba(255, 255, 255, 0.769231)), to(transparent)); background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; background-position: right 0px, right 1px; }
+
+viewswitcher button.needs-attention > stack > box label:backdrop { background-size: 6px 6px, 0 0; }
+
+viewswitcher button.needs-attention > stack > box label:dir(rtl) { background-position: left 0px, left 1px; }
+
+viewswitcherbar actionbar > revealer > box { padding: 0; }
+
+flap > dimming { background: rgba(0, 0, 0, 0.24); }
+
+flap > border { min-width: 1px; min-height: 1px; background: #686868; }
+
+flap > shadow { min-width: 56px; min-height: 56px; }
+
+flap > shadow.left { background-image: linear-gradient(to right, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.02) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to right, rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.02) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.right { background-image: linear-gradient(to left, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.02) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to left, rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.02) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.up { background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.02) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to bottom, rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.02) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.down { background-image: linear-gradient(to top, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.02) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to top, rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.02) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > outline { min-width: 1px; min-height: 1px; background: transparent; }
diff --git a/gtk/theme/HighContrast/gtk-contained.css b/gtk/theme/HighContrast/gtk-contained.css
index e0c37f5..95d09e5 100644
--- a/gtk/theme/HighContrast/gtk-contained.css
+++ b/gtk/theme/HighContrast/gtk-contained.css
@@ -2050,3 +2050,70 @@ popover.emoji-completion arrow { border: none; background: none; }
popover.emoji-completion contents row box { padding: 2px 10px; }
popover.emoji-completion .emoji:hover { background: white; }
+
+/************ libhandy * */
+viewswitcher, viewswitcher button { margin: 0; padding: 0; }
+
+viewswitcher button { border-radius: 0; border-top: 0; border-bottom: 0; box-shadow: none; font-size: 1rem; }
+
+viewswitcher button:not(:checked):not(:hover) { background: transparent; }
+
+viewswitcher button:not(:only-child):not(:last-child) { border-right-width: 0px; }
+
+viewswitcher button:not(only-child):first-child:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):not(:hover) { border-left-color: transparent; }
+
+viewswitcher button:not(only-child):last-child:not(:checked):not(:hover) { border-right-color: transparent; }
+
+viewswitcher button:not(:checked):hover:not(:backdrop) { background-image: image(lighter(#fdfdfc)); }
+
+viewswitcher button:not(only-child):first-child:not(:checked):hover, viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { border-left-color: shade(#877b6e, 1.15); }
+
+viewswitcher button:not(only-child):last-child:not(:checked):hover { border-right-color: shade(#877b6e, 1.15); }
+
+viewswitcher button:not(:checked):hover:backdrop { background-image: image(#fdfdfc); }
+
+headerbar viewswitcher button:not(:checked):hover:not(:backdrop) { background-image: linear-gradient(to top, shade(alpha(#fdfdfc,0.7), 0.96) 2px, alpha(#fdfdfc,0.7)); }
+
+headerbar viewswitcher button:not(:checked):not(only-child):first-child:hover, headerbar viewswitcher button:not(:checked):hover + button:not(:checked):not(:hover), headerbar viewswitcher button:not(:checked):not(:hover) + button:not(:checked):hover { border-left-color: #877b6e; }
+
+headerbar viewswitcher button:not(:checked):not(only-child):last-child:hover { border-right-color: #877b6e; }
+
+headerbar viewswitcher button:not(:checked):hover:backdrop { background-image: image(#fdfdfc); }
+
+viewswitcher button > stack > box.narrow { font-size: 0.75rem; padding-top: 7px; padding-bottom: 5px; }
+
+viewswitcher button > stack > box.narrow image, viewswitcher button > stack > box.narrow label { padding-left: 8px; padding-right: 8px; }
+
+viewswitcher button > stack > box.wide { padding: 8px 12px; }
+
+viewswitcher button > stack > box.wide label:dir(ltr) { padding-right: 7px; }
+
+viewswitcher button > stack > box.wide label:dir(rtl) { padding-left: 7px; }
+
+viewswitcher button > stack > box label.active { font-weight: bold; }
+
+viewswitcher button.needs-attention:active > stack > box label, viewswitcher button.needs-attention:checked > stack > box label { animation: none; background-image: none; }
+
+viewswitcher button.needs-attention > stack > box label { animation: needs_attention 150ms ease-in; background-image: -gtk-gradient(radial, center center, 0, center center, 0.5, to(#3584e4), to(transparent)), -gtk-gradient(radial, center center, 0, center center, 0.5, to(rgba(255, 255, 255, 0.769231)), to(transparent)); background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; background-position: right 0px, right 1px; }
+
+viewswitcher button.needs-attention > stack > box label:backdrop { background-size: 6px 6px, 0 0; }
+
+viewswitcher button.needs-attention > stack > box label:dir(rtl) { background-position: left 0px, left 1px; }
+
+viewswitcherbar actionbar > revealer > box { padding: 0; }
+
+flap > dimming { background: rgba(0, 0, 0, 0.12); }
+
+flap > border { min-width: 1px; min-height: 1px; background: #877b6e; }
+
+flap > shadow { min-width: 56px; min-height: 56px; }
+
+flap > shadow.left { background-image: linear-gradient(to right, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to right, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.right { background-image: linear-gradient(to left, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to left, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.up { background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to bottom, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > shadow.down { background-image: linear-gradient(to top, rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.01) 40px, rgba(0, 0, 0, 0) 56px), linear-gradient(to top, rgba(0, 0, 0, 0.03), rgba(0, 0, 0, 0.01) 7px, rgba(0, 0, 0, 0) 24px); }
+
+flap > outline { min-width: 1px; min-height: 1px; background: transparent; }

View file

@ -0,0 +1,32 @@
From: Alexander Mikhaylenko <alexander.mikhaylenko@puri.sm>
Date: Wed, 4 Nov 2020 19:22:32 +0500
Subject: window: Disable window dragging on phones
See https://gitlab.gnome.org/GNOME/gtk/-/issues/3321
The issue does not seem to be fixable in GTK3 without breaking the API in
process, so do the minimum we can.
Fixes https://source.puri.sm/Librem5/debs/gtk/-/issues/19
Fixes https://source.puri.sm/Librem5/debs/gtk/-/issues/21
---
gtk/gtkwindow.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index d7f8e26..6025385 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -1589,6 +1589,12 @@ drag_gesture_begin_cb (GtkGestureDrag *gesture,
region = get_active_region_type (window, (GdkEventAny*) event, x, y);
+ if (_gtk_get_is_phone ())
+ {
+ gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
+ return;
+ }
+
switch (region)
{
case GTK_WINDOW_REGION_TITLE:

View file

@ -0,0 +1,41 @@
From: Adrien Plazas <kekun.plazas@laposte.net>
Date: Thu, 11 Jul 2019 14:18:39 +0200
Subject: window: Maximize resizable pseudo-dialogs on mobile
This will make them look better on phone screens.
---
gtk/gtkwindow.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 39b01ee..d7f8e26 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -39,6 +39,7 @@
#include "gtkcssiconthemevalueprivate.h"
#include "gtkcssrgbavalueprivate.h"
#include "gtkcssshadowsvalueprivate.h"
+#include "gtkdialog.h"
#include "gtkkeyhash.h"
#include "gtkmain.h"
#include "gtkmnemonichash.h"
@@ -6317,6 +6318,7 @@ gtk_window_map (GtkWidget *widget)
GdkWindow *gdk_window;
GList *link;
GdkDisplay *display;
+ gboolean is_dialog;
if (!_gtk_widget_is_toplevel (widget))
{
@@ -6341,7 +6343,10 @@ gtk_window_map (GtkWidget *widget)
gdk_window = _gtk_widget_get_window (widget);
- if (priv->maximize_initially)
+ /* Transient windows can be considered pseudo-dialogs. */
+ is_dialog = GTK_IS_DIALOG (widget) || !!gtk_window_get_transient_for (window);
+ if (priv->maximize_initially ||
+ (is_dialog && gtk_window_get_resizable (window) && _gtk_get_is_phone ()))
gdk_window_maximize (gdk_window);
else
gdk_window_unmaximize (gdk_window);

48
livi/PKGBUILD Normal file
View file

@ -0,0 +1,48 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=livi
pkgver=0.1.0
pkgrel=1
pkgdesc="GTK4 video player using GStreamer as backend"
arch=('x86_64' 'armv7h' 'aarch64')
url="https://gitlab.gnome.org/guidog/livi"
license=('GPL-3.0-or-later')
depends=(
'gstreamer'
'gst-plugins-bad'
'gst-plugins-base'
'gtk4'
'libadwaita'
)
makedepends=(
'git'
'meson'
'python-packaging'
)
checkdepends=('xorg-server-xvfb')
_commit="2995b99d079b9310d794eaeee8c2e849ed69f31f" # tags/v0.1.0
source=("livi::git+https://gitlab.gnome.org/guidog/livi.git#commit=${_commit}")
pkgver() {
cd $pkgname
git describe --tags | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
}
prepare() {
cd livi
git submodule update --init
}
build() {
arch-meson livi output
meson compile -C output
}
check() {
xvfb-run meson test -C output
}
package() {
meson install -C output --destdir "$pkgdir"
}
md5sums=('SKIP')

69
phoc/PKGBUILD Normal file
View file

@ -0,0 +1,69 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=phoc
pkgver=0.40.1
pkgrel=1
pkgdesc="wlroots based Wayland compositor for mobile phones"
arch=('x86_64' 'armv7h' 'aarch64')
url="https://phosh.mobi"
license=('LGPL-2.1-or-later AND GPL-3.0-or-later AND MIT AND (GPL-3.0-or-later or MIT)')
depends=(
'gobject-introspection'
'gnome-desktop'
'libglvnd'
'libgmobile'
'libinput'
'libliftoff'
'libxcb'
'mutter'
'seatd'
'xcb-util-errors'
'xcb-util-renderutil'
'xcb-util-wm'
'wayland-protocols'
)
makedepends=(
'gi-docgen'
'glib2-devel'
'glslang'
'meson'
'python-docutils'
'vulkan-headers'
)
checkdepends=('xorg-server-xvfb')
source=(https://sources.phosh.mobi/releases/$pkgname/$pkgname-$pkgver.tar.xz{,.asc})
sha256sums=('cbc65258a00dcb9f24a86ed8216a363a1d0d11b977f47987048ccf7874ca3eb9'
'SKIP')
validpgpkeys=('0DB3932762F78E592F6522AFBB5A2C77584122D3')
prepare() {
cd $pkgname-$pkgver/subprojects/wlroots
patch -p1 -i "../packagefiles/wlroots/0001-Revert-layer-shell-error-on-0-dimension-without-anch.patch"
}
build() {
local meson_options=(
--wrap-mode default
-D embed-wlroots=enabled
-D gtk_doc=true
-D man=true
--default-library=static
)
arch-meson $pkgname-$pkgver build "${meson_options[@]}"
meson compile -C build
}
check() {
WLR_RENDERER=pixman xvfb-run meson test -C build --print-errorlogs
}
package() {
meson install -C build --destdir "$pkgdir"
# Install scale-to-fit helper
install -Dm755 "$pkgname-$pkgver"/helpers/scale-to-fit "$pkgdir"/usr/bin/scale-to-fit
# Remove unnecessary files
rm -r "$pkgdir"/usr/lib
rm -r "$pkgdir"/usr/include
}

35
phosh-antispam/PKGBUILD Normal file
View file

@ -0,0 +1,35 @@
# Maintainer: Danct12 <danct12@disroot.org>
# Contributor: Francisco Carpio <carpiofj@gmail.com>
pkgname=phosh-antispam
pkgver=3.5
pkgrel=1
pkgdesc='An anti-spam program designed to work with Phosh'
arch=('x86_64' 'armv7h' 'aarch64')
url="https://gitlab.com/kop316/phosh-antispam"
license=('GPL-3.0-or-later')
depends=(
'gnome-calls'
'libadwaita'
)
makedepends=(meson)
_commit=${pkgver}
source=("${url}/-/archive/${_commit}/${pkgname}-${_commit}.tar.gz")
sha256sums=('62b5e63727da62c2574d4ddf10a02f6db25a2aa8d43db8d84651bc6a3e512702')
prepare() {
cd $pkgname-$pkgver
}
build() {
arch-meson $pkgname-$pkgver build
meson compile -C build
}
check() {
meson test -C build --print-errorlogs
}
package() {
meson install -C build --destdir "$pkgdir"
}

View file

@ -0,0 +1,37 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=phosh-mobile-settings
pkgver=0.40.0
pkgrel=1
pkgdesc="A (Phosh-specific) settings app for mobile"
arch=('x86_64' 'armv7h' 'aarch64')
url="https://phosh.mobi"
license=('GPL-3.0-or-later')
depends=(
'gtk4'
'gsound'
'libadwaita'
'libgmobile'
'lm_sensors'
'phosh'
'wayland'
)
makedepends=(
'git'
'glib2-devel'
'meson'
'python-packaging'
'wayland-protocols'
)
source=(https://sources.phosh.mobi/releases/$pkgname/$pkgname-$pkgver.tar.xz{,.asc})
sha256sums=('484880729782a464355ac8a9308b6956ec3080b981e83f1d7c573e02f93d6110'
'SKIP')
validpgpkeys=('0DB3932762F78E592F6522AFBB5A2C77584122D3')
build() {
arch-meson $pkgname-$pkgver output
meson compile -C output
}
package() {
meson install -C output --skip-subprojects --destdir "$pkgdir"
}

39
phosh-wallpapers/PKGBUILD Normal file
View file

@ -0,0 +1,39 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgbase=phosh-wallpapers
pkgname=('phosh-wallpapers' 'plymouth-theme-phosh' 'sound-theme-phosh')
pkgver=0.40.0
pkgrel=1
pkgdesc="Wallpapers for Phosh UI"
arch=(any)
url="https://gitlab.gnome.org/guidog/phosh-wallpapers"
makedepends=('meson' 'plymouth')
source=($url/-/archive/v$pkgver/$pkgname-v$pkgver.tar.gz)
sha256sums=('d05609b4df8938966d4c68133aff0b6626b1bdf1263f77e3fde46abaa573bc7d')
build() {
arch-meson $pkgname-v$pkgver output
meson compile -C output
}
package_phosh-wallpapers() {
pkgdesc="Wallpapers for Phosh UI"
license=('CC-BY-SA-4.0 AND GPL-3.0-or-later')
meson install -C output --destdir "$pkgdir"
mv "$pkgdir"/usr/share/plymouth "$srcdir"/usr_share_plymouth
mv "$pkgdir"/usr/share/sounds "$srcdir"/usr_share_sounds
}
package_plymouth-theme-phosh() {
pkgdesc="Plymouth theme for Phosh UI"
license=('CC-BY-SA-4.0 AND GPL-3.0-or-later')
depends=('plymouth')
mkdir -p "$pkgdir"/usr/share
mv "$srcdir"/usr_share_plymouth "$pkgdir"/usr/share/plymouth
}
package_sound-theme-phosh() {
pkgdesc="Sound theme for Phosh UI"
license=('CC0 AND CC-BY-SA-4.0')
mkdir -p "$pkgdir"/usr/share
mv "$srcdir"/usr_share_sounds "$pkgdir"/usr/share/sounds
}

76
phosh/PKGBUILD Normal file
View file

@ -0,0 +1,76 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=phosh
pkgver=0.40.0
pkgrel=1
pkgdesc="A Wayland shell for GNOME on mobile devices."
arch=('x86_64' 'armv7h' 'aarch64')
url="https://gitlab.gnome.org/World/Phosh/phosh"
license=('GPL-3.0-or-later')
depends=(
'callaudiod'
'evince'
'evolution-data-server'
'feedbackd'
'gcr'
'gtk3'
'libadwaita'
'libcap'
'libgmobile'
'libhandy'
'libnm'
'libpulse'
'gnome-desktop'
'gnome-session'
'gnome-shell'
'phoc'
'squeekboard'
'upower'
)
makedepends=(
'gi-docgen'
'glib2-devel'
'meson'
'python-docutils'
'python-packaging'
'wayland-protocols'
)
checkdepends=('xorg-server-xvfb')
install="$pkgname.install"
source=(https://sources.phosh.mobi/releases/$pkgname/$pkgname-$pkgver.tar.xz{,.asc}
'pam_phosh'
'phosh.service')
sha256sums=('d08895b19095a4a9fbe824700304973615936c55c0b04877f20269254d7dd640'
'SKIP'
'43b94d0d9f4d083f028c77d18cb0d0f8037d160c41f333878c7cae3df0163c3d'
'48dfe40c42218c92eec59969c06f203dc8a3928b21ca9ee2b92b0987de874a66')
validpgpkeys=('0DB3932762F78E592F6522AFBB5A2C77584122D3')
prepare() {
cd $pkgname-$pkgver
}
build() {
local meson_options=(
--libexecdir=/usr/lib/$pkgname
-D gtk_doc=true
-D man=true
-D phoc_tests=disabled
)
arch-meson $pkgname-$pkgver output "${meson_options[@]}"
meson compile -C output
}
check() {
xvfb-run meson test -C output --print-errorlogs
}
package() {
meson install -C output --destdir "$pkgdir"
install -Dm644 "$srcdir"/phosh.service \
"$pkgdir"/usr/lib/systemd/system/phosh.service
install -Dm644 "$srcdir"/pam_phosh \
"$pkgdir"/etc/pam.d/phosh
mkdir -p "$pkgdir"/usr/share/applications
ln -s sm.puri.Squeekboard.desktop "$pkgdir"/usr/share/applications/sm.puri.OSK0.desktop
}

5
phosh/pam_phosh Normal file
View file

@ -0,0 +1,5 @@
#%PAM-1.0
auth include system-local-login
account include system-local-login
session include system-local-login

8
phosh/phosh.install Normal file
View file

@ -0,0 +1,8 @@
post_install() {
gio-querymodules /usr/lib/phosh/plugins
gio-querymodules /usr/lib/phosh/plugins/prefs
}
post_upgrade() {
post_install
}

60
phosh/phosh.service Normal file
View file

@ -0,0 +1,60 @@
[Unit]
Description=Phosh, a shell for mobile phones
Documentation=https://gitlab.gnome.org/World/Phosh/phosh
# replaces the getty
Conflicts=getty@tty1.service
After=getty@tty1.service
# Needs all the dependencies of the services it's replacing
# (currently getty@tty1.service):
After=rc-local.service plymouth-quit-wait.service systemd-user-sessions.service
OnFailure=getty@tty1.service
# D-Bus is necessary for contacting logind. Logind is required.
Wants=dbus.socket
After=dbus.socket
# This scope is created by pam_systemd when logging in as the user.
# This directive is a workaround to a systemd bug, where the setup of the
# user session by PAM has some race condition, possibly leading to a failure.
# See README for more details.
After=session-c1.scope
# Since we are part of the graphical session, make sure we are started before
# it is complete.
Before=graphical.target
# Prevent starting on systems without virtual consoles
ConditionPathExists=/dev/tty0
[Service]
Environment=XDG_CURRENT_DESKTOP=Phosh:GNOME
Environment=XDG_SESSION_DESKTOP=phosh
Environment=XDG_SESSION_TYPE=wayland
ExecStart=capsh --noamb -- -c "exec /usr/bin/phosh-session"
TimeoutStartSec=30
User=1000
PAMName=login
WorkingDirectory=~
Restart=always
RestartSec=5s
# A virtual terminal is needed.
TTYPath=/dev/tty7
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
# Fail to start if not controlling the tty.
StandardInput=tty-fail
StandardOutput=journal
StandardError=journal
# Log this user with utmp, letting it show up with commands 'w' and 'who'.
UtmpIdentifier=tty7
UtmpMode=user
[Install]
WantedBy=graphical.target

View file

@ -0,0 +1,30 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=portfolio-file-manager
pkgver=1.0.1
pkgrel=1
pkgdesc="A minimalist file manager for those who want to use Linux mobile devices."
url="https://github.com/tchx84/Portfolio"
license=('GPL3')
arch=('any')
depends=('python' 'gtk4' 'libadwaita' 'python-gobject')
makedepends=('meson')
checkdepends=('python-pytest' 'xorg-server-xvfb')
replaces=('portfolio-fm')
source=(Portfolio-${pkgver}.tar.gz::https://github.com/tchx84/Portfolio/archive/v${pkgver}.tar.gz)
sha512sums=('ef297550bee61862bf17b8ffd4170dc4d7a1205a2006783ff27bb96f22427f2da322b1e4633472084b05365bb1d2201bd554cfb385412e535a58000a8c062c03')
build() {
arch-meson Portfolio-${pkgver} output
ninja -C output
}
# python tests are broken
#check() {
# xvfb-run ninja test -C output
#}
package() {
DESTDIR="${pkgdir}" ninja -C output install
}

58
purism-chatty/PKGBUILD Normal file
View file

@ -0,0 +1,58 @@
# Maintainer: Danct12 <danct12@disroot.org>
_pkgname=chatty
pkgname=purism-chatty
pkgver=0.8.4
pkgrel=1
pkgdesc="SMS/MMS, Matrix and (optionally) XMPP messaging app"
url="https://gitlab.gnome.org/World/Chatty"
license=('GPL')
arch=('x86_64' 'armv7h' 'aarch64')
depends=(
'evolution-data-server'
'feedbackd'
'gnome-desktop-4'
'gtksourceview5'
'gtk4'
'libadwaita'
'libmm-glib'
'libolm'
'libpurple'
'libspelling'
)
replaces=('chatty<=0.7.3')
makedepends=('git' 'itstool' 'meson' 'ninja')
checkdepends=('xorg-server-xvfb')
optdepends=(
'libpurple-carbons: message carbons support'
'libpurple-lurch: OMEMO encryption'
'libpurple-xmpp-http-upload: XMPP HTTP File Upload support'
'mmsd-tng: MMS support'
'purple-telegram: Telegram chat protocol support'
)
_commit="28b23d3d1a376b4691e031010fbe4a4b0da64d69" # tags/v0.8.4
source=($_pkgname::git+https://gitlab.gnome.org/World/Chatty.git#commit=${_commit})
pkgver() {
cd $_pkgname
git describe --tags | sed 's/^v//;s/\([^-]*-g\)/r\1/;s/-/./g'
}
prepare() {
cd $_pkgname
git submodule update --init
}
build() {
arch-meson $_pkgname output
ninja -C output
}
# FAIL: secure memory pool is not locked while in FIPS mode
#check() {
# xvfb-run ninja -C output test
#}
package() {
DESTDIR="$pkgdir" ninja -C output install
}
md5sums=('SKIP')

View file

@ -0,0 +1,16 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=sound-theme-librem5
pkgver=0.1.0
pkgrel=0
pkgdesc="Sound theme for the Librem 5"
arch=(any)
url="https://source.puri.sm/Librem5/sound-theme-librem5"
license=('GPL')
source=(https://source.puri.sm/Librem5/sound-theme-librem5/-/archive/v$pkgver/sound-theme-librem5-v$pkgver.tar.gz)
package() {
mkdir -p "$pkgdir"/usr/share/sounds
cp -rv "$srcdir"/$pkgname-v$pkgver/librem5 "$pkgdir"/usr/share/sounds
}
md5sums=('67df906054555e8dab065073361881db')

26
squeekboard/PKGBUILD Normal file
View file

@ -0,0 +1,26 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=squeekboard
pkgver=1.39.0
pkgrel=1
pkgdesc="An on-screen-keyboard input method for Wayland"
arch=('x86_64' 'armv7h' 'aarch64')
url="https://gitlab.gnome.org/World/Phosh/squeekboard"
license=('GPL-3.0-or-later')
depends=('feedbackd' 'gtk3' 'gnome-desktop' 'libbsd' 'wayland-protocols')
makedepends=('rust' 'meson' 'ninja' 'python-packaging')
source=(https://gitlab.gnome.org/World/Phosh/squeekboard/-/archive/v$pkgver/squeekboard-v$pkgver.tar.gz)
build() {
arch-meson ${pkgname}-v${pkgver} output
ninja -C output
}
check() {
meson test -C output --print-errorlogs
}
package() {
DESTDIR="$pkgdir" ninja -C output install
}
md5sums=('90fc61e2fc617b895162a1a422f548fc')

28
wys/PKGBUILD Normal file
View file

@ -0,0 +1,28 @@
# Maintainer: Danct12 <danct12@disroot.org>
pkgname=wys
pkgver=0.1.11
pkgrel=1
pkgdesc="A daemon to bring up and take down PulseAudio loopbacks for phone call audio"
url="https://source.puri.sm/Librem5/wys"
license=('GPL')
arch=('x86_64' 'armv7h' 'aarch64')
depends=('glib2' 'libpulse' 'modemmanager')
makedepends=('meson' 'ninja')
source=("https://source.puri.sm/Librem5/wys/-/archive/v$pkgver/wys-v$pkgver.tar.gz")
prepare() {
cd $pkgname-v$pkgver
}
build() {
arch-meson $pkgname-v$pkgver output
ninja -C output
}
package() {
DESTDIR="$pkgdir" ninja -C output install
install -Dm644 $pkgname-v$pkgver/debian/wys.user-service "$pkgdir"/usr/lib/systemd/user/wys.service
}
md5sums=('4cecd05e1d35214d64402073b9234115')