Commit f5411c92 authored by Guido Gunther's avatar Guido Gunther

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.
parent 33eec084
......@@ -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.
......@@ -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>
......@@ -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" $@
......@@ -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);
}
......@@ -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__ */
/*
* 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;
}
/*
* 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 */
......@@ -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,
......
......@@ -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);
}
......
......@@ -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);