Skip to content

Commit b845243

Browse files
JosephMccmtwebster
authored andcommitted
Reimplement the locate pointer functionality
We lost this in the rebase due to changes in how they are handled. Reimplement them the new way and also allow them to be themed by the Cinnamon theme. Also adding a new ripples.js that we can reuse for the hot corners since this same functionality is now being used in more than one place.
1 parent 76224fe commit b845243

File tree

4 files changed

+156
-0
lines changed

4 files changed

+156
-0
lines changed

data/theme/cinnamon.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ StScrollBar StButton#vhandle:hover {
7676
font-weight: normal;
7777
text-align: center;
7878
}
79+
.ripple-pointer-location {
80+
width: 50px;
81+
height: 50px;
82+
border-radius: 25px;
83+
background-color: rgba(160,160,160,0.3);
84+
box-shadow: 0 0 2px 2px rgba(160,160,160,1.0);
85+
}
7986
/* ===================================================================
8087
* Shared button properties
8188
* ===================================================================*/

js/ui/locatePointer.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
2+
3+
const { Clutter, Gio, GLib, St } = imports.gi;
4+
const Ripples = imports.ui.ripples;
5+
const Main = imports.ui.main;
6+
7+
const LOCATE_POINTER_ENABLED_SCHEMA = "org.cinnamon.desktop.peripherals.mouse"
8+
const LOCATE_POINTER_SCHEMA = "org.cinnamon.muffin"
9+
10+
var locatePointer = class {
11+
constructor() {
12+
this._enabledSettings = new Gio.Settings({schema_id: LOCATE_POINTER_ENABLED_SCHEMA});
13+
this._keySettings = new Gio.Settings({schema_id: LOCATE_POINTER_SCHEMA});
14+
this._keySettings.connect('changed::locate-pointer-key', this._updateKey.bind(this));
15+
this._updateKey();
16+
17+
this._ripples = new Ripples.Ripples(0.5, 0.5, 'ripple-pointer-location');
18+
this._ripples.addTo(Main.uiGroup);
19+
}
20+
21+
_updateKey() {
22+
let modifierKey = this._keySettings.get_string('locate-pointer-key');
23+
Main.keybindingManager.addHotKey('locate-pointer', modifierKey, () => { this.show() });
24+
}
25+
26+
show() {
27+
if (!this._enabledSettings.get_boolean("locate-pointer"))
28+
return;
29+
30+
let [x, y, mods] = global.get_pointer();
31+
this._ripples.playAnimation(x, y);
32+
}
33+
};

