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 @@
+
+
+
+
+
+ False
+
+
+
+
+
+
+
+
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();
+}