From f9a1300290a032e8f892774c2db3e4c79c758679 Mon Sep 17 00:00:00 2001 From: Robert Tari Date: Mon, 4 Mar 2024 10:45:24 +0100 Subject: Add a Magnus fork and wrap it in a new window fixes https://github.com/ArcticaProject/arctica-greeter/issues/100 --- Makefile.am | 3 +- arctica-greeter-magnifier | 107 ++++++++++++++++++++++++++++++++++++++++++++ src/arctica-greeter.vala | 110 +++++++++++++++++++++++++++++++--------------- 3 files changed, 184 insertions(+), 36 deletions(-) create mode 100755 arctica-greeter-magnifier mode change 100644 => 100755 src/arctica-greeter.vala diff --git a/Makefile.am b/Makefile.am index 112eb3e..16dc40c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,7 +12,8 @@ pkglibexec_SCRIPTS = lightdm-arctica-greeter-session \ arctica-greeter-guest-session-setup.sh \ arctica-greeter-check-hidpi \ arctica-greeter-enable-tap-to-click \ - arctica-greeter-set-keyboard-layout + arctica-greeter-set-keyboard-layout \ + arctica-greeter-magnifier EXTRA_DIST = \ autogen.sh \ diff --git a/arctica-greeter-magnifier b/arctica-greeter-magnifier new file mode 100755 index 0000000..c4e5180 --- /dev/null +++ b/arctica-greeter-magnifier @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 + +import setproctitle +import sys +from functools import lru_cache +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk, Gdk, GLib, GdkPixbuf, Gio + +class Main(object): + + def __init__(self): + + self.window_x = 0 + self.window_y = 0 + self.w = Gtk.Window.new(Gtk.WindowType.TOPLEVEL) + self.w.set_size_request(300, 300) + self.w.set_title("Magnus") + self.w.connect("destroy", lambda a: Gtk.main_quit()) + self.w.connect("configure-event", self.window_configure) + self.img = Gtk.Image() + scrolled_window = Gtk.ScrolledWindow() + scrolled_window.add(self.img) + self.w.add(scrolled_window) + self.w.show_all() + sys.stdout.write('%d\n' % self.w.get_window().get_xid()) + sys.stdout.flush() + GLib.timeout_add(250, self.poll) + Gtk.main() + + def poll(self, *args): + + loc = self.w.get_size() + width = loc.width + height = loc.height + (screen, x, y) = Gdk.Display.get_default().get_default_seat().get_pointer().get_position() + + if (x > self.window_x and x <= (self.window_x + width + 0) and y > self.window_y and y <= (self.window_y + height + 0)): + + white = self.get_white_pixbuf(width, height) + self.img.set_from_pixbuf(white) + + else: + + root = Gdk.get_default_root_window() + scaled_width = width // 2 + scaled_height = height // 2 + scaled_xoff = scaled_width // 2 + scaled_yoff = scaled_height // 2 + screenshot = Gdk.pixbuf_get_from_window(root, x - scaled_xoff, y - scaled_yoff, scaled_width, scaled_height) + scaled_pb = screenshot.scale_simple(width, height, GdkPixbuf.InterpType.NEAREST) + self.img.set_from_pixbuf(scaled_pb) + + return True + + @lru_cache() + def makesquares(self, overall_width, overall_height, square_size, value_on, value_off): + + on_sq = list(value_on) * square_size + off_sq = list(value_off) * square_size + on_row = [] + off_row = [] + + while len(on_row) < overall_width * len(value_on): + + on_row += on_sq + on_row += off_sq + off_row += off_sq + off_row += on_sq + + on_row = on_row[:overall_width * len(value_on)] + off_row = off_row[:overall_width * len(value_on)] + on_sq_row = on_row * square_size + off_sq_row = off_row * square_size + overall = [] + count = 0 + + while len(overall) < overall_width * overall_height * len(value_on): + + overall += on_sq_row + overall += off_sq_row + count += 2 + + overall = overall[:overall_width * overall_height * len(value_on)] + + return overall + + @lru_cache() + def get_white_pixbuf(self, width, height): + + square_size = 16 + light = (153, 153, 153, 255) + dark = (102, 102, 102, 255) + whole = self.makesquares(width, height, square_size, light, dark) + arr = GLib.Bytes.new(whole) + + return GdkPixbuf.Pixbuf.new_from_bytes(arr, GdkPixbuf.Colorspace.RGB, True, 8, width, height, width * len(light)) + + def window_configure(self, window, ev): + + self.window_x = ev.x + self.window_y = ev.y + +if __name__ == "__main__": + + setproctitle.setproctitle('magnus') + Main() diff --git a/src/arctica-greeter.vala b/src/arctica-greeter.vala old mode 100644 new mode 100755 index 7e7fd47..a2aa59e --- a/src/arctica-greeter.vala +++ b/src/arctica-greeter.vala @@ -2,7 +2,7 @@ * * Copyright (C) 2011 Canonical Ltd * Copyright (C) 2015-2017 Mike Gabriel - * Copyright (C) 2023 Robert Tari + * Copyright (C) 2023-2024 Robert Tari * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -32,13 +32,13 @@ public class ArcticaGreeter : Object public signal void starting_session (); public MainWindow main_window { get; private set; default = null; } public Gtk.Window? pKeyboardWindow { get; set; default = null; } + public Gtk.Window? pMagnifierWindow { get; set; default = null; } public bool test_mode { get; construct; default = false; } public bool test_highcontrast { get; construct; default = false; } private string state_file; private KeyFile state; private DBusServer pServer; private Cairo.XlibSurface background_surface; - private SettingsDaemon settings_daemon; public bool orca_needs_kick; @@ -57,7 +57,6 @@ public class ArcticaGreeter : Object construct { Bus.own_name (BusType.SESSION, "org.ayatana.greeter", BusNameOwnerFlags.NONE, onBusAcquired); - greeter = new LightDM.Greeter (); greeter.show_message.connect ((text, type) => { show_message (text, type); }); @@ -667,13 +666,28 @@ public class ArcticaGreeter : Object keyboard_xid = pWindow.get_xid (); } - if (xwin != keyboard_xid && win.get_type_hint() != Gdk.WindowTypeHint.NOTIFICATION) + // Now check to see if this is the magnifier - no focus for it, either + X.Window nMagnifier = 0; + + if (this.pMagnifierWindow != null) + { + Gdk.X11.Window pWindow = (Gdk.X11.Window) this.pMagnifierWindow.get_window (); + nMagnifier = pWindow.get_xid (); + } + + if (xwin != keyboard_xid && xwin != nMagnifier && win.get_type_hint() != Gdk.WindowTypeHint.NOTIFICATION) { win.focus (Gdk.CURRENT_TIME); /* Make sure to keep keyboard above */ if (this.pKeyboardWindow != null) this.pKeyboardWindow.get_window ().raise (); + + // And the magnifier on top of everything + if (this.pMagnifierWindow != null) + { + this.pMagnifierWindow.get_window ().raise (); + } } } } @@ -698,6 +712,12 @@ public class ArcticaGreeter : Object /* Make sure to keep keyboard above */ if (this.pKeyboardWindow != null) this.pKeyboardWindow.get_window ().raise (); + + // And the magnifier on top of everything + if (this.pMagnifierWindow != null) + { + this.pMagnifierWindow.get_window ().raise (); + } } } return Gdk.FilterReturn.CONTINUE; @@ -1439,23 +1459,10 @@ public class DBusServer : Object private Pid nOrca = 0; private Pid nOnBoard = 0; private Pid nMagnifier = 0; - private Gtk.Socket pSocket = null; + private Gtk.Socket pKeyboardSocket = null; + private Gtk.Socket pMagnifierSocket = null; private bool high_contrast_osk = AGSettings.get_boolean(AGSettings.KEY_HIGH_CONTRAST); - private void onMagnifierClosed (Pid nPid, int nStatus) - { - nMagnifier = 0; - - try - { - this.pConnection.emit_signal (null, "/org/ayatana/greeter", "org.ayatana.greeter", "MagnifierClosed", null); - } - catch (Error pError) - { - error ("Panic: Could not send magnifier closed signal: %s", pError.message); - } - } - private void closePid (ref Pid nPid, int nMultiplier) { if (nPid > 0) @@ -1554,11 +1561,11 @@ public class DBusServer : Object closePid (ref nOnBoard, -1); /* Sending SIGTERM to the plug (i.e. the onboard process group) - * will destroy pSocket, so NULLing it now. + * will destroy pKeyboardSocket, so NULLing it now. */ debug ("Tearing down OSK's Gtk.Socket"); - this.pGreeter.pKeyboardWindow.remove (pSocket); - pSocket = null; + this.pGreeter.pKeyboardWindow.remove (pKeyboardSocket); + pKeyboardSocket = null; /* Start with fresh Gkt.Window object for OSK relaunch. */ @@ -1635,14 +1642,14 @@ public class DBusServer : Object } } - if (pSocket == null) + if (pKeyboardSocket == null) { debug ("Creating Gtk.Socket for OSK"); - pSocket = new Gtk.Socket (); - pSocket.show (); + pKeyboardSocket = new Gtk.Socket (); + pKeyboardSocket.show (); } - if ((this.pGreeter.pKeyboardWindow == null) && (pSocket != null)) + if ((this.pGreeter.pKeyboardWindow == null) && (pKeyboardSocket != null)) { debug ("Creating Gtk.Window for OSK"); this.pGreeter.pKeyboardWindow = new Gtk.Window (); @@ -1651,14 +1658,14 @@ public class DBusServer : Object this.pGreeter.pKeyboardWindow.set_title("OSK (theme: %s)".printf(sTheme)); } - if ((this.pGreeter.pKeyboardWindow != null) && (pSocket != null) && (nId != 0)) + if ((this.pGreeter.pKeyboardWindow != null) && (pKeyboardSocket != null) && (nId != 0)) { /* attach the GtkSocket, which will host the onboard keyboard, to pKeyboardWindow */ debug ("Adding OSK Gtk.Socket to OSK Gtk.Window"); - this.pGreeter.pKeyboardWindow.add (pSocket); + this.pGreeter.pKeyboardWindow.add (pKeyboardSocket); debug ("Attaching new onboard process to OSK Gtk.Socket (+ Gtk.Window)"); - pSocket.add_id (nId); + pKeyboardSocket.add_id (nId); /* resize the keyboard window to cover the lower part of the screen */ debug ("Resizing OSK window."); @@ -1733,24 +1740,57 @@ public class DBusServer : Object public void ToggleMagnifier (bool bActive) throws GLib.DBusError, GLib.IOError { + int nId = 0; AGSettings.set_boolean (AGSettings.KEY_MAGNIFIER, bActive); - if (bActive) + if (this.nMagnifier == 0) { try { - Process.spawn_async (null, {"magnus"}, null, SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD, null, out nMagnifier); - GLib.ChildWatch.add (nMagnifier, onMagnifierClosed); + int nMagnifierFD = 0; + string sPath = Path.build_filename (Config.PKGLIBEXECDIR, "arctica-greeter-magnifier"); + Process.spawn_async_with_pipes (null, {sPath}, null, SpawnFlags.SEARCH_PATH, null, out this.nMagnifier, null, out nMagnifierFD, null); + var pFile = FileStream.fdopen (nMagnifierFD, "r"); + var sText = new char[1024]; + + if (pFile.gets (sText) != null) + { + nId = int.parse ((string) sText); + } } catch (Error pError) { warning ("Failed to run magnifier: %s", pError.message); + + return; } } - else + + if (pMagnifierSocket == null) + { + debug ("Creating Gtk.Socket for the magnifier"); + pMagnifierSocket = new Gtk.Socket (); + pMagnifierSocket.show (); + } + + if ((this.pGreeter.pMagnifierWindow == null) && (pMagnifierSocket != null)) { - closePid (ref nMagnifier, 1); - nMagnifier = 0; + debug ("Creating Gtk.Window for the magnifier"); + this.pGreeter.pMagnifierWindow = new Gtk.Window (); + this.pGreeter.pMagnifierWindow.accept_focus = false; + this.pGreeter.pMagnifierWindow.focus_on_map = false; + this.pGreeter.pMagnifierWindow.set_title ("Magnifier"); } + + if ((this.pGreeter.pMagnifierWindow != null) && (pMagnifierSocket != null) && (nId != 0)) + { + debug ("Adding the magnifier Gtk.Socket to the magnifier Gtk.Window"); + this.pGreeter.pMagnifierWindow.add (pMagnifierSocket); + + debug ("Attaching new magnifier process to the magnifier Gtk.Socket (+ Gtk.Window)"); + pMagnifierSocket.add_id (nId); + } + + this.pGreeter.pMagnifierWindow.visible = bActive; } } -- cgit v1.2.3