js/ui/main.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* Muffin actors
2121
*
2222
* @magnifier (Magnifier.Magnifier): The magnifier
23+
* @locatePointer (LocatePointer.LocatePointer): The locate pointer object
2324
* @xdndHandler (XdndHandler.XdndHandler): The X DND handler
2425
* @statusIconDispatcher (StatusIconDispatcher.StatusIconDispatcher): The status icon dispatcher
2526
* @virtualKeyboard (VirtualKeyboard.Keyboard): The keyboard object
@@ -108,6 +109,7 @@ const CinnamonDBus = imports.ui.cinnamonDBus;
108109
const Screenshot = imports.ui.screenshot;
109110
const ThemeManager = imports.ui.themeManager;
110111
const Magnifier = imports.ui.magnifier;
112+
const LocatePointer = imports.ui.locatePointer;
111113
const XdndHandler = imports.ui.xdndHandler;
112114
const StatusIconDispatcher = imports.ui.statusIconDispatcher;
113115
const Util = imports.misc.util;
@@ -150,6 +152,7 @@ var modalCount = 0;
150152
var modalActorFocusStack = [];
151153
var uiGroup = null;
152154
var magnifier = null;
155+
var locatePointer = null;
153156
var xdndHandler = null;
154157
var statusIconDispatcher = null;
155158
var virtualKeyboard = null;
@@ -417,6 +420,7 @@ function start() {
417420
placesManager = new PlacesManager.PlacesManager();
418421

419422
magnifier = new Magnifier.Magnifier();
423+
locatePointer = new LocatePointer.locatePointer();
420424

421425
layoutManager.init();
422426
virtualKeyboard.init();

js/ui/ripples.js

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
2+
3+
const { Clutter, St } = imports.gi;
4+
5+
// Shamelessly copied from the layout "hotcorner" ripples implementation
6+
var Ripples = class Ripples {
7+
constructor(px, py, styleClass) {
8+
this._x = 0;
9+
this._y = 0;
10+
11+
this._px = px;
12+
this._py = py;
13+
14+
this._ripple1 = new St.BoxLayout({
15+
style_class: styleClass,
16+
important: true,
17+
opacity: 0,
18+
can_focus: false,
19+
reactive: false,
20+
visible: false,
21+
});
22+
this._ripple1.set_pivot_point(px, py);
23+
24+
this._ripple2 = new St.BoxLayout({
25+
style_class: styleClass,
26+
important: true,
27+
opacity: 0,
28+
can_focus: false,
29+
reactive: false,
30+
visible: false,
31+
});
32+
this._ripple2.set_pivot_point(px, py);
33+
34+
this._ripple3 = new St.BoxLayout({
35+
style_class: styleClass,
36+
important: true,
37+
opacity: 0,
38+
can_focus: false,
39+
reactive: false,
40+
visible: false,
41+
});
42+
this._ripple3.set_pivot_point(px, py);
43+
}
44+
45+
destroy() {
46+
this._ripple1.destroy();
47+
this._ripple2.destroy();
48+
this._ripple3.destroy();
49+
}
50+
51+
_animRipple(ripple, delay, duration, startScale, startOpacity, finalScale) {
52+
// We draw a ripple by using a source image and animating it scaling
53+
// outwards and fading away. We want the ripples to move linearly
54+
// or it looks unrealistic, but if the opacity of the ripple goes
55+
// linearly to zero it fades away too quickly, so we use a separate
56+
// tween to give a non-linear curve to the fade-away and make
57+
// it more visible in the middle section.
58+
59+
ripple.x = this._x;
60+
ripple.y = this._y;
61+
ripple.visible = true;
62+
ripple.opacity = 255 * Math.sqrt(startOpacity);
63+
ripple.scale_x = ripple.scale_y = startScale;
64+
ripple.set_translation(-this._px * ripple.width, -this._py * ripple.height, 0.0);
65+
66+
ripple.ease({
67+
opacity: 0,
68+
delay,
69+
duration,
70+
mode: Clutter.AnimationMode.EASE_IN_QUAD,
71+
});
72+
ripple.ease({
73+
scale_x: finalScale,
74+
scale_y: finalScale,
75+
delay,
76+
duration,
77+
mode: Clutter.AnimationMode.LINEAR,
78+
onComplete: () => (ripple.visible = false),
79+
});
80+
}
81+
82+
addTo(stage) {
83+
if (this._stage !== undefined)
84+
throw new Error('Ripples already added');
85+
86+
this._stage = stage;
87+
this._stage.add_actor(this._ripple1);
88+
this._stage.add_actor(this._ripple2);
89+
this._stage.add_actor(this._ripple3);
90+
}
91+
92+
playAnimation(x, y) {
93+
if (this._stage === undefined)
94+
throw new Error('Ripples not added');
95+
96+
this._x = x;
97+
this._y = y;
98+
99+
this._stage.set_child_above_sibling(this._ripple1, null);
100+
this._stage.set_child_above_sibling(this._ripple2, this._ripple1);
101+
this._stage.set_child_above_sibling(this._ripple3, this._ripple2);
102+
103+
// Show three concentric ripples expanding outwards; the exact
104+
// parameters were found by trial and error, so don't look
105+
// for them to make perfect sense mathematically
106+
107+
// delay time scale opacity => scale
108+
this._animRipple(this._ripple1, 0, 830, 0.25, 1.0, 1.5);
109+
this._animRipple(this._ripple2, 50, 1000, 0.0, 0.7, 1.25);
110+
this._animRipple(this._ripple3, 350, 1000, 0.0, 0.3, 1);
111+
}
112+
};

0 commit comments

Comments
 (0)