Skip to content

Commit a9767b6

Browse files
committed
Automatic commit Thu Nov 26 07:40:12 PM EET 2020
1 parent 1283b33 commit a9767b6

File tree

2 files changed

+317
-0
lines changed

2 files changed

+317
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
'''
4+
**************************************************************
5+
* Description: A Gtk GUI with buttons bound to commands. *
6+
* It can be used as a logoff/shutdown interface *
7+
* for windows managers that lack one. *
8+
* *
9+
* Licence : Public Domain. *
10+
* *
11+
* Author : Antonios Tsolis (2016) *
12+
**************************************************************
13+
'''
14+
import os
15+
import gi
16+
gi.require_version("Gtk", "3.0")
17+
from gi.repository import Gtk
18+
from collections import OrderedDict
19+
20+
21+
# We define a get_resource_path function to help us find
22+
# the path of our icons in the system:
23+
def get_resource_path(rel_path):
24+
dir_of_py_file = os.path.dirname(__file__)
25+
rel_path_to_resource = os.path.join(dir_of_py_file, rel_path)
26+
abs_path_to_resource = os.path.abspath(rel_path_to_resource)
27+
return abs_path_to_resource
28+
29+
30+
class SystemDialog (Gtk.Window):
31+
def __init__(self):
32+
super(SystemDialog, self).__init__()
33+
34+
# We define a dictionary with button label-command key-value
35+
# pairs. The reason we use an OrderedDict is that in python
36+
# the simple dict does not keep the order of the keys and we
37+
# do not want our buttons to appear in arbitrary order.
38+
# Keep in mind that you have to edit the commands according
39+
# to your system and your needs.
40+
self.actions = OrderedDict([
41+
("Cancel", None),
42+
("Lock", "slock &"),
43+
("Restart WM", "sudo killall dwm &"),
44+
("Sleep", "sudo pm-suspend &"),
45+
("Hibernate", "sudo pm-hibernate &"),
46+
("Sleep + Hibernate", "sudo pm-suspend-hybrid &"),
47+
("Logout", "sudo killall X &"),
48+
("Reboot", "sudo reboot &"),
49+
("Shutdown", "sudo poweroff &")])
50+
51+
self.buttons = {}
52+
53+
# We make our window undecorated, centered on screen
54+
# and we keep it on top.
55+
self.set_border_width(0)
56+
self.set_decorated(False)
57+
self.set_position(Gtk.WindowPosition.CENTER)
58+
self.set_keep_above(True)
59+
60+
# We define one vertical box and three horizontal boxes.
61+
# The vertical box will contain and align vertical the 3
62+
# horizontal boxes while each horizontal box while keep and align
63+
# horizontally 3 of our buttons. Therefore, in the end, we will
64+
# have a nice 3x3 buttons square,
65+
self.vbox = Gtk.VBox(homogeneous=True, spacing=5)
66+
self.hboxes = [Gtk.HBox(homogeneous=True, spacing=5), Gtk.HBox(homogeneous=True, spacing=5), Gtk.HBox(homogeneous=True, spacing=5)]
67+
68+
# We create our buttons, put some icons and labels on them,
69+
# ‘connect’ their click event with a callback handler and pack
70+
# them inside the empty horizontal boxes (3 buttons in each
71+
# horizontal box).
72+
c = 0
73+
boxIndex = 0
74+
for label in self.actions.keys():
75+
self.buttons[label] = Gtk.Button(label=label)
76+
ico = Gtk.Image()
77+
ico.set_from_file(get_resource_path("images/"+label+".png"))
78+
self.buttons[label].set_image(ico)
79+
self.buttons[label].set_image_position(Gtk.PositionType.TOP)
80+
self.hboxes[boxIndex].pack_start(self.buttons[label], True, True, 0)
81+
self.buttons[label].connect('clicked', self.callback, label)
82+
c += 1
83+
if not (c % 3):
84+
boxIndex += 1
85+
86+
# We pack the horizontal boxes inside the vertical box and
87+
# the vertical box inside our window. Do not forget to show
88+
# all our widgets with self.show_all().
89+
for hbox in self.hboxes:
90+
self.vbox.pack_start(hbox, True, True, 0)
91+
self.add(self.vbox)
92+
self.show_all()
93+
94+
# If our window is deleted/destroyed call self.callback (to exit)
95+
self.connect("delete-event", self.callback)
96+
# If a key is pressed call self.key_press_event
97+
self.connect("key-press-event", self.key_press_event)
98+
99+
# This is the our keyboard callback/event handler function.
100+
# If the user has pressed Escape, we quit.
101+
def key_press_event(self, widget=None, event=None):
102+
keyval = event.keyval
103+
keyval_name = Gtk.gdk.keyval_name(keyval)
104+
# state = event.state
105+
# ctrl = (state & Gtk.gdk.CONTROL_MASK)
106+
if keyval_name == "Escape":
107+
Gtk.main_quit()
108+
return False
109+
110+
# This is the our generic callback function
111+
def callback(self, widget=None, data=None):
112+
if (data is not None and
113+
data in self.actions and
114+
self.actions[data] is not None):
115+
os.system(self.actions[data])
116+
Gtk.main_quit()
117+
118+
119+
if __name__ == "__main__":
120+
SystemDialog()
121+
Gtk.main()
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
'''
4+
**************************************************************
5+
* Description: A transparent gtk GUI with buttons bound to *
6+
* commands. It can be used as a logoff/shutdown *
7+
* manager for windows managers that lack one. *
8+
* *
9+
* Licence : Public Domain. *
10+
* *
11+
* Author : Antonios Tsolis (2016) *
12+
**************************************************************
13+
'''
14+
15+
import os
16+
import gi
17+
import cairo
18+
from math import pi
19+
gi.require_version("Gtk", "3.0")
20+
gi.require_version('Gdk', '3.0')
21+
from gi.repository import Gtk
22+
from gi.repository import Gdk
23+
from collections import OrderedDict
24+
25+
FULL_SCREEN = False
26+
27+
28+
# We define a get_resource_path function to help us find
29+
# the path of our icons in the system:
30+
def get_resource_path(rel_path):
31+
dir_of_py_file = os.path.dirname(__file__)
32+
rel_path_to_resource = os.path.join(dir_of_py_file, rel_path)
33+
abs_path_to_resource = os.path.abspath(rel_path_to_resource)
34+
return abs_path_to_resource
35+
36+
37+
class SystemDialog (Gtk.Window):
38+
def __init__(self):
39+
super(SystemDialog, self).__init__()
40+
41+
# We define a dictionary with button label-command key-value
42+
# pairs. The reason we use an OrderedDict is that in python
43+
# the simple dict does not keep the order of the keys and we
44+
# do not want our buttons to appear in arbitrary order.
45+
# Keep in mind that you have to edit the commands according
46+
# to your system and your needs.
47+
self.actions = OrderedDict([
48+
("Cancel", None),
49+
("Lock", "slock &"),
50+
("Restart WM", "sudo killall dwm &"),
51+
("Sleep", "sudo pm-suspend &"),
52+
("Hibernate", "sudo pm-hibernate &"),
53+
("Sleep + Hibernate", "sudo pm-suspend-hybrid &"),
54+
("Logout", "sudo killall X &"),
55+
("Reboot", "sudo reboot &"),
56+
("Shutdown", "sudo poweroff &")])
57+
58+
# We need some small vboxes to align vertically each icon with
59+
# its label. Οur clickable "buttons" will be the event_boxes which
60+
# will contain the small_vboxes.
61+
self.small_vboxes = {}
62+
self.event_boxes = {}
63+
self.labels = {}
64+
65+
# If the system supports it, we will use an rgba visual
66+
# (i.e. one with an alpha channel).
67+
# Note: you need a compositor manager, like compton or xcompmgr
68+
# for example, in order for transperancy to work.
69+
screen = self.get_screen()
70+
visual = screen.get_rgba_visual()
71+
if visual and screen.is_composited():
72+
self.set_visual(visual)
73+
74+
# We make our window undecorated, paintable
75+
# and we keep it on top.
76+
self.set_decorated(False)
77+
self.set_keep_above(True)
78+
self.set_app_paintable(True)
79+
80+
display = Gdk.Display.get_default()
81+
monitor = display.get_primary_monitor()
82+
geometry = monitor.get_geometry()
83+
scale_factor = monitor.get_scale_factor()
84+
screen_width = scale_factor * geometry.width
85+
screen_height = scale_factor * geometry.height
86+
87+
# Some more settings, mostly for the fullscreen option. The function
88+
# set_border_width sets the size of the outer margin. Adjust it to
89+
# your liking.
90+
if FULL_SCREEN:
91+
self.set_border_width(150)
92+
self.set_size_request(screen_width, screen_height)
93+
self.set_position(Gtk.WindowPosition.CENTER)
94+
else:
95+
self.set_border_width(5)
96+
97+
# We define one vertical box and three horizontal boxes.
98+
# The vertical box will contain and align vertical the 3
99+
# horizontal boxes while each horizontal box while keep and align
100+
# horizontally 3 of our buttons. Therefore, in the end, we will
101+
# have a nice 3x3 buttons square
102+
self.vbox = Gtk.VBox(homogeneous=True, spacing=20)
103+
self.hboxes = [Gtk.HBox(homogeneous=True, spacing=5), Gtk.HBox(homogeneous=True, spacing=5), Gtk.HBox(homogeneous=True, spacing=5)]
104+
105+
# Now, we are ready to create our "buttons". We load each icon and
106+
# we pack/align it vertically with its label inside a small_vbox.
107+
# We add each of the small_vboxes to an event_box. We connect their
108+
# click with a callback event handler and we pack them inside the
109+
# empty horizontal boxes (3 "buttons" in each horizontal box).
110+
# Finally, to make our "buttons" transparent, we have to connect
111+
# their draw event with our self.draw function and to set them
112+
# as paintable.
113+
c = 0
114+
boxIndex = 0
115+
for key in self.actions.keys():
116+
# Load image
117+
ico = Gtk.Image()
118+
ico.set_from_file(get_resource_path("images/"+key+".png"))
119+
# Load label
120+
self.labels[key] = Gtk.Label(label=key)
121+
#self.labels[key].override_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(1, 1, 1, 1))
122+
# Pack/align image and label vertically
123+
self.small_vboxes[key] = Gtk.VBox(homogeneous=False, spacing=3)
124+
self.small_vboxes[key].pack_start(ico, 0, 1, 0)
125+
self.small_vboxes[key].pack_start(self.labels[key], True, True, 0)
126+
# Create transparent "buttons" (event_boxes)
127+
self.event_boxes[key] = Gtk.EventBox()
128+
self.event_boxes[key].add(self.small_vboxes[key])
129+
self.event_boxes[key].connect('button-release-event',
130+
self.callback, key)
131+
self.event_boxes[key].connect('draw', self.draw)
132+
self.event_boxes[key].set_app_paintable(True)
133+
# Pack/align up to 3 "buttons" (event_boxes) horizontally
134+
self.hboxes[boxIndex].pack_start((self.event_boxes[key]), True, True, 0)
135+
c += 1
136+
if not (c % 3):
137+
boxIndex += 1
138+
139+
# And now, let's pack the horizontal boxes inside the vertical box and
140+
# the vertical box inside our window. Do not forget to show all our
141+
# widgets with self.show_all()
142+
for hbox in self.hboxes:
143+
self.vbox.pack_start(hbox, True, True, 0)
144+
self.add(self.vbox)
145+
self.show_all()
146+
147+
# Finally, we connect some events for our window with
148+
# their callback handlers:
149+
# For our window to be transparent
150+
self.connect('draw', self.draw)
151+
# If our window is destroyed, call self.callback (to exit)
152+
self.connect("delete-event", self.callback)
153+
# If a key is pressed, call self.key_press_event
154+
self.connect("key-press-event", self.key_press_event)
155+
156+
# If our window is not fullscreen, we can move it where we want it.
157+
# Let's put it on the bottom right corner of the screen.
158+
if not FULL_SCREEN:
159+
w, h = self.get_size()
160+
self.move(screen_width - w, screen_height - h - 40)
161+
162+
# This is the function where the magic of transparency happens. Using
163+
# the function set_source_rgba(r, g, b, a) you can set the color and the
164+
# opacity of our window.
165+
def draw(self, widget, event):
166+
cr = widget.get_window().cairo_create()
167+
cr.set_source_rgba(0, 0, 0, 0.65)
168+
cr.set_operator(cairo.OPERATOR_SOURCE)
169+
cr.paint()
170+
cr.set_operator(cairo.OPERATOR_OVER)
171+
return False
172+
173+
# This is the our keyboard callback/event handler function.
174+
# If the user has pressed Escape, we quit.
175+
def key_press_event(self, widget=None, event=None):
176+
keyval = event.keyval
177+
keyval_name = Gdk.keyval_name(keyval)
178+
# state = event.state
179+
# ctrl = (state & Gdk.ModifierType.CONTROL_MASK)
180+
if keyval_name == "Escape":
181+
Gtk.main_quit()
182+
return False
183+
184+
# This is the our generic callback function
185+
def callback(self, widget=None, event=None, data=None):
186+
if (data is not None and
187+
data in self.actions and
188+
self.actions[data] is not None and
189+
event.button == 1): # left click
190+
os.system(self.actions[data])
191+
Gtk.main_quit()
192+
193+
194+
if __name__ == "__main__":
195+
SystemDialog()
196+
Gtk.main()

0 commit comments

Comments
 (0)