#!/usr/bin/python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib
import cairo

class App(Gtk.Window):
    def __init__(self):
        super().__init__(title='Screen Magnifier')
        self.set_default_size(500, 520)
        self.zoom = 2.0
        self.mx = self.my = 0
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        vbox.set_margin_top(6); vbox.set_margin_bottom(6)
        vbox.set_margin_start(6); vbox.set_margin_end(6)
        self.add(vbox)
        hbox = Gtk.Box(spacing=8)
        hbox.add(Gtk.Label(label='Zoom:'))
        self.slider = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, 1, 4, 0.25)
        self.slider.set_value(2.0)
        self.slider.connect('value-changed', lambda s: setattr(self, 'zoom', s.get_value()))
        hbox.pack_start(self.slider, True, True, 0)
        vbox.pack_start(hbox, False, False, 0)
        self.da = Gtk.DrawingArea()
        self.da.set_size_request(480, 480)
        self.da.connect('draw', self.draw)
        vbox.pack_start(self.da, True, True, 0)
        self.info = Gtk.Label(label='Move mouse over this window')
        vbox.pack_start(self.info, False, False, 0)
        self.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
        self.connect('motion-notify-event', self.motion)
        GLib.timeout_add(100, lambda: self.da.queue_draw() or True)
    def motion(self, w, e):
        self.mx = int(e.x_root); self.my = int(e.y_root)
        self.info.set_text(f'Cursor: ({self.mx}, {self.my})  Zoom: {self.zoom:.2f}x')
    def draw(self, w, cr):
        alloc = w.get_allocation()
        W, H = alloc.width, alloc.height
        display = Gdk.Display.get_default()
        screen = display.get_default_screen()
        root = Gdk.get_default_root_window()
        pw = int(W / self.zoom); ph = int(H / self.zoom)
        sx = max(0, self.mx - pw//2); sy = max(0, self.my - ph//2)
        sw = screen.get_width(); sh = screen.get_height()
        sx = min(sx, sw - pw); sy = min(sy, sh - ph)
        try:
            pb = Gdk.pixbuf_get_from_window(root, sx, sy, pw, ph)
            if pb:
                scaled = pb.scale_simple(W, H, 2)
                Gdk.cairo_set_source_pixbuf(cr, scaled, 0, 0)
                cr.paint()
            else:
                cr.set_source_rgb(0.2,0.2,0.2); cr.paint()
                cr.set_source_rgb(1,1,1)
                cr.move_to(10,H//2); cr.show_text('Move mouse to see magnified area')
        except Exception:
            cr.set_source_rgb(0.15,0.15,0.15); cr.paint()
        # crosshair
        cr.set_source_rgba(1,0,0,0.7); cr.set_line_width(1)
        cr.move_to(W//2, 0); cr.line_to(W//2, H); cr.stroke()
        cr.move_to(0, H//2); cr.line_to(W, H//2); cr.stroke()

win = App()
win.connect('destroy', Gtk.main_quit)
win.show_all()
Gtk.main()
