mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 15:22:11 +02:00
clapper-app: Handle alternative headerbar buttons placements
Handle all possible combinations of window state buttons placement. These are "right" and "left" combined along with either LTR or RTL. Fixes #402
This commit is contained in:
@@ -28,13 +28,19 @@ struct _ClapperAppWindowStateButtons
|
||||
{
|
||||
GtkBox parent;
|
||||
|
||||
GtkWidget *menu_button;
|
||||
GtkWidget *minimize_button;
|
||||
GtkWidget *maximize_button;
|
||||
GtkWidget *close_button;
|
||||
|
||||
/* Props */
|
||||
GtkWidget *menu_button;
|
||||
GtkPositionType position;
|
||||
|
||||
gboolean has_minimize;
|
||||
gboolean has_maximize;
|
||||
gboolean has_close;
|
||||
|
||||
gboolean has_buttons;
|
||||
|
||||
gboolean is_maximized;
|
||||
gboolean is_fullscreen;
|
||||
@@ -42,9 +48,19 @@ struct _ClapperAppWindowStateButtons
|
||||
GtkSettings *settings;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_POSITION,
|
||||
PROP_MENU_BUTTON,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
#define parent_class clapper_app_window_state_buttons_parent_class
|
||||
G_DEFINE_TYPE (ClapperAppWindowStateButtons, clapper_app_window_state_buttons, GTK_TYPE_BOX)
|
||||
|
||||
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
|
||||
|
||||
static void
|
||||
minimize_button_clicked_cb (GtkButton *button, ClapperAppWindowStateButtons *self)
|
||||
{
|
||||
@@ -67,12 +83,27 @@ close_button_clicked_cb (GtkButton *button, ClapperAppWindowStateButtons *self)
|
||||
}
|
||||
|
||||
static void
|
||||
_refresh_min_max_visibility (ClapperAppWindowStateButtons *self)
|
||||
_refresh_buttons_visibility (ClapperAppWindowStateButtons *self)
|
||||
{
|
||||
gtk_widget_set_visible (self->minimize_button,
|
||||
(self->has_minimize && !self->is_fullscreen));
|
||||
gtk_widget_set_visible (self->maximize_button,
|
||||
(self->has_maximize && !self->is_fullscreen));
|
||||
gboolean show_minimize = (self->has_minimize && !self->is_fullscreen);
|
||||
gboolean show_maximize = (self->has_maximize && !self->is_fullscreen);
|
||||
gboolean has_buttons;
|
||||
|
||||
gtk_widget_set_visible (self->minimize_button, show_minimize);
|
||||
gtk_widget_set_visible (self->maximize_button, show_maximize);
|
||||
gtk_widget_set_visible (self->close_button, self->has_close);
|
||||
|
||||
has_buttons = (self->menu_button != NULL || show_minimize
|
||||
|| show_maximize || self->has_close);
|
||||
|
||||
if (self->has_buttons != has_buttons) {
|
||||
self->has_buttons = has_buttons;
|
||||
|
||||
if (self->has_buttons)
|
||||
gtk_widget_add_css_class (GTK_WIDGET (self), "filled");
|
||||
else
|
||||
gtk_widget_remove_css_class (GTK_WIDGET (self), "filled");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -89,46 +120,57 @@ clapper_app_window_state_buttons_parse_layout (ClapperAppWindowStateButtons *sel
|
||||
|
||||
if (G_LIKELY (org_layout != NULL)) {
|
||||
GtkWidget *last_widget = self->menu_button;
|
||||
const gchar *layout = org_layout;
|
||||
gboolean can_parse = (self->position == GTK_POS_LEFT);
|
||||
gboolean had_sign = can_parse;
|
||||
guint i;
|
||||
|
||||
for (i = 0; layout[i]; ++i) {
|
||||
GtkWidget *widget = NULL;
|
||||
const gchar *next = layout + i + 1;
|
||||
for (i = 0; org_layout[i] != '\0'; ++i) {
|
||||
const gchar *layout = org_layout + i;
|
||||
|
||||
if (next[0] != '\0' && next[0] != ',' && next[0] != ':')
|
||||
if (layout[0] == ',') {
|
||||
had_sign = TRUE;
|
||||
continue;
|
||||
|
||||
GST_TRACE_OBJECT (self, "Remaining layout: %s", layout);
|
||||
|
||||
if (g_str_has_prefix (layout, "minimize")) {
|
||||
widget = self->minimize_button;
|
||||
has_minimize = TRUE;
|
||||
} else if (g_str_has_prefix (layout, "maximize")) {
|
||||
widget = self->maximize_button;
|
||||
has_maximize = TRUE;
|
||||
} else if (g_str_has_prefix (layout, "close")) {
|
||||
widget = self->close_button;
|
||||
has_close = TRUE;
|
||||
}
|
||||
|
||||
if (widget) {
|
||||
gtk_box_reorder_child_after (GTK_BOX (self), widget, last_widget);
|
||||
last_widget = widget;
|
||||
if (layout[0] == ':') {
|
||||
if (self->position == GTK_POS_LEFT)
|
||||
break;
|
||||
else
|
||||
can_parse = TRUE;
|
||||
|
||||
had_sign = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (next[0] == '\0')
|
||||
break;
|
||||
if (had_sign && can_parse) {
|
||||
GtkWidget *widget = NULL;
|
||||
|
||||
layout = next + 1;
|
||||
i = 0;
|
||||
GST_TRACE_OBJECT (self, "Remaining layout: %s", layout);
|
||||
|
||||
if (g_str_has_prefix (layout, "minimize")) {
|
||||
widget = self->minimize_button;
|
||||
has_minimize = TRUE;
|
||||
} else if (g_str_has_prefix (layout, "maximize")) {
|
||||
widget = self->maximize_button;
|
||||
has_maximize = TRUE;
|
||||
} else if (g_str_has_prefix (layout, "close")) {
|
||||
widget = self->close_button;
|
||||
has_close = TRUE;
|
||||
}
|
||||
|
||||
if (widget) {
|
||||
gtk_box_reorder_child_after (GTK_BOX (self), widget, last_widget);
|
||||
last_widget = widget;
|
||||
}
|
||||
|
||||
had_sign = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->has_minimize = has_minimize;
|
||||
self->has_maximize = has_maximize;
|
||||
|
||||
gtk_widget_set_visible (self->close_button, has_close);
|
||||
self->has_close = has_close;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Buttons layout parsed");
|
||||
|
||||
@@ -140,7 +182,7 @@ _decoration_layout_changed_cb (GtkSettings *settings,
|
||||
GParamSpec *pspec G_GNUC_UNUSED, ClapperAppWindowStateButtons *self)
|
||||
{
|
||||
clapper_app_window_state_buttons_parse_layout (self);
|
||||
_refresh_min_max_visibility (self);
|
||||
_refresh_buttons_visibility (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -162,16 +204,31 @@ _surface_state_changed_cb (GdkSurface *surface,
|
||||
}
|
||||
if (self->is_fullscreen != is_fullscreen) {
|
||||
self->is_fullscreen = is_fullscreen;
|
||||
_refresh_min_max_visibility (self);
|
||||
_refresh_buttons_visibility (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_app_window_state_buttons_init (ClapperAppWindowStateButtons *self)
|
||||
{
|
||||
self->position = GTK_POS_RIGHT;
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_app_window_state_buttons_constructed (GObject *object)
|
||||
{
|
||||
ClapperAppWindowStateButtons *self = CLAPPER_APP_WINDOW_STATE_BUTTONS_CAST (object);
|
||||
|
||||
if (self->position == GTK_POS_RIGHT)
|
||||
gtk_widget_add_css_class (GTK_WIDGET (self), "right");
|
||||
else
|
||||
gtk_widget_add_css_class (GTK_WIDGET (self), "left");
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
_clear_stored_settings (ClapperAppWindowStateButtons *self)
|
||||
{
|
||||
@@ -245,24 +302,57 @@ clapper_app_window_state_buttons_dispose (GObject *object)
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_app_window_state_buttons_set_property (GObject *object, guint prop_id,
|
||||
const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
ClapperAppWindowStateButtons *self = CLAPPER_APP_WINDOW_STATE_BUTTONS_CAST (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_POSITION:
|
||||
self->position = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_MENU_BUTTON:
|
||||
if ((self->menu_button = GTK_WIDGET (g_value_get_object (value)))) {
|
||||
gtk_box_prepend (GTK_BOX (self), self->menu_button);
|
||||
_refresh_buttons_visibility (self);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_app_window_state_buttons_class_init (ClapperAppWindowStateButtonsClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
GtkWidgetClass *widget_class = (GtkWidgetClass *) klass;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clappergtkwindowstatebuttons", 0,
|
||||
"Clapper GTK Window State Buttons");
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperappwindowstatebuttons", 0,
|
||||
"Clapper App Window State Buttons");
|
||||
|
||||
gobject_class->constructed = clapper_app_window_state_buttons_constructed;
|
||||
gobject_class->set_property = clapper_app_window_state_buttons_set_property;
|
||||
gobject_class->dispose = clapper_app_window_state_buttons_dispose;
|
||||
|
||||
widget_class->realize = clapper_app_window_state_buttons_realize;
|
||||
widget_class->unrealize = clapper_app_window_state_buttons_unrealize;
|
||||
|
||||
param_specs[PROP_POSITION] = g_param_spec_enum ("position",
|
||||
NULL, NULL, GTK_TYPE_POSITION_TYPE, GTK_POS_RIGHT,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
param_specs[PROP_MENU_BUTTON] = g_param_spec_object ("menu-button",
|
||||
NULL, NULL, GTK_TYPE_MENU_BUTTON,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class,
|
||||
CLAPPER_APP_RESOURCE_PREFIX "/ui/clapper-app-window-state-buttons.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (widget_class, ClapperAppWindowStateButtons, menu_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ClapperAppWindowStateButtons, minimize_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ClapperAppWindowStateButtons, maximize_button);
|
||||
gtk_widget_class_bind_template_child (widget_class, ClapperAppWindowStateButtons, close_button);
|
||||
|
@@ -54,12 +54,18 @@ clapper-app-headerbar .titlelabel label {
|
||||
clapper-app-headerbar clapper-app-window-state-buttons {
|
||||
margin-top: 8px;
|
||||
}
|
||||
clapper-app-headerbar clapper-app-window-state-buttons:dir(ltr) {
|
||||
clapper-app-headerbar clapper-app-window-state-buttons.filled.right:dir(ltr) {
|
||||
padding-right: 6px;
|
||||
}
|
||||
clapper-app-headerbar clapper-app-window-state-buttons:dir(rtl) {
|
||||
clapper-app-headerbar clapper-app-window-state-buttons.filled.right:dir(rtl) {
|
||||
padding-left: 6px;
|
||||
}
|
||||
clapper-app-headerbar clapper-app-window-state-buttons.filled.left:dir(ltr) {
|
||||
padding-left: 6px;
|
||||
}
|
||||
clapper-app-headerbar clapper-app-window-state-buttons.filled.left:dir(rtl) {
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
clapper-app-queue-list .topseparator {
|
||||
margin-top: 2px;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
src/bin/clapper-app/ui/clapper-app-audio-stream-list-item.ui
|
||||
src/bin/clapper-app/ui/clapper-app-headerbar.ui
|
||||
src/bin/clapper-app/ui/clapper-app-help-overlay.ui
|
||||
src/bin/clapper-app/ui/clapper-app-info-window.ui
|
||||
src/bin/clapper-app/ui/clapper-app-initial-state.ui
|
||||
@@ -7,7 +8,6 @@ src/bin/clapper-app/ui/clapper-app-queue-list.ui
|
||||
src/bin/clapper-app/ui/clapper-app-subtitle-stream-list-item.ui
|
||||
src/bin/clapper-app/ui/clapper-app-uri-dialog.ui
|
||||
src/bin/clapper-app/ui/clapper-app-video-stream-list-item.ui
|
||||
src/bin/clapper-app/ui/clapper-app-window-state-buttons.ui
|
||||
|
||||
src/bin/clapper-app/clapper-app-about-window.c
|
||||
src/bin/clapper-app/clapper-app-info-window.c
|
||||
|
@@ -8,6 +8,22 @@
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="halign">fill</property>
|
||||
<property name="valign">start</property>
|
||||
<child type="start">
|
||||
<object class="GtkRevealer">
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="transition-type">slide-right</property>
|
||||
<property name="transition-duration">500</property>
|
||||
<property name="reveal-child" bind-source="win_buttons_revealer" bind-property="reveal-child" bind-flags="sync-create"/>
|
||||
<child>
|
||||
<object class="ClapperAppWindowStateButtons">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="position">left</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="center">
|
||||
<object class="ClapperGtkLeadContainer">
|
||||
<property name="blocked-actions">toggle-play|seek-request</property>
|
||||
@@ -143,6 +159,17 @@
|
||||
<object class="ClapperAppWindowStateButtons">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="menu-button">
|
||||
<object class="GtkMenuButton">
|
||||
<property name="icon-name">open-menu-symbolic</property>
|
||||
<property name="menu-model">app_menu</property>
|
||||
<style>
|
||||
<class name="osd"/>
|
||||
<class name="flat"/>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -150,4 +177,23 @@
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
<menu id="app_menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Preferences</attribute>
|
||||
<attribute name="action">app.preferences</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Keyboard Shortcuts</attribute>
|
||||
<attribute name="action">win.show-help-overlay</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<!-- TRANSLATORS: Please do not translate application name -->
|
||||
<attribute name="label" translatable="yes">About Clapper</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
||||
|
@@ -3,17 +3,6 @@
|
||||
<template class="ClapperAppWindowStateButtons" parent="GtkBox">
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="menu_button">
|
||||
<property name="icon-name">open-menu-symbolic</property>
|
||||
<property name="menu-model">app_menu</property>
|
||||
<style>
|
||||
<class name="osd"/>
|
||||
<class name="flat"/>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="minimize_button">
|
||||
<property name="icon_name">window-minimize-symbolic</property>
|
||||
@@ -51,23 +40,4 @@
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
<menu id="app_menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Preferences</attribute>
|
||||
<attribute name="action">app.preferences</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Keyboard Shortcuts</attribute>
|
||||
<attribute name="action">win.show-help-overlay</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<!-- TRANSLATORS: Please do not translate application name -->
|
||||
<attribute name="label" translatable="yes">About Clapper</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
||||
|
Reference in New Issue
Block a user