From ae1c76ff830d146d41e88d6fba724c0a54bce868 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:45:20 +0200 Subject: Adding upstream version 1:43.6. Signed-off-by: Daniel Baumann --- panels/mouse/cc-mouse-caps-helper.c | 148 ++++++++ panels/mouse/cc-mouse-caps-helper.h | 33 ++ panels/mouse/cc-mouse-panel.c | 414 +++++++++++++++++++++ panels/mouse/cc-mouse-panel.h | 30 ++ panels/mouse/cc-mouse-panel.ui | 219 +++++++++++ panels/mouse/cc-mouse-test.c | 389 +++++++++++++++++++ panels/mouse/cc-mouse-test.h | 32 ++ panels/mouse/cc-mouse-test.ui | 69 ++++ panels/mouse/gnome-mouse-panel.desktop.in.in | 18 + panels/mouse/icons/meson.build | 4 + .../scalable/org.gnome.Settings-mouse-symbolic.svg | 4 + panels/mouse/meson.build | 70 ++++ panels/mouse/mouse.gresource.xml | 9 + panels/mouse/scroll-test-gegl.svg | 1 + panels/mouse/scroll-test.svg | 1 + panels/mouse/test-gnome-mouse-test.c | 24 ++ 16 files changed, 1465 insertions(+) create mode 100644 panels/mouse/cc-mouse-caps-helper.c create mode 100644 panels/mouse/cc-mouse-caps-helper.h create mode 100644 panels/mouse/cc-mouse-panel.c create mode 100644 panels/mouse/cc-mouse-panel.h create mode 100644 panels/mouse/cc-mouse-panel.ui create mode 100644 panels/mouse/cc-mouse-test.c create mode 100644 panels/mouse/cc-mouse-test.h create mode 100644 panels/mouse/cc-mouse-test.ui create mode 100644 panels/mouse/gnome-mouse-panel.desktop.in.in create mode 100644 panels/mouse/icons/meson.build create mode 100644 panels/mouse/icons/scalable/org.gnome.Settings-mouse-symbolic.svg create mode 100644 panels/mouse/meson.build create mode 100644 panels/mouse/mouse.gresource.xml create mode 100644 panels/mouse/scroll-test-gegl.svg create mode 100644 panels/mouse/scroll-test.svg create mode 100644 panels/mouse/test-gnome-mouse-test.c (limited to 'panels/mouse') diff --git a/panels/mouse/cc-mouse-caps-helper.c b/panels/mouse/cc-mouse-caps-helper.c new file mode 100644 index 0000000..6658f41 --- /dev/null +++ b/panels/mouse/cc-mouse-caps-helper.c @@ -0,0 +1,148 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2015 Red Hat, Inc, + * + * 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, see . + * + * Author: Felipe Borges + */ + +#include +#include +#include + +#include "cc-mouse-caps-helper.h" + +static gboolean +touchpad_check_capabilities_x11 (gboolean *have_two_finger_scrolling, + gboolean *have_edge_scrolling, + gboolean *have_tap_to_click) +{ + GdkDisplay *gdisplay; + Display *display; + g_autoptr(GList) devicelist = NULL; + GList *l; + Atom realtype, prop_scroll_methods, prop_tapping_enabled; + int realformat; + unsigned long nitems, bytes_after; + unsigned char *data; + + gdisplay = gdk_display_get_default (); + display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + prop_scroll_methods = XInternAtom (display, "libinput Scroll Methods Available", False); + prop_tapping_enabled = XInternAtom (display, "libinput Tapping Enabled", False); + if (!prop_scroll_methods || !prop_tapping_enabled) + return FALSE; + + *have_two_finger_scrolling = FALSE; + *have_edge_scrolling = FALSE; + *have_tap_to_click = FALSE; + + gdk_x11_display_error_trap_push (gdisplay); + + devicelist = gdk_seat_get_devices (gdk_display_get_default_seat (gdk_display_get_default ()), + GDK_SEAT_CAPABILITY_ALL_POINTING); + for (l = devicelist; l != NULL; l = l->next) { + GdkDevice *device = l->data; + if (gdk_device_get_source (device) != GDK_SOURCE_TOUCHPAD) + continue; + + /* xorg-x11-drv-libinput */ + if ((XIGetProperty (display, gdk_x11_device_get_id (device), prop_scroll_methods, + 0, 2, False, XA_INTEGER, &realtype, &realformat, &nitems, + &bytes_after, &data) == Success) && (realtype != None)) { + /* Property data is booleans for two-finger, edge, on-button scroll available. */ + + if (data[0]) + *have_two_finger_scrolling = TRUE; + + if (data[1]) + *have_edge_scrolling = TRUE; + + XFree (data); + } + + if ((XIGetProperty (display, gdk_x11_device_get_id (device), prop_tapping_enabled, + 0, 1, False, XA_INTEGER, &realtype, &realformat, &nitems, + &bytes_after, &data) == Success) && (realtype != None)) { + /* Property data is boolean for tapping enabled. */ + *have_tap_to_click = TRUE; + + XFree (data); + } + } + + gdk_x11_display_error_trap_pop_ignored (gdisplay); + + return TRUE; +} + +gboolean +cc_touchpad_check_capabilities (gboolean *have_two_finger_scrolling, + gboolean *have_edge_scrolling, + gboolean *have_tap_to_click) +{ + if (GDK_IS_X11_DISPLAY (gdk_display_get_default ())) + return touchpad_check_capabilities_x11 (have_two_finger_scrolling, + have_edge_scrolling, + have_tap_to_click); + /* else we unconditionally show all touchpad knobs */ + *have_two_finger_scrolling = TRUE; + *have_edge_scrolling = TRUE; + *have_tap_to_click = TRUE; + return FALSE; +} + +gboolean +cc_synaptics_check (void) +{ + GdkDisplay *gdisplay; + Display *display; + g_autoptr(GList) devicelist = NULL; + GList *l; + Atom prop, realtype; + int realformat; + unsigned long nitems, bytes_after; + unsigned char *data; + gboolean have_synaptics = FALSE; + + if (!GDK_IS_X11_DISPLAY (gdk_display_get_default ())) + return FALSE; + + gdisplay = gdk_display_get_default (); + display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); + prop = XInternAtom (display, "Synaptics Capabilities", False); + + gdk_x11_display_error_trap_push (gdisplay); + + devicelist = gdk_seat_get_devices (gdk_display_get_default_seat (gdk_display_get_default ()), + GDK_SEAT_CAPABILITY_ALL_POINTING); + for (l = devicelist; l != NULL; l = l->next) { + GdkDevice *device = l->data; + + if ((XIGetProperty (display, gdk_x11_device_get_id (device), prop, + 0, 2, False, XA_INTEGER, &realtype, &realformat, &nitems, + &bytes_after, &data) == Success) && (realtype != None)) { + have_synaptics = TRUE; + XFree (data); + } + + if (have_synaptics) + break; + } + + gdk_x11_display_error_trap_pop_ignored (gdisplay); + + return have_synaptics; +} diff --git a/panels/mouse/cc-mouse-caps-helper.h b/panels/mouse/cc-mouse-caps-helper.h new file mode 100644 index 0000000..93d9082 --- /dev/null +++ b/panels/mouse/cc-mouse-caps-helper.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2015 Red Hat, Inc, + * + * 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, see . + * + * Author: Felipe Borges + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gboolean cc_touchpad_check_capabilities (gboolean *have_two_finger_scrolling, + gboolean *have_edge_scrolling, + gboolean *have_tap_to_click); + +gboolean cc_synaptics_check (void); + +G_END_DECLS diff --git a/panels/mouse/cc-mouse-panel.c b/panels/mouse/cc-mouse-panel.c new file mode 100644 index 0000000..cdd28ab --- /dev/null +++ b/panels/mouse/cc-mouse-panel.c @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2010 Intel, Inc + * Copyright (C) 2012 Red Hat, Inc. + * + * 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, see . + * + * Authors: Thomas Wood + * Rodrigo Moya + * Ondrej Holy + * + */ + +#include +#include + +#include "cc-mouse-caps-helper.h" +#include "cc-mouse-panel.h" +#include "cc-mouse-resources.h" +#include "cc-mouse-test.h" +#include "gsd-device-manager.h" +#include "gsd-input-helper.h" + +struct _CcMousePanel +{ + CcPanel parent_instance; + + GtkListBoxRow *edge_scrolling_row; + GtkSwitch *edge_scrolling_switch; + AdwPreferencesGroup *mouse_group; + GtkSwitch *mouse_natural_scrolling_switch; + GtkScale *mouse_speed_scale; + CcMouseTest *mouse_test; + GtkBox *primary_button_box; + GtkToggleButton *primary_button_left; + GtkToggleButton *primary_button_right; + AdwPreferencesPage*preferences; + GtkStack *stack; + GtkListBoxRow *tap_to_click_row; + GtkSwitch *tap_to_click_switch; + GtkButton *test_button; + AdwPreferencesGroup *touchpad_group; + GtkListBoxRow *touchpad_natural_scrolling_row; + GtkSwitch *touchpad_natural_scrolling_switch; + GtkListBoxRow *touchpad_speed_row; + GtkScale *touchpad_speed_scale; + GtkSwitch *touchpad_toggle_switch; + GtkListBoxRow *two_finger_scrolling_row; + GtkSwitch *two_finger_scrolling_switch; + + GSettings *mouse_settings; + GSettings *touchpad_settings; + + gboolean have_mouse; + gboolean have_touchpad; + gboolean have_touchscreen; + gboolean have_synaptics; + + gboolean left_handed; + GtkGesture *left_gesture; + GtkGesture *right_gesture; +}; + +CC_PANEL_REGISTER (CcMousePanel, cc_mouse_panel) + +static void +setup_touchpad_options (CcMousePanel *self) +{ + gboolean edge_scroll_enabled; + gboolean two_finger_scroll_enabled; + gboolean have_two_finger_scrolling; + gboolean have_edge_scrolling; + gboolean have_tap_to_click; + + if (self->have_synaptics || !self->have_touchpad) { + gtk_widget_hide (GTK_WIDGET (self->touchpad_group)); + return; + } + + cc_touchpad_check_capabilities (&have_two_finger_scrolling, &have_edge_scrolling, &have_tap_to_click); + + gtk_widget_show (GTK_WIDGET (self->touchpad_group)); + + gtk_widget_set_visible (GTK_WIDGET (self->two_finger_scrolling_row), have_two_finger_scrolling); + gtk_widget_set_visible (GTK_WIDGET (self->edge_scrolling_row), have_edge_scrolling); + gtk_widget_set_visible (GTK_WIDGET (self->tap_to_click_row), have_tap_to_click); + + edge_scroll_enabled = g_settings_get_boolean (self->touchpad_settings, "edge-scrolling-enabled"); + two_finger_scroll_enabled = g_settings_get_boolean (self->touchpad_settings, "two-finger-scrolling-enabled"); + if (edge_scroll_enabled && two_finger_scroll_enabled) + { + /* You cunning user set both, but you can only have one set in that UI */ + gtk_switch_set_active (self->edge_scrolling_switch, FALSE); + } +} + +static void +two_finger_scrolling_changed_event (CcMousePanel *self, + gboolean state) +{ + /* Updating the setting will cause the "state" of the switch to be updated. */ + g_settings_set_boolean (self->touchpad_settings, "two-finger-scrolling-enabled", state); + + /* Disable edge scrolling if two-finger scrolling is enabled */ + if (state && gtk_widget_get_visible (GTK_WIDGET (self->edge_scrolling_row))) + gtk_switch_set_active (self->edge_scrolling_switch, FALSE); +} + +static void +edge_scrolling_changed_event (CcMousePanel *self, + gboolean state) +{ + /* Updating the setting will cause the "state" of the switch to be updated. */ + g_settings_set_boolean (self->touchpad_settings, "edge-scrolling-enabled", state); + + /* Disable two-finger scrolling if edge scrolling is enabled */ + if (state && gtk_widget_get_visible (GTK_WIDGET (self->two_finger_scrolling_row))) + gtk_switch_set_active (self->two_finger_scrolling_switch, FALSE); +} + +static gboolean +get_touchpad_enabled (GSettings *settings) +{ + GDesktopDeviceSendEvents send_events; + + send_events = g_settings_get_enum (settings, "send-events"); + + return send_events == G_DESKTOP_DEVICE_SEND_EVENTS_ENABLED; +} + +static gboolean +show_touchpad_enabling_switch (CcMousePanel *self) +{ + if (!self->have_touchpad) + return FALSE; + + g_debug ("Should we show the touchpad disable switch: have_mouse: %s have_touchscreen: %s\n", + self->have_mouse ? "true" : "false", + self->have_touchscreen ? "true" : "false"); + + /* Let's show the button when a mouse or touchscreen is present */ + if (self->have_mouse || self->have_touchscreen) + return TRUE; + + /* Let's also show when the touchpad is disabled. */ + if (!get_touchpad_enabled (self->touchpad_settings)) + return TRUE; + + return FALSE; +} + +static gboolean +touchpad_enabled_get_mapping (GValue *value, + GVariant *variant, + gpointer user_data) +{ + gboolean enabled; + + enabled = g_strcmp0 (g_variant_get_string (variant, NULL), "enabled") == 0; + g_value_set_boolean (value, enabled); + + return TRUE; +} + +static GVariant * +touchpad_enabled_set_mapping (const GValue *value, + const GVariantType *type, + gpointer user_data) +{ + gboolean enabled; + + enabled = g_value_get_boolean (value); + + return g_variant_new_string (enabled ? "enabled" : "disabled"); +} + +static void +pressed_cb (GtkButton *button) +{ + g_signal_emit_by_name (button, "activate"); +} + +static void +handle_secondary_button (CcMousePanel *self, + GtkToggleButton *button, + GtkGesture *gesture) +{ + gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE); + gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (gesture), TRUE); + gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY); + g_signal_connect_swapped (gesture, "pressed", G_CALLBACK (pressed_cb), button); + gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), GTK_PHASE_BUBBLE); + gtk_widget_add_controller (GTK_WIDGET (button), GTK_EVENT_CONTROLLER (gesture)); +} + +/* Set up the property editors in the dialog. */ +static void +setup_dialog (CcMousePanel *self) +{ + GtkToggleButton *button; + + gtk_widget_set_direction (GTK_WIDGET (self->primary_button_box), GTK_TEXT_DIR_LTR); + + self->left_handed = g_settings_get_boolean (self->mouse_settings, "left-handed"); + button = self->left_handed ? self->primary_button_right : self->primary_button_left; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); + + g_settings_bind (self->mouse_settings, "left-handed", + self->primary_button_left, "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN); + g_settings_bind (self->mouse_settings, "left-handed", + self->primary_button_right, "active", + G_SETTINGS_BIND_DEFAULT); + + /* Allow changing orientation with either button */ + button = self->primary_button_right; + self->right_gesture = gtk_gesture_click_new (); + handle_secondary_button (self, button, self->right_gesture); + button = self->primary_button_left; + self->left_gesture = gtk_gesture_click_new (); + handle_secondary_button (self, button, self->left_gesture); + + g_settings_bind (self->mouse_settings, "natural-scroll", + self->mouse_natural_scrolling_switch, "active", + G_SETTINGS_BIND_DEFAULT); + + /* Mouse section */ + gtk_widget_set_visible (GTK_WIDGET (self->mouse_group), self->have_mouse); + + g_settings_bind (self->mouse_settings, "speed", + gtk_range_get_adjustment (GTK_RANGE (self->mouse_speed_scale)), "value", + G_SETTINGS_BIND_DEFAULT); + + /* Touchpad section */ + gtk_widget_set_visible (GTK_WIDGET (self->touchpad_toggle_switch), show_touchpad_enabling_switch (self)); + + g_settings_bind_with_mapping (self->touchpad_settings, "send-events", + self->touchpad_toggle_switch, "active", + G_SETTINGS_BIND_DEFAULT, + touchpad_enabled_get_mapping, + touchpad_enabled_set_mapping, + NULL, NULL); + g_settings_bind_with_mapping (self->touchpad_settings, "send-events", + self->touchpad_natural_scrolling_row, "sensitive", + G_SETTINGS_BIND_GET, + touchpad_enabled_get_mapping, + touchpad_enabled_set_mapping, + NULL, NULL); + g_settings_bind_with_mapping (self->touchpad_settings, "send-events", + self->touchpad_speed_row, "sensitive", + G_SETTINGS_BIND_GET, + touchpad_enabled_get_mapping, + touchpad_enabled_set_mapping, + NULL, NULL); + g_settings_bind_with_mapping (self->touchpad_settings, "send-events", + self->tap_to_click_row, "sensitive", + G_SETTINGS_BIND_GET, + touchpad_enabled_get_mapping, + touchpad_enabled_set_mapping, + NULL, NULL); + g_settings_bind_with_mapping (self->touchpad_settings, "send-events", + self->two_finger_scrolling_row, "sensitive", + G_SETTINGS_BIND_GET, + touchpad_enabled_get_mapping, + touchpad_enabled_set_mapping, + NULL, NULL); + g_settings_bind_with_mapping (self->touchpad_settings, "send-events", + self->edge_scrolling_row, "sensitive", + G_SETTINGS_BIND_GET, + touchpad_enabled_get_mapping, + touchpad_enabled_set_mapping, + NULL, NULL); + + g_settings_bind (self->touchpad_settings, "natural-scroll", + self->touchpad_natural_scrolling_switch, "active", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind (self->touchpad_settings, "speed", + gtk_range_get_adjustment (GTK_RANGE (self->touchpad_speed_scale)), "value", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind (self->touchpad_settings, "tap-to-click", + self->tap_to_click_switch, "active", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind (self->touchpad_settings, "two-finger-scrolling-enabled", + self->two_finger_scrolling_switch, "state", + G_SETTINGS_BIND_GET); + + g_settings_bind (self->touchpad_settings, "edge-scrolling-enabled", + self->edge_scrolling_switch, "state", + G_SETTINGS_BIND_GET); + + setup_touchpad_options (self); +} + +/* Callback issued when a button is clicked on the dialog */ +static void +device_changed (CcMousePanel *self) +{ + self->have_touchpad = touchpad_is_present (); + + setup_touchpad_options (self); + + self->have_mouse = mouse_is_present (); + gtk_widget_set_visible (GTK_WIDGET (self->mouse_group), self->have_mouse); + gtk_widget_set_visible (GTK_WIDGET (self->touchpad_toggle_switch), show_touchpad_enabling_switch (self)); +} + +static void +cc_mouse_panel_dispose (GObject *object) +{ + CcMousePanel *self = CC_MOUSE_PANEL (object); + + g_clear_object (&self->mouse_settings); + g_clear_object (&self->touchpad_settings); + + G_OBJECT_CLASS (cc_mouse_panel_parent_class)->dispose (object); +} + +static const char * +cc_mouse_panel_get_help_uri (CcPanel *panel) +{ + return "help:gnome-help/mouse"; +} + +static void +test_button_toggled_cb (CcMousePanel *self) +{ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->test_button))) + gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->mouse_test)); + else + gtk_stack_set_visible_child (self->stack, GTK_WIDGET (self->preferences)); +} + +static void +cc_mouse_panel_init (CcMousePanel *self) +{ + GsdDeviceManager *device_manager; + + g_resources_register (cc_mouse_get_resource ()); + + cc_mouse_test_get_type (); + gtk_widget_init_template (GTK_WIDGET (self)); + + self->mouse_settings = g_settings_new ("org.gnome.desktop.peripherals.mouse"); + self->touchpad_settings = g_settings_new ("org.gnome.desktop.peripherals.touchpad"); + + device_manager = gsd_device_manager_get (); + g_signal_connect_object (device_manager, "device-added", + G_CALLBACK (device_changed), self, G_CONNECT_SWAPPED); + g_signal_connect_object (device_manager, "device-removed", + G_CALLBACK (device_changed), self, G_CONNECT_SWAPPED); + + self->have_mouse = mouse_is_present (); + self->have_touchpad = touchpad_is_present (); + self->have_touchscreen = touchscreen_is_present (); + self->have_synaptics = cc_synaptics_check (); + if (self->have_synaptics) + g_warning ("Detected synaptics X driver, please migrate to libinput"); + + setup_dialog (self); +} + +static void +cc_mouse_panel_class_init (CcMousePanelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + CcPanelClass *panel_class = CC_PANEL_CLASS (klass); + + panel_class->get_help_uri = cc_mouse_panel_get_help_uri; + + object_class->dispose = cc_mouse_panel_dispose; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/mouse/cc-mouse-panel.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, edge_scrolling_row); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, edge_scrolling_switch); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, mouse_group); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, mouse_natural_scrolling_switch); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, mouse_speed_scale); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, mouse_test); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, primary_button_box); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, primary_button_left); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, primary_button_right); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, preferences); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, stack); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, tap_to_click_row); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, tap_to_click_switch); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, test_button); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, touchpad_group); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, touchpad_natural_scrolling_row); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, touchpad_natural_scrolling_switch); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, touchpad_speed_row); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, touchpad_speed_scale); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, touchpad_toggle_switch); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, two_finger_scrolling_row); + gtk_widget_class_bind_template_child (widget_class, CcMousePanel, two_finger_scrolling_switch); + + gtk_widget_class_bind_template_callback (widget_class, edge_scrolling_changed_event); + gtk_widget_class_bind_template_callback (widget_class, test_button_toggled_cb); + gtk_widget_class_bind_template_callback (widget_class, two_finger_scrolling_changed_event); +} diff --git a/panels/mouse/cc-mouse-panel.h b/panels/mouse/cc-mouse-panel.h new file mode 100644 index 0000000..ae83e8e --- /dev/null +++ b/panels/mouse/cc-mouse-panel.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 Intel, Inc + * + * 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, see . + * + * Author: Thomas Wood + * + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define CC_TYPE_MOUSE_PANEL (cc_mouse_panel_get_type ()) +G_DECLARE_FINAL_TYPE (CcMousePanel, cc_mouse_panel, CC, MOUSE_PANEL, CcPanel) + +G_END_DECLS diff --git a/panels/mouse/cc-mouse-panel.ui b/panels/mouse/cc-mouse-panel.ui new file mode 100644 index 0000000..c5d1351 --- /dev/null +++ b/panels/mouse/cc-mouse-panel.ui @@ -0,0 +1,219 @@ + + + + + -1 + 1 + + + -1 + 1 + + + horizontal + + + + + + diff --git a/panels/mouse/cc-mouse-test.c b/panels/mouse/cc-mouse-test.c new file mode 100644 index 0000000..145cb74 --- /dev/null +++ b/panels/mouse/cc-mouse-test.c @@ -0,0 +1,389 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2012 Red Hat, Inc. + * + * Written by: Ondrej Holy , + * + * 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, 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, see . + */ + +#include + +#include +#include +#include +#include +#include + +#include "cc-mouse-test.h" + +#include +#include + +/* Click test button sizes. */ +#define SHADOW_SIZE (10.0 / 180 * size) +#define SHADOW_SHIFT_Y (-1.0 / 180 * size) +#define SHADOW_OPACITY (0.15 / 180 * size) +#define OUTER_CIRCLE_SIZE (22.0 / 180 * size) +#define ANNULUS_SIZE (6.0 / 180 * size) +#define INNER_CIRCLE_SIZE (52.0 / 180 * size) + +static void setup_information_label (CcMouseTest *self); +static void setup_scroll_image (CcMouseTest *self); + +enum +{ + DOUBLE_CLICK_TEST_OFF, + DOUBLE_CLICK_TEST_MAYBE, + DOUBLE_CLICK_TEST_ON, + DOUBLE_CLICK_TEST_STILL_ON, + DOUBLE_CLICK_TEST_ALMOST_THERE, + DOUBLE_CLICK_TEST_GEGL +}; + +struct _CcMouseTest +{ + AdwBin parent_instance; + + GtkWidget *button_drawing_area; + GtkWidget *information_label; + GtkWidget *image; + GtkWidget *scrolled_window_adjustment; + GtkWidget *viewport; + + guint32 double_click_timestamp; + gint double_click_state; + gint button_state; + + GSettings *mouse_settings; + + gint information_label_timeout_id; + gint button_drawing_area_timeout_id; + gint scroll_image_timeout_id; +}; + +G_DEFINE_TYPE (CcMouseTest, cc_mouse_test, ADW_TYPE_BIN); + +/* Timeout for the double click test */ + +static gboolean +test_maybe_timeout (CcMouseTest *self) +{ + self->double_click_state = DOUBLE_CLICK_TEST_OFF; + + gtk_widget_queue_draw (self->button_drawing_area); + + self->button_drawing_area_timeout_id = 0; + + return FALSE; +} + +/* Timeout for the information label */ + +static gboolean +information_label_timeout (CcMouseTest *self) +{ + setup_information_label (self); + + self->information_label_timeout_id = 0; + + return FALSE; +} + +/* Timeout for the scroll image */ + +static gboolean +scroll_image_timeout (CcMouseTest *self) +{ + setup_scroll_image (self); + + self->scroll_image_timeout_id = 0; + + return FALSE; +} + +/* Set information label */ + +static void +setup_information_label (CcMouseTest *self) +{ + const gchar *message = NULL; + g_autofree gchar *label_text = NULL; + gboolean double_click; + + if (self->information_label_timeout_id != 0) { + g_source_remove (self->information_label_timeout_id); + self->information_label_timeout_id = 0; + } + + if (self->double_click_state == DOUBLE_CLICK_TEST_OFF) { + gtk_label_set_label (GTK_LABEL (self->information_label), _("Try clicking, double clicking, scrolling")); + return; + } + + if (self->double_click_state == DOUBLE_CLICK_TEST_GEGL) { + message = _("Five clicks, GEGL time!"); + } else { + double_click = (self->double_click_state >= DOUBLE_CLICK_TEST_ON); + switch (self->button_state) { + case 1: + message = (double_click) ? _("Double click, primary button") : _("Single click, primary button"); + break; + case 2: + message = (double_click) ? _("Double click, middle button") : _("Single click, middle button"); + break; + case 3: + message = (double_click) ? _("Double click, secondary button") : _("Single click, secondary button"); + break; + } + } + + label_text = g_strconcat ("", message, "", NULL); + gtk_label_set_markup (GTK_LABEL (self->information_label), label_text); + + self->information_label_timeout_id = g_timeout_add (2500, (GSourceFunc) information_label_timeout, self); +} + +/* Update scroll image */ + +static void +setup_scroll_image (CcMouseTest *self) +{ + const char *resource; + + if (self->scroll_image_timeout_id != 0) { + g_source_remove (self->scroll_image_timeout_id); + self->scroll_image_timeout_id = 0; + } + + if (self->double_click_state == DOUBLE_CLICK_TEST_GEGL) + resource = "/org/gnome/control-center/mouse/scroll-test-gegl.svg"; + else + resource = "/org/gnome/control-center/mouse/scroll-test.svg"; + gtk_picture_set_resource (GTK_PICTURE (self->image), resource); + + if (self->double_click_state != DOUBLE_CLICK_TEST_GEGL) + return; + + self->scroll_image_timeout_id = g_timeout_add (5000, (GSourceFunc) scroll_image_timeout, self); +} + +/* Callback issued when the user clicks the double click testing area. */ + +static void +button_drawing_area_button_pressed_cb (GtkGestureClick *click_gesture, + gint n_press, + gdouble x, + gdouble y, + CcMouseTest *self) +{ + guint32 event_time; + guint current_button; + gint double_click_time; + + current_button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (click_gesture)); + + if (current_button > 3) + return; + + double_click_time = g_settings_get_int (self->mouse_settings, "double-click"); + + if (self->button_drawing_area_timeout_id != 0) { + g_source_remove (self->button_drawing_area_timeout_id); + self->button_drawing_area_timeout_id = 0; + } + + /* Ignore fake double click using different buttons. */ + if (self->double_click_state != DOUBLE_CLICK_TEST_OFF && self->button_state != current_button) + self->double_click_state = DOUBLE_CLICK_TEST_OFF; + + event_time = gtk_event_controller_get_current_event_time (GTK_EVENT_CONTROLLER (click_gesture)); + switch (self->double_click_state) { + case DOUBLE_CLICK_TEST_OFF: + self->double_click_state = DOUBLE_CLICK_TEST_MAYBE; + self->button_drawing_area_timeout_id = g_timeout_add (double_click_time, (GSourceFunc) test_maybe_timeout, self); + break; + case DOUBLE_CLICK_TEST_MAYBE: + case DOUBLE_CLICK_TEST_ON: + case DOUBLE_CLICK_TEST_STILL_ON: + case DOUBLE_CLICK_TEST_ALMOST_THERE: + if (event_time - self->double_click_timestamp < double_click_time) { + self->double_click_state++; + self->button_drawing_area_timeout_id = g_timeout_add (2500, (GSourceFunc) test_maybe_timeout, self); + } else { + test_maybe_timeout (self); + } + break; + case DOUBLE_CLICK_TEST_GEGL: + self->double_click_state = DOUBLE_CLICK_TEST_OFF; + break; + } + + self->double_click_timestamp = event_time; + + gtk_widget_queue_draw (self->button_drawing_area); + + self->button_state = current_button; + setup_information_label (self); + setup_scroll_image (self); +} + +static void +button_drawing_area_draw_func (GtkDrawingArea *drawing_area, + cairo_t *cr, + int width, + int height, + gpointer user_data) +{ + CcMouseTest *self = CC_MOUSE_TEST (user_data); + gdouble center_x, center_y, size; + GdkRGBA inner_color, outer_color; + cairo_pattern_t *pattern; + + size = MAX (MIN (width, height), 1); + center_x = width / 2.0; + center_y = height / 2.0; + + switch (self->double_click_state) { + case DOUBLE_CLICK_TEST_ON: + case DOUBLE_CLICK_TEST_STILL_ON: + case DOUBLE_CLICK_TEST_ALMOST_THERE: + case DOUBLE_CLICK_TEST_GEGL: + gdk_rgba_parse (&outer_color, "#729fcf"); + gdk_rgba_parse (&inner_color, "#729fcf"); + break; + case DOUBLE_CLICK_TEST_MAYBE: + gdk_rgba_parse (&outer_color, "#729fcf"); + gdk_rgba_parse (&inner_color, "#ffffff"); + break; + case DOUBLE_CLICK_TEST_OFF: + gdk_rgba_parse (&outer_color, "#ffffff"); + gdk_rgba_parse (&inner_color, "#ffffff"); + break; + } + + /* Draw shadow. */ + cairo_rectangle (cr, center_x - size / 2, center_y - size / 2, size, size); + pattern = cairo_pattern_create_radial (center_x, center_y, 0, center_x, center_y, size); + cairo_pattern_add_color_stop_rgba (pattern, 0.5 - SHADOW_SIZE / size, 0, 0, 0, SHADOW_OPACITY); + cairo_pattern_add_color_stop_rgba (pattern, 0.5, 0, 0, 0, 0); + cairo_set_source (cr, pattern); + cairo_fill (cr); + + /* Draw outer circle. */ + cairo_set_line_width (cr, OUTER_CIRCLE_SIZE); + cairo_arc (cr, center_x, center_y + SHADOW_SHIFT_Y, + INNER_CIRCLE_SIZE + ANNULUS_SIZE + OUTER_CIRCLE_SIZE / 2, + 0, 2 * G_PI); + gdk_cairo_set_source_rgba (cr, &outer_color); + cairo_stroke (cr); + + /* Draw inner circle. */ + cairo_set_line_width (cr, 0); + cairo_arc (cr, center_x, center_y + SHADOW_SHIFT_Y, + INNER_CIRCLE_SIZE, + 0, 2 * G_PI); + gdk_cairo_set_source_rgba (cr, &inner_color); + cairo_fill (cr); +} + +static void +setup_dialog (CcMouseTest *self) +{ + GtkAdjustment *adjustment; + GtkStyleProvider *provider; + + adjustment = GTK_ADJUSTMENT (self->scrolled_window_adjustment); + gtk_adjustment_set_value (adjustment, + gtk_adjustment_get_upper (adjustment)); + + provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ()); + gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (provider), "* {background: #26a269;}", -1); + gtk_style_context_add_provider (gtk_widget_get_style_context (self->viewport), + provider, + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_object_unref (provider); +} + +static void +cc_mouse_test_finalize (GObject *object) +{ + CcMouseTest *self = CC_MOUSE_TEST (object); + + g_clear_object (&self->mouse_settings); + + if (self->information_label_timeout_id != 0) { + g_source_remove (self->information_label_timeout_id); + self->information_label_timeout_id = 0; + } + + if (self->scroll_image_timeout_id != 0) { + g_source_remove (self->scroll_image_timeout_id); + self->scroll_image_timeout_id = 0; + } + + if (self->button_drawing_area_timeout_id != 0) { + g_source_remove (self->button_drawing_area_timeout_id); + self->button_drawing_area_timeout_id = 0; + } + + G_OBJECT_CLASS (cc_mouse_test_parent_class)->finalize (object); +} + +static void +cc_mouse_test_class_init (CcMouseTestClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = cc_mouse_test_finalize; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/mouse/cc-mouse-test.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcMouseTest, button_drawing_area); + gtk_widget_class_bind_template_child (widget_class, CcMouseTest, information_label); + gtk_widget_class_bind_template_child (widget_class, CcMouseTest, image); + gtk_widget_class_bind_template_child (widget_class, CcMouseTest, scrolled_window_adjustment); + gtk_widget_class_bind_template_child (widget_class, CcMouseTest, viewport); + + gtk_widget_class_bind_template_callback (widget_class, button_drawing_area_button_pressed_cb); +} + +static void +cc_mouse_test_init (CcMouseTest *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (self->button_drawing_area), + button_drawing_area_draw_func, + self, NULL); + + self->double_click_timestamp = 0; + self->double_click_state = DOUBLE_CLICK_TEST_OFF; + self->button_state = 0; + + self->mouse_settings = g_settings_new ("org.gnome.desktop.peripherals.mouse"); + + self->information_label_timeout_id = 0; + self->button_drawing_area_timeout_id = 0; + self->scroll_image_timeout_id = 0; + + setup_dialog (self); +} + +GtkWidget * +cc_mouse_test_new (void) +{ + return (GtkWidget *) g_object_new (CC_TYPE_MOUSE_TEST, NULL); +} diff --git a/panels/mouse/cc-mouse-test.h b/panels/mouse/cc-mouse-test.h new file mode 100644 index 0000000..dc425f8 --- /dev/null +++ b/panels/mouse/cc-mouse-test.h @@ -0,0 +1,32 @@ +/* -*- mode: c; style: linux -*- + * + * Copyright (C) 2012 Red Hat, Inc. + * + * Written by: Ondrej Holy + * + * 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, 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, see . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define CC_TYPE_MOUSE_TEST (cc_mouse_test_get_type ()) +G_DECLARE_FINAL_TYPE (CcMouseTest, cc_mouse_test, CC, MOUSE_TEST, AdwBin) + +GtkWidget *cc_mouse_test_new (void); + +G_END_DECLS diff --git a/panels/mouse/cc-mouse-test.ui b/panels/mouse/cc-mouse-test.ui new file mode 100644 index 0000000..c007361 --- /dev/null +++ b/panels/mouse/cc-mouse-test.ui @@ -0,0 +1,69 @@ + + + + + 100 + 100 + 1 + 10 + + + diff --git a/panels/mouse/gnome-mouse-panel.desktop.in.in b/panels/mouse/gnome-mouse-panel.desktop.in.in new file mode 100644 index 0000000..2d9ed7c --- /dev/null +++ b/panels/mouse/gnome-mouse-panel.desktop.in.in @@ -0,0 +1,18 @@ +[Desktop Entry] +Name=Mouse & Touchpad +Comment=Change your mouse or touchpad sensitivity and select right or left-handed +Exec=gnome-control-center mouse +# Translators: Do NOT translate or transliterate this text (this is an icon file name)! +Icon=org.gnome.Settings-mouse-symbolic +Terminal=false +Type=Application +NoDisplay=true +StartupNotify=true +Categories=GNOME;GTK;Settings;HardwareSettings;X-GNOME-Settings-Panel;X-GNOME-DevicesSettings; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=mouse +X-GNOME-Bugzilla-Version=@VERSION@ +# Translators: Search terms to find the Mouse and Touchpad panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! +Keywords=Trackpad;Pointer;Click;Tap;Double;Button;Trackball;Scroll; diff --git a/panels/mouse/icons/meson.build b/panels/mouse/icons/meson.build new file mode 100644 index 0000000..02e9235 --- /dev/null +++ b/panels/mouse/icons/meson.build @@ -0,0 +1,4 @@ +install_data( + 'scalable/org.gnome.Settings-mouse-symbolic.svg', + install_dir: join_paths(control_center_icondir, 'hicolor', 'scalable', 'apps') +) diff --git a/panels/mouse/icons/scalable/org.gnome.Settings-mouse-symbolic.svg b/panels/mouse/icons/scalable/org.gnome.Settings-mouse-symbolic.svg new file mode 100644 index 0000000..cdcaa63 --- /dev/null +++ b/panels/mouse/icons/scalable/org.gnome.Settings-mouse-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/panels/mouse/meson.build b/panels/mouse/meson.build new file mode 100644 index 0000000..8ebf3fc --- /dev/null +++ b/panels/mouse/meson.build @@ -0,0 +1,70 @@ +panels_list += cappletname +desktop = 'gnome-@0@-panel.desktop'.format(cappletname) + +desktop_in = configure_file( + input: desktop + '.in.in', + output: desktop + '.in', + configuration: desktop_conf +) + +i18n.merge_file( + type: 'desktop', + input: desktop_in, + output: desktop, + po_dir: po_dir, + install: true, + install_dir: control_center_desktopdir +) + +resource_data = files( + 'cc-mouse-panel.ui', + 'cc-mouse-test.ui', + 'scroll-test-gegl.svg', + 'scroll-test.svg' +) + +common_sources = gnome.compile_resources( + 'cc-' + cappletname + '-resources', + cappletname + '.gresource.xml', + c_name: 'cc_' + cappletname, + dependencies: resource_data, + export: true +) + +sources = common_sources + files( + 'cc-mouse-panel.c', + 'cc-mouse-caps-helper.c', + 'cc-mouse-test.c', +) + +deps = common_deps + [ + gnome_settings_dep, + libdevice_dep, + x11_dep, + xi_dep +] + +panels_libs += static_library( + cappletname + '-properties', + sources: sources, + include_directories: top_inc, + dependencies: deps, + c_args: cflags +) + +test_name = 'test-gnome-mouse-test' + +sources = common_sources + files( + 'cc-mouse-test.c', + test_name + '.c' +) + +executable( + test_name, + sources, + include_directories: top_inc, + dependencies: deps, + c_args: cflags +) + +subdir('icons') diff --git a/panels/mouse/mouse.gresource.xml b/panels/mouse/mouse.gresource.xml new file mode 100644 index 0000000..0568705 --- /dev/null +++ b/panels/mouse/mouse.gresource.xml @@ -0,0 +1,9 @@ + + + + cc-mouse-panel.ui + cc-mouse-test.ui + scroll-test.svg + scroll-test-gegl.svg + + diff --git a/panels/mouse/scroll-test-gegl.svg b/panels/mouse/scroll-test-gegl.svg new file mode 100644 index 0000000..81ed22b --- /dev/null +++ b/panels/mouse/scroll-test-gegl.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/panels/mouse/scroll-test.svg b/panels/mouse/scroll-test.svg new file mode 100644 index 0000000..8614713 --- /dev/null +++ b/panels/mouse/scroll-test.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/panels/mouse/test-gnome-mouse-test.c b/panels/mouse/test-gnome-mouse-test.c new file mode 100644 index 0000000..ca37f90 --- /dev/null +++ b/panels/mouse/test-gnome-mouse-test.c @@ -0,0 +1,24 @@ +#include +#include + +#include "cc-mouse-resources.h" +#include "cc-mouse-test.h" + +int main (int argc, char **argv) +{ + GtkWidget *widget; + GtkWidget *window; + + gtk_init (); + + widget = cc_mouse_test_new (); + + window = gtk_window_new (); + gtk_window_set_child (GTK_WINDOW (window), widget); + gtk_window_present (GTK_WINDOW (window)); + + while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0) + g_main_context_iteration (NULL, TRUE); + + return 0; +} -- cgit v1.2.3