5cb02c1cb5
Before the move to Clutters implicit animations with0846238f6
andbf497ed64
, we used Tweener to do a fake-animation of the opacity and Tweeners `onUpdate` signal to queue a repaint of the PieTimer everytime Tweener tries to update the animation. Now, with Clutters implicit animations, there is no `onUpdate` signal anymore and also `notify::opacity` no longer gets emitted since the value doesn't actually change. This lead to the PieTimer no longer being repainted, which broke the animation. Fix this by implementing the current angle of the pie using a custom GObject property `angle` and animating this property using the new `actor.ease_property` method. Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/1533
115 lines
3.2 KiB
JavaScript
115 lines
3.2 KiB
JavaScript
/* exported PointerA11yTimeout */
|
|
const { Clutter, GLib, GObject, Meta, St } = imports.gi;
|
|
const Main = imports.ui.main;
|
|
const Cairo = imports.cairo;
|
|
|
|
var PieTimer = GObject.registerClass({
|
|
Properties: {
|
|
'angle': GObject.ParamSpec.double(
|
|
'angle', 'angle', 'angle',
|
|
GObject.ParamFlags.READWRITE,
|
|
0, 2 * Math.PI, 0)
|
|
}
|
|
}, class PieTimer extends St.DrawingArea {
|
|
_init() {
|
|
this._x = 0;
|
|
this._y = 0;
|
|
this._angle = 0;
|
|
super._init({
|
|
style_class: 'pie-timer',
|
|
visible: false,
|
|
can_focus: false,
|
|
reactive: false
|
|
});
|
|
}
|
|
|
|
get angle() {
|
|
return this._angle;
|
|
}
|
|
|
|
set angle(angle) {
|
|
if (this._angle == angle)
|
|
return;
|
|
|
|
this._angle = angle;
|
|
this.notify('angle');
|
|
this.queue_repaint();
|
|
}
|
|
|
|
vfunc_repaint() {
|
|
let node = this.get_theme_node();
|
|
let backgroundColor = node.get_color('-pie-background-color');
|
|
let borderColor = node.get_color('-pie-border-color');
|
|
let borderWidth = node.get_length('-pie-border-width');
|
|
let [width, height] = this.get_surface_size();
|
|
let radius = Math.min(width / 2, height / 2);
|
|
|
|
let startAngle = 3 * Math.PI / 2;
|
|
let endAngle = startAngle + this._angle;
|
|
|
|
let cr = this.get_context();
|
|
cr.setLineCap(Cairo.LineCap.ROUND);
|
|
cr.setLineJoin(Cairo.LineJoin.ROUND);
|
|
cr.translate(width / 2, height / 2);
|
|
|
|
cr.moveTo(0, 0);
|
|
cr.arc(0, 0, radius - borderWidth, startAngle, endAngle);
|
|
cr.lineTo(0, 0);
|
|
cr.closePath();
|
|
|
|
cr.setLineWidth(0);
|
|
Clutter.cairo_set_source_color(cr, backgroundColor);
|
|
cr.fillPreserve();
|
|
|
|
cr.setLineWidth(borderWidth);
|
|
Clutter.cairo_set_source_color(cr, borderColor);
|
|
cr.stroke();
|
|
|
|
cr.$dispose();
|
|
}
|
|
|
|
start(x, y, duration) {
|
|
this.remove_all_transitions();
|
|
|
|
this.x = x - this.width / 2;
|
|
this.y = y - this.height / 2;
|
|
this._angle = 0;
|
|
|
|
this.show();
|
|
Main.uiGroup.set_child_above_sibling(this, null);
|
|
|
|
this.ease_property('angle', 2 * Math.PI, {
|
|
duration,
|
|
mode: Clutter.AnimationMode.LINEAR,
|
|
onComplete: () => this.stop()
|
|
});
|
|
}
|
|
|
|
stop() {
|
|
this.remove_all_transitions();
|
|
this.hide();
|
|
}
|
|
});
|
|
|
|
var PointerA11yTimeout = class PointerA11yTimeout {
|
|
constructor() {
|
|
let manager = Clutter.DeviceManager.get_default();
|
|
let pieTimer = new PieTimer();
|
|
|
|
Main.uiGroup.add_actor(pieTimer);
|
|
|
|
manager.connect('ptr-a11y-timeout-started', (manager, device, type, timeout) => {
|
|
let [x, y] = global.get_pointer();
|
|
pieTimer.start(x, y, timeout);
|
|
if (type == Clutter.PointerA11yTimeoutType.GESTURE)
|
|
global.display.set_cursor(Meta.Cursor.CROSSHAIR);
|
|
});
|
|
|
|
manager.connect('ptr-a11y-timeout-stopped', (manager, device, type) => {
|
|
pieTimer.stop();
|
|
if (type == Clutter.PointerA11yTimeoutType.GESTURE)
|
|
global.display.set_cursor(Meta.Cursor.DEFAULT);
|
|
});
|
|
}
|
|
};
|