2023-08-16 19:17:50 +08:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
from Xlib import display
|
2023-08-28 18:55:29 +08:00
|
|
|
# from pprint import pprint as print
|
2023-08-16 19:17:50 +08:00
|
|
|
import gi, cairo
|
|
|
|
gi.require_version('Gtk', '3.0')
|
2023-08-30 09:33:21 +08:00
|
|
|
from gi.repository import Gtk, Gdk, GdkPixbuf
|
2023-08-16 19:17:50 +08:00
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
|
|
|
|
from utils import blur_image
|
|
|
|
|
2023-08-16 19:17:50 +08:00
|
|
|
# 获取默认显示器
|
|
|
|
dp = Gdk.Display.get_default()
|
|
|
|
|
|
|
|
root = display.Display().screen().root
|
|
|
|
|
|
|
|
|
|
|
|
# 计算所有显示器的总大小
|
|
|
|
total_width = 0
|
|
|
|
total_height = 0
|
|
|
|
for i in range(dp.get_n_monitors()):
|
|
|
|
monitor = dp.get_monitor(i)
|
|
|
|
geometry = monitor.get_geometry()
|
|
|
|
total_width += geometry.width
|
|
|
|
total_height = max(total_height, geometry.height)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_draw(widget, cr):
|
|
|
|
cr.set_source_rgba(0, 0, 0, 0.3) # 设置颜色和透明度
|
|
|
|
cr.set_operator(cairo.OPERATOR_SOURCE)
|
|
|
|
cr.paint()
|
|
|
|
cr.set_operator(cairo.OPERATOR_OVER)
|
|
|
|
|
|
|
|
def on_mouse_move(widget, event):
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
print(event.x_root, event.y_root)
|
|
|
|
# pointer = root.query_pointer()
|
2023-08-16 19:17:50 +08:00
|
|
|
# print("Mouse at (%d, %d)" % (pointer.root_x, pointer.root_y))
|
2023-08-28 18:55:29 +08:00
|
|
|
# win_at_pointer = pointer.child
|
|
|
|
# print(win_at_pointer.get_wm_class())
|
2023-08-16 19:17:50 +08:00
|
|
|
|
|
|
|
# print(dir(Gtk.WindowType))
|
|
|
|
|
|
|
|
# 创建遮罩窗口
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
class App(Gtk.Window):
|
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
saved = False
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
def __init__(self):
|
|
|
|
Gtk.Window.__init__(self, type=Gtk.WindowType.POPUP)
|
2023-08-30 09:33:21 +08:00
|
|
|
|
|
|
|
self.set_name('Xshot')
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
self.set_default_size(total_width, total_height)
|
|
|
|
self.set_type_hint(Gdk.WindowTypeHint.DESKTOP)
|
|
|
|
|
|
|
|
# 设置透明背景
|
|
|
|
screen = self.get_screen()
|
|
|
|
visual = screen.get_rgba_visual()
|
2023-08-30 19:22:53 +08:00
|
|
|
if visual and screen.is_composited():
|
|
|
|
self.set_visual(visual)
|
2023-08-28 18:55:29 +08:00
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
self.set_app_paintable(True)
|
|
|
|
self.set_focus()
|
2023-08-28 18:55:29 +08:00
|
|
|
|
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
# self.set_events(Gdk.EventMask.POINTER_MOTION_MASK)
|
2023-08-28 18:55:29 +08:00
|
|
|
# window.connect("button-press-event", on_mouse_move)
|
|
|
|
# window.connect("button-release-event", on_mouse_move)
|
|
|
|
# window.connect("motion-notify-event", on_mouse_move)
|
|
|
|
# window.connect("motion-notify-event", on_mouse_move)
|
|
|
|
|
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
layout = Gtk.Fixed()
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
# self.add(layout)
|
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
# layout = Gtk.Fixed()
|
2023-08-28 18:55:29 +08:00
|
|
|
self.drawing_area = Gtk.DrawingArea()
|
2023-08-30 09:33:21 +08:00
|
|
|
self.drawing_area.set_size_request(total_width, total_height)
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
self.drawing_area.add_events(
|
|
|
|
Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK)
|
|
|
|
self.drawing_area.connect("draw", self.on_draw)
|
|
|
|
self.drawing_area.connect("button-press-event", self.on_button_press)
|
|
|
|
self.drawing_area.connect("button-release-event", self.on_button_release)
|
|
|
|
self.drawing_area.connect("motion-notify-event", self.on_motion_notify)
|
2023-08-30 09:33:21 +08:00
|
|
|
layout.add(self.drawing_area)
|
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
btn = Gtk.Button(label = 'hello world')
|
|
|
|
btn.set_size_request(200, 60)
|
|
|
|
layout.put(btn, 200, 100)
|
2023-08-30 09:33:21 +08:00
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
self.layout = layout
|
2023-08-30 09:33:21 +08:00
|
|
|
self.add(layout)
|
2023-08-28 18:55:29 +08:00
|
|
|
# Initialize rectangle and control point size
|
|
|
|
self.start_x = None
|
|
|
|
self.start_y = None
|
|
|
|
self.current_x = None
|
|
|
|
self.current_y = None
|
2023-08-30 09:33:21 +08:00
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
self.dragging = False
|
|
|
|
self.resize_dragging = False
|
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
self.connect("draw", self.on_before_start)
|
|
|
|
self.connect("delete-event", Gtk.main_quit)
|
|
|
|
self.connect("key-press-event", self.on_key_down)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_before_start(self, win, cr):
|
|
|
|
|
|
|
|
if not self.saved:
|
|
|
|
# print('又进来了')
|
|
|
|
window = Gdk.get_default_root_window()
|
|
|
|
width, height = window.get_width(), window.get_height()
|
|
|
|
self.entire_desktop = Gdk.pixbuf_get_from_window(window, 0, 0, width, height)
|
|
|
|
# self.entire_desktop.savev("entire_desktop.png", "png", [], [])
|
|
|
|
self.saved = True
|
|
|
|
|
|
|
|
cr.set_source_rgba(0, 0, 0, 0.3) # 设置颜色和透明度
|
|
|
|
cr.set_operator(cairo.OPERATOR_SOURCE)
|
|
|
|
cr.paint()
|
|
|
|
cr.set_operator(cairo.OPERATOR_OVER)
|
2023-08-28 18:55:29 +08:00
|
|
|
|
2023-08-30 09:33:21 +08:00
|
|
|
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
def on_draw(self, widget, cr):
|
2023-08-30 09:33:21 +08:00
|
|
|
if self.start_x is not None and self.start_y is not None:
|
|
|
|
width = self.current_x - self.start_x
|
|
|
|
height = self.current_y - self.start_y
|
2023-08-30 19:22:53 +08:00
|
|
|
|
|
|
|
# print(abs(width), abs(height))
|
|
|
|
|
|
|
|
# 白色
|
|
|
|
# cr.set_source_rgb(1, 1, 1)
|
|
|
|
|
|
|
|
cr.set_source_rgb(208/255, 234/255, 1)
|
|
|
|
cr.set_line_width(2)
|
|
|
|
|
|
|
|
|
2023-08-30 09:33:21 +08:00
|
|
|
cr.set_dash([6.0, 4.0])
|
|
|
|
cr.rectangle(self.start_x, self.start_y, width, height)
|
|
|
|
cr.stroke()
|
2023-08-30 19:22:53 +08:00
|
|
|
center = (self.start_x + width / 2, self.start_y + height / 2)
|
2023-08-30 09:33:21 +08:00
|
|
|
# draw resizing dots
|
2023-08-30 19:22:53 +08:00
|
|
|
for x in [self.start_x, center[0], self.current_x]:
|
|
|
|
for y in [self.start_y, center[1], self.current_y]:
|
|
|
|
# 中心的圆点不画
|
|
|
|
if x == center[0] and y == center[1]:
|
|
|
|
continue
|
|
|
|
|
2023-08-30 09:33:21 +08:00
|
|
|
cr.arc(x, y, 5, 0, 2 * 3.14)
|
|
|
|
cr.fill()
|
|
|
|
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
def on_button_press(self, widget, event):
|
2023-08-30 09:33:21 +08:00
|
|
|
if event.button == 1: # left mouse button
|
|
|
|
self.start_x = event.x
|
|
|
|
self.start_y = event.y
|
|
|
|
self.current_x = event.x
|
|
|
|
self.current_y = event.y
|
|
|
|
self.dragging = True
|
|
|
|
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
def on_button_release(self, widget, event):
|
2023-08-30 09:33:21 +08:00
|
|
|
if event.button == 1: # left mouse button
|
|
|
|
self.dragging = False
|
2023-08-30 19:22:53 +08:00
|
|
|
self.screenshot()
|
2023-08-30 09:33:21 +08:00
|
|
|
self.queue_draw()
|
|
|
|
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
def on_motion_notify(self, widget, event):
|
2023-08-30 09:33:21 +08:00
|
|
|
if self.dragging:
|
|
|
|
self.current_x = event.x
|
|
|
|
self.current_y = event.y
|
|
|
|
self.queue_draw()
|
2023-08-28 18:55:29 +08:00
|
|
|
|
|
|
|
|
2023-08-30 19:22:53 +08:00
|
|
|
def screenshot(self):
|
|
|
|
x = self.start_x
|
|
|
|
y = self.start_y
|
|
|
|
w = self.current_x - x
|
|
|
|
h = self.current_y - y
|
|
|
|
pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, abs(w), abs(h))
|
|
|
|
self.entire_desktop.copy_area(x, y, w, h, pixbuf, 0, 0)
|
|
|
|
|
|
|
|
# pixbuf = blur_image(pixbuf)
|
|
|
|
# pixbuf.savev("screenshot.png", "png", [], [])
|
|
|
|
img = Gtk.Image()
|
|
|
|
img.set_from_pixbuf(pixbuf)
|
|
|
|
self.layout.put(img, x + 1, y + 1)
|
|
|
|
self.layout.show_all()
|
|
|
|
|
|
|
|
|
|
|
|
def on_key_down(self, win, ev):
|
|
|
|
if ev.keyval == Gdk.KEY_Escape:
|
|
|
|
Gtk.main_quit()
|
|
|
|
|
2023-08-28 18:55:29 +08:00
|
|
|
|
|
|
|
def run(self):
|
2023-08-30 09:33:21 +08:00
|
|
|
try:
|
|
|
|
self.show_all()
|
|
|
|
Gtk.main()
|
|
|
|
except:
|
|
|
|
pass
|
2023-08-28 18:55:29 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
App().run()
|