Skip to content

Commit

Permalink
Reimplement the locate pointer functionality
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
JosephMcc authored and mtwebster committed Aug 14, 2022
1 parent 76224fe commit b845243
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 0 deletions.
7 changes: 7 additions & 0 deletions data/theme/cinnamon.css
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ StScrollBar StButton#vhandle:hover {
font-weight: normal;
text-align: center;
}
.ripple-pointer-location {
width: 50px;
height: 50px;
border-radius: 25px;
background-color: rgba(160,160,160,0.3);
box-shadow: 0 0 2px 2px rgba(160,160,160,1.0);
}
/* ===================================================================
* Shared button properties
* ===================================================================*/
Expand Down
33 changes: 33 additions & 0 deletions js/ui/locatePointer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-

const { Clutter, Gio, GLib, St } = imports.gi;
const Ripples = imports.ui.ripples;
const Main = imports.ui.main;

const LOCATE_POINTER_ENABLED_SCHEMA = "org.cinnamon.desktop.peripherals.mouse"
const LOCATE_POINTER_SCHEMA = "org.cinnamon.muffin"

var locatePointer = class {
constructor() {
this._enabledSettings = new Gio.Settings({schema_id: LOCATE_POINTER_ENABLED_SCHEMA});
this._keySettings = new Gio.Settings({schema_id: LOCATE_POINTER_SCHEMA});
this._keySettings.connect('changed::locate-pointer-key', this._updateKey.bind(this));
this._updateKey();

this._ripples = new Ripples.Ripples(0.5, 0.5, 'ripple-pointer-location');
this._ripples.addTo(Main.uiGroup);
}

_updateKey() {
let modifierKey = this._keySettings.get_string('locate-pointer-key');
Main.keybindingManager.addHotKey('locate-pointer', modifierKey, () => { this.show() });
}

show() {
if (!this._enabledSettings.get_boolean("locate-pointer"))
return;

let [x, y, mods] = global.get_pointer();
this._ripples.playAnimation(x, y);
}
};
4 changes: 4 additions & 0 deletions js/ui/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* Muffin actors
*
* @magnifier (Magnifier.Magnifier): The magnifier
* @locatePointer (LocatePointer.LocatePointer): The locate pointer object
* @xdndHandler (XdndHandler.XdndHandler): The X DND handler
* @statusIconDispatcher (StatusIconDispatcher.StatusIconDispatcher): The status icon dispatcher
* @virtualKeyboard (VirtualKeyboard.Keyboard): The keyboard object
Expand Down Expand Up @@ -108,6 +109,7 @@ const CinnamonDBus = imports.ui.cinnamonDBus;
const Screenshot = imports.ui.screenshot;
const ThemeManager = imports.ui.themeManager;
const Magnifier = imports.ui.magnifier;
const LocatePointer = imports.ui.locatePointer;
const XdndHandler = imports.ui.xdndHandler;
const StatusIconDispatcher = imports.ui.statusIconDispatcher;
const Util = imports.misc.util;
Expand Down Expand Up @@ -150,6 +152,7 @@ var modalCount = 0;
var modalActorFocusStack = [];
var uiGroup = null;
var magnifier = null;
var locatePointer = null;
var xdndHandler = null;
var statusIconDispatcher = null;
var virtualKeyboard = null;
Expand Down Expand Up @@ -417,6 +420,7 @@ function start() {
placesManager = new PlacesManager.PlacesManager();

magnifier = new Magnifier.Magnifier();
locatePointer = new LocatePointer.locatePointer();

layoutManager.init();
virtualKeyboard.init();
Expand Down
112 changes: 112 additions & 0 deletions js/ui/ripples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-

const { Clutter, St } = imports.gi;

// Shamelessly copied from the layout "hotcorner" ripples implementation
var Ripples = class Ripples {
constructor(px, py, styleClass) {
this._x = 0;
this._y = 0;

this._px = px;
this._py = py;

this._ripple1 = new St.BoxLayout({
style_class: styleClass,
important: true,
opacity: 0,
can_focus: false,
reactive: false,
visible: false,
});
this._ripple1.set_pivot_point(px, py);

this._ripple2 = new St.BoxLayout({
style_class: styleClass,
important: true,
opacity: 0,
can_focus: false,
reactive: false,
visible: false,
});
this._ripple2.set_pivot_point(px, py);

this._ripple3 = new St.BoxLayout({
style_class: styleClass,
important: true,
opacity: 0,
can_focus: false,
reactive: false,
visible: false,
});
this._ripple3.set_pivot_point(px, py);
}

destroy() {
this._ripple1.destroy();
this._ripple2.destroy();
this._ripple3.destroy();
}

_animRipple(ripple, delay, duration, startScale, startOpacity, finalScale) {
// We draw a ripple by using a source image and animating it scaling
// outwards and fading away. We want the ripples to move linearly
// or it looks unrealistic, but if the opacity of the ripple goes
// linearly to zero it fades away too quickly, so we use a separate
// tween to give a non-linear curve to the fade-away and make
// it more visible in the middle section.

ripple.x = this._x;
ripple.y = this._y;
ripple.visible = true;
ripple.opacity = 255 * Math.sqrt(startOpacity);
ripple.scale_x = ripple.scale_y = startScale;
ripple.set_translation(-this._px * ripple.width, -this._py * ripple.height, 0.0);

ripple.ease({
opacity: 0,
delay,
duration,
mode: Clutter.AnimationMode.EASE_IN_QUAD,
});
ripple.ease({
scale_x: finalScale,
scale_y: finalScale,
delay,
duration,
mode: Clutter.AnimationMode.LINEAR,
onComplete: () => (ripple.visible = false),
});
}

addTo(stage) {
if (this._stage !== undefined)
throw new Error('Ripples already added');

this._stage = stage;
this._stage.add_actor(this._ripple1);
this._stage.add_actor(this._ripple2);
this._stage.add_actor(this._ripple3);
}

playAnimation(x, y) {
if (this._stage === undefined)
throw new Error('Ripples not added');

this._x = x;
this._y = y;

this._stage.set_child_above_sibling(this._ripple1, null);
this._stage.set_child_above_sibling(this._ripple2, this._ripple1);
this._stage.set_child_above_sibling(this._ripple3, this._ripple2);

// Show three concentric ripples expanding outwards; the exact
// parameters were found by trial and error, so don't look
// for them to make perfect sense mathematically

// delay time scale opacity => scale
this._animRipple(this._ripple1, 0, 830, 0.25, 1.0, 1.5);
this._animRipple(this._ripple2, 50, 1000, 0.0, 0.7, 1.25);
this._animRipple(this._ripple3, 350, 1000, 0.0, 0.3, 1);
}
};

0 comments on commit b845243

Please sign in to comment.