1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
|
#!/usr/bin/env python
#----------------------------------------------------
# Author: ZaB|SHC|@irc.freenode.net
#
# License: Beerware
#----------------------------------------------------
"""
shutdown script for Openbox with configurable buttons and actions
needs pygtk for gui
"""
# standard stuff
import os
import re
import sys
# gui modules
try:
import gtk
import pygtk
except ImportError:
sys.stderr.write('pygtk is needed for using this script')
sys.exit(1)
if sys.version_info < (2, 5, 0):
sys.stderr.write('Python 2.5.0 or higher is needed')
sys.exit(1)
# a simple parser for the configuration
class ConfigParser(dict):
"""
ConfigParser(file) -> dict
reads file and creates dict object containing corresponding
configuration
"""
def __init__(self, filename):
self._section_match_regexp = re.compile(r'\[(\w+)\]')
self._key_val_match_regexp = re.compile(r'\s*=\s*')
self._comment_remov_regexp = re.compile(r'#.*')
try:
config_handle = open(filename, 'r')
except IOError:
sys.stderr.write('Could not read %s. Aborting ...\n' % filename)
sys.exit(1)
linecount = 0
for line in config_handle.readlines():
linecount += 1
line = self._comment_remov_regexp.sub('', line.strip())
if len(line) == 0:
continue
if self._section_match_regexp.match(line):
section = self._section_match_regexp.match(line).groups()[0]
self[section] = {}
continue
try:
(key, value) = self._key_val_match_regexp.split(line)
except ValueError:
sys.stderr.write('Syntax error in line %d of %s.' % (linecount,
filename))
sys.exit(1)
if key == 'command' and not key in self[section]:
self[section][key] = [value]
continue
if key in self[section] and key == 'command':
self[section][key].append(value)
else:
self[section][key] = value
def check(self):
"""
checks if configuration is complete
"""
for section in self:
for needed_key in ['command', 'image', 'info_text', 'label']:
if not needed_key in self[section]:
sys.stderr.write('Missing option %s in %s.' % (needed_key, section))
sys.exit(1)
# the main class for this script
class OpenBoxShutdown(object):
"""
main class for this script
reads configuration and displays buttons as requested
on click, the specified actions are made
"""
def __init__(self, basedir):
self._config = ConfigParser(os.path.join(basedir, 'openbox-shutdown.conf'))
self._config.check()
# button box on top for the action buttons
button_box = gtk.HButtonBox()
for key in self._config:
button_box.pack_start(self._create_button(key,
self._config[key]['label'],
self._config[key]['info_text'],
self._config[key]['image']))
button_box.show()
# create cancel button
cancel_button = gtk.Button(stock = gtk.STOCK_CANCEL)
cancel_button.connect('clicked', self._click_callback, 'cancel')
cancel_button.show()
# label widget for small hints
self._label = gtk.Label()
self._label.show()
# frame widget to contain label
frame = gtk.Frame()
frame.set_shadow_type(gtk.SHADOW_NONE)
frame.add(self._label)
frame.show()
# area containing hints and cancel button
action_area = gtk.HBox()
action_area.pack_end(cancel_button, expand=False)
action_area.pack_end(frame)
action_area.show()
# box containing button box and action area
vbox = gtk.VBox()
vbox.pack_start(button_box)
vbox.pack_end(action_area)
vbox.show()
# the main window with all widgets
# always on top and on all desktops
window = gtk.Window()
window.set_position('center')
window.set_decorated(False)
window.stick()
window.set_keep_above(True)
window.set_skip_pager_hint(True)
window.set_skip_taskbar_hint(True)
window.add(vbox)
window.show()
# give control to gtk
gtk.main()
def _click_callback(self, event, action):
"""
_click_callback(event, action)
executes commands on button click
"""
gtk.main_quit()
if action == 'cancel':
sys.exit(0)
for command in self._config[action]['command']:
os.system(command)
def _create_button(self, key, label_text, info_text, image_file):
"""
_create_button(key, label, info, image) -> button
creates a button widget with key (used for handling actions),
a label for the button, a small text as hint and an image
"""
button = gtk.Button()
if label_text != 'None':
button.set_label(label_text)
if image_file != 'None':
button.set_image(self._create_image(image_file))
button.set_image_position(gtk.POS_TOP)
button.connect('clicked', self._click_callback, key)
button.connect('leave', lambda event: self._label.set_text(''))
button.connect('enter', self._set_label, info_text)
button.show()
return button
def _create_image(self, image_file):
"""
_create_image(image) -> image
creates an image widget from the specified file
"""
image = gtk.Image()
image.set_from_file(image_file)
return image
def _set_label(self, event, info_text):
"""
_set_label(event, info_text)
set label on entering the widget
"""
if info_text != 'None':
self._label.set_markup('<span size="smaller">%s</span>' % info_text)
# start the script if called standalone
if __name__ == '__main__':
# get the real path for the configuration file
conf_path = os.path.realpath(os.path.dirname(os.readlink(__file__))) \
if os.path.islink(__file__) \
else os.path.realpath(os.path.dirname(__file__))
shutdown = OpenBoxShutdown(conf_path)
|