diff --git a/README.md b/README.md index 9b04a0abf8d6724787706621e9bbfe28f202db7b..7e56a8e581dd339b7a237948283b4df728219542 100644 --- a/README.md +++ b/README.md @@ -22,19 +22,28 @@ way to get going is to do the following: ninja -C _build ninja -C _build install +# Testing + +To run the tests run + + ninja -C _build test + +For details see the *.gitlab-ci.yml* file. ## Running ### Running from the source tree When running from the source tree start the compositor *rootston*. Then start *phosh* using: - _build/run + _build/run -U or in one command: - ../wlroots/_build/rootston/rootston -E _build/run -C ./rootston.ini + ../wlroots/_build/rootston/rootston -E '_build/run -U' -C ./rootston.ini -This will make sure the needed gsettings schema is found. +This will make sure the needed gsettings schema is found. The '-U' option makes +sure the shell is not locked on startup so you can test with arbitrary +passwords. ### Running from the Debian packages If installed via the Debian packages you can also run phosh via gnome-session. diff --git a/protocol/phosh-private.xml b/protocol/phosh-private.xml index 79b9b9b0d55952d9fa1b12c349c6b247b5151b0e..4eede1e58be63ed20b7086ba74cf7bfe456713c2 100644 --- a/protocol/phosh-private.xml +++ b/protocol/phosh-private.xml @@ -1,5 +1,5 @@ - + Private protocol between phosh and the compositor. @@ -9,13 +9,61 @@ summary="an invalid argument was provided in a request"/> - - - - Rotate the display clockwise 0, 90, 180 or 270 degree. + + + + Rotate the output clockwise 0, 90, 180 or 270 degree. + + + + + + + + + + The interface is meant to list xdg surfaces (see the xdg-shell + stable wayland protocol) and to raise these surfaces to the top + of the window stack. + + It's up to the compositor if it only lists surfaces of the + xdg-shell stable protocol or also surfaces using unstable versions of + the xdg-shell protocol. + + + + + + + + Request to list xdg shell toplevels. + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app.c b/src/app.c new file mode 100644 index 0000000000000000000000000000000000000000..12e52dc86441ddb2b0445f627dc82df3538b6442 --- /dev/null +++ b/src/app.c @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2018 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + * Author: Guido Günther + */ + +#define G_LOG_DOMAIN "phosh-app" + +#include "config.h" +#include "app.h" +#include "phosh.h" + +#include + +/** + * SECTION:phosh-app + * @short_description: An app in the faovorites overview + * @Title: PhoshApp + * + * The #PhoshApp is used to select a running application + * in the favorites overview. + */ + +#define APP_ICON_SIZE GTK_ICON_SIZE_DIALOG + +enum { + PHOSH_APP_PROP_0, + PHOSH_APP_PROP_APP_ID, + PHOSH_APP_PROP_TITLE, + PHOSH_APP_PROP_LAST_PROP, +}; +static GParamSpec *props[PHOSH_APP_PROP_LAST_PROP]; + +typedef struct +{ + GtkWidget *image; + GtkWidget *box; + + char *app_id; + char *title; + GDesktopAppInfo *info; +} PhoshAppPrivate; + + +struct _PhoshApp +{ + GtkButton parent; +}; + +G_DEFINE_TYPE_WITH_PRIVATE(PhoshApp, phosh_app, GTK_TYPE_BUTTON) + + +static void +phosh_app_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshApp *self = PHOSH_APP (object); + PhoshAppPrivate *priv = phosh_app_get_instance_private(self); + + switch (property_id) { + case PHOSH_APP_PROP_APP_ID: + g_free (priv->app_id); + priv->app_id = g_value_dup_string (value); + g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_APP_PROP_APP_ID]); + break; + case PHOSH_APP_PROP_TITLE: + g_free (priv->title); + priv->title = g_value_dup_string (value); + g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_APP_PROP_TITLE]); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_app_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshApp *self = PHOSH_APP (object); + PhoshAppPrivate *priv = phosh_app_get_instance_private(self); + + switch (property_id) { + case PHOSH_APP_PROP_APP_ID: + g_value_set_string (value, priv->app_id); + break; + case PHOSH_APP_PROP_TITLE: + g_value_set_string (value, priv->title); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +/* In GTK+4 we can just call gtk_image_new_from_gicon since it got rid of the + restrictive size element */ +static GtkWidget * +get_image_from_gicon (PhoshApp *self, int scale) +{ + PhoshAppPrivate *priv = phosh_app_get_instance_private (self); + GtkIconTheme *theme = gtk_icon_theme_get_for_screen (gdk_screen_get_default ()); + GIcon *icon; + GError *err = NULL; + g_autoptr(GdkPixbuf) pixbuf = NULL; + g_autoptr(GtkIconInfo) info = NULL; + + icon = g_app_info_get_icon (G_APP_INFO (priv->info)); + info = gtk_icon_theme_lookup_by_gicon_for_scale(theme, icon, 128, scale, 0); + if (!info) { + g_warning ("Failed to lookup icon for %s", priv->app_id); + return NULL; + } + pixbuf = gtk_icon_info_load_icon (info, &err); + if (!pixbuf) { + g_warning ("Failed to load icon for %s: %s", priv->app_id, err->message); + return NULL; + } + return gtk_image_new_from_pixbuf (pixbuf); +} + + +static GtkWidget * +get_missing_image (int scale) +{ + GtkIconTheme *theme = gtk_icon_theme_get_for_screen (gdk_screen_get_default ()); + GError *err = NULL; + g_autoptr(GdkPixbuf) pixbuf = NULL; + g_autoptr(GtkIconInfo) info = NULL; + + info = gtk_icon_theme_lookup_icon_for_scale(theme, "image-missing", 128, scale, 0); + pixbuf = gtk_icon_info_load_icon (info, &err); + return gtk_image_new_from_pixbuf (pixbuf); +} + + +static void +phosh_app_constructed (GObject *object) +{ + PhoshApp *self = PHOSH_APP (object); + PhoshAppPrivate *priv = phosh_app_get_instance_private (self); + GtkWidget *lbl_name = NULL, *lbl_title = NULL; + g_autofree gchar *desktop_id = NULL; + g_autofree gchar *name = NULL; + gint scale = 1; + PhoshMonitor *monitor = phosh_shell_get_primary_monitor (phosh_shell_get_default()); + + if (monitor) + scale = monitor->scale; + + desktop_id = g_strdup_printf ("%s.desktop", priv->app_id); + g_return_if_fail (desktop_id); + priv->info = g_desktop_app_info_new (desktop_id); + if (priv->info) { + priv->image = get_image_from_gicon (self, scale); + name = g_desktop_app_info_get_locale_string (priv->info, "Name"); + lbl_name = gtk_label_new (name ? name : priv->app_id); + } else { + lbl_name = gtk_label_new (priv->app_id); + } + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(lbl_name)), + "phosh-app-name"); + + if (!priv->info || !priv->image) { + priv->image = get_missing_image (scale); + } + + if (priv->title) { + lbl_title = gtk_label_new (priv->title); + gtk_label_set_max_width_chars (GTK_LABEL (lbl_title), 30); + gtk_label_set_ellipsize (GTK_LABEL (lbl_title), PANGO_ELLIPSIZE_MIDDLE); + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(lbl_title)), + "phosh-app-title"); + } + + priv->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_box_pack_start (GTK_BOX (priv->box), priv->image, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (priv->box), lbl_name, FALSE, FALSE, 0); + if (lbl_title) { + gtk_box_pack_start (GTK_BOX (priv->box), lbl_title, FALSE, FALSE, 0); + } + gtk_container_add (GTK_CONTAINER (self), priv->box); + + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(self)), + "phosh-app-btn"); + + G_OBJECT_CLASS (phosh_app_parent_class)->constructed (object); +} + + +static void +phosh_app_dispose (GObject *object) +{ + PhoshApp *self = PHOSH_APP (object); + PhoshAppPrivate *priv = phosh_app_get_instance_private (self); + + g_clear_object (&priv->info); + + G_OBJECT_CLASS (phosh_app_parent_class)->dispose (object); +} + + +static void +phosh_app_finalize (GObject *object) +{ + PhoshApp *self = PHOSH_APP (object); + PhoshAppPrivate *priv = phosh_app_get_instance_private (self); + + g_free (priv->app_id); + g_free (priv->title); + + G_OBJECT_CLASS (phosh_app_parent_class)->finalize (object); +} + + + +static void +phosh_app_class_init (PhoshAppClass *klass) +{ + GObjectClass *object_class = (GObjectClass *)klass; + + object_class->constructed = phosh_app_constructed; + object_class->dispose = phosh_app_dispose; + object_class->finalize = phosh_app_finalize; + + object_class->set_property = phosh_app_set_property; + object_class->get_property = phosh_app_get_property; + + props[PHOSH_APP_PROP_APP_ID] = + g_param_spec_string ( + "app-id", + "app-id", + "The application id", + "", + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + props[PHOSH_APP_PROP_TITLE] = + g_param_spec_string ( + "title", + "title", + "The window's title", + "", + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, PHOSH_APP_PROP_LAST_PROP, props); +} + + +static void +phosh_app_init (PhoshApp *self) +{ +} + + +GtkWidget * +phosh_app_new (const char *app_id, const char *title) +{ + return g_object_new (PHOSH_TYPE_APP, + "app-id", app_id, + "title", title, + NULL); +} + + +const char * +phosh_app_get_app_id (PhoshApp *self) +{ + PhoshAppPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_APP (self), NULL); + priv = phosh_app_get_instance_private (self); + + return priv->app_id; +} + + +const char * +phosh_app_get_title (PhoshApp *self) +{ + PhoshAppPrivate *priv; + + g_return_val_if_fail (PHOSH_IS_APP (self), NULL); + priv = phosh_app_get_instance_private (self); + + return priv->title; +} diff --git a/src/app.h b/src/app.h new file mode 100644 index 0000000000000000000000000000000000000000..46c3e357c8ae93d1aaec6ab2c2e5564f4bff438f --- /dev/null +++ b/src/app.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0+ + */ +#pragma once + +#include + +#define PHOSH_TYPE_APP (phosh_app_get_type()) + +G_DECLARE_FINAL_TYPE (PhoshApp, phosh_app, PHOSH, APP, GtkButton) + +GtkWidget * phosh_app_new (const char *app_id, const char *title); +const char *phosh_app_get_app_id (PhoshApp *self); +const char *phosh_app_get_title (PhoshApp *self); + diff --git a/src/favorites.c b/src/favorites.c index 0ae1bc47323bf4950398c27d82a0b5395c81a318..e8b66de03e859d9137b238971840760b5ec498e4 100644 --- a/src/favorites.c +++ b/src/favorites.c @@ -13,12 +13,16 @@ #include "config.h" #include "favorites.h" +#include "app.h" #include "phosh.h" +#include "phosh-private-client-protocol.h" +#include "phosh-wayland.h" #include enum { APP_LAUNCHED, + APP_RAISED, SELECTION_ABORTED, N_SIGNALS }; @@ -26,10 +30,19 @@ static guint signals[N_SIGNALS] = { 0 }; typedef struct { - GtkWidget *scroll; - GtkWidget *evbox; - GtkWidget *flowbox; + /* Favorites */ + GtkWidget *evbox_favorites; + GtkWidget *sw_favorites; + GtkWidget *fb_favorites; GSettings *settings; + + /* Running apps */ + GtkWidget *evbox_running_apps; + GtkWidget *sw_running_apps; + GtkWidget *fb_running_apps; + GtkWidget *box_running_apps; + struct phosh_private_xdg_switcher *xdg_switcher; + } PhoshFavoritesPrivate; @@ -41,6 +54,86 @@ struct _PhoshFavorites G_DEFINE_TYPE_WITH_PRIVATE(PhoshFavorites, phosh_favorites, GTK_TYPE_WINDOW) +static void +app_clicked_cb (GtkButton *btn, gpointer user_data) +{ + PhoshFavorites *self = PHOSH_FAVORITES (user_data); + PhoshFavoritesPrivate *priv; + PhoshApp *app = PHOSH_APP (btn); + + g_return_if_fail (PHOSH_IS_FAVORITES (self)); + priv = phosh_favorites_get_instance_private (self); + g_return_if_fail (priv->xdg_switcher); + + g_debug("Will raise %s (%s)", + phosh_app_get_app_id (app), + phosh_app_get_title (app)); + + phosh_private_xdg_switcher_raise_xdg_surface (priv->xdg_switcher, + phosh_app_get_app_id (app), + phosh_app_get_title (app)); + g_signal_emit(self, signals[APP_RAISED], 0); +} + + + +static void +handle_xdg_switcher_xdg_surface ( + void *data, struct phosh_private_xdg_switcher *phosh_private_xdg_switcher, + const char *app_id, + const char *title) +{ + PhoshFavorites *self = data; + PhoshFavoritesPrivate *priv; + GtkWidget *app; + + g_return_if_fail (PHOSH_IS_FAVORITES (self)); + priv = phosh_favorites_get_instance_private (self); + + g_debug ("Building activator for '%s' (%s)", app_id, title); + app = phosh_app_new (app_id, title); + gtk_flow_box_insert (GTK_FLOW_BOX (priv->fb_running_apps), app, -1); + + g_signal_connect (app, "clicked", G_CALLBACK (app_clicked_cb), self); + gtk_widget_show (GTK_WIDGET (self)); +} + + +static void +handle_xdg_switcher_list_xdg_surfaces_done( + void *data, + struct phosh_private_xdg_switcher *phosh_private_xdg_switcher) +{ + g_debug ("Got all apps"); +} + + +static const struct phosh_private_xdg_switcher_listener xdg_switcher_listener = { + handle_xdg_switcher_xdg_surface, + handle_xdg_switcher_list_xdg_surfaces_done, +}; + + +static void +get_running_apps (PhoshFavorites *self) +{ + PhoshFavoritesPrivate *priv = phosh_favorites_get_instance_private (self); + struct phosh_private *phosh_private; + + phosh_private = phosh_wayland_get_phosh_private ( + phosh_wayland_get_default ()); + + if (!phosh_private) { + g_debug ("Skipping app list due to missing phosh_private protocol extension"); + return; + } + + priv->xdg_switcher = phosh_private_get_xdg_switcher (phosh_private); + phosh_private_xdg_switcher_add_listener (priv->xdg_switcher, &xdg_switcher_listener, self); + phosh_private_xdg_switcher_list_xdg_surfaces (priv->xdg_switcher); +} + + static void term_btn_clicked (PhoshFavorites *self, GtkButton *btn) @@ -97,7 +190,7 @@ add_favorite (PhoshFavorites *self, "circular"); gtk_button_set_image (GTK_BUTTON (btn), image); - g_object_set (image, "margin", 20, NULL); + g_object_set (image, "margin", 10, NULL); g_object_set_data (G_OBJECT (btn), "favorites", self); g_signal_connect (btn, "clicked", G_CALLBACK (favorite_clicked_cb), info); @@ -128,7 +221,7 @@ add_weston_terminal (PhoshFavorites *self) "circular"); g_signal_connect_swapped (btn, "clicked", G_CALLBACK (term_btn_clicked), self); - gtk_flow_box_insert (GTK_FLOW_BOX (priv->flowbox), btn, -1); + gtk_flow_box_insert (GTK_FLOW_BOX (priv->fb_favorites), btn, -1); } @@ -142,14 +235,14 @@ favorites_changed (GSettings *settings, GtkWidget *btn; /* Remove all favorites first */ - gtk_container_foreach (GTK_CONTAINER (priv->flowbox), + gtk_container_foreach (GTK_CONTAINER (priv->fb_favorites), (GtkCallback) gtk_widget_destroy, NULL); for (gint i = 0; i < g_strv_length (favorites); i++) { gchar *fav = favorites[i]; btn = add_favorite (self, fav); if (btn) - gtk_flow_box_insert (GTK_FLOW_BOX (priv->flowbox), btn, -1); + gtk_flow_box_insert (GTK_FLOW_BOX (priv->fb_favorites), btn, -1); } g_strfreev (favorites); add_weston_terminal (self); @@ -159,7 +252,13 @@ favorites_changed (GSettings *settings, static gboolean draw_cb (GtkWidget *widget, cairo_t *cr, gpointer unused) { - cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.1); + GtkStyleContext *context = gtk_widget_get_style_context (widget); + GdkRGBA c; + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &c); + G_GNUC_END_IGNORE_DEPRECATIONS + cairo_set_source_rgba (cr, c.red, c.green, c.blue, 0.8); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); return FALSE; @@ -200,37 +299,49 @@ phosh_favorites_constructed (GObject *object) gtk_widget_get_style_context (GTK_WIDGET (self)), "phosh-favorites"); - /* Flowbox */ - priv->flowbox = gtk_widget_new (GTK_TYPE_FLOW_BOX, - "halign", GTK_ALIGN_START, - "valign", GTK_ALIGN_CENTER, - "selection-mode", GTK_SELECTION_NONE, - "orientation", GTK_ORIENTATION_VERTICAL, - NULL); - gtk_flow_box_set_max_children_per_line (GTK_FLOW_BOX(priv->flowbox), G_MAXINT); - gtk_flow_box_set_homogeneous (GTK_FLOW_BOX(priv->flowbox), TRUE); - - /* Scrolled window */ - priv->scroll = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scroll), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_NEVER); - gtk_container_add (GTK_CONTAINER (priv->scroll), priv->flowbox); - - /* Eventbox */ - priv->evbox = gtk_event_box_new (); - gtk_container_add (GTK_CONTAINER (priv->evbox), priv->scroll); - g_signal_connect_swapped (priv->evbox, "button_press_event", + /* Favorites */ + priv->fb_favorites = gtk_widget_new (GTK_TYPE_FLOW_BOX, + "halign", GTK_ALIGN_CENTER, + "valign", GTK_ALIGN_START, + "selection-mode", GTK_SELECTION_NONE, + "orientation", GTK_ORIENTATION_HORIZONTAL, + NULL); + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(priv->fb_favorites)), + "phosh-favorites-flowbox"); + gtk_flow_box_set_max_children_per_line (GTK_FLOW_BOX(priv->fb_favorites), G_MAXINT); + gtk_flow_box_set_homogeneous (GTK_FLOW_BOX(priv->fb_favorites), TRUE); + gtk_container_add (GTK_CONTAINER (priv->sw_favorites), priv->fb_favorites); + gtk_widget_show (GTK_WIDGET(priv->evbox_favorites)); + /* Close on click */ + g_signal_connect_swapped (priv->evbox_favorites, "button_press_event", G_CALLBACK (evbox_button_press_event_cb), self); - gtk_widget_set_events (priv->evbox, GDK_BUTTON_PRESS_MASK); - - gtk_container_add (GTK_CONTAINER (self), priv->evbox); + gtk_widget_set_events (priv->evbox_favorites, GDK_BUTTON_PRESS_MASK); priv->settings = g_settings_new ("sm.puri.phosh"); g_signal_connect (priv->settings, "changed::favorites", G_CALLBACK (favorites_changed), self); favorites_changed (priv->settings, "favorites", self); + + /* Running apps */ + priv->fb_running_apps = gtk_widget_new (GTK_TYPE_FLOW_BOX, + "halign", GTK_ALIGN_CENTER, + "valign", GTK_ALIGN_FILL, + "selection-mode", GTK_SELECTION_NONE, + "orientation", GTK_ORIENTATION_HORIZONTAL, + NULL); + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(priv->fb_running_apps)), + "phosh-running-apps-flowbox"); + gtk_flow_box_set_max_children_per_line (GTK_FLOW_BOX(priv->fb_running_apps), G_MAXINT); + gtk_flow_box_set_homogeneous (GTK_FLOW_BOX(priv->fb_running_apps), TRUE); + gtk_container_add (GTK_CONTAINER (priv->sw_running_apps), priv->fb_running_apps); + gtk_widget_show (GTK_WIDGET(priv->evbox_running_apps)); + /* Close on click */ + g_signal_connect_swapped (priv->evbox_running_apps, "button_press_event", + G_CALLBACK (evbox_button_press_event_cb), + self); + gtk_widget_set_events (priv->evbox_running_apps, GDK_BUTTON_PRESS_MASK); + get_running_apps (self); } @@ -242,6 +353,11 @@ phosh_favorites_dispose (GObject *object) g_clear_object (&priv->settings); + if (priv->xdg_switcher) { + phosh_private_xdg_switcher_destroy (priv->xdg_switcher); + priv->xdg_switcher = NULL; + } + G_OBJECT_CLASS (phosh_favorites_parent_class)->dispose (object); } @@ -250,13 +366,26 @@ static void phosh_favorites_class_init (PhoshFavoritesClass *klass) { GObjectClass *object_class = (GObjectClass *)klass; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); object_class->dispose = phosh_favorites_dispose; object_class->constructed = phosh_favorites_constructed; + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/phosh/ui/favorites.ui"); + + gtk_widget_class_bind_template_child_private (widget_class, PhoshFavorites, evbox_favorites); + gtk_widget_class_bind_template_child_private (widget_class, PhoshFavorites, sw_favorites); + gtk_widget_class_bind_template_child_private (widget_class, PhoshFavorites, evbox_running_apps); + gtk_widget_class_bind_template_child_private (widget_class, PhoshFavorites, sw_running_apps); + gtk_widget_class_bind_template_child_private (widget_class, PhoshFavorites, box_running_apps); + signals[APP_LAUNCHED] = g_signal_new ("app-launched", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + signals[APP_RAISED] = g_signal_new ("app-raised", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); signals[SELECTION_ABORTED] = g_signal_new ("selection-aborted", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); @@ -266,6 +395,7 @@ phosh_favorites_class_init (PhoshFavoritesClass *klass) static void phosh_favorites_init (PhoshFavorites *self) { + gtk_widget_init_template (GTK_WIDGET (self)); } diff --git a/src/meson.build b/src/meson.build index 65f6c83fe2f5ba5d2af57de2067e9ac7efb4c1d8..f7eeef181a6d346e82f7eb195a0a7968d0e9eb8e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -9,6 +9,8 @@ phosh_resources = gnome.compile_resources( ) phosh_sources = [ + 'app.c', + 'app.h', 'auth.c', 'auth.h', 'background.c', @@ -51,6 +53,7 @@ phosh_sources = [ ] phosh_deps = [ + dependency('gio-2.0', version: '>= 2.56'), dependency('gcr-3', version: '>= 3.7.5'), dependency('gio-2.0', version: '>=2.50.0'), dependency('gio-unix-2.0', version: '>=2.50.0'), diff --git a/src/phosh-wayland.c b/src/phosh-wayland.c index b3a8baf4e19ecec882c8aefb8b7dd7758bd24b5d..654e1ab20d88695321bdbfdcb4b40dcc0cd48f65 100644 --- a/src/phosh-wayland.c +++ b/src/phosh-wayland.c @@ -59,7 +59,7 @@ registry_handle_global (void *data, registry, name, &phosh_private_interface, - 1); + 2); } else if (!strcmp (interface, zwlr_layer_shell_v1_interface.name)) { priv->layer_shell = wl_registry_bind ( registry, diff --git a/src/phosh.c b/src/phosh.c index 3489a6d32ca60b619b7b00ddcff0777ee03e3791..927bd5c9470c364e62adef56549cb4c67d7158dc 100644 --- a/src/phosh.c +++ b/src/phosh.c @@ -105,19 +105,8 @@ close_menu (struct popup **popup) static void -app_launched_cb (PhoshShell *self, - PhoshFavorites *favorites) -{ - PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); - - g_return_if_fail (priv->favorites); - close_menu (&priv->favorites); -} - - -static void -favorites_selection_aborted (PhoshShell *self, - PhoshFavorites *favorites) +close_favorites_menu_cb (PhoshShell *self, + PhoshFavorites *favorites) { PhoshShellPrivate *priv = phosh_shell_get_instance_private (self); @@ -222,11 +211,15 @@ favorites_activated_cb (PhoshShell *self, g_signal_connect_swapped (priv->favorites->window, "app-launched", - G_CALLBACK(app_launched_cb), + G_CALLBACK(close_favorites_menu_cb), + self); + g_signal_connect_swapped (priv->favorites->window, + "app-raised", + G_CALLBACK(close_favorites_menu_cb), self); g_signal_connect_swapped (priv->favorites->window, "selection-aborted", - G_CALLBACK(favorites_selection_aborted), + G_CALLBACK(close_favorites_menu_cb), self); } diff --git a/src/phosh.gresources.xml b/src/phosh.gresources.xml index 4cc7ea7d40f7f8992355dfa2ee2d23dff38f1fc8..1e98cfb819d034941477a8f01cb70e60fe34d577 100644 --- a/src/phosh.gresources.xml +++ b/src/phosh.gresources.xml @@ -1,6 +1,7 @@ + ui/favorites.ui ui/home.ui ui/lockscreen.ui ui/settings-menu.ui diff --git a/src/style.css b/src/style.css index 19ead20413b1c6088b45e37e876af227781124b1..31c144c286194468beddfd40cea3be020baad77f 100644 --- a/src/style.css +++ b/src/style.css @@ -1,3 +1,4 @@ +/* Top bar panel */ .phosh-panel { font: 15px lato-regular; } @@ -6,3 +7,31 @@ background-image: none; border-width: 0; } + +/* Settings menu */ +.phosh-settings-menu { + border-bottom-right-radius: 10px; + border-bottom-left-radius: 10px; + } + +/* Favorites / Home screen */ +.phosh-app-btn { + background-image: none; + background-color: black; + border-width: 3px; + border-radius: 10px; +} + +.phosh-app-name { + font-size: larger; + font-weight: bold; +} + +.phosh-app-title { + font-size: larger; +} + +.phosh-running-apps-flowbox { + padding-top: 10px; + padding-bottom: 10px; +} diff --git a/src/ui/favorites.ui b/src/ui/favorites.ui new file mode 100644 index 0000000000000000000000000000000000000000..4fa8f5dc0e044be29085fdfbf4632d57c016000b --- /dev/null +++ b/src/ui/favorites.ui @@ -0,0 +1,128 @@ + + + + + + diff --git a/src/ui/settings-menu.ui b/src/ui/settings-menu.ui index 9309e531b50a798e74446307d4736ed92aeccc60..45d23bfd45a40d58d9793307b36673b884fa9ddc 100644 --- a/src/ui/settings-menu.ui +++ b/src/ui/settings-menu.ui @@ -237,5 +237,8 @@ + diff --git a/tests/meson.build b/tests/meson.build index 764f5369ddf38a697e132c539276bc27cbd600df..64abea6211fc1276316a647dbae8dabe5bd3f051 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -21,25 +21,29 @@ test_link_args = [ '-fPIC', ] -test_stubs = [ +# Deps for all tests +test_deps = [ 'phoshstub.c', wl_proto_sources, + phosh_resources, ] -cls_names = [ - 'favorites', +tests = [ + ['app', []], + ['favorites', [ '@0@/src/app.c'.format(meson.source_root())]] ] -foreach cls_name : cls_names - t = executable('test-@0@'.format(cls_name), - ['test-@0@.c'.format(cls_name), - '../src/@0@.c'.format(cls_name), - test_stubs], +foreach test : tests + t = executable('test-@0@'.format(test[0]), + ['test-@0@.c'.format(test[0]), + '@0@/src/@1@.c'.format(meson.source_root(), test[0]), + test[1], + test_deps], c_args: test_cflags, link_args: test_link_args, dependencies: phosh_deps, ) - test(cls_name, t, env: test_env) + test(test[0], t, env: test_env) endforeach endif diff --git a/tests/phoshstub.c b/tests/phoshstub.c index 6a529db2df5605b0b58f0c84f76539e2956d4e15..ea6010ab5f3349b7627c74601e4944c67e9cad02 100644 --- a/tests/phoshstub.c +++ b/tests/phoshstub.c @@ -23,3 +23,23 @@ phosh_shell_get_usable_area (PhoshShell *self, gint *x, gint *y, gint *width, g *height = 128; return; } + + +PhoshWayland * +phosh_wayland_get_default (void) +{ + return NULL; +} + +struct phosh_private* +phosh_wayland_get_phosh_private (PhoshWayland *self) +{ + return NULL; +} + +PhoshMonitor * +phosh_shell_get_primary_monitor (PhoshShell *self) +{ + return NULL; +} + diff --git a/tests/test-app.c b/tests/test-app.c new file mode 100644 index 0000000000000000000000000000000000000000..de678af4786b991641ad55c78e960b5449382a2e --- /dev/null +++ b/tests/test-app.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 Purism SPC + * SPDX-License-Identifier: GPL-3.0+ + * Author: Guido Günther + */ + +#include "app.h" + +static void +test_phosh_app_new(void) +{ + PhoshApp *app = PHOSH_APP (phosh_app_new ("com.example.foo", "bar")); + g_assert (app); + g_assert_cmpstr (phosh_app_get_app_id (app), ==, "com.example.foo"); + g_assert_cmpstr (phosh_app_get_title (app), ==, "bar"); + gtk_widget_destroy (GTK_WIDGET (app)); +} + + +gint +main (gint argc, + gchar *argv[]) +{ + gtk_test_init (&argc, &argv, NULL); + + g_test_add_func("/phosh/app/new", test_phosh_app_new); + return g_test_run(); +}