-
Notifications
You must be signed in to change notification settings - Fork 0
/
switch.py
executable file
·346 lines (299 loc) · 13.5 KB
/
switch.py
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#===============================================================================
# Written by Rentouch 2012 - http://www.rentouch.ch
#===============================================================================
'''
Switch
======
Witch the switch you are able to close progs and switch between them.
Normally the switch can appear just as a close button in the upper right corner.
You can deactivate the switch button in the settings. In this case you can only
show the switch button by making a gesture. When you have a Probazaar account
you can also close progs from probazaar.ch remotely. (via PBUpdater)
'''
#kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.support import install_gobject_iteration
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import BooleanProperty
from kivy.animation import Animation
from kivy.core.window import Window
#global
from functools import partial
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop
import sqlite3
import logging
#local
#initialize logger
log = logging.getLogger('Switch')
log.setLevel(logging.INFO)
hdlr = logging.FileHandler('data/logs/log.log')
consoleHandler = logging.StreamHandler()
formatter = logging.Formatter("%(asctime)s [%(levelname)-8s] %(module)s%(lineno)-3s %(message)s")
hdlr.setFormatter(formatter)
consoleHandler.setFormatter(formatter)
log.addHandler(hdlr)
log.addHandler(consoleHandler)
log.info("*-----------Switch(Controller) started-----------*")
#load kv file
Builder.load_file('switcher.kv')
class Switcher(Widget):
'''This is the "main" class, it handels all the events. Also it displays
the close button and all the switch uix widgets.
'''
switch_open=BooleanProperty(False)
open_prog_list=[]
prog_buttons={}
def __init__(self, k_app, **kwargs):
super(Switcher, self).__init__(**kwargs)
self.k_app=k_app
#bind functions
self.bind(switch_open=self._show_hide_switch)
#remove from kv creation
self.background.remove_widget(self.background_image)
self.remove_widget(self.close_switch_button)
self.remove_widget(self.progs_layout)
self.remove_widget(self.pbase_button)
self.remove_widget(self.shutdown_button)
self.remove_widget(self.popup)
self.remove_widget(self.install_updates_buttons)
#init dbus client
self.bus = dbus.SessionBus()
#preload animations
self.close_switch_animation=Animation(y=Window.height, duration=0.25, transition="in_circ")
self.close_switch_animation.bind(on_complete=self.close_animation_step1)
#try to fetch open running progs
server=self.try_reach_dbus_PBController()
if server:
progs=server.get_open_progs(dbus_interface = 'org.PB.PBController')
for prog_id in progs:
if not prog_id:
return
self.open_prog_list.append(int(prog_id))
def prog_opened(self, prog_id, *kwargs):
'''This function gets called whenever a prog opens
If the switch is already open we add a new button (prog icon)
to the prog layout. If the switch is not already loaded we just
add the prog_id to a list. In case the switch get opened, we
know which prog is open, cause of the list.
'''
if int(prog_id) in self.open_prog_list:
return
if self.switch_open:
name=self.get_prog_info(prog_id)
path=str("../data/icons/"+str(prog_id)+".png")
prog={"path":path, "name":name, "prog_id":prog_id}
self.prog_buttons[prog_id]=Builder.template('ButtonItem', **prog)
self.prog_buttons[prog_id].bind(on_press=partial(self.open_prog, prog["prog_id"]))
self.prog_buttons[prog_id].close_prog_button.bind(on_press=partial(self.close_prog, prog["prog_id"]))
self.progs_layout.add_widget(self.prog_buttons[prog_id])
self.open_prog_list.append(int(prog_id))
def prog_closed(self, prog_id, *kwargs):
'''This function gets called whenver a prog closed.
We remove the button from the switch when it is open.
Else we just remove the prog_id from the list.
'''
if self.switch_open:
self.progs_layout.remove_widget(self.prog_buttons[prog_id])
if int(prog_id) in self.open_prog_list:
self.open_prog_list.remove(int(prog_id))
def close_prog(self, prog_id, *kwargs):
'''This function sends s signal to the PBController to close
the prog.
'''
server=self.try_reach_dbus_PBController()
if server:
try:
server.close_prog(prog_id, dbus_interface = 'org.PB.PBController')
except dbus.exceptions.DBusException:
log.exception('dbus close prog exception')
self.switch_open=False
def open_prog(self, prog_id, *kwargs):
'''This function sends a signal over DBUS to the PBController to
open a prog / switching to a open prog.
'''
server=self.try_reach_dbus_PBController()
if server:
try:
server.open_prog(prog_id, dbus_interface = 'org.PB.PBController')
except dbus.exceptions.DBusException:
log.exception('dbus open prog eception')
self.switch_open=False
def show_pbase(self, *kwargs):
'''This function gets called whenever the button PBase from the switch
gets touched. This will close the switch and call the function show_pbase
over D-Bus on PBController.
'''
server=self.try_reach_dbus_PBController()
if server:
try:
server.show_pbase(dbus_interface = 'org.PB.PBController')
except dbus.exceptions.DBusException:
log.exception('dbus show pbase exception')
self.switch_open=False
def request_shutdown(self, *kwargs):
'''This function gets called whenever the button Shutdown gets pressed
in the switch. This will show a popup which ask if you are sure to
shutdown the machine
'''
self.popup.open()
def request_installation(self, *kwargs):
'''This function displays the information for the user which should
decide if he is willing to install the updates
'''
if self.install_updates_buttons not in self.children:
self.add_widget(self.install_updates_buttons)
def install_updates(self, *kwargs):
'''This function informs PBUpdater to install all softwares
'''
server=self.try_reach_dbus_PBUpdater()
if server:
try:
server.install_updates(dbus_interface = 'org.PB.PBUpdater')
except dbus.exceptions.DBusException, e:
log.warning('PBase: DBUS Error(PBUpdater.close_prog): '+str(e))
def shutdown(self, reboot):
'''This function should inform the controller to shutdown the device.
It calls the function shutdown() on PBController session bus.
'''
self.popup.dismiss()
server=self.try_reach_dbus_PBController()
if server:
try:
server.shutdown(reboot, dbus_interface = 'org.PB.PBController')
except dbus.exceptions.DBusException, e:
log.exception('Switch: DBUS Error(PBController.shutdown): '+str(e))
def _show_hide_switch(self, wid, open_switch):
'''This function opens /show and close/hides the switch.
You shouldn't call this function. Use instead the property switch_open.
:param wid: placeholder for widget passed by bind
:param open_switch: Bool, True:show-switch
'''
if open_switch:
#stop close animation, if its running
self.close_switch_animation.stop(self.background_image)
#add widgets for open switch
self.background.add_widget(self.background_image)
self.remove_widget(self.open_switch_button)
self.add_widget(self.close_switch_button)
self.add_widget(self.progs_layout)
#fetch open progs icons
prog_icons=[]
for prog_id in self.open_prog_list:
name=self.get_prog_info(prog_id)
path=str("../data/icons/"+str(prog_id)+".png")
prog_icons.append({"path":path, "name":name, "prog_id":prog_id})
#add open prog icons to layout
for prog in prog_icons:
self.prog_buttons[prog_id]=Builder.template('ButtonItem', **prog)
self.prog_buttons[prog_id].bind(on_press=partial(self.open_prog, prog["prog_id"]))
self.prog_buttons[prog_id].close_prog_button.bind(on_press=partial(self.close_prog, prog["prog_id"]))
self.progs_layout.add_widget(self.prog_buttons[prog_id])
#animate open switch
self.open_switch_animation=Animation(y=Window.height-150, duration=0.25, transition="out_circ")
self.open_switch_animation.bind(on_complete=self.open_animation_step1)
open_switch_animation_progs=Animation(y=Window.height-123, duration=0.25, transition="out_circ")
self.open_switch_animation.start(self.background_image)
open_switch_animation_progs.start(self.progs_layout)
else:
#stop open animation
self.open_switch_animation.stop(self.background_image)
#animate close switch
self.close_switch_animation.start(self.background_image)
self.close_switch_animation.start(self.progs_layout)
#remove widgets which belongs to the open switch
self.add_widget(self.open_switch_button)
self.remove_widget(self.close_switch_button)
self.progs_layout.clear_widgets()
self.remove_widget(self.pbase_button)
self.remove_widget(self.shutdown_button)
def open_animation_step1(self, *kwargs):
'''Internal function. Gets called as soon the open animation finshed
'''
self.add_widget(self.pbase_button)
self.add_widget(self.shutdown_button)
def close_animation_step1(self, *kwargs):
'''Internal function. Gets called as soon the close animation finshed
'''
self.background.remove_widget(self.background_image)
self.remove_widget(self.progs_layout)
def try_reach_dbus_PBController(self):
'''Int this function we try to reach the PBController via dbus.
:return server: the server instance from dbus.
'''
try:
server = self.bus.get_object('org.PB.PBController', '/PBController')
except dbus.exceptions.DBusException:
log.exception('try reaching dbus failed:')
return False
return server
def try_reach_dbus_PBUpdater(self):
'''Int this function we try to reach the PBController via dbus.
:return server: the server instance from dbus.
'''
try:
server = self.bus.get_object('org.PB.PBUpdater', '/PBUpdater')
except dbus.exceptions.DBusException:
log.exception('try reaching dbus PBupdater failed:')
return False
return server
def get_prog_info(self, prog_id):
'''This function gets all the informations from the DB.
:param prog_id: id of the prog
:return name: name
'''
DB_connection = sqlite3.connect("../PBase/data/database.sqlite")
DB_cursor = DB_connection.cursor()
DB_cursor.execute("SELECT name FROM progs WHERE id = '%i'" %prog_id)
DB_connection.commit()
for row in DB_cursor: name=row[0]
DB_connection.close()
return name
class DBusServer(dbus.service.Object):
'''DBus server from switch.
Reachable under session bus: org.PB.PBSwitch (/PBSwitch)
'''
def __init__(self, switch):
'''Initialize the session bus under:
org.PB.PBase
:param pbase: PBase object
'''
self.switch=switch
bus_name = dbus.service.BusName('org.PB.PBSwitch', bus=dbus.SessionBus())
dbus.service.Object.__init__(self, bus_name, '/PBSwitch')
@dbus.service.method('org.PB.PBSwitch')
def prog_opened(self, prog_id):
'''This function gets called whenever a prog got opened.
(normally from PBController)
:param prog_id: id of prog
'''
Clock.schedule_once(partial(self.switch.prog_opened, prog_id), 0)
return
@dbus.service.method('org.PB.PBSwitch')
def prog_closed(self, prog_id):
'''This function gets called whenever a prog got closed.
(normally from PBController)
:param prog_id: id of prog
'''
Clock.schedule_once(partial(self.switch.prog_closed, prog_id), 0)
return
@dbus.service.method('org.PB.PBSwitch')
def request_installation(self):
'''This function gets called when the PBUpdater requests installing updaes
'''
Clock.schedule_once(self.switch.request_installation, 0)
return
DBusGMainLoop(set_as_default=True)
class SwitchApp(App):
title="PBSwitch"
def build(self):
install_gobject_iteration()
switch=Switcher(k_app=self)
DBusServer(switch=switch)
return switch
if __name__ == '__main__':
SwitchApp().run()