diff options
author | Viktor Odintsev <zakhams@gmail.com> | 2017-06-28 22:57:26 +0300 |
---|---|---|
committer | Viktor Odintsev <ninetls@xfce.org> | 2017-06-28 22:57:26 +0300 |
commit | 473ef8458b4e31711cbf2f7675d6bf0bbba52df5 (patch) | |
tree | e14748523e44b2d2df8b6683106ce8ca257f19a4 /settings-dialogs | |
parent | 4c101f9b807fbd5e1067ca7254740a4ef1744e68 (diff) | |
download | xfwm4-473ef8458b4e31711cbf2f7675d6bf0bbba52df5.tar.gz |
Implement RangeDebouncer
This object allows to easily listen GtkRange value when drag
was finished. This was allowed in GTK2 with "update-policy" attribute
set to "discontinuous" which was removed in GTK3.
Diffstat (limited to 'settings-dialogs')
-rw-r--r-- | settings-dialogs/Makefile.am | 4 | ||||
-rw-r--r-- | settings-dialogs/range-debouncer.c | 232 | ||||
-rw-r--r-- | settings-dialogs/range-debouncer.h | 44 | ||||
-rw-r--r-- | settings-dialogs/tweaks-settings.c | 11 | ||||
-rw-r--r-- | settings-dialogs/xfwm4-settings.c | 9 |
5 files changed, 291 insertions, 9 deletions
diff --git a/settings-dialogs/Makefile.am b/settings-dialogs/Makefile.am index 4d96f2c3e..f477c605d 100644 --- a/settings-dialogs/Makefile.am +++ b/settings-dialogs/Makefile.am @@ -36,6 +36,8 @@ xfwm4_settings_SOURCES = \ xfwm4-settings.c \ xfwm4-settings.h \ xfwm4-dialog_ui.h \ + range-debouncer.c \ + range-debouncer.h \ common.c \ common.h @@ -61,6 +63,8 @@ xfwm4_settings_LDADD = \ xfwm4_tweaks_settings_SOURCES = \ tweaks-settings.c \ xfwm4-tweaks-dialog_ui.h \ + range-debouncer.c \ + range-debouncer.h \ common.c \ common.h diff --git a/settings-dialogs/range-debouncer.c b/settings-dialogs/range-debouncer.c new file mode 100644 index 000000000..571670bb1 --- /dev/null +++ b/settings-dialogs/range-debouncer.c @@ -0,0 +1,232 @@ +/* vi:set sw=2 sts=2 ts=2 et ai tw=100: */ +/*- + * Copyright (c) 2017 Viktor Odintsev <zakhams@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "range-debouncer.h" + + + +struct _RangeDebouncerClass +{ + GObjectClass __parent__; +}; + +struct _RangeDebouncer +{ + GObject __parent__; + + GtkRange *range; + gboolean pressed : 1; + + gulong signal1; + gulong signal2; + gulong signal3; +}; + +enum +{ + PROP_0, + PROP_VALUE, + N_PROPERTIES, +}; + +static void range_debouncer_finalize (GObject *object); +static void range_debouncer_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void range_debouncer_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); + +static void range_debouncer_weak_notify (RangeDebouncer *range_debouncer); + +static void range_debouncer_value_changed (RangeDebouncer *range_debouncer); +static gboolean range_debouncer_button_pressed (RangeDebouncer *range_debouncer); +static gboolean range_debouncer_button_released (RangeDebouncer *range_debouncer); + +G_DEFINE_TYPE (RangeDebouncer, range_debouncer, G_TYPE_OBJECT) + + + +static void +range_debouncer_class_init (RangeDebouncerClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = range_debouncer_finalize; + gobject_class->get_property = range_debouncer_get_property; + gobject_class->set_property = range_debouncer_set_property; + + g_object_class_install_property (gobject_class, PROP_VALUE, + g_param_spec_double ("value", NULL, NULL, + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + + + +static void +range_debouncer_init (RangeDebouncer *range_debouncer) +{ + range_debouncer->range = NULL; + range_debouncer->pressed = FALSE; + + range_debouncer->signal1 = 0; + range_debouncer->signal2 = 0; + range_debouncer->signal3 = 0; +} + + + +RangeDebouncer * +range_debouncer_bind (GtkRange *range) +{ + RangeDebouncer *range_debouncer; + + g_return_val_if_fail (GTK_IS_RANGE (range), NULL); + + range_debouncer = g_object_new (TYPE_RANGE_DEBOUNCER, NULL); + range_debouncer->range = range; + + /* RangeDebouncer will be destroyed with GtkRange */ + g_object_weak_ref (G_OBJECT (range), (GWeakNotify)range_debouncer_weak_notify, range_debouncer); + + range_debouncer->signal1 = + g_signal_connect_swapped (range, "value-changed", + G_CALLBACK (range_debouncer_value_changed), range_debouncer); + range_debouncer->signal2 = + g_signal_connect_swapped (range, "button-press-event", + G_CALLBACK (range_debouncer_button_pressed), range_debouncer); + range_debouncer->signal3 = + g_signal_connect_swapped (range, "button-release-event", + G_CALLBACK (range_debouncer_button_released), range_debouncer); + + return range_debouncer; +} + + + +static void +range_debouncer_finalize (GObject *object) +{ + RangeDebouncer *range_debouncer = RANGE_DEBOUNCER (object); + + if (G_UNLIKELY (range_debouncer->range != NULL)) + { + g_signal_handler_disconnect(range_debouncer->range, range_debouncer->signal1); + g_signal_handler_disconnect(range_debouncer->range, range_debouncer->signal2); + g_signal_handler_disconnect(range_debouncer->range, range_debouncer->signal3); + } + + G_OBJECT_CLASS (range_debouncer_parent_class)->finalize (object); +} + + + +static void +range_debouncer_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + RangeDebouncer *range_debouncer = RANGE_DEBOUNCER (object); + + switch (prop_id) + { + case PROP_VALUE: + if (G_LIKELY (range_debouncer->range != NULL)) + g_value_set_double (value, gtk_range_get_value (range_debouncer->range)); + else + g_value_set_double (value, 0); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static void +range_debouncer_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + RangeDebouncer *range_debouncer = RANGE_DEBOUNCER (object); + gdouble val_double; + + switch (prop_id) + { + case PROP_VALUE: + val_double = g_value_get_double (value); + if (G_LIKELY (range_debouncer->range != NULL) && + gtk_range_get_value (range_debouncer->range) != val_double) + { + gtk_range_set_value (range_debouncer->range, val_double); + g_object_notify (object, "value"); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static void +range_debouncer_weak_notify (RangeDebouncer *range_debouncer) +{ + range_debouncer->range = NULL; + g_object_unref (range_debouncer); +} + + + +static void +range_debouncer_value_changed (RangeDebouncer *range_debouncer) +{ + if (!range_debouncer->pressed) + g_object_notify (G_OBJECT (range_debouncer), "value"); +} + + + +static gboolean +range_debouncer_button_pressed (RangeDebouncer *range_debouncer) +{ + range_debouncer->pressed = TRUE; + return FALSE; +} + + + +static gboolean +range_debouncer_button_released (RangeDebouncer *range_debouncer) +{ + range_debouncer->pressed = FALSE; + g_object_notify (G_OBJECT (range_debouncer), "value"); + return FALSE; +} diff --git a/settings-dialogs/range-debouncer.h b/settings-dialogs/range-debouncer.h new file mode 100644 index 000000000..4db04b4c2 --- /dev/null +++ b/settings-dialogs/range-debouncer.h @@ -0,0 +1,44 @@ +/* vi:set sw=2 sts=2 ts=2 et ai tw=100: */ +/*- + * Copyright (c) 2017 Viktor Odintsev <zakhams@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef __RANGE_DEBOUNCER_H__ +#define __RANGE_DEBOUNCER_H__ + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +typedef struct _RangeDebouncerClass RangeDebouncerClass; +typedef struct _RangeDebouncer RangeDebouncer; + +#define TYPE_RANGE_DEBOUNCER (range_debouncer_get_type ()) +#define RANGE_DEBOUNCER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_RANGE_DEBOUNCER, RangeDebouncer)) +#define RANGE_DEBOUNCER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_RANGE_DEBOUNCER, RangeDebouncerClass)) +#define IS_RANGE_DEBOUNCER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_RANGE_DEBOUNCER)) +#define IS_RANGE_DEBOUNCER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_RANGE_DEBOUNCER)) +#define RANGE_DEBOUNCER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_RANGE_DEBOUNCER, RangeDebouncerClass)) + +GType range_debouncer_get_type (void) G_GNUC_CONST; + +RangeDebouncer * range_debouncer_bind (GtkRange *range); + +G_END_DECLS + +#endif /* __RANGE_DEBOUNCER_H__ */ diff --git a/settings-dialogs/tweaks-settings.c b/settings-dialogs/tweaks-settings.c index d3b45c5dd..1ed110941 100644 --- a/settings-dialogs/tweaks-settings.c +++ b/settings-dialogs/tweaks-settings.c @@ -44,6 +44,7 @@ #include <xfconf/xfconf.h> #include "xfwm4-tweaks-dialog_ui.h" +#include "range-debouncer.h" #include "common.h" static Window opt_socket_id = 0; @@ -420,23 +421,23 @@ wm_tweaks_dialog_configure_widgets (GtkBuilder *builder) xfconf_g_property_bind (xfwm4_channel, "/general/frame_opacity", G_TYPE_INT, - (GObject *) gtk_range_get_adjustment (GTK_RANGE (frame_opacity_scale)), "value"); + (GObject *) range_debouncer_bind (GTK_RANGE (frame_opacity_scale)), "value"); xfconf_g_property_bind (xfwm4_channel, "/general/resize_opacity", G_TYPE_INT, - (GObject *) gtk_range_get_adjustment (GTK_RANGE (resize_opacity_scale)), "value"); + (GObject *) range_debouncer_bind (GTK_RANGE (resize_opacity_scale)), "value"); xfconf_g_property_bind (xfwm4_channel, "/general/move_opacity", G_TYPE_INT, - (GObject *) gtk_range_get_adjustment (GTK_RANGE (move_opacity_scale)), "value"); + (GObject *) range_debouncer_bind (GTK_RANGE (move_opacity_scale)), "value"); xfconf_g_property_bind (xfwm4_channel, "/general/inactive_opacity", G_TYPE_INT, - (GObject *) gtk_range_get_adjustment (GTK_RANGE (inactive_opacity_scale)), "value"); + (GObject *) range_debouncer_bind (GTK_RANGE (inactive_opacity_scale)), "value"); xfconf_g_property_bind (xfwm4_channel, "/general/popup_opacity", G_TYPE_INT, - (GObject *) gtk_range_get_adjustment (GTK_RANGE (popup_opacity_scale)), "value"); + (GObject *) range_debouncer_bind (GTK_RANGE (popup_opacity_scale)), "value"); vbox = GTK_WIDGET (gtk_builder_get_object (builder, "main-vbox")); gtk_widget_show_all (vbox); diff --git a/settings-dialogs/xfwm4-settings.c b/settings-dialogs/xfwm4-settings.c index 45daa35c1..094b3044b 100644 --- a/settings-dialogs/xfwm4-settings.c +++ b/settings-dialogs/xfwm4-settings.c @@ -48,6 +48,7 @@ #include "xfwm4-dialog_ui.h" #include "xfwm4-settings.h" +#include "range-debouncer.h" #include "common.h" @@ -561,9 +562,9 @@ xfwm_settings_constructed (GObject *object) /* Focus tab */ xfconf_g_property_bind (settings->priv->wm_channel, "/general/focus_delay", G_TYPE_INT, - gtk_range_get_adjustment (GTK_RANGE (focus_delay_scale)), "value"); + range_debouncer_bind (GTK_RANGE (focus_delay_scale)), "value"); xfconf_g_property_bind (settings->priv->wm_channel, "/general/raise_delay", G_TYPE_INT, - gtk_range_get_adjustment (GTK_RANGE (focus_raise_delay_scale)), "value"); + range_debouncer_bind (GTK_RANGE (focus_raise_delay_scale)), "value"); xfconf_g_property_bind (settings->priv->wm_channel, "/general/raise_on_click", G_TYPE_BOOLEAN, raise_on_click_check, "active"); xfconf_g_property_bind (settings->priv->wm_channel, "/general/raise_on_focus", G_TYPE_BOOLEAN, @@ -630,9 +631,9 @@ xfwm_settings_constructed (GObject *object) /* Advanced tab */ xfconf_g_property_bind (settings->priv->wm_channel, "/general/snap_width", G_TYPE_INT, - gtk_range_get_adjustment (GTK_RANGE (snap_width_scale)), "value"); + range_debouncer_bind (GTK_RANGE (snap_width_scale)), "value"); xfconf_g_property_bind (settings->priv->wm_channel, "/general/wrap_resistance", G_TYPE_INT, - gtk_range_get_adjustment (GTK_RANGE (wrap_resistance_scale)), "value"); + range_debouncer_bind (GTK_RANGE (wrap_resistance_scale)), "value"); xfconf_g_property_bind (settings->priv->wm_channel, "/general/box_move", G_TYPE_BOOLEAN, box_move_check, "active"); xfconf_g_property_bind (settings->priv->wm_channel, "/general/box_resize", G_TYPE_BOOLEAN, |