Skip to content

Commit 57d7337

Browse files
authored
Merge pull request #14 from elcste/49
Merge 49 to main
2 parents 0e09f4b + eea7bbd commit 57d7337

9 files changed

Lines changed: 237 additions & 57 deletions

Makefile

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# --- Settings ---
2+
UUID = hide-cursor@elcste.com
3+
SCHEMA_ID = org.gnome.shell.extensions.hide-cursor-elcste-com
4+
DOMAIN = $(UUID)
5+
6+
# Directories
7+
EXTENSION_DIR = $(HOME)/.local/share/gnome-shell/extensions/$(UUID)
8+
SCHEMAS_DIR = $(HOME)/.local/share/glib-2.0/schemas
9+
LOCALE_DIR = $(HOME)/.local/share/locale
10+
11+
# Files
12+
SCHEMA_XML = schemas/$(SCHEMA_ID).gschema.xml
13+
PO_FILES = $(wildcard po/*.po)
14+
LANGUAGES = $(notdir $(PO_FILES:.po=))
15+
16+
# Commands
17+
GLIB_COMPILE_SCHEMAS = glib-compile-schemas
18+
MSGFMT = msgfmt
19+
20+
.PHONY: all install uninstall schemas local-schemas translations pot clean
21+
22+
# --- Main target ---
23+
all: schemas local-schemas translations
24+
25+
# --- Installation ---
26+
install: schemas local-schemas translations
27+
@echo "Installing extension to $(EXTENSION_DIR)..."
28+
@mkdir -p "$(EXTENSION_DIR)"
29+
@cp -r extension.js metadata.json prefs.js schemas po "$(EXTENSION_DIR)/"
30+
# .mo files already copied by translations → to $(EXTENSION_DIR)/locale/
31+
@echo "✅ Extension installed."
32+
33+
# --- Global schema compilation (required for GNOME 42+) ---
34+
schemas:
35+
@echo "Compiling schema to global directory..."
36+
@mkdir -p "$(SCHEMAS_DIR)"
37+
@cp "$(SCHEMA_XML)" "$(SCHEMAS_DIR)/"
38+
@$(GLIB_COMPILE_SCHEMAS) "$(SCHEMAS_DIR)"
39+
40+
# --- Local schema compilation (in extension folder) ---
41+
local-schemas:
42+
@echo "Compiling schema to extension folder (locally)..."
43+
@$(GLIB_COMPILE_SCHEMAS) schemas/
44+
45+
# --- Translations ---
46+
translations: $(PO_FILES:.po=.mo)
47+
48+
%.mo: %.po
49+
@lang=$$(basename $< .po); \
50+
mkdir -p "$(EXTENSION_DIR)/locale/$$lang/LC_MESSAGES"; \
51+
$(MSGFMT) -o "$(EXTENSION_DIR)/locale/$$lang/LC_MESSAGES/$(DOMAIN).mo" $<
52+
53+
# --- Uninstallation ---
54+
uninstall:
55+
@echo "Removing extension $(UUID)..."
56+
@rm -rf "$(EXTENSION_DIR)"
57+
@echo "Removing global schema..."
58+
@rm -f "$(SCHEMAS_DIR)/$(SCHEMA_ID).gschema.xml"
59+
@$(GLIB_COMPILE_SCHEMAS) "$(SCHEMAS_DIR)" 2>/dev/null || true
60+
@echo "Removing translations..."
61+
@for lang in $(LANGUAGES); do \
62+
if [ -n "$$lang" ]; then \
63+
echo " Removing $$lang..."; \
64+
rm -f "$(LOCALE_DIR)/$$lang/LC_MESSAGES/$(DOMAIN).mo"; \
65+
rmdir "$(LOCALE_DIR)/$$lang/LC_MESSAGES" 2>/dev/null || true; \
66+
rmdir "$(LOCALE_DIR)/$$lang" 2>/dev/null || true; \
67+
fi \
68+
done
69+
@echo "✅ Uninstallation completed."
70+
71+
# --- POT Generation (optional) ---
72+
pot:
73+
@xgettext --from-code=UTF-8 \
74+
--output=po/$(DOMAIN).pot \
75+
--keyword=_ \
76+
--package-name="$(UUID)" \
77+
extension.js prefs.js
78+
79+
# --- Cleaning local .mo files ---
80+
clean:
81+
@rm -f po/*.mo schemas/*.compiled
82+
@echo "Cleaning local .mo files. and compiled schemas"

README.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
## Hide Cursor
22

3-
### *Help needed for GNOME 49 (and beyond)*
4-
5-
*The cursor hiding API changed in the upcoming Gnome 49 release and [I haven't found a way to get this extension working](https://discourse.gnome.org/t/un-hiding-cursor-on-gnome-49/30747).*
6-
7-
<b>⁂</b>
8-
93
### Install from the [GNOME Shell Extensions website](https://extensions.gnome.org/extension/6727/hide-cursor/)
104

115
GNOME Shell extension to hide the cursor on inactivity
126

137
For use on Wayland, since `unclutter`, `unclutter-xfixes` and `xbanish` only work on X11.
148

15-
Works with GNOME Shell 45 and later. The latest version supports GS 48. For GS 45–47, use version 1.3.0.
9+
Works with GNOME Shell 49. For GS 45–47, use version 1.3.0.
1610

1711
<b>⁂</b>
1812

extension.js

Lines changed: 74 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,82 @@
1-
/*
2-
* Copyright 2024-25 Alexander Browne
3-
* Copyright 2020 Evan Welsh (https://gjs.guide/extensions/review-guidelines/review-guidelines.html#remove-main-loop-sources)
4-
* Copyright 2020 Jeff Channell (https://github.com/jeffchannell/jiggle/blob/master/cursor.js)
5-
*/
6-
7-
/* extension.js
8-
*
9-
* This program is free software: you can redistribute it and/or modify
10-
* it under the terms of the GNU General Public License as published by
11-
* the Free Software Foundation, either version 2 of the License, or
12-
* (at your option) any later version.
13-
*
14-
* This program is distributed in the hope that it will be useful,
15-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17-
* GNU General Public License for more details.
18-
*
19-
* You should have received a copy of the GNU General Public License
20-
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21-
*
22-
* SPDX-License-Identifier: GPL-2.0-or-later
23-
*/
24-
25-
import Clutter from 'gi://Clutter';
26-
import GLib from 'gi://GLib';
27-
28-
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
1+
import GLib from 'gi://GLib'
2+
import Clutter from 'gi://Clutter'
3+
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js'
4+
295

306
export default class HideCursor extends Extension {
31-
enable() {
32-
this._hideCursor = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 5, () => {
33-
let tracker = global.backend.get_cursor_tracker();
34-
const seat = Clutter.get_default_backend().get_default_seat();
7+
TICK_TIMEOUT = 1
8+
9+
enable() {
10+
this._settings = this.getSettings()
11+
this.HIDE_TIMEOUT = this._settings.get_int('timeout') * 1000
12+
this._settingsConnectionID = this._settings.connect('changed::timeout', () =>
13+
this.HIDE_TIMEOUT = this._settings.get_int('timeout') * 1000)
14+
15+
this._seat = Clutter.get_default_backend().get_default_seat()
16+
this._timer = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, this.TICK_TIMEOUT, this.tick)
17+
this._tracker = global.backend.get_cursor_tracker()
18+
this._positionChangedId = this._tracker.connect('position-invalidated', this.move)
19+
this._lastMove = Date.now()
20+
}
21+
22+
disable() {
23+
if (this._positionChangedId) {
24+
this._tracker.disconnect(this._positionChangedId)
25+
this._positionChangedId = null
26+
}
27+
28+
if (this._settingsConnectionID) {
29+
this._settings.disconnect(this._settingsConnectionID)
30+
this._settingsConnectionID = null
31+
}
32+
33+
if (this._tracker) {
34+
if (this._hasVisibilityInhibited && !this._tracker.get_pointer_visible())
35+
this._tracker.uninhibit_cursor_visibility()
36+
this._tracker = null
37+
this._hasVisibilityInhibited = null
38+
}
39+
40+
if (this._timer) {
41+
GLib.Source.remove(this._timer)
42+
this._timer = null
43+
}
44+
45+
if (this._hasFocusInhibited) {
46+
this._seat.uninhibit_unfocus()
47+
this._hasFocusInhibited = null
48+
}
3549

36-
if (!seat.is_unfocus_inhibited())
37-
seat.inhibit_unfocus();
38-
tracker.set_pointer_visible(false);
50+
this._seat = null
51+
this._lastMove = null
52+
this._settings = null
53+
this.HIDE_TIMEOUT = null
54+
}
3955

40-
return GLib.SOURCE_CONTINUE;
41-
});
56+
tick = () => {
57+
if (Date.now() - this._lastMove > this.HIDE_TIMEOUT && this._tracker.get_pointer_visible()) {
58+
if (!this._hasFocusInhibited) {
59+
this._seat.inhibit_unfocus()
60+
this._hasFocusInhibited = true
61+
}
62+
this._tracker.inhibit_cursor_visibility()
63+
this._hasVisibilityInhibited = true
4264
}
4365

44-
disable() {
45-
if (this._hideCursor) {
46-
GLib.Source.remove(this._hideCursor);
47-
this._hideCursor = null;
48-
}
49-
let tracker = global.backend.get_cursor_tracker();
50-
const seat = Clutter.get_default_backend().get_default_seat();
51-
52-
if (seat.is_unfocus_inhibited())
53-
seat.uninhibit_unfocus();
54-
tracker.set_pointer_visible(true);
66+
return GLib.SOURCE_CONTINUE
67+
}
68+
69+
move = () => {
70+
this._lastMove = Date.now()
71+
72+
if (this._hasFocusInhibited) {
73+
this._seat.uninhibit_unfocus()
74+
this._hasFocusInhibited = false
5575
}
76+
77+
if (!this._tracker.get_pointer_visible())
78+
this._tracker.uninhibit_cursor_visibility()
79+
80+
this._hasVisibilityInhibited = false
81+
}
5682
}

metadata.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
"description": "Hide the mouse cursor on inactivity.\n\nFor use on Wayland, since unclutter, unclutter-xfixes and xbanish only work on X11.\n\nA backport to GNOME Shell 42 was provided by a contributor. I have not tested it myself. Feedback welcome! Does it work with GS 43 or 44?",
44
"uuid": "hide-cursor@elcste.com",
55
"shell-version": [
6-
"48"
6+
"49"
77
],
8-
"url": "https://github.com/elcste/hide-cursor"
8+
"url": "https://github.com/elcste/hide-cursor",
9+
"settings-schema": "org.gnome.shell.extensions.hide-cursor-elcste-com",
10+
"gettext-domain": "hide-cursor@elcste.com"
911
}

