我正在运行 Ubuntu 20.04 Mate Desktop。我发现了一个很酷的旧屏幕小部件,它显示时钟、CPU、内存、Wi-Fi 强度。它不依赖于 screenlet 包。虽然它很旧,但我设法仅通过安装即可运行http://mirrors.kernel.org/ubuntu/pool/universe/g/gnome-python/python-gconf_2.28.1+dfsg-1.2_amd64.deb
它python2.7
。
我找到的原始代码如下webarchive
:
https://web.archive.org/web/20130323064138if_/http://kanslozebagger.org/sphinX/sphinX-0.2.tar.bz2
我的想法是:
我用了pygi-convert.sh进行基本转换。
#!/usr/bin/env python
# vim: ts=4 sts=4 sw=4 ai et
# Copyright (C) 2006 Wander Boessenkool
#
# sphinX is a graphical system-monitor using pycairo
#
#` Author: Wander Boessenkool <[email protected]>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307 USA
#
NAME = 'sphinX'
VERSION = '0.2'
AUTHORS = ['Wander Boessenkool <[email protected]>']
import os
import sys
import gi
from gi.repository import GObject
import math
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
#import Gtk.gdk
import cairo
from datetime import datetime
from gi.repository import GConf
class cpustat(object):
def __init__(self, u=0.0, n=0.0, s=0.0, id=0.0, io=0.0, ir=0.0, si=0.0):
self.user = u
self.nice = n
self.system = s
self.idle = id
self.iowait = io
self.irq = ir
self.softirq = si
self.cur_freq = 0.0
self.max_freq = 1.0
self.scale = self.cur_freq / self.max_freq
class memstat(object):
def __init__(self, total=0 , free=0 , buffers=0, cached=0):
self.total = total
self.free = free
self.buffers = buffers
self.cached = cached
self.used = total - free - buffers - cached
class wifistat(object):
def __init__(self):
self.quality = 0.0
def hr(i):
sizes = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']
i = float(i)
index = 0
while (i > 1024 and index < len(sizes) - 1):
i = i / 1024.0
index += 1
return '%.2f %s' % (i, sizes[index])
class stats(object):
def __init__(self):
self.rawcpustats = [0 for i in range(8)]
self.cpu = cpustat()
self.mem = memstat()
self.swap = memstat()
self.wifi = wifistat()
self.update_all()
def update_mem(self):
statlines = open('/proc/meminfo', 'r').readlines()
meminfo = {}
for line in statlines:
splitline = line.split()
meminfo[splitline[0]] = float(splitline[1])
self.mem.total = meminfo['MemTotal:']
self.mem.free = meminfo['MemFree:'] / self.mem.total
self.mem.buffers = meminfo['Buffers:'] / self.mem.total
self.mem.cached = meminfo['Cached:'] / self.mem.total
self.mem.used = 1.0 \
- self.mem.free \
- self.mem.buffers \
- self.mem.cached
self.swap.total = meminfo['SwapTotal:']
if self.swap.total > 0:
self.swap.free = meminfo['SwapFree:'] / self.swap.total
else:
self.swap.free = -1.0
self.swap.used = 1.0 - self.swap.free
def update_cpu(self):
statlines = open('/proc/stat', 'r').readlines()
for line in statlines:
splitline = line.split()
if splitline[0] == 'cpu':
rawcpu = [int(i) for i in splitline[1:]]
diff = [rawcpu[i] - self.rawcpustats[i] for i in range(8)]
totaldiff = float(sum(diff))
if totaldiff != 0:
self.cpu.user = diff[0] / totaldiff
self.cpu.nice = diff[1] / totaldiff
self.cpu.system = diff[2] / totaldiff
self.cpu.idle = diff[3] / totaldiff
self.cpu.iowait = diff[4] / totaldiff
self.cpu.irq = diff[5] / totaldiff
self.cpu.softirq = diff[6] / totaldiff
self.rawcpustats = rawcpu
try:
self.cpu.max_freq = float(file(
'/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq', 'r').read())
self.cpu.cur_freq = float(file(
'/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq', 'r').read())
self.cpu.scale = self.cpu.cur_freq / self.cpu.max_freq
except:
self.cpu.max_freq = 1.0
self.cpu.cur_freq = 1.0
self.cpu.scale = 0.0
def update_wifi(self):
try:
statlines = file('/proc/net/wireless', 'r').readlines()
except:
statlines = ["", "", "0 0 0"]
while len(statlines) < 3:
statlines.append("0 0 0")
self.wifi.quality = float(statlines[2].split()[2]) / 100.0
def update_all(self):
self.update_cpu()
self.update_mem()
self.update_wifi()
class Witsjet(Gdk.Window):
'''
__gsignals__ = {
'draw': 'override',
'screen-changed': 'override',
}
'''
#window = Gdk.Window
def __init__(self, stats):
GObject.GObject.__init__(self)
#Gtk.Window.__init__(self, title="clock")
#super().__init__(title="Hello World")
self.gconfclient = GConf.Client.get_default()
sw = self.gconfclient.get_int('/apps/sphinX/width')
if sw is 0:
sw = 200
sh = self.gconfclient.get_int('/apps/sphinX/height')
if sh is 0:
sh = 200
sx = self.gconfclient.get_int('/apps/sphinX/xpos')
sy = self.gconfclient.get_int('/apps/sphinX/ypos')
self.set_size_request(32, 32)
self.set_default_size(sw, sh)
self.move(sx, sy)
self.stats = stats
self.stick()
self.set_keep_below(True)
self.set_property('accept-focus', False)
self.set_property('skip-pager-hint', True)
self.set_property('skip-taskbar-hint', True)
self.set_property('resizable', True)
self.drawing_stack = []
self.set_app_paintable(True)
self.set_decorated(False)
self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self.connect('button-press-event', self.buttonpress)
self.connect('configure-event', self.configure_handler)
self.do_screen_changed()
self.swapgradient = cairo.LinearGradient(0.2, 0.8, 1.0, 0.5)
self.swapgradient.add_color_stop_rgba(0.0, 1.0, 0.0, 0.0, 0.6)
self.swapgradient.add_color_stop_rgba(1.0, 1.0, 0.0, 0.0, 1.0)
self.memgradient = cairo.LinearGradient(0.8, 0.2, 0.0, 0.5)
self.memgradient.add_color_stop_rgba(0.0, 0.0, 1.0, 0.0, 0.6)
self.memgradient.add_color_stop_rgba(1.0, 0.0, 1.0, 0.0, 1.0)
self.scalegradient = cairo.LinearGradient(0.2, 0.8, 1.0, 0.5)
self.scalegradient.add_color_stop_rgba(0.0, 0.0, 0.0, 1.0, 0.3)
self.scalegradient.add_color_stop_rgba(1.0, 0.0, 0.0, 1.0, 1.0)
self.menu = Gtk.Menu()
'''
about = Gtk.Action('About', None, None, Gtk.STOCK_ABOUT)
about.connect('activate', self.about)
aboutmenu = Gtk.ImageMenuItem()
about.connect_proxy(aboutmenu)
self.menu.add(aboutmenu)
quit = Gtk.Action('Quit', None, None, Gtk.STOCK_QUIT)
quit.connect('activate', Gtk.main_quit)
quitmenu = Gtk.ImageMenuItem()
quit.connect_proxy(quitmenu)
self.menu.add(quitmenu)
'''
def about(self, *args):
dialog = Gtk.AboutDialog()
dialog.set_name('sphinX')
dialog.set_logo_icon_name('system')
dialog.set_copyright('(C) 2006 Red Hat, Inc.')
dialog.set_authors(AUTHORS)
dialog.set_version(VERSION)
dialog.connect('response', lambda d, r: d.destroy())
dialog.show()
def configure_handler(self, window, event):
w,h = self.get_size()
x, y = self.get_position()
self.gconfclient.set_int('/apps/sphinX/width', w)
self.gconfclient.set_int('/apps/sphinX/height', h)
self.gconfclient.set_int('/apps/sphinX/xpos', x)
self.gconfclient.set_int('/apps/sphinX/ypos', y)
return False
def buttonpress(self, window, event):
if event.button == 1:
self.begin_move_drag(event.button,
int(event.x_root),
int(event.y_root),
event.time)
return True
if event.button == 2:
self.begin_resize_drag(Gdk.WINDOW_EDGE_SOUTH_EAST,
event.button,
int(event.x_root),
int(event.y_root),
event.time)
return True
if event.button == 3:
self.menu.popup(None, None, None, event.button, event.time)
return True
def do_expose_event(self, event):
window = self.get_window()
(width, height) = self.get_size()
self.Gtk.Window.begin_paint_rect(width, height)
bmp = Gdk.Pixmap(None, width, height, 1)
cm = bmp.cairo_create()
cm.translate(5, 5)
cm.scale(width - 10, height -10)
cm.set_source_rgb(0, 0, 0)
cm.set_operator(cairo.OPERATOR_DEST_OUT)
cm.paint()
cm.set_operator(cairo.OPERATOR_OVER)
cm.arc(0.5, 0.5, 0.51, 0, 2 * math.pi)
cm.fill()
if not self.supports_alpha:
self.window.shape_combine_mask(bmp, 0, 0)
else:
self.window.input_shape_combine_mask(bmp, 0, 0)
cr = self.window.cairo_create()
self.draw(cr, width, height)
self.window.end_paint()
def draw(self, cr, width, height):
if self.supports_alpha:
cr.set_source_rgba(1.0, 1.0, 1.0, 0.0)
else:
cr.set_source_rgb(0.5, 0.5, 0.5)
# Draw the background
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_operator(cairo.OPERATOR_OVER)
cr.translate(5, 5)
cr.scale(width - 10 , height -10)
#Inner circle - wifi
cr.move_to(0.8, 0.5)
cr.arc(0.5, 0.5, 0.3, 0, 2 * math.pi)
wifigrad = cairo.RadialGradient(0.5, 0.5, 0.0, 0.5, 0.5, 0.3)
wifigrad.add_color_stop_rgba(0.0, 0.0, 0.0, 1.0, 1.0)
interval = 0.02
while interval < self.stats.wifi.quality:
wifigrad.add_color_stop_rgba(interval, 0.0, 0.0, 1.0, 0.8)
interval += 0.04
wifigrad.add_color_stop_rgba(interval, 0.0, 0.0, 1.0, 0.4)
interval += 0.04
wifigrad.add_color_stop_rgba(1.0, 0.0, 0.0, 1.0, 0.0)
cr.set_source(wifigrad)
cr.fill()
if self.stats.swap.free >= 0:
#Lower small bar - swap
cr.move_to(0.2, 0.5)
cr.arc_negative(0.6, 0.5, 0.4, math.pi, self.stats.swap.free * math.pi)
cr.arc(0.5, 0.5, 0.3, self.stats.swap.free * math.pi, math.pi)
cr.close_path()
cr.set_source(self.swapgradient)
cr.fill()
#Lower small outline
cr.move_to(0.2, 0.5)
cr.arc_negative(0.6, 0.5, 0.4, math.pi, 0)
cr.arc(0.5, 0.5, 0.3, 0, math.pi)
cr.close_path()
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.set_line_width(0.01)
cr.stroke()
#Lower large bar - cpu
cr.move_to(1.0, 0.5)
cr.arc(0.5, 0.5, 0.5, 0, (1.0 - self.stats.cpu.idle) * math.pi)
cr.arc_negative(0.6, 0.5, 0.4, (1.0 - self.stats.cpu.idle) * math.pi, 0)
cr.close_path()
gradient = cairo.LinearGradient(1.0, 1.0, 0.0, 0.5)
gradient.add_color_stop_rgba(0.0, 0.0, 1.0, 0.0, 0.6)
u = self.stats.cpu.user + self.stats.cpu.nice
s = self.stats.cpu.system + u
i = self.stats.cpu.irq + self.stats.cpu.softirq + \
self.stats.cpu.iowait + s
gradient.add_color_stop_rgba(u, 0.0, 1.0, 0.0, 0.8)
gradient.add_color_stop_rgba(s, 1.0, 1.0, 0.0, 0.8)
gradient.add_color_stop_rgba(i, 1.0, 0.0, 0.0, 1.0)
gradient.add_color_stop_rgba(1.0, 1.0, 0.0, 0.0, 1.0)
cr.set_source(gradient)
cr.fill()
#Lower large outline
cr.move_to(1.0, 0.5)
cr.arc(0.5, 0.5, 0.5, 0, math.pi)
cr.arc_negative(0.6, 0.5, 0.4, math.pi, 0)
cr.close_path()
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.set_line_width(0.01)
cr.stroke()
#Upper small bar - mem
cr.move_to(0.8, 0.5)
cr.arc_negative(0.4, 0.5, 0.4, 0, -self.stats.mem.used * math.pi)
cr.arc(0.5, 0.5, 0.3, -self.stats.mem.used * math.pi, 0)
cr.close_path()
cr.set_source(self.memgradient)
cr.fill()
#Upper small outline
cr.move_to(0.8, 0.5)
cr.arc_negative(0.4, 0.5, 0.4, 0, math.pi)
cr.arc(0.5, 0.5, 0.3, math.pi, 0)
cr.close_path()
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.set_line_width(0.01)
cr.stroke()
if self.stats.cpu.scale > 0.0:
#Upper large bar - cpu-scale
cr.move_to(0.0, 0.5)
cr.arc(0.4, 0.5, 0.4, math.pi, math.pi * -(1 - self.stats.cpu.scale))
cr.arc_negative(0.5, 0.5, 0.5, math.pi * -(1 - self.stats.cpu.scale),
math.pi)
cr.close_path()
cr.set_source(self.scalegradient)
cr.fill()
#Upper large outline
cr.move_to(0.0, 0.5)
cr.arc(0.4, 0.5, 0.4, math.pi, 0)
cr.arc_negative(0.5, 0.5, 0.5, 0, math.pi)
cr.close_path()
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.set_line_width(0.01)
cr.stroke()
#Clock
curtime = datetime.now()
h = float(curtime.hour)
m = float(curtime.minute)
s = float(curtime.second)
m += s / 60
h += m / 60
h = (h % 12) / 6 * math.pi
m = m / 30 * math.pi
s = s / 30 * math.pi
try:
cr.push_group()
except:
pass
cr.set_line_cap(cairo.LINE_CAP_ROUND)
cr.move_to(0.5, 0.5)
cr.line_to(0.5 + 0.3 * math.sin(h), 0.5 - 0.3 * math.cos(h))
cr.set_source_rgba(0.0, 0.0, 0.0, 0.8)
cr.set_line_width(0.075)
cr.stroke_preserve()
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.set_line_width(0.05)
cr.stroke()
cr.move_to(0.5, 0.5)
cr.line_to(0.5 + 0.35 * math.sin(m), 0.5 - 0.35 * math.cos(m))
cr.set_source_rgba(0.0, 0.0, 0.0, 0.8)
cr.set_line_width(0.065)
cr.stroke_preserve()
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.set_line_width(0.04)
cr.stroke()
cr.move_to(0.5, 0.5)
cr.line_to(0.5 + 0.4 * math.sin(s), 0.5 - 0.4 * math.cos(s))
cr.set_source_rgba(0.0, 0.0, 0.0, 0.8)
cr.set_line_width(0.055)
cr.stroke_preserve()
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.set_line_width(0.03)
cr.stroke()
cr.move_to(0.55, 0.5)
cr.arc(0.5, 0.5, 0.05, 0, 2 * math.pi)
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.fill_preserve()
cr.set_line_width(0.015)
cr.set_source_rgba(0.0, 0.0, 0.0, 1.0)
cr.stroke()
try:
cr.pop_group_to_source()
cr.paint_with_alpha(0.5)
except:
pass
def do_screen_changed(self, old_screen=None):
screen = self.get_screen()
try:
colormap = screen.get_rgba_visual()
if colormap:
self.supports_alpha = True
else:
self.supports_alpha = False
except:
colormap = screen.get_rgb_visual()
self.supports_alpha = False
if colormap:
self.set_visual(colormap)
def update(self):
self.stats.update_all()
self.do_expose_event('update')
return True
if __name__ == '__main__':
mystat = stats()
mystat.update_all()
window = Witsjet(mystat)
window.set_title('Witsjet Demo')
window.connect('delete-event', Gtk.main_quit)
window.show()
GObject.timeout_add(1000, window.update)
try:
Gtk.main()
except KeyboardInterrupt:
pass
你能帮我将它移植到 python3 吗?
编辑:我发现这个 PyGobject cairo 示例看起来很有启发性https://pygobject.readthedocs.io/en/latest/guide/cairo_integration.html
答案1
虽然我没能按原样移植上述小部件,但我还是从头开始拼凑了自己的 Python 开罗时钟。它不是sphinX
小部件的完全替代品,但它为我提供了事物运作的基本概念。我不是 Python 程序员,但我在这个项目期间学到了一些东西。它需要清理,但它可以工作。
#!/usr/bin/env python3
"""
whiteclock by https://askubuntu.com/users/81249/kenn [email protected]
Based on https://pygobject.readthedocs.io/en/latest/guide/cairo_integration.html, Wander Boessenkool's sphinX.py clock and cairo-demo/X11/cairo-demo.c and
"""
import math
from datetime import datetime
import cairo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib
FPS = 24
# drag method taken from https://github.com/s-zeid/bin/blob/main/display-transparent
def _drag_callback(window, event):
"""Called when the window is clicked on."""
window.begin_move_drag(
event.button,
int(round(event.x + window.get_window().get_root_origin()\[0\])),
int(round(event.y + window.get_window().get_root_origin()\[1\])),
event.time
)
# ticks method taken from https://codegolf.stackexchange.com/users/2381/luser-droog xclock.c
def ticks(ctx):
#t = 12
ctx.set_source_rgb(1, 1, 1)
ctx.save()
ctx.translate(100, 100)
ctx.rotate(math.pi/12)
for i in range(1, 13):
#ctx.translate(50, 50)
ctx.set_line_width(1)
for j in range(4):
ctx.rotate(math.pi/30)
#ctx.translate(50, 50)
ctx.move_to(50, 50)
ctx.rel_line_to(2, 2)
#ctx.close_path()
ctx.stroke()
ctx.set_line_width(3)
ctx.rotate(math.pi/30)
#ctx.translate(50, 50)
ctx.move_to(50, 50)
ctx.rel_line_to(2, 2)
#ctx.stroke()
#ctx.close_path()
ctx.stroke()
ctx.restore()
#based on Mael Ponchant's algorithm https://stackoverflow.com/questions/58589643/cant-show-text-in-cairomm-gtkmm-context
def face(ctx):
ctx.translate(100, 100)
#ctx.rotate(-math.pi/120)
for i in range(1, 13):
#ctx.translate(50, 50)
#ctx.move_to(40, 60)
ctx.move_to(58 * math.cos (2 * (i - 7.5) * 0.75 * math.pi / 9 + (0.75 * math.pi )) - 5, 58 * math.sin (2 * (i - 7.5) * 0.75 * math.pi / 9 + (0.75 * math.pi)) + 5);
#ctx.move_to(58 * math.cos (2 * (i - 8) * 0.75 * math.pi / 9 + (0.75 * math.pi )) - 3, 58 * math.sin (2 * (i - 8) * 0.75 * math.pi / 9 + (0.75 * math.pi)) + 5);
ctx.set_line_width(1)
ctx.select_font_face("Serif", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
ctx.set_font_size(12)
ctx.set_source_rgb(1, 1, 1)
#ctx.move_to(40, 60)
#ctx.rotate(j * - math.pi/30)
ctx.show_text(str(i))
# hands methon taken from Wander Boessenkool's sphinX.py clock
def hands(ctx):
ctx.set_source_rgba(1.0, 1.0, 1.0, 0.0)
ctx.set_operator(cairo.OPERATOR_SOURCE)
ctx.paint()
ctx.set_operator(cairo.OPERATOR_CLEAR)
ctx.set_operator(cairo.OPERATOR_OVER)
ctx.translate(50, 50)
ctx.scale(100 , 100)
curtime = datetime.now()
h = float(curtime.hour)
m = float(curtime.minute)
s = float(curtime.second)
m += s / 60
h += m / 60
h = (h % 12) / 6 * math.pi
m = m / 30 * math.pi
s = s / 30 * math.pi
ctx.set_line_cap(cairo.LINE_CAP_ROUND)
ctx.move_to(0.5, 0.5)
ctx.line_to(0.5 + 0.3 * math.sin(h), 0.5 - 0.3 * math.cos(h))
ctx.set_source_rgba(0.0, 0.0, 0.0, 0.8)
ctx.set_line_width(0.075)
ctx.stroke_preserve()
ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
ctx.set_line_width(0.05)
ctx.stroke()
ctx.move_to(0.5, 0.5)
ctx.line_to(0.5 + 0.35 * math.sin(m), 0.5 - 0.35 * math.cos(m))
ctx.set_source_rgba(0.0, 0.0, 0.0, 0.8)
ctx.set_line_width(0.065)
ctx.stroke_preserve()
ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
ctx.set_line_width(0.04)
ctx.stroke()
ctx.move_to(0.5, 0.5)
ctx.line_to(0.5 + 0.4 * math.sin(s), 0.5 - 0.4 * math.cos(s))
ctx.set_source_rgba(0.0, 0.0, 0.0, 0.8)
ctx.set_line_width(0.055)
ctx.stroke_preserve()
ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
ctx.set_line_width(0.03)
ctx.stroke()
ctx.move_to(0.55, 0.5)
ctx.arc(0.5, 0.5, 0.05, 0, 2 * math.pi)
ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
ctx.fill_preserve()
ctx.set_line_width(0.015)
ctx.set_source_rgba(0.0, 0.0, 0.0, 1.0)
ctx.stroke()
def circle(ctx):
#ctx.move_to(50, 50)
#ctx.translate(100, 100)
ctx.arc(100, 100, 75, 0, 4 * math.pi/2)
#ctx.set_source_rgb(0, 0, 0)
#ctx.set_line_width(0.04)
#ctx.stroke()
def draw(da, ctx):
#ctx.set_line_width(SIZE / 4)
ctx.set_tolerance(0.1)
#stroke_shapes(ctx, 0, 9 * SIZE)
ctx.save()
ctx.new_path()
#ctx.translate(3 * SIZE, 0)
#arc(ctx)
hands(ctx)
ctx.restore()
circle(ctx)
ticks(ctx)
face(ctx)
#hands(ctx)
#ctx.arc(50, 50, 50, 0, 4 * math.pi/2)
ctx.stroke()
# to update the screen, taken from http://bazaar.launchpad.net/~macslow/cairo-countdown/trunk/view/head:/countdown.py
def onTimeout (widget):
widget.queue_draw ()
return True
def main():
win = Gtk.Window(title="Hayriye Saati")
#win.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
#win.connect('button-press-event', buttonpress)
# Make the window draggable
screen = win.get_screen()
rgba = screen.get_rgba_visual()
win.set_visual(rgba)
win.connect("button-press-event", _drag_callback)
win.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
#win.set_type_hint (Gdk.WindowTypeHint.DOCK)
win.connect('destroy', lambda w: Gtk.main_quit())
win.set_default_size(200, 200)
win.set_app_paintable (True)
win.set_decorated (False)
win.set_skip_taskbar_hint (True)
drawingarea = Gtk.DrawingArea()
win.add(drawingarea)
drawingarea.connect('draw', draw)
timeoutId = GLib.timeout_add (1000 / FPS, onTimeout, win)
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()