1#!/usr/local/bin/python3.8 2 3import gi 4gi.require_version("Gtk", "3.0") 5from gi.repository import Gtk, Gdk, GObject 6from PIL import Image 7 8class EyeDropper(Gtk.HBox): 9 __gsignals__ = { 10 'color-picked': (GObject.SignalFlags.RUN_LAST, None, (GObject.TYPE_STRING,)) 11 } 12 13 def __init__(self): 14 Gtk.HBox.__init__ (self) 15 16 self.button = Gtk.Button("") 17 self.button.set_tooltip_text(_("Click the eyedropper, then click a color anywhere on your screen to select that color")) 18 self.button.set_image(Gtk.Image().new_from_stock(Gtk.STOCK_COLOR_PICKER, Gtk.IconSize.BUTTON)) 19 self.button.get_property('image').show() 20 self.button.set_events(Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.POINTER_MOTION_HINT_MASK); 21 22 self.pack_start(self.button, False, False, 2) 23 24 self.bp_handler = None 25 self.br_handler = None 26 self.kp_handler = None 27 28 self.button.connect("clicked", self.on_button_clicked) 29 30 def on_button_clicked(self, widget): 31 screen = widget.get_screen() 32 self.time = Gtk.get_current_event_time() 33 self.device = Gtk.get_current_event_device() 34 35 self.grab_widget = Gtk.Window(Gtk.WindowType.POPUP) 36 self.grab_widget.set_screen(screen) 37 self.grab_widget.resize(1, 1) 38 self.grab_widget.move(-100, -100) 39 self.grab_widget.show() 40 41 self.grab_widget.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.POINTER_MOTION_MASK) 42 toplevel = widget.get_toplevel() 43 44 if isinstance(toplevel, Gtk.Window): 45 if toplevel.has_group(): 46 toplevel.add_window(grab_widget) 47 48 window = self.grab_widget.get_window() 49 50 picker_cursor = Gdk.Cursor(screen.get_display(), Gdk.CursorType.CROSSHAIR); 51 52 grab_status = self.device.grab(window, Gdk.GrabOwnership.APPLICATION, False, 53 Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.POINTER_MOTION_MASK, 54 picker_cursor, self.time) 55 56 if grab_status != Gdk.GrabStatus.SUCCESS: 57 return 58 59 Gtk.device_grab_add(self.grab_widget, self.device, True) 60 61 self.bp_handler = self.grab_widget.connect("button-press-event", self.mouse_press) 62 self.kp_handler = self.grab_widget.connect("key-press-event", self.key_press) 63 64 def mouse_press(self, widget, event): 65 if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 1: 66 self.br_handler = widget.connect("button-release-event", self.mouse_release) 67 return True 68 return False 69 70 def key_press(self, widget, event): 71 screen, x_root, y_root = self.device.get_position() 72 if event.keyval == Gdk.KEY_Escape: 73 self.ungrab(self.device) 74 return True 75 elif event.keyval in (Gdk.KEY_space, Gdk.KEY_Return, Gdk.KEY_ISO_Enter, Gdk.KEY_KP_Enter, Gdk.KEY_KP_Space): 76 self.grab_color_at_pointer(event, screen, x_root, y_root) 77 return True 78 return False 79 80 def mouse_release(self, widget, event): 81 screen, x, y = self.device.get_position() 82 if event.button != 1: 83 return False 84 self.grab_color_at_pointer(event, screen, event.x_root, event.y_root) 85 return True 86 87 def grab_color_at_pointer(self, event, screen, x_root, y_root): 88 device = self.device 89 window = screen.get_root_window() 90 pixbuf = Gdk.pixbuf_get_from_window(window, x_root, y_root, 1, 1) 91 image = pixbuf2Image(pixbuf) 92 93 r, g, b = image.getpixel((0, 0)) 94 95 color = Gdk.RGBA() 96 color.red = r / 255.0 97 color.green = g / 255.0 98 color.blue = b / 255.0 99 self.emit('color-picked', color.to_string()) 100 self.ungrab(device) 101 102 def ungrab(self, device): 103 device.ungrab(self.time) 104 Gtk.device_grab_remove(self.grab_widget, device) 105 self.grab_widget.handler_disconnect(self.bp_handler) 106 self.grab_widget.handler_disconnect(self.br_handler) 107 self.grab_widget.handler_disconnect(self.kp_handler) 108 109def pixbuf2Image(pb): 110 width,height = pb.get_width(),pb.get_height() 111 return Image.fromstring("RGB",(width,height),pb.get_pixels() ) 112