Skip to content

Commit

Permalink
DwellClickTimer: inline namespace (#2246)
Browse files Browse the repository at this point in the history
  • Loading branch information
lenemter authored Jan 25, 2025
1 parent 86f1940 commit 4ed139b
Showing 1 changed file with 125 additions and 140 deletions.
265 changes: 125 additions & 140 deletions src/Widgets/DwellClickTimer.vala
Original file line number Diff line number Diff line change
@@ -1,183 +1,168 @@
//
// Copyright 2020 elementary, Inc. (https://elementary.io)
//
// 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 3 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/>.
//

namespace Gala {
public class DwellClickTimer : Clutter.Actor, Clutter.Animatable {
private const double BACKGROUND_OPACITY = 0.7;
private const int BORDER_WIDTH_PX = 1;

private const double START_ANGLE = 3 * Math.PI / 2;

/**
* Delay, in milliseconds, before showing the animation.
* libinput uses a timeout of 180ms when tapping is enabled. Use that value plus a safety
* margin so the animation is never displayed when tapping.
*/
private const double DELAY_TIMEOUT = 185;

private float scaling_factor = 1.0f;
private int cursor_size = 24;

private Cogl.Pipeline pipeline;
private Clutter.PropertyTransition transition;
private Cairo.Pattern stroke_color;
private Cairo.Pattern fill_color;
private GLib.Settings interface_settings;
private Cairo.ImageSurface surface;

public Meta.Display display { get; construct; }

public double angle { get; set; }

public DwellClickTimer (Meta.Display display) {
Object (display: display);
}
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2020, 2025 elementary, Inc. (https://elementary.io)
*/

construct {
visible = false;
reactive = false;
public class Gala.DwellClickTimer : Clutter.Actor, Clutter.Animatable {
private const double BACKGROUND_OPACITY = 0.7;
private const int BORDER_WIDTH_PX = 1;

private const double START_ANGLE = 3 * Math.PI / 2;

/**
* Delay, in milliseconds, before showing the animation.
* libinput uses a timeout of 180ms when tapping is enabled. Use that value plus a safety
* margin so the animation is never displayed when tapping.
*/
private const double DELAY_TIMEOUT = 185;

private float scaling_factor = 1.0f;
private int cursor_size = 24;

private Cogl.Pipeline pipeline;
private Clutter.PropertyTransition transition;
private Cairo.Pattern stroke_color;
private Cairo.Pattern fill_color;
private GLib.Settings interface_settings;
private Cairo.ImageSurface surface;

public Meta.Display display { get; construct; }

public double angle { get; set; }

public DwellClickTimer (Meta.Display display) {
Object (display: display);
}

construct {
visible = false;
reactive = false;

#if HAS_MUTTER47
unowned var backend = context.get_backend ();
unowned var backend = context.get_backend ();
#else
unowned var backend = Clutter.get_default_backend ();
unowned var backend = Clutter.get_default_backend ();
#endif

pipeline = new Cogl.Pipeline (backend.get_cogl_context ());
pipeline = new Cogl.Pipeline (backend.get_cogl_context ());

transition = new Clutter.PropertyTransition ("angle");
transition.set_progress_mode (Clutter.AnimationMode.EASE_OUT_QUAD);
transition.set_animatable (this);
transition.set_from_value (START_ANGLE);
transition.set_to_value (START_ANGLE + (2 * Math.PI));
transition = new Clutter.PropertyTransition ("angle");
transition.set_progress_mode (Clutter.AnimationMode.EASE_OUT_QUAD);
transition.set_animatable (this);
transition.set_from_value (START_ANGLE);
transition.set_to_value (START_ANGLE + (2 * Math.PI));

transition.new_frame.connect (() => {
queue_redraw ();
});
transition.new_frame.connect (() => {
queue_redraw ();
});

interface_settings = new GLib.Settings ("org.gnome.desktop.interface");
interface_settings = new GLib.Settings ("org.gnome.desktop.interface");

var seat = backend.get_default_seat ();
seat.set_pointer_a11y_dwell_click_type (Clutter.PointerA11yDwellClickType.PRIMARY);
var seat = backend.get_default_seat ();
seat.set_pointer_a11y_dwell_click_type (Clutter.PointerA11yDwellClickType.PRIMARY);

seat.ptr_a11y_timeout_started.connect ((device, type, timeout) => {
var scale = display.get_monitor_scale (display.get_current_monitor ());
update_cursor_size (scale);
seat.ptr_a11y_timeout_started.connect ((device, type, timeout) => {
var scale = display.get_monitor_scale (display.get_current_monitor ());
update_cursor_size (scale);

unowned var tracker = display.get_cursor_tracker ();
Graphene.Point coords = {};
tracker.get_pointer (out coords, null);
unowned var tracker = display.get_cursor_tracker ();
Graphene.Point coords = {};
tracker.get_pointer (out coords, null);

x = coords.x - (width / 2);
y = coords.y - (width / 2);
x = coords.x - (width / 2);
y = coords.y - (width / 2);

transition.set_duration (timeout);
visible = true;
transition.start ();
});
transition.set_duration (timeout);
visible = true;
transition.start ();
});

seat.ptr_a11y_timeout_stopped.connect ((device, type, clicked) => {
transition.stop ();
visible = false;
});
}

private void update_cursor_size (float scale) {
scaling_factor = scale;
seat.ptr_a11y_timeout_stopped.connect ((device, type, clicked) => {
transition.stop ();
visible = false;
});
}

cursor_size = (int) (interface_settings.get_int ("cursor-size") * scaling_factor * 1.25);
private void update_cursor_size (float scale) {
scaling_factor = scale;

if (surface == null || surface.get_width () != cursor_size || surface.get_height () != cursor_size) {
surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, cursor_size, cursor_size);
}
cursor_size = (int) (interface_settings.get_int ("cursor-size") * scaling_factor * 1.25);

set_size (cursor_size, cursor_size);
if (surface == null || surface.get_width () != cursor_size || surface.get_height () != cursor_size) {
surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, cursor_size, cursor_size);
}

public override void paint (Clutter.PaintContext context) {
if (angle == 0) {
return;
}
set_size (cursor_size, cursor_size);
}

var rgba = Drawing.StyleManager.get_instance ().theme_accent_color;
public override void paint (Clutter.PaintContext context) {
if (angle == 0) {
return;
}

/* Don't use alpha from the stylesheet to ensure contrast */
stroke_color = new Cairo.Pattern.rgb (rgba.red, rgba.green, rgba.blue);
fill_color = new Cairo.Pattern.rgba (rgba.red, rgba.green, rgba.blue, BACKGROUND_OPACITY);
var rgba = Drawing.StyleManager.get_instance ().theme_accent_color;

var radius = int.min (cursor_size / 2, cursor_size / 2);
var end_angle = START_ANGLE + angle;
var border_width = InternalUtils.scale_to_int (BORDER_WIDTH_PX, scaling_factor);
/* Don't use alpha from the stylesheet to ensure contrast */
stroke_color = new Cairo.Pattern.rgb (rgba.red, rgba.green, rgba.blue);
fill_color = new Cairo.Pattern.rgba (rgba.red, rgba.green, rgba.blue, BACKGROUND_OPACITY);

var cr = new Cairo.Context (surface);
var radius = int.min (cursor_size / 2, cursor_size / 2);
var end_angle = START_ANGLE + angle;
var border_width = InternalUtils.scale_to_int (BORDER_WIDTH_PX, scaling_factor);

// Clear the surface
cr.save ();
cr.set_source_rgba (0, 0, 0, 0);
cr.set_operator (Cairo.Operator.SOURCE);
cr.paint ();
cr.restore ();
var cr = new Cairo.Context (surface);

cr.set_line_cap (Cairo.LineCap.ROUND);
cr.set_line_join (Cairo.LineJoin.ROUND);
cr.translate (cursor_size / 2, cursor_size / 2);
// Clear the surface
cr.save ();
cr.set_source_rgba (0, 0, 0, 0);
cr.set_operator (Cairo.Operator.SOURCE);
cr.paint ();
cr.restore ();

cr.move_to (0, 0);
cr.arc (0, 0, radius - border_width, START_ANGLE, end_angle);
cr.line_to (0, 0);
cr.close_path ();
cr.set_line_cap (Cairo.LineCap.ROUND);
cr.set_line_join (Cairo.LineJoin.ROUND);
cr.translate (cursor_size / 2, cursor_size / 2);

cr.set_line_width (0);
cr.set_source (fill_color);
cr.fill_preserve ();
cr.move_to (0, 0);
cr.arc (0, 0, radius - border_width, START_ANGLE, end_angle);
cr.line_to (0, 0);
cr.close_path ();

cr.set_line_width (border_width);
cr.set_source (stroke_color);
cr.stroke ();
cr.set_line_width (0);
cr.set_source (fill_color);
cr.fill_preserve ();

var cogl_context = context.get_framebuffer ().get_context ();
cr.set_line_width (border_width);
cr.set_source (stroke_color);
cr.stroke ();

try {
var texture = new Cogl.Texture2D.from_data (cogl_context, cursor_size, cursor_size, Cogl.PixelFormat.BGRA_8888_PRE,
surface.get_stride (), surface.get_data ());
var cogl_context = context.get_framebuffer ().get_context ();

pipeline.set_layer_texture (0, texture);
try {
var texture = new Cogl.Texture2D.from_data (cogl_context, cursor_size, cursor_size, Cogl.PixelFormat.BGRA_8888_PRE,
surface.get_stride (), surface.get_data ());

context.get_framebuffer ().draw_rectangle (pipeline, 0, 0, cursor_size, cursor_size);
} catch (Error e) {}
pipeline.set_layer_texture (0, texture);

base.paint (context);
}
context.get_framebuffer ().draw_rectangle (pipeline, 0, 0, cursor_size, cursor_size);
} catch (Error e) {}

public bool interpolate_value (string property_name, Clutter.Interval interval, double progress, out Value @value) {
if (property_name == "angle") {
@value = 0;
base.paint (context);
}

var elapsed_time = transition.get_elapsed_time ();
if (elapsed_time > DELAY_TIMEOUT) {
double delayed_progress = (elapsed_time - DELAY_TIMEOUT) / (transition.duration - DELAY_TIMEOUT);
@value = (delayed_progress * 2 * Math.PI);
}
public bool interpolate_value (string property_name, Clutter.Interval interval, double progress, out Value @value) {
if (property_name == "angle") {
@value = 0;

return true;
var elapsed_time = transition.get_elapsed_time ();
if (elapsed_time > DELAY_TIMEOUT) {
double delayed_progress = (elapsed_time - DELAY_TIMEOUT) / (transition.duration - DELAY_TIMEOUT);
@value = (delayed_progress * 2 * Math.PI);
}

return base.interpolate_value (property_name, interval, progress, out @value);
return true;
}

return base.interpolate_value (property_name, interval, progress, out @value);
}
}

0 comments on commit 4ed139b

Please sign in to comment.