summaryrefslogtreecommitdiff
path: root/endless/eostopbar.c
diff options
context:
space:
mode:
Diffstat (limited to 'endless/eostopbar.c')
-rw-r--r--endless/eostopbar.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/endless/eostopbar.c b/endless/eostopbar.c
index 9d7f276..3c1596d 100644
--- a/endless/eostopbar.c
+++ b/endless/eostopbar.c
@@ -29,6 +29,7 @@
#define _EOS_TOP_BAR_MAXIMIZE_ICON_NAME "window-maximize-symbolic"
#define _EOS_TOP_BAR_UNMAXIMIZE_ICON_NAME "window-unmaximize-symbolic"
#define _EOS_TOP_BAR_CLOSE_ICON_NAME "window-close-symbolic"
+#define _EOS_TOP_BAR_CREDITS_ICON_NAME "user-info-symbolic"
typedef struct {
GtkWidget *actions_grid;
@@ -44,6 +45,13 @@ typedef struct {
GtkWidget *maximize_icon;
GtkWidget *close_button;
GtkWidget *close_icon;
+ GtkWidget *credits_button;
+ GtkWidget *credits_icon;
+ GtkWidget *credits_stack;
+
+ gboolean show_credits_button;
+ guint credits_enter_handler;
+ guint credits_leave_handler;
} EosTopBarPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (EosTopBar, eos_top_bar, GTK_TYPE_EVENT_BOX)
@@ -52,11 +60,58 @@ enum {
CLOSE_CLICKED,
MINIMIZE_CLICKED,
MAXIMIZE_CLICKED,
+ CREDITS_CLICKED,
LAST_SIGNAL
};
static guint top_bar_signals[LAST_SIGNAL] = { 0 };
+enum {
+ PROP_0,
+ PROP_SHOW_CREDITS_BUTTON,
+ NPROPS
+};
+
+static GParamSpec *eos_top_bar_props[NPROPS] = { NULL, };
+
+static void
+eos_top_bar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EosTopBar *self = EOS_TOP_BAR (object);
+
+ switch (property_id)
+ {
+ case PROP_SHOW_CREDITS_BUTTON:
+ g_value_set_boolean (value, eos_top_bar_get_show_credits_button (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+eos_top_bar_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EosTopBar *self = EOS_TOP_BAR (object);
+
+ switch (property_id)
+ {
+ case PROP_SHOW_CREDITS_BUTTON:
+ eos_top_bar_set_show_credits_button (self, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
static void
eos_top_bar_get_preferred_height (GtkWidget *widget,
int *minimum,
@@ -98,6 +153,8 @@ eos_top_bar_class_init (EosTopBarClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ object_class->get_property = eos_top_bar_get_property;
+ object_class->set_property = eos_top_bar_set_property;
widget_class->get_preferred_height = eos_top_bar_get_preferred_height;
widget_class->draw = eos_top_bar_draw;
@@ -133,6 +190,19 @@ eos_top_bar_class_init (EosTopBarClass *klass)
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
+
+ top_bar_signals[CREDITS_CLICKED] =
+ g_signal_new ("credits-clicked", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
+ eos_top_bar_props[PROP_SHOW_CREDITS_BUTTON] =
+ g_param_spec_boolean ("show-credits-button", "Show credits button",
+ "Whether the credits button is discoverable",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, NPROPS, eos_top_bar_props);
}
static void
@@ -159,6 +229,23 @@ on_close_clicked_cb (GtkButton *button,
g_signal_emit (self, top_bar_signals[CLOSE_CLICKED], 0);
}
+static gboolean
+on_stack_hover (GtkStack *stack,
+ GdkEvent *event,
+ gpointer data)
+{
+ gboolean show = GPOINTER_TO_INT (data);
+ gtk_stack_set_visible_child_name (stack, show ? "button" : "blank");
+ return GDK_EVENT_PROPAGATE;
+}
+
+static void
+on_credits_clicked (GtkButton *button,
+ EosTopBar *self)
+{
+ g_signal_emit (self, top_bar_signals[CREDITS_CLICKED], 0);
+}
+
static void
eos_top_bar_init (EosTopBar *self)
{
@@ -236,10 +323,36 @@ eos_top_bar_init (EosTopBar *self)
gtk_container_add (GTK_CONTAINER (priv->close_button),
priv->close_icon);
+ /* This works like a revealer but it's really a GtkStack so that it takes up
+ space and presents a target even when it's not shown. */
+ priv->credits_stack = gtk_stack_new ();
+ gtk_stack_set_transition_type (GTK_STACK (priv->credits_stack),
+ GTK_STACK_TRANSITION_TYPE_CROSSFADE);
+ gtk_widget_add_events (priv->credits_stack,
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+ gtk_stack_add_named (GTK_STACK (priv->credits_stack),
+ gtk_event_box_new (), "blank");
+ priv->credits_button = g_object_new (GTK_TYPE_BUTTON,
+ "can-focus", FALSE,
+ "halign", GTK_ALIGN_END,
+ "valign", GTK_ALIGN_CENTER,
+ NULL);
+ priv->credits_icon =
+ gtk_image_new_from_icon_name (_EOS_TOP_BAR_CREDITS_ICON_NAME,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ g_object_set (priv->credits_icon,
+ "pixel-size", _EOS_TOP_BAR_ICON_SIZE_PX,
+ "margin", _EOS_TOP_BAR_BUTTON_PADDING_PX,
+ NULL);
+ gtk_container_add (GTK_CONTAINER (priv->credits_button), priv->credits_icon);
+ gtk_stack_add_named (GTK_STACK (priv->credits_stack),
+ priv->credits_button, "button");
+
gtk_container_add (GTK_CONTAINER (priv->actions_grid),
priv->left_top_bar_attach);
gtk_container_add (GTK_CONTAINER (priv->actions_grid),
priv->center_top_bar_attach);
+ gtk_container_add (GTK_CONTAINER (priv->actions_grid), priv->credits_stack);
gtk_container_add (GTK_CONTAINER (priv->actions_grid),
priv->minimize_button);
gtk_container_add (GTK_CONTAINER (priv->actions_grid),
@@ -258,6 +371,16 @@ eos_top_bar_init (EosTopBar *self)
G_CALLBACK (on_maximize_clicked_cb), self);
g_signal_connect (priv->close_button, "clicked",
G_CALLBACK (on_close_clicked_cb), self);
+ priv->credits_enter_handler =
+ g_signal_connect (priv->credits_stack, "enter-notify-event",
+ G_CALLBACK (on_stack_hover), GINT_TO_POINTER (TRUE));
+ priv->credits_leave_handler =
+ g_signal_connect (priv->credits_stack, "leave-notify-event",
+ G_CALLBACK (on_stack_hover), GINT_TO_POINTER (FALSE));
+ g_signal_handler_block (priv->credits_stack, priv->credits_enter_handler);
+ g_signal_handler_block (priv->credits_stack, priv->credits_leave_handler);
+ g_signal_connect (priv->credits_button, "clicked",
+ G_CALLBACK (on_credits_clicked), self);
}
GtkWidget *
@@ -355,3 +478,55 @@ eos_top_bar_update_window_maximized (EosTopBar *self,
else
gtk_style_context_remove_class (context, _EOS_STYLE_CLASS_UNMAXIMIZED);
}
+
+/*
+ * eos_top_bar_get_show_credits_button:
+ * @self: the top bar
+ *
+ * See eos_top_bar_set_show_credits_button().
+ *
+ * Returns: %TRUE if credits button should be discoverable, %FALSE if not.
+ */
+gboolean
+eos_top_bar_get_show_credits_button (EosTopBar *self)
+{
+ EosTopBarPrivate *priv = eos_top_bar_get_instance_private (self);
+ return priv->show_credits_button;
+}
+
+/*
+ * eos_top_bar_set_show_credits_button:
+ * @self: the top bar
+ * @show_credits_button: whether the credits button should be discoverable.
+ *
+ * Gets whether the credits button should be discoverable.
+ * Note that the credits button is not visible as such, but when the mouse
+ * hovers over it, it becomes visible if this is set to %TRUE.
+ * If this is %FALSE, the button never becomes visible.
+ */
+void
+eos_top_bar_set_show_credits_button (EosTopBar *self,
+ gboolean show_credits_button)
+{
+ EosTopBarPrivate *priv = eos_top_bar_get_instance_private (self);
+ if (priv->show_credits_button == show_credits_button)
+ return;
+
+ priv->show_credits_button = show_credits_button;
+ if (show_credits_button)
+ {
+ g_signal_handler_unblock (priv->credits_stack,
+ priv->credits_enter_handler);
+ g_signal_handler_unblock (priv->credits_stack,
+ priv->credits_leave_handler);
+ }
+ else
+ {
+ gtk_stack_set_visible_child_name (GTK_STACK (priv->credits_stack),
+ "blank");
+ g_signal_handler_block (priv->credits_stack, priv->credits_enter_handler);
+ g_signal_handler_block (priv->credits_stack, priv->credits_leave_handler);
+ }
+ g_object_notify_by_pspec (G_OBJECT (self),
+ eos_top_bar_props[PROP_SHOW_CREDITS_BUTTON]);
+}