po/POTFILES.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
prefs.js

po/hide-cursor@elcste.com.pot

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
msgid ""
2+
msgstr ""
3+
"MIME-Version: 1.0\n"
4+
"Content-Type: text/plain; charset=CHARSET\n"
5+
"Content-Transfer-Encoding: 8bit\n"
6+
"Language: \n"
7+
8+
#: prefs.js:16
9+
msgid "Cursor Hiding"
10+
msgstr ""
11+
12+
#: prefs.js:22
13+
msgid "Hide cursor after (seconds)"
14+
msgstr ""

po/ru.po

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
msgid ""
2+
msgstr ""
3+
"MIME-Version: 1.0\n"
4+
"Content-Type: text/plain; charset=UTF-8\n"
5+
"Language: ru\n"
6+
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
7+
8+
#: prefs.js:16
9+
msgid "Cursor Hiding"
10+
msgstr "Скрытие курсора"
11+
12+
#: prefs.js:22
13+
msgid "Hide cursor after (seconds)"
14+
msgstr "Скрывать курсор через (секунд)"

prefs.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Adw from 'gi://Adw'
2+
import Gio from 'gi://Gio'
3+
import Gtk from 'gi://Gtk'
4+
import {ExtensionPreferences, gettext as _} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'
5+
6+
7+
export default class HideCursorPrefs extends ExtensionPreferences {
8+
fillPreferencesWindow(window) {
9+
const page = new Adw.PreferencesPage({
10+
title: 'General',
11+
icon_name: 'dialog-information-symbolic',
12+
})
13+
window.add(page)
14+
15+
const group = new Adw.PreferencesGroup({
16+
title: _('Cursor Hiding'),
17+
})
18+
page.add(group)
19+
20+
const timeoutRow = new Adw.SpinRow({
21+
title: _('Hide cursor after (seconds)'),
22+
adjustment: new Gtk.Adjustment({
23+
lower: 1,
24+
upper: 30,
25+
step_increment: 1,
26+
page_increment: 5,
27+
value: this.getSettings().get_int('timeout'),
28+
}),
29+
numeric: true,
30+
})
31+
32+
this.getSettings().bind('timeout', timeoutRow, 'value', Gio.SettingsBindFlags.DEFAULT)
33+
34+
group.add(timeoutRow)
35+
}
36+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<schemalist>
3+
<schema id="org.gnome.shell.extensions.hide-cursor-elcste-com"
4+
path="/org/gnome/shell/extensions/hide-cursor-elcste-com/">
5+
<key name="timeout" type="i">
6+
<default>5</default>
7+
<summary>Hide cursor timeout</summary>
8+
<description>Time in seconds after which the cursor is hidden when idle.</description>
9+
</key>
10+
</schema>
11+
</schemalist>

0 commit comments

Comments
 (0)