diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:45:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:45:20 +0000 |
commit | ae1c76ff830d146d41e88d6fba724c0a54bce868 (patch) | |
tree | 3c354bec95af07be35fc71a4b738268496f1a1c4 /panels/wacom/calibrator/calibrator-gui.c | |
parent | Initial commit. (diff) | |
download | gnome-control-center-upstream/1%43.6.tar.xz gnome-control-center-upstream/1%43.6.zip |
Adding upstream version 1:43.6.upstream/1%43.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'panels/wacom/calibrator/calibrator-gui.c')
-rw-r--r-- | panels/wacom/calibrator/calibrator-gui.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/panels/wacom/calibrator/calibrator-gui.c b/panels/wacom/calibrator/calibrator-gui.c new file mode 100644 index 0000000..2d5d7ec --- /dev/null +++ b/panels/wacom/calibrator/calibrator-gui.c @@ -0,0 +1,429 @@ +/* + * Copyright © 2013 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 <http://www.gnu.org/licenses/>. + * + * Author: Carlos Garnacho <carlosg@gnome.org> + * (based on previous work by Joaquim Rocha, Tias Guns and Soren Hauberg) + */ + +#include "config.h" + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <glib/gi18n.h> +#include <gdk/x11/gdkx.h> +#include <gtk/gtk.h> + +#include "calibrator.h" +#include "calibrator-gui.h" +#include "cc-clock.h" + +struct _CcCalibArea +{ + GtkWindow parent_instance; + + struct Calib calibrator; + XYinfo axis; + gboolean swap; + gboolean success; + GdkDevice *device; + + GtkWidget *error_revealer; + GtkWidget *title_revealer; + GtkWidget *subtitle_revealer; + GtkWidget *clock; + GtkWidget *target1, *target2, *target3, *target4; + GtkWidget *stack; + GtkWidget *success_page; + GtkCssProvider *style_provider; + + FinishCallback callback; + gpointer user_data; +}; + +G_DEFINE_TYPE (CcCalibArea, cc_calib_area, GTK_TYPE_WINDOW) + +/* Timeout parameters */ +#define MAX_TIME 15000 /* 15000 = 15 sec */ +#define END_TIME 750 /* 750 = 0.75 sec */ + +static void +cc_calib_area_notify_finish (CcCalibArea *area) +{ + gtk_widget_hide (GTK_WIDGET (area)); + + (*area->callback) (area, area->user_data); +} + +static gboolean +on_close_request (GtkWidget *widget, + CcCalibArea *area) +{ + cc_calib_area_notify_finish (area); + return GDK_EVENT_PROPAGATE; +} + +static gboolean +cc_calib_area_finish_idle_cb (CcCalibArea *area) +{ + cc_calib_area_notify_finish (area); + return FALSE; +} + +static void +set_success (CcCalibArea *area) +{ + gtk_stack_set_visible_child (GTK_STACK (area->stack), area->success_page); +} + +static void +set_calibration_status (CcCalibArea *area) +{ + area->success = finish (&area->calibrator, &area->axis, &area->swap); + + if (area->success) + { + set_success (area); + g_timeout_add (END_TIME, + (GSourceFunc) cc_calib_area_finish_idle_cb, + area); + } + else + { + g_idle_add ((GSourceFunc) cc_calib_area_finish_idle_cb, area); + } +} + +static void +show_error_message (CcCalibArea *area) +{ + gtk_revealer_set_reveal_child (GTK_REVEALER (area->error_revealer), TRUE); +} + +static void +hide_error_message (CcCalibArea *area) +{ + gtk_revealer_set_reveal_child (GTK_REVEALER (area->error_revealer), FALSE); +} + +static void +set_active_target (CcCalibArea *area, + int n_target) +{ + GtkWidget *targets[] = { + area->target1, + area->target2, + area->target3, + area->target4, + }; + int i; + + for (i = 0; i < G_N_ELEMENTS (targets); i++) + gtk_widget_set_sensitive (targets[i], i == n_target); +} + +static void +on_gesture_press (GtkGestureClick *gesture, + guint n_press, + gdouble x, + gdouble y, + CcCalibArea *area) +{ + gint num_clicks; + gboolean success; + GdkDevice *source; + + if (area->success) + return; + + source = gtk_gesture_get_device (GTK_GESTURE (gesture)); + + if (gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN) + return; + + /* Check matching device if a device was provided */ + if (area->device && area->device != source) + { + g_debug ("Ignoring input from device %s", + gdk_device_get_name (source)); + return; + } + + /* Handle click */ + /* FIXME: reset clock */ + success = add_click(&area->calibrator, + (int) x, + (int) y); + + num_clicks = area->calibrator.num_clicks; + + if (!success && num_clicks == 0) + show_error_message (area); + else + hide_error_message (area); + + /* Are we done yet? */ + if (num_clicks >= 4) + { + set_calibration_status (area); + return; + } + + set_active_target (area, num_clicks); +} + +static gboolean +on_key_release (GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + CcCalibArea *area) +{ + if (area->success || keyval != GDK_KEY_Escape) + return GDK_EVENT_PROPAGATE; + + cc_calib_area_notify_finish (area); + return GDK_EVENT_STOP; +} + +static void +on_clock_finished (CcClock *clock, + CcCalibArea *area) +{ + set_calibration_status (area); +} + +static void +on_title_revealed (CcCalibArea *area) +{ + gtk_revealer_set_reveal_child (GTK_REVEALER (area->subtitle_revealer), TRUE); +} + +static void +on_fullscreen (GtkWindow *window, + GParamSpec *pspec, + CcCalibArea *area) +{ + if (!gtk_window_is_fullscreen (window)) + return; + + g_signal_connect_swapped (area->title_revealer, + "notify::child-revealed", + G_CALLBACK (on_title_revealed), + area); + gtk_revealer_set_reveal_child (GTK_REVEALER (area->title_revealer), TRUE); + + set_active_target (area, 0); +} + +static void +cc_calib_area_finalize (GObject *object) +{ + CcCalibArea *area = CC_CALIB_AREA (object); + + gtk_style_context_remove_provider_for_display (gtk_widget_get_display (GTK_WIDGET (area)), + GTK_STYLE_PROVIDER (area->style_provider)); + + G_OBJECT_CLASS (cc_calib_area_parent_class)->finalize (object); +} + +static void +cc_calib_area_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + CcCalibArea *calib_area = CC_CALIB_AREA (widget); + + if (calib_area->calibrator.geometry.width != width || + calib_area->calibrator.geometry.height != height) + { + calib_area->calibrator.geometry.width = width; + calib_area->calibrator.geometry.height = height; + + /* reset calibration if already started */ + reset (&calib_area->calibrator); + set_active_target (calib_area, 0); + } + + GTK_WIDGET_CLASS (cc_calib_area_parent_class)->size_allocate (widget, + width, + height, + baseline); +} + +static void +cc_calib_area_class_init (CcCalibAreaClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = cc_calib_area_finalize; + + widget_class->size_allocate = cc_calib_area_size_allocate; + + g_type_ensure (CC_TYPE_CLOCK); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/wacom/calibrator/calibrator.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, error_revealer); + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, title_revealer); + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, subtitle_revealer); + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, clock); + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, target1); + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, target2); + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, target3); + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, target4); + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, stack); + gtk_widget_class_bind_template_child (widget_class, CcCalibArea, success_page); +} + +static void +cc_calib_area_init (CcCalibArea *calib_area) +{ + GtkGesture *click; + GtkEventController *key; + + gtk_widget_init_template (GTK_WIDGET (calib_area)); + + calib_area->style_provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (calib_area->style_provider, "/org/gnome/control-center/wacom/calibrator/calibrator.css"); + gtk_style_context_add_provider_for_display (gtk_widget_get_display (GTK_WIDGET (calib_area)), + GTK_STYLE_PROVIDER (calib_area->style_provider), + GTK_STYLE_PROVIDER_PRIORITY_USER); + + cc_clock_set_duration (CC_CLOCK (calib_area->clock), MAX_TIME); + g_signal_connect (calib_area->clock, "finished", + G_CALLBACK (on_clock_finished), calib_area); + +#ifndef FAKE_AREA + /* No cursor */ + gtk_widget_realize (GTK_WIDGET (calib_area)); + gtk_widget_set_cursor_from_name (GTK_WIDGET (calib_area), "blank"); + + gtk_widget_set_can_focus (GTK_WIDGET (calib_area), TRUE); +#endif /* FAKE_AREA */ + + g_signal_connect (calib_area, + "close-request", + G_CALLBACK (on_close_request), + calib_area); + g_signal_connect (calib_area, + "notify::fullscreened", + G_CALLBACK (on_fullscreen), + calib_area); + + click = gtk_gesture_click_new (); + gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (click), GDK_BUTTON_PRIMARY); + g_signal_connect (click, "pressed", + G_CALLBACK (on_gesture_press), calib_area); + gtk_widget_add_controller (GTK_WIDGET (calib_area), + GTK_EVENT_CONTROLLER (click)); + + key = gtk_event_controller_key_new (); + g_signal_connect (key, "key-released", + G_CALLBACK (on_key_release), calib_area); + gtk_widget_add_controller (GTK_WIDGET (calib_area), key); +} + +/** + * Creates the windows and other objects required to do calibration + * under GTK. When the window is closed (timed out, calibration finished + * or user cancellation), callback will be called, where you should call + * cc_calib_area_finish(). + */ +CcCalibArea * +cc_calib_area_new (GdkDisplay *display, + GdkMonitor *monitor, + GdkDevice *device, + FinishCallback callback, + gpointer user_data, + int threshold_doubleclick, + int threshold_misclick) +{ + CcCalibArea *calib_area; + + g_return_val_if_fail (callback, NULL); + + calib_area = g_object_new (CC_TYPE_CALIB_AREA, NULL); + calib_area->callback = callback; + calib_area->user_data = user_data; + calib_area->device = device; + calib_area->calibrator.threshold_doubleclick = threshold_doubleclick; + calib_area->calibrator.threshold_misclick = threshold_misclick; + + /* Move to correct screen */ + if (monitor) + gtk_window_fullscreen_on_monitor (GTK_WINDOW (calib_area), monitor); + else + gtk_window_fullscreen (GTK_WINDOW (calib_area)); + + gtk_widget_show (GTK_WIDGET (calib_area)); + + return calib_area; +} + +/* Finishes the calibration. Note that CalibArea + * needs to be destroyed with Cccalib_area_free() afterwards */ +gboolean +cc_calib_area_finish (CcCalibArea *area) +{ + g_return_val_if_fail (area != NULL, FALSE); + + if (area->success) + g_debug ("Final calibration: %f, %f, %f, %f\n", + area->axis.x_min, + area->axis.y_min, + area->axis.x_max, + area->axis.y_max); + else + g_debug ("Calibration was aborted or timed out"); + + return area->success; +} + +void +cc_calib_area_free (CcCalibArea *area) +{ + gtk_window_destroy (GTK_WINDOW (area)); +} + +void +cc_calib_area_get_axis (CcCalibArea *area, + XYinfo *new_axis, + gboolean *swap_xy) +{ + g_return_if_fail (area != NULL); + + *new_axis = area->axis; + *swap_xy = area->swap; +} + +void +cc_calib_area_get_padding (CcCalibArea *area, + XYinfo *padding) +{ + g_return_if_fail (area != NULL); + + /* min/max values are monitor coordinates scaled to be between + * 0 and 1, padding starts at 0 on "the edge", and positive + * values grow towards the center of the rectangle. + */ + padding->x_min = area->axis.x_min; + padding->y_min = area->axis.y_min; + padding->x_max = 1 - area->axis.x_max; + padding->y_max = 1 - area->axis.y_max; +} |