From f5411c92b2578aaeb44e951a81ba39fb48517d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= <agx@sigxcpu.org> Date: Tue, 13 Feb 2018 12:14:53 +0100 Subject: [PATCH] Add basic settings menu This adds a common base class PhoshMenu for all top panel menus so phosh.c itself doesn't need to care about the details and we don't duplicate the code. --- README.md | 6 + protocol/phosh-mobile-shell.xml | 21 ++- run.in | 3 + src/favorites.c | 33 ++-- src/favorites.h | 29 +--- src/menu.c | 295 ++++++++++++++++++++++++++++++++ src/menu.h | 38 ++++ src/meson.build | 5 + src/panel.c | 51 ++++-- src/phosh.c | 72 ++++---- src/phosh.gresources.xml | 1 + src/settings.c | 102 +++++++++++ src/settings.h | 18 ++ src/settings/brightness.c | 124 ++++++++++++++ src/settings/brightness.h | 9 + src/style.css | 2 +- src/ui/settings-menu.ui | 97 +++++++++++ src/ui/top-panel.ui | 21 ++- 18 files changed, 824 insertions(+), 103 deletions(-) create mode 100644 src/menu.c create mode 100644 src/menu.h create mode 100644 src/settings.c create mode 100644 src/settings.h create mode 100644 src/settings/brightness.c create mode 100644 src/settings/brightness.h create mode 100644 src/ui/settings-menu.ui diff --git a/README.md b/README.md index 5b9b5ef..18946b3 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,9 @@ using: _build/run +If you want to test interaction with gnome-settings-daemon e.g. for brightness +start a session like: + + gnome-session --session=gnome-dummy --disable-acceleration-check & + +before running phosh. diff --git a/protocol/phosh-mobile-shell.xml b/protocol/phosh-mobile-shell.xml index 259d2f7..887f6cb 100644 --- a/protocol/phosh-mobile-shell.xml +++ b/protocol/phosh-mobile-shell.xml @@ -129,15 +129,14 @@ </request> </interface> - <!-- - <enum name="menu_position"> - <!- only supported for top panels -> - <entry name="left" value="0"/> - <entry name="right" value="1"/> - </enum> - - <request name="set_menu_position"> - <arg name="position" type="uint"/> - </request> - --> + <enum name="menu_position"> + <!-- only supported for top panels --> + <entry name="left" value="0"/> + <entry name="right" value="1"/> + </enum> + + <request name="set_menu_position"> + <arg name="surface" type="object" interface="wl_surface"/> + <arg name="position" type="uint"/> + </request> </protocol> diff --git a/run.in b/run.in index 6f7f2f0..7348a9e 100755 --- a/run.in +++ b/run.in @@ -2,6 +2,9 @@ ABS_BUILDDIR='@ABS_BUILDDIR@' +# Start up gsd, etc. +gnome-session --session=gnome-dummy --disable-acceleration-check & + export GSETTINGS_SCHEMA_DIR="${ABS_BUILDDIR}/data" exec "${ABS_BUILDDIR}/src/phosh" $@ diff --git a/src/favorites.c b/src/favorites.c index 30c881b..60bf2f0 100644 --- a/src/favorites.c +++ b/src/favorites.c @@ -21,12 +21,19 @@ enum { }; static guint signals[N_SIGNALS] = { 0 }; -struct PhoshFavoritesPrivate { +typedef struct +{ GtkWidget *grid; GSettings *settings; +} PhoshFavoritesPrivate; + + +struct _PhoshFavorites +{ + PhoshMenuClass parent; }; -G_DEFINE_TYPE_WITH_PRIVATE(PhoshFavorites, phosh_favorites, GTK_TYPE_WINDOW) +G_DEFINE_TYPE_WITH_PRIVATE(PhoshFavorites, phosh_favorites, PHOSH_TYPE_MENU) static void @@ -109,7 +116,7 @@ favorites_changed (GSettings *settings, for (gint i = 0; i < g_strv_length (favorites); i++) { gchar *fav = favorites[i]; btn = add_favorite (self, fav); - gtk_grid_attach (GTK_GRID (self->priv->grid), btn, 1, top++, 1, 1); + gtk_grid_attach (GTK_GRID (priv->grid), btn, 1, top++, 1, 1); } g_strfreev (favorites); } @@ -138,10 +145,10 @@ phosh_favorites_constructed (GObject *object) GTK_ALIGN_CENTER, NULL); gtk_container_add (GTK_CONTAINER (self), priv->grid); - self->priv->settings = g_settings_new ("sm.puri.phosh"); - g_signal_connect (self->priv->settings, "changed::favorites", + priv->settings = g_settings_new ("sm.puri.phosh"); + g_signal_connect (priv->settings, "changed::favorites", G_CALLBACK (favorites_changed), self); - favorites_changed (self->priv->settings, "favorites", self); + favorites_changed (priv->settings, "favorites", self); } @@ -149,8 +156,9 @@ static void phosh_favorites_dispose (GObject *object) { PhoshFavorites *self = PHOSH_FAVORITES (object); + PhoshFavoritesPrivate *priv = phosh_favorites_get_instance_private (self); - g_clear_object (&self->priv->settings); + g_clear_object (&priv->settings); G_OBJECT_CLASS (phosh_favorites_parent_class)->dispose (object); } @@ -173,14 +181,15 @@ phosh_favorites_class_init (PhoshFavoritesClass *klass) static void phosh_favorites_init (PhoshFavorites *self) { - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - PHOSH_FAVORITES_TYPE, - PhoshFavoritesPrivate); } GtkWidget * -phosh_favorites_new (void) +phosh_favorites_new (int position, const gpointer *shell) { - return g_object_new (PHOSH_FAVORITES_TYPE, NULL); + return g_object_new (PHOSH_TYPE_FAVORITES, + "name", "favorites", + "shell", shell, + "position", position, + NULL); } diff --git a/src/favorites.h b/src/favorites.h index 8584aeb..4b94cdb 100644 --- a/src/favorites.h +++ b/src/favorites.h @@ -7,33 +7,12 @@ #ifndef __PHOSH_FAVORITES_H__ #define __PHOSH_FAVORITES_H__ -#include <gtk/gtk.h> +#include "menu.h" -#define PHOSH_FAVORITES_TYPE (phosh_favorites_get_type ()) -#define PHOSH_FAVORITES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PHOSH_FAVORITES_TYPE, PhoshFavorites)) -#define PHOSH_FAVORITES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PHOSH_FAVORITES_TYPE, PhoshFavoritesClass)) -#define PHOSH_IS_FAVORITES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PHOSH_FAVORITES_TYPE)) -#define PHOSH_IS_FAVORITES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PHOSH_FAVORITES_TYPE)) -#define PHOSH_FAVORITES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PHOSH_FAVORITES_TYPE, PhoshFavoritesClass)) +#define PHOSH_TYPE_FAVORITES (phosh_favorites_get_type()) -typedef struct PhoshFavorites PhoshFavorites; -typedef struct PhoshFavoritesClass PhoshFavoritesClass; -typedef struct PhoshFavoritesPrivate PhoshFavoritesPrivate; +G_DECLARE_FINAL_TYPE (PhoshFavorites, phosh_favorites, PHOSH, FAVORITES, PhoshMenu) -struct PhoshFavorites -{ - GtkWindow parent; - - PhoshFavoritesPrivate *priv; -}; - -struct PhoshFavoritesClass -{ - GtkWindowClass parent_class; -}; - -GType phosh_favorites_get_type (void) G_GNUC_CONST; - -GtkWidget * phosh_favorites_new (void); +GtkWidget * phosh_favorites_new (int position, const gpointer *shell); #endif /* __PHOSH_FAVORITES_H__ */ diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..1cf024c --- /dev/null +++ b/src/menu.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3+ + * Author: Guido Günther <agx@sigxcpu.org> + */ + +#include <glib/gi18n.h> + +#include "menu.h" +#include "phosh-mobile-shell-client-protocol.h" + +/** + * SECTION:phosh-menu + * @short_description: A menu of the phosh wayland shell + * @Title: PhoshMenu + * + * The #PhoshMenu widget is a shell menu attached to a panel + * Don't let the wayland details leak to child classes. + */ + + +typedef struct +{ + struct wl_surface *surface; + struct phosh_mobile_shell *mshell; + gboolean shown; + gchar *name; + int position; +} PhoshMenuPrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (PhoshMenu, phosh_menu, GTK_TYPE_WINDOW) + + +enum { + PHOSH_MENU_PROP_0 = 0, + PHOSH_MENU_PROP_SHOWN, + PHOSH_MENU_PROP_NAME, + PHOSH_MENU_PROP_SHELL, + PHOSH_MENU_PROP_POSITION, + PHOSH_MENU_PROP_LAST_PROP, +}; +static GParamSpec *props[PHOSH_MENU_PROP_LAST_PROP] = { NULL, }; + +enum { + TOGGLED = 1, + LAST_SIGNAL, +}; +static guint signals [LAST_SIGNAL]; + + +static void +phosh_menu_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + PhoshMenu *self = PHOSH_MENU (object); + PhoshMenuPrivate *priv = phosh_menu_get_instance_private(self); + + switch (property_id) { + case PHOSH_MENU_PROP_SHOWN: + priv->shown = g_value_get_boolean (value); + break; + + case PHOSH_MENU_PROP_NAME: + g_free (priv->name); + priv->name = g_value_dup_string (value); + break; + + case PHOSH_MENU_PROP_SHELL: + priv->mshell = g_value_get_pointer (value); + break; + + case PHOSH_MENU_PROP_POSITION: + priv->position = g_value_get_int (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_menu_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + PhoshMenu *self = PHOSH_MENU (object); + PhoshMenuPrivate *priv = phosh_menu_get_instance_private(self); + + switch (property_id) { + case PHOSH_MENU_PROP_SHOWN: + g_value_set_boolean (value, priv->shown); + break; + + case PHOSH_MENU_PROP_NAME: + g_value_set_string (value, priv->name); + break; + + case PHOSH_MENU_PROP_SHELL: + g_value_set_pointer (value, priv->mshell); + + case PHOSH_MENU_PROP_POSITION: + g_value_set_int (value, priv->position); + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +static void +phosh_menu_constructed (GObject *object) +{ + PhoshMenu *self = PHOSH_MENU (object); + PhoshMenuPrivate *priv = phosh_menu_get_instance_private (self); + GdkWindow *gdk_window; + g_autofree gchar *name;; + + G_OBJECT_CLASS (phosh_menu_parent_class)->constructed (object); + + name = g_strdup_printf("phosh-menu-%s", priv->name); + + /* window properties */ + gtk_window_set_title (GTK_WINDOW (self), name); + gtk_window_set_decorated (GTK_WINDOW (self), FALSE); + gtk_widget_realize(GTK_WIDGET (self)); + + gtk_style_context_add_class ( + gtk_widget_get_style_context (GTK_WIDGET (self)), + "phosh-menu"); + + gtk_style_context_add_class ( + gtk_widget_get_style_context (GTK_WIDGET (self)), + name); + + gdk_window = gtk_widget_get_window (GTK_WIDGET (self)); + gdk_wayland_window_set_use_custom_surface (gdk_window); + priv->surface = gdk_wayland_window_get_wl_surface (gdk_window); + + g_return_if_fail (priv->surface != NULL); + + phosh_mobile_shell_set_panel_menu (priv->mshell, priv->surface); + phosh_mobile_shell_set_menu_position(priv->mshell, + priv->surface, + priv->position); +} + + +static void +phosh_menu_finalize (GObject *object) +{ + PhoshMenuPrivate *priv = phosh_menu_get_instance_private (PHOSH_MENU(object)); + GObjectClass *parent_class = G_OBJECT_CLASS (phosh_menu_parent_class); + + g_free (priv->name); + + if (parent_class->finalize != NULL) + parent_class->finalize (object); +} + + +static void +phosh_menu_class_init (PhoshMenuClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = phosh_menu_constructed; + object_class->finalize = phosh_menu_finalize; + + object_class->set_property = phosh_menu_set_property; + object_class->get_property = phosh_menu_get_property; + + /** + * PhoshMenu::toggled: + * @self: The #PhoshMenu instance. + * + * This signal is emitted when the menu state changes. + * That is if it's shown or hidden on the screen. + */ + signals [TOGGLED] = g_signal_new ("toggled", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); + + props[PHOSH_MENU_PROP_SHOWN] = g_param_spec_boolean ("shown", + "menu shown", + "Whether the menu is shown on screen", + FALSE, + G_PARAM_READABLE); + props[PHOSH_MENU_PROP_NAME] = g_param_spec_string ("name", + "menu name", + "the menus name", + "unnamed", + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE); + props[PHOSH_MENU_PROP_SHELL] = g_param_spec_pointer ("shell", + "mobile shell", + "the mobile shell", + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE); + props[PHOSH_MENU_PROP_POSITION] = g_param_spec_int ("position", + "menu position", + "menu position on top bar", + 0, + INT_MAX, + PHOSH_MOBILE_SHELL_MENU_POSITION_LEFT, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, PHOSH_MENU_PROP_LAST_PROP, props); +} + + +/** + * phosh_menu_new: + * + * Create a new #PhoshMenu widget. + * + * Returns: the newly created #PhoshMenu widget + * + */ +GtkWidget * +phosh_menu_new (const char* name, int position, const gpointer *shell) +{ + return g_object_new (PHOSH_TYPE_MENU, + "name", name, + "shell", shell, + "position", position, + NULL); +} + + +static void +phosh_menu_init (PhoshMenu *self) +{ + PhoshMenuPrivate *priv = phosh_menu_get_instance_private(self); + + priv->shown = FALSE; + priv->name = NULL; + priv->mshell = NULL; +} + + +gboolean +phosh_menu_is_shown (PhoshMenu *self) +{ + PhoshMenuPrivate *priv = phosh_menu_get_instance_private(self); + + return priv->shown; +} + + +void +phosh_menu_hide (PhoshMenu *self) +{ + PhoshMenuPrivate *priv = phosh_menu_get_instance_private(self); + + g_return_if_fail (priv->mshell); + g_return_if_fail (priv->surface); + + if (priv->shown) + phosh_mobile_shell_hide_panel_menu(priv->mshell, + priv->surface); + priv->shown = FALSE; +} + + +void +phosh_menu_show (PhoshMenu *self) +{ + PhoshMenuPrivate *priv = phosh_menu_get_instance_private(self); + + g_return_if_fail (priv->mshell); + g_return_if_fail (priv->surface); + + if (!priv->shown) + phosh_mobile_shell_show_panel_menu(priv->mshell, + priv->surface); + priv->shown = TRUE; +} + + +gboolean +phosh_menu_toggle (PhoshMenu *self) +{ + PhoshMenuPrivate *priv = phosh_menu_get_instance_private(self); + + priv->shown ? phosh_menu_hide (self) : phosh_menu_show (self); + return priv->shown; +} diff --git a/src/menu.h b/src/menu.h new file mode 100644 index 0000000..30da854 --- /dev/null +++ b/src/menu.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3+ + */ + +#ifndef PHOSH_MENU_H +#define PHOSH_MENU_H + +#include <gtk/gtk.h> +#include <gdk/gdkwayland.h> + +G_BEGIN_DECLS + +#define PHOSH_TYPE_MENU (phosh_menu_get_type()) + +G_DECLARE_DERIVABLE_TYPE (PhoshMenu, phosh_menu, PHOSH, MENU, GtkWindow) + +/** + * PhoshMenuClass + * @parent_class: The parent class + */ +struct _PhoshMenuClass +{ + GtkWindowClass parent_class; +}; + +GtkWidget * phosh_menu_new (const char* name, + int position, + const gpointer *shell); +gboolean phosh_menu_is_shown (PhoshMenu *self); +void phosh_menu_show (PhoshMenu *self); +void phosh_menu_hide (PhoshMenu *self); +gboolean phosh_menu_toggle (PhoshMenu *self); + +G_END_DECLS + +#endif /* PHOSH_MENU_H */ diff --git a/src/meson.build b/src/meson.build index 9d7a49d..861b758 100644 --- a/src/meson.build +++ b/src/meson.build @@ -22,9 +22,14 @@ phosh_sources = [ 'favorites.h', 'lockscreen.c', 'lockscreen.h', + 'menu.c', + 'menu.h', 'panel.c', 'panel.h', 'phosh.c', + 'settings.c', + 'settings.h', + 'settings/brightness.c', shell_proto_header, shell_proto_code, phosh_resources, diff --git a/src/panel.c b/src/panel.c index 9bc4a9d..f66c14b 100644 --- a/src/panel.c +++ b/src/panel.c @@ -15,17 +15,18 @@ #define GNOME_DESKTOP_USE_UNSTABLE_API #include <libgnome-desktop/gnome-wall-clock.h> -#define TOPLEFT_LABEL_TEXT "Librem5 dev board" +#define FAVORITES_LABEL_TEXT "Librem5 dev board" enum { FAVORITES_ACTIVATED, + SETTINGS_ACTIVATED, N_SIGNALS }; static guint signals[N_SIGNALS] = { 0 }; struct PhoshPanelPrivate { - GtkWidget *btn_topleft; - GtkWidget *label_clock; + GtkWidget *btn_favorites; + GtkWidget *btn_settings; GnomeWallClock *wall_clock; }; @@ -33,9 +34,8 @@ struct PhoshPanelPrivate { G_DEFINE_TYPE_WITH_PRIVATE (PhoshPanel, phosh_panel, GTK_TYPE_WINDOW) -/* FIXME: Temporarily add a term button until we have the menu system */ static void -topleft_clicked_cb (PhoshPanel *self, GtkButton *btn) +favorites_clicked_cb (PhoshPanel *self, GtkButton *btn) { g_return_if_fail (PHOSH_IS_PANEL (self)); g_return_if_fail (GTK_IS_BUTTON (btn)); @@ -43,6 +43,15 @@ topleft_clicked_cb (PhoshPanel *self, GtkButton *btn) } +static void +settings_clicked_cb (PhoshPanel *self, GtkButton *btn) +{ + g_return_if_fail (PHOSH_IS_PANEL (self)); + g_return_if_fail (GTK_IS_BUTTON (btn)); + g_signal_emit(self, signals[SETTINGS_ACTIVATED], 0); +} + + static void wall_clock_notify_cb (GnomeWallClock *wall_clock, GParamSpec *pspec, @@ -55,7 +64,7 @@ wall_clock_notify_cb (GnomeWallClock *wall_clock, datetime = g_date_time_new_now_local (); str = g_date_time_format (datetime, "%H:%M"); - gtk_label_set_markup (GTK_LABEL (priv->label_clock), str); + gtk_button_set_label (GTK_BUTTON (priv->btn_settings), str); g_date_time_unref (datetime); } @@ -69,16 +78,22 @@ phosh_panel_constructed (GObject *object) G_OBJECT_CLASS (phosh_panel_parent_class)->constructed (object); - gtk_button_set_label (GTK_BUTTON (priv->btn_topleft), TOPLEFT_LABEL_TEXT); + gtk_button_set_label (GTK_BUTTON (priv->btn_favorites), FAVORITES_LABEL_TEXT); priv->wall_clock = g_object_new (GNOME_TYPE_WALL_CLOCK, NULL); g_signal_connect (priv->wall_clock, "notify::clock", G_CALLBACK (wall_clock_notify_cb), self); - g_signal_connect_object (priv->btn_topleft, + g_signal_connect_object (priv->btn_favorites, + "clicked", + G_CALLBACK (favorites_clicked_cb), + self, + G_CONNECT_SWAPPED); + + g_signal_connect_object (priv->btn_settings, "clicked", - G_CALLBACK (topleft_clicked_cb), + G_CALLBACK (settings_clicked_cb), self, G_CONNECT_SWAPPED); @@ -92,12 +107,14 @@ phosh_panel_constructed (GObject *object) "phosh-panel"); /* Button properites */ - gtk_style_context_remove_class (gtk_widget_get_style_context (priv->btn_topleft), + gtk_style_context_remove_class (gtk_widget_get_style_context (priv->btn_favorites), + "button"); + gtk_style_context_remove_class (gtk_widget_get_style_context (priv->btn_favorites), + "image-button"); + gtk_style_context_remove_class (gtk_widget_get_style_context (priv->btn_settings), "button"); - gtk_style_context_remove_class (gtk_widget_get_style_context (priv->btn_topleft), + gtk_style_context_remove_class (gtk_widget_get_style_context (priv->btn_settings), "image-button"); - gtk_style_context_add_class (gtk_widget_get_style_context (priv->btn_topleft), - "phosh-panel-btn-top-left"); wall_clock_notify_cb (priv->wall_clock, NULL, self); } @@ -128,10 +145,14 @@ phosh_panel_class_init (PhoshPanelClass *klass) G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + signals[SETTINGS_ACTIVATED] = g_signal_new ("settings-activated", + G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, + NULL, G_TYPE_NONE, 0); + gtk_widget_class_set_template_from_resource (widget_class, "/sm/puri/phosh/ui/top-panel.ui"); - gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, btn_topleft); - gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, label_clock); + gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, btn_favorites); + gtk_widget_class_bind_template_child_private (widget_class, PhoshPanel, btn_settings); } diff --git a/src/phosh.c b/src/phosh.c index 26c71d1..126da23 100644 --- a/src/phosh.c +++ b/src/phosh.c @@ -16,9 +16,11 @@ #include "phosh-mobile-shell-client-protocol.h" -#include "favorites.h" + #include "lockscreen.h" #include "panel.h" +#include "favorites.h" +#include "settings.h" struct elem { GtkWidget *window; @@ -48,8 +50,10 @@ struct desktop { gulong unlock_handler_id; /* Favorites menu */ - struct elem *favorites; - gboolean favorites_shown; + GtkWidget *favorites; + + /* Settings menu */ + GtkWidget *settings; }; @@ -67,26 +71,23 @@ lockscreen_unlock_cb (struct desktop *desktop, PhoshLockscreen *window) static void -favorites_activated_cb (struct desktop *desktop, PhoshLockscreen *window) +favorites_activated_cb (struct desktop *desktop, PhoshPanel *window) { - if (desktop->favorites_shown) { - phosh_mobile_shell_hide_panel_menu(desktop->mshell, - desktop->favorites->surface); - - } else { - phosh_mobile_shell_show_panel_menu(desktop->mshell, - desktop->favorites->surface); - } - desktop->favorites_shown = !desktop->favorites_shown; + phosh_menu_toggle (PHOSH_MENU (desktop->favorites)); } static void app_launched_cb (struct desktop *desktop, PhoshFavorites *favorites) { - phosh_mobile_shell_hide_panel_menu(desktop->mshell, - desktop->favorites->surface); - desktop->favorites_shown = FALSE; + phosh_menu_hide (PHOSH_MENU (desktop->favorites)); +} + + +static void +settings_activated_cb (struct desktop *desktop, PhoshPanel *window) +{ + phosh_menu_toggle (PHOSH_MENU (desktop->settings)); } @@ -120,29 +121,27 @@ lockscreen_create (struct desktop *desktop) static void favorites_create(struct desktop *desktop) { - struct elem *favorites; - GdkWindow *gdk_window; - - favorites = calloc (1, sizeof *favorites); - favorites->window = phosh_favorites_new (); + desktop->favorites = phosh_favorites_new (PHOSH_MOBILE_SHELL_MENU_POSITION_LEFT, + (gpointer) desktop->mshell); - gdk_window = gtk_widget_get_window (favorites->window); - gdk_wayland_window_set_use_custom_surface (gdk_window); - favorites->surface = gdk_wayland_window_get_wl_surface (gdk_window); + gtk_widget_show_all (desktop->favorites); - phosh_mobile_shell_set_panel_menu (desktop->mshell, - favorites->surface); - gtk_widget_show_all (favorites->window); - desktop->favorites = favorites; - desktop->favorites_shown = FALSE; - - g_signal_connect_swapped (favorites->window, + g_signal_connect_swapped (desktop->favorites, "app-launched", G_CALLBACK(app_launched_cb), desktop); } +static void +settings_create(struct desktop *desktop) +{ + desktop->settings = phosh_settings_new (PHOSH_MOBILE_SHELL_MENU_POSITION_RIGHT, + (gpointer) desktop->mshell); + gtk_widget_show_all (desktop->settings); +} + + static void panel_create (struct desktop *desktop) { @@ -171,6 +170,12 @@ panel_create (struct desktop *desktop) "favorites-activated", G_CALLBACK(favorites_activated_cb), desktop); + + g_signal_connect_swapped ( + panel->window, + "settings-activated", + G_CALLBACK(settings_activated_cb), + desktop); } @@ -300,6 +305,10 @@ shell_configure (struct desktop *desktop, width, PHOSH_PANEL_HEIGHT); phosh_mobile_shell_desktop_ready (desktop->mshell); + + /* Create menus once we now the panel's position */ + favorites_create (desktop); + settings_create (desktop); } @@ -414,7 +423,6 @@ int main(int argc, char *argv[]) css_setup (desktop); background_create (desktop); panel_create (desktop); - favorites_create (desktop); gtk_main (); diff --git a/src/phosh.gresources.xml b/src/phosh.gresources.xml index 25d8c25..d633fa2 100644 --- a/src/phosh.gresources.xml +++ b/src/phosh.gresources.xml @@ -2,6 +2,7 @@ <gresources> <gresource prefix="/sm/puri/phosh"> <file preprocess="xml-stripblanks">ui/top-panel.ui</file> + <file preprocess="xml-stripblanks">ui/settings-menu.ui</file> <file compressed="true">style.css</file> </gresource> </gresources> diff --git a/src/settings.c b/src/settings.c new file mode 100644 index 0000000..0da163e --- /dev/null +++ b/src/settings.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3+ + * Author: Guido Günther <agx@sigxcpu.org> + */ + +#include <glib/gi18n.h> + +#include "settings.h" +#include "settings/brightness.h" + + +typedef struct +{ + GtkWidget *scale_brightness; + GtkWidget *scale_volume; + + GtkAdjustment *adj_brightness; + GtkAdjustment *adj_volume; + +} PhoshSettingsPrivate; + + +typedef struct _PhoshSettings +{ + PhoshMenu parent; +} PhoshSettings; + + +G_DEFINE_TYPE_WITH_PRIVATE (PhoshSettings, phosh_settings, PHOSH_TYPE_MENU) + + +GtkWidget *phosh_settings (const char* name) +{ + return g_object_new (PHOSH_TYPE_SETTINGS, "name", name, NULL); +} + + +static void +brightness_changed_cb (GtkAdjustment *adj_brightness, gpointer *unused) +{ + int brightness; + + brightness = (int)gtk_adjustment_get_value (adj_brightness); + brightness_set (brightness); +} + + +static void +phosh_settings_constructed (GObject *object) +{ + PhoshSettings *self = PHOSH_SETTINGS (object); + PhoshSettingsPrivate *priv = phosh_settings_get_instance_private (self); + + priv->adj_brightness = gtk_adjustment_new (0, 0, 100, 1, 10, 10); + gtk_range_set_adjustment (GTK_RANGE (priv->scale_brightness), priv->adj_brightness); + gtk_range_set_round_digits (GTK_RANGE (priv->scale_brightness), 0); + + brightness_init (priv->adj_brightness); + g_signal_connect (priv->adj_brightness, + "value-changed", + G_CALLBACK(brightness_changed_cb), + NULL); + + priv->adj_volume = gtk_adjustment_new (0, 0, 100, 1, 10, 10); + gtk_range_set_adjustment (GTK_RANGE (priv->scale_volume), priv->adj_volume); + + G_OBJECT_CLASS (phosh_settings_parent_class)->constructed (object); +} + + +static void +phosh_settings_class_init (PhoshSettingsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + gtk_widget_class_set_template_from_resource (widget_class, + "/sm/puri/phosh/ui/settings-menu.ui"); + + object_class->constructed = phosh_settings_constructed; + gtk_widget_class_bind_template_child_private (widget_class, PhoshSettings, scale_volume); + gtk_widget_class_bind_template_child_private (widget_class, PhoshSettings, scale_brightness); +} + + +static void +phosh_settings_init (PhoshSettings *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +GtkWidget * +phosh_settings_new (int position, const gpointer *shell) +{ + return g_object_new (PHOSH_TYPE_SETTINGS, + "name", "settings", + "shell", shell, + "position", position, + NULL); +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..b65bf9e --- /dev/null +++ b/src/settings.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3.0+ + */ + +#ifndef __PHOSH_SETTINGS_H__ +#define __PHOSH_SETTINGS_H__ + +#include "menu.h" + +#define PHOSH_TYPE_SETTINGS (phosh_settings_get_type()) + +G_DECLARE_FINAL_TYPE (PhoshSettings, phosh_settings, PHOSH, SETTINGS, PhoshMenu) + +GtkWidget * phosh_settings_new (int position, const gpointer* shell); + +#endif /* __PHOSH_SETTINGS_H__ */ diff --git a/src/settings/brightness.c b/src/settings/brightness.c new file mode 100644 index 0000000..331578b --- /dev/null +++ b/src/settings/brightness.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3+ + * Author: Guido Günther <agx@sigxcpu.org> + */ + +#include <gio/gio.h> +#include <gtk/gtk.h> + +GDBusProxy *brightness_proxy; + + +void +brightness_changed_cb (GDBusProxy *proxy, + GVariant *changed_props, + GVariant *invalidated_props, + GtkAdjustment *adj) +{ + gboolean ret; + gint value, cur; + + ret = g_variant_lookup (changed_props, + "Brightness", + "i", &value); + + /* The value returned from DBUs is one lower + * than the value we set */ + cur = gtk_adjustment_get_value (adj); + if (ret && cur != value + 1) { + gtk_adjustment_set_value (adj, value + 1); + } +} + + +void +brightness_init (GtkAdjustment *adj) +{ + GError *err = NULL; + GDBusConnection *session_con; + GDBusProxy *proxy; + GVariant *var; + gint value; + + session_con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err); + if (err != NULL) { + g_error ("Can not connect to session bus: %s", err->message); + g_error_free (err); + return; + } + + proxy = g_dbus_proxy_new_sync(session_con, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon.Power", + "/org/gnome/SettingsDaemon/Power", + "org.gnome.SettingsDaemon.Power.Screen", + NULL, + &err); + if (!proxy || err) { + g_warning("Could not connect to brightness service %s", err->message); + g_error_free(err); + return; + } + + /* Set adjustment to current brightness */ + var = g_dbus_proxy_get_cached_property (proxy, "Brightness"); + if (var) { + g_variant_get (var, "i", &value); + gtk_adjustment_set_value (adj, value); + g_variant_unref (var); + } + + g_signal_connect (proxy, + "g-properties-changed", + G_CALLBACK(brightness_changed_cb), + adj); + + brightness_proxy = proxy; +} + + + +void +brightness_set_cb (GDBusProxy *proxy, GAsyncResult *res, gpointer unused) +{ + GError *err = NULL; + GVariant *var; + + var = g_dbus_proxy_call_finish (proxy, res, &err); + + if (err) { + g_warning("Could not set brightness %s", err->message); + g_error_free(err); + return; + } + + if (var) + g_variant_unref (var); +} + + +void +brightness_set (int brightness) +{ + g_return_if_fail (brightness_proxy); + + /* Don't let the display go completely dark for now */ + if (brightness < 10) + brightness = 10; + + g_dbus_proxy_call (brightness_proxy, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ( + "(ssv)", + "org.gnome.SettingsDaemon.Power.Screen", + "Brightness", + g_variant_new ("i", brightness)), + G_DBUS_CALL_FLAGS_NONE, + 2000, + NULL, + (GAsyncReadyCallback)brightness_set_cb, + NULL); +} diff --git a/src/settings/brightness.h b/src/settings/brightness.h new file mode 100644 index 0000000..c3f265f --- /dev/null +++ b/src/settings/brightness.h @@ -0,0 +1,9 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: GPL-3+ + * Author: Guido Günther <agx@sigxcpu.org> + */ + +void brightness_init (); +void brightness_set (int brightness); diff --git a/src/style.css b/src/style.css index 4ebe35e..19ead20 100644 --- a/src/style.css +++ b/src/style.css @@ -2,7 +2,7 @@ font: 15px lato-regular; } -.phosh-panel-btn-top-left { +.phosh-panel-btn { background-image: none; border-width: 0; } diff --git a/src/ui/settings-menu.ui b/src/ui/settings-menu.ui new file mode 100644 index 0000000..8bb2d20 --- /dev/null +++ b/src/ui/settings-menu.ui @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.20.2 --> +<interface> + <requires lib="gtk+" version="3.20"/> + <template class="PhoshSettings" parent="PhoshMenu"> + <property name="width_request">200</property> + <property name="can_focus">False</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_left">10</property> + <property name="margin_right">10</property> + <property name="margin_top">10</property> + <property name="margin_bottom">10</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_right">10</property> + <property name="icon_name">audio-speakers-symbolic</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScale" id="scale_volume"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="round_digits">1</property> + <property name="draw_value">False</property> + </object> + <packing> + <property name="expand">True</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">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_right">10</property> + <property name="icon_name">display-brightness-symbolic</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScale" id="scale_brightness"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="round_digits">1</property> + <property name="draw_value">False</property> + </object> + <packing> + <property name="expand">True</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> + </packing> + </child> + </object> + </child> + <child type="titlebar"> + <placeholder/> + </child> + </template> +</interface> diff --git a/src/ui/top-panel.ui b/src/ui/top-panel.ui index f4c470e..c470706 100644 --- a/src/ui/top-panel.ui +++ b/src/ui/top-panel.ui @@ -10,14 +10,16 @@ <property name="can_focus">False</property> <property name="homogeneous">True</property> <child> - <object class="GtkButton" id="btn_topleft"> - <property name="label"></property> + <object class="GtkButton" id="btn_favorites"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> - <property name="xalign">0.1</property> + <property name="xalign">0.10000000149011612</property> <property name="yalign">0.5</property> <property name="always_show_image">True</property> + <style> + <class name="phosh-panel-btn"/> + </style> </object> <packing> <property name="expand">False</property> @@ -39,11 +41,16 @@ <placeholder/> </child> <child> - <object class="GtkLabel" id="label_clock"> - <property name="visible">True</property> - <property name="can_focus">False</property> + <object class="GtkButton" id="btn_settings"> <property name="label" translatable="yes">00:00</property> - <property name="xalign">0.9</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="xalign">0.89999997615814209</property> + <property name="yalign">0.5</property> + <style> + <class name="phosh-panel-btn"/> + </style> </object> <packing> <property name="expand">True</property> -- GitLab