Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ LOGIN_DESTOP_PATH = $(SHARE_DIR)
IMAGE_DIR:=$(SHARE_DIR)/pixmaps
GLADE_DIR:=$(SHARE_DIR)
SCHEMA_DIR:=$(gsettingsschemadir)
GNOME_SHELL_EXTDIR:=$(datadir)/gnome-shell/extensions

SLUG:=fragment_name

Expand Down Expand Up @@ -68,7 +69,7 @@ ln-venv:
clean-ln-venv:
@rm -f .venv

install-system: install-schemas install-locale install-guake
install-system: install-schemas install-locale install-guake install-gnome-extension

install-guake:
# you probably want to execute this target with sudo:
Expand Down Expand Up @@ -144,7 +145,22 @@ install-schemas:
install -Dm644 "$(DEV_DATA_DIR)/org.guake.gschema.xml" "$(DESTDIR)$(SCHEMA_DIR)/"
if [ $(COMPILE_SCHEMA) = 1 ]; then glib-compile-schemas $(DESTDIR)$(SCHEMA_DIR); fi

uninstall-system: uninstall-schemas uninstall-locale
install-gnome-extension:
install -dm755 "$(DESTDIR)$(GNOME_SHELL_EXTDIR)/guake-pointer-helper@guake.org"
install -Dm644 "$(DEV_DATA_DIR)/gnome-shell-extension/guake-pointer-helper@guake.org/metadata.json" \
"$(DESTDIR)$(GNOME_SHELL_EXTDIR)/guake-pointer-helper@guake.org/"
install -Dm644 "$(DEV_DATA_DIR)/gnome-shell-extension/guake-pointer-helper@guake.org/extension.js" \
"$(DESTDIR)$(GNOME_SHELL_EXTDIR)/guake-pointer-helper@guake.org/"
@echo
@echo "Installed GNOME Shell extension: guake-pointer-helper@guake.org"
@echo "Enable it with: gnome-extensions enable guake-pointer-helper@guake.org"
@echo "A session restart (log out/in) may be required for GNOME to detect the extension."
@echo

uninstall-gnome-extension:
rm -rf "$(DESTDIR)$(GNOME_SHELL_EXTDIR)/guake-pointer-helper@guake.org"

uninstall-system: uninstall-schemas uninstall-locale uninstall-gnome-extension
$(SHELL) -c $(PYTHON_SITEDIRS_FOR_PREFIX) \
| while read sitedir; do \
echo "rm -rf $(DESTDIR)$$sitedir/{guake,guake-*.egg-info}"; \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';

const DBUS_IFACE = `
<node>
<interface name="org.guake.JsonPointer">
<method name="GetPointer">
<arg type="i" direction="out" name="x"/>
<arg type="i" direction="out" name="y"/>
</method>
</interface>
</node>`;

export default class GuakePointerExtension {
_dbusId = null;

enable() {
const nodeInfo = Gio.DBusNodeInfo.new_for_xml(DBUS_IFACE);

this._dbusId = Gio.DBus.session.register_object(
'/org/guake/JsonPointer',
nodeInfo.interfaces[0],
(connection, sender, path, ifaceName, methodName, params, invocation) => {
if (methodName === 'GetPointer') {
const tracker = global.backend.get_cursor_tracker();
const [coords] = tracker.get_pointer();
invocation.return_value(
new GLib.Variant('(ii)', [
Math.round(coords.x),
Math.round(coords.y),
])
);
}
},
null,
null,
);
}

disable() {
if (this._dbusId) {
Gio.DBus.session.unregister_object(this._dbusId);
this._dbusId = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "Guake Pointer Helper",
"description": "Exposes Wayland cursor position over D-Bus for Guake multi-monitor support",
"uuid": "guake-pointer-helper@guake.org",
"shell-version": ["45", "46", "47", "48", "49", "50", "51"],
"url": "https://github.com/Guake/guake"
}
66 changes: 60 additions & 6 deletions guake/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,41 @@ def set_final_window_rect(cls, settings, window):

return window_rect

@classmethod
def _get_gnome_shell_pointer(cls):
"""Get cursor position via guake-pointer-helper GNOME Shell extension.

Under XWayland, GDK only sees cursor updates when hovering over
X11-compat windows. The guake-pointer-helper extension queries
Mutter's CursorTracker for the real Wayland pointer coordinates
and exposes them over a dedicated D-Bus interface.

Returns (x, y) or None on failure.
"""
try:
result = subprocess.run(
[
"gdbus", "call", "--session",
"--dest", "org.gnome.Shell",
"--object-path", "/org/guake/JsonPointer",
"--method", "org.guake.JsonPointer.GetPointer",
],
capture_output=True,
text=True,
timeout=1,
)
if result.returncode != 0:
return None
# Output: (1234, 567)
match = re.search(r"\((\d+),\s*(\d+)\)", result.stdout)
if match:
return int(match.group(1)), int(match.group(2))
except Exception as e:
log.debug("GNOME Shell pointer query failed: %s", e)
return None

_wayland_extension_warned = False

@classmethod
def get_final_window_monitor(cls, settings, window):
"""Gets the final monitor for the main window of guake."""
Expand All @@ -334,12 +369,31 @@ def get_final_window_monitor(cls, settings, window):
num_monitor = settings.general.get_int("display-n")

if use_mouse:
pointer = display.get_default_seat().get_pointer()
if pointer is None:
monitor = display.get_primary_monitor()
else:
_, x, y = pointer.get_position()
monitor = display.get_monitor_at_point(x, y)
monitor = None

if os.environ.get("XDG_SESSION_TYPE") == "wayland":
pos = cls._get_gnome_shell_pointer()
if pos is not None:
x, y = pos
monitor = display.get_monitor_at_point(x, y)
log.debug("Wayland pointer via GNOME Shell: (%s, %s)", x, y)
elif not cls._wayland_extension_warned:
cls._wayland_extension_warned = True
log.warning(
"Wayland session detected but guake-pointer-helper GNOME Shell "
"extension is not available. Multi-monitor 'appear on mouse "
"display' may not work correctly. Install and enable the "
"extension with: gnome-extensions enable "
"guake-pointer-helper@guake.org"
)

if monitor is None:
pointer = display.get_default_seat().get_pointer()
if pointer is None:
monitor = display.get_primary_monitor()
else:
_, x, y = pointer.get_position()
monitor = display.get_monitor_at_point(x, y)
else:
monitor = display.get_monitor(num_monitor)
if monitor is None:
Expand Down