summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--endless/eosapplication.c18
-rw-r--r--endless/eostopbar-private.h5
-rw-r--r--endless/eostopbar.c175
-rw-r--r--endless/eoswindow.c41
4 files changed, 234 insertions, 5 deletions
diff --git a/endless/eosapplication.c b/endless/eosapplication.c
index 91dbd73..510ff3b 100644
--- a/endless/eosapplication.c
+++ b/endless/eosapplication.c
@@ -612,6 +612,16 @@ eos_application_class_init (EosApplicationClass *klass)
}
static void
+set_image_credits_action_enabled (EosApplication *self,
+ gboolean enabled)
+{
+ GAction *action = g_action_map_lookup_action (G_ACTION_MAP (self),
+ "image-credits");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
+ /* action map owns action */
+}
+
+static void
eos_application_init (EosApplication *self)
{
EosApplicationPrivate *priv = eos_application_get_instance_private (self);
@@ -623,6 +633,7 @@ eos_application_init (EosApplication *self)
};
g_action_map_add_action_entries (G_ACTION_MAP (self), actions,
G_N_ELEMENTS (actions), self);
+ set_image_credits_action_enabled (self, FALSE);
g_signal_connect (self, "notify::application-id",
G_CALLBACK (on_app_id_set), self);
@@ -734,11 +745,8 @@ eos_application_set_image_attribution_file (EosApplication *self,
if (priv->image_attribution_file == NULL || file == NULL)
{
- GAction *action = g_action_map_lookup_action (G_ACTION_MAP (self),
- "image-credits");
- gboolean enabled = (file == NULL);
- g_simple_action_set_enabled (G_SIMPLE_ACTION (self), enabled);
- /* action map owns action */
+ gboolean enabled = (file != NULL);
+ set_image_credits_action_enabled (self, enabled);
}
g_clear_object (&priv->image_attribution_file);
diff --git a/endless/eostopbar-private.h b/endless/eostopbar-private.h
index 3d0f4a7..aa6e44b 100644
--- a/endless/eostopbar-private.h
+++ b/endless/eostopbar-private.h
@@ -57,6 +57,11 @@ void eos_top_bar_set_center_widget (EosTopBar *self,
void eos_top_bar_update_window_maximized (EosTopBar *self,
gboolean is_maximized);
+gboolean eos_top_bar_get_show_credits_button (EosTopBar *self);
+
+void eos_top_bar_set_show_credits_button (EosTopBar *self,
+ gboolean show_credits_button);
+
G_END_DECLS
#endif /* EOS_TOP_BAR_H */
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]);
+}
diff --git a/endless/eoswindow.c b/endless/eoswindow.c
index 0b39ffb..d128a5e 100644
--- a/endless/eoswindow.c
+++ b/endless/eoswindow.c
@@ -342,6 +342,34 @@ update_page (EosWindow *self)
}
static void
+on_image_credits_enabled_changed (GActionGroup *group,
+ const gchar *action_name,
+ gboolean enabled,
+ EosWindow *self)
+{
+ EosWindowPrivate *priv = eos_window_get_instance_private (self);
+ eos_top_bar_set_show_credits_button (EOS_TOP_BAR (priv->top_bar), enabled);
+}
+
+static void
+eos_window_constructed (GObject *object)
+{
+ EosWindow *self = EOS_WINDOW (object);
+ EosWindowPrivate *priv = eos_window_get_instance_private (self);
+
+ G_OBJECT_CLASS (eos_window_parent_class)->constructed (object);
+
+ GtkApplication *application =
+ gtk_window_get_application (GTK_WINDOW (object));
+ GFile *credits_file =
+ eos_application_get_image_attribution_file (EOS_APPLICATION (application));
+ eos_top_bar_set_show_credits_button (EOS_TOP_BAR (priv->top_bar),
+ (credits_file != NULL));
+ g_signal_connect (application, "action-enabled-changed::image-credits",
+ G_CALLBACK (on_image_credits_enabled_changed), self);
+}
+
+static void
eos_window_get_property (GObject *object,
guint property_id,
GValue *value,
@@ -510,6 +538,7 @@ eos_window_class_init (EosWindowClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ object_class->constructed = eos_window_constructed;
object_class->get_property = eos_window_get_property;
object_class->set_property = eos_window_set_property;
object_class->finalize = eos_window_finalize;
@@ -631,6 +660,16 @@ on_close_clicked_cb (GtkWidget *top_bar,
gtk_window_close (GTK_WINDOW (self));
}
+static void
+on_credits_clicked (GtkWidget *top_bar,
+ EosWindow *self)
+{
+ GtkApplication *application = gtk_window_get_application (GTK_WINDOW (self));
+ /* application cannot be NULL */
+ g_action_group_activate_action (G_ACTION_GROUP (application), "image-credits",
+ NULL);
+}
+
static gboolean
on_window_state_event_cb (GtkWidget *widget,
GdkEventWindowState *event)
@@ -748,6 +787,8 @@ eos_window_init (EosWindow *self)
G_CALLBACK (on_maximize_clicked_cb), self);
g_signal_connect (priv->top_bar, "close-clicked",
G_CALLBACK (on_close_clicked_cb), self);
+ g_signal_connect (priv->top_bar, "credits-clicked",
+ G_CALLBACK (on_credits_clicked), self);
g_signal_connect (self, "window-state-event",
G_CALLBACK (on_window_state_event_cb), NULL);