-
Notifications
You must be signed in to change notification settings - Fork 14
/
kano-signal
executable file
·217 lines (178 loc) · 6.98 KB
/
kano-signal
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
#!/usr/bin/env python
# kano-signal
#
# Copyright (C) 2014-2016 Kano Computing Ltd.
# License: http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2
#
# Sends a signal to a Kano app (save, load, share, make, launch-share)
#
# This script is invoked by the Kano Keyboard hotkeys (xbindkeys in Kano Desktop).
# If you call it from a shell or command line, make sure you export DISPLAY
# to point to your desktop.
#
# It is also invoked from Kano World when launching a Share.
# The chromium hook connected to kano-profile.apps module,
# calls this script with "launch-share <share_filename>",
# which will open a share on the currently running app by sending a signal.
#
# Exit code 0 means the signal could be delivered, any other value means error,
# in which case you should launch the app.
# NB this has been converted line by line from bash. Needs cleanup
#
import sys
import os
import stat
from optparse import OptionParser
# verbose flag for debugging on the console
verbose=False
dry_run=False
# pipe name to send javascript code
pipe_name = "/tmp/webapp.pipe"
def is_running(cmd):
rc = os.system('xwininfo -tree -root | grep -i "{}" > /dev/null 2>&1'.format(cmd))
return rc == 0
def set_focus(app, verbose=False):
'''
Sets user input focus to the app name.
'''
app_titles_dict = {
'make-minecraft': 'Make Minecraft',
'make-pong': 'Make Pong',
'sonicpi': 'Sonic Pi',
'make-light': 'Make Light',
'kano-draw': 'Art'
}
if app in app_titles_dict:
# switch user focus back to the game app.
cmd = 'wmctrl -a "{}"'.format(app_titles_dict[app])
if verbose:
print cmd
rc = os.system(cmd)
if rc != 0:
# delay loading for performance reasons
from kano.logging import logger
logger.error("error raising window {}".format(app_titles_dict[app]))
return (rc==0)
return False
if __name__ == '__main__':
app = None
share_filename=None
usage_help='Usage: kano-signal < save | load | share | make | ' \
'launch-share <share_filename> > [ --verbose ] [ --dry-run ]'
# Collect arguments, first one is the signal name, optional "verbose"
parser = OptionParser()
parser.add_option('-v', '--verbose',
action='store_true', dest='verbose', default=False,
help='Be verbose', metavar="FILE")
parser.add_option('-d', '--dry-run',
action='store_true', dest='dry_run', default=False,
help='Only explain what would be done', metavar="FILE")
(options, args) = parser.parse_args()
verbose=options.verbose
if not len(args):
print usage_help
sys.exit(1)
else:
# sanity check
signal=args[0]
if signal == 'launch-share':
if len(args) < 2:
print 'Please specify a Kano World share file to open'
sys.exit(1)
else:
share_filename=args[1]
# Prepare signal based on arguments received
if signal == "save":
jscmd = "Signal.save()"
elif signal == "load":
jscmd = "Signal.load()"
elif signal == "share":
jscmd = "Signal.share()"
elif signal == "make":
jscmd = "Signal.make()"
elif signal == "launch-share":
# dbus doesn't like '-' so we use '_'
signal = "load_share"
# Make sure the kano world share creation was downloaded
if not os.path.exists(share_filename):
print "Please specify a valid share file to 'launch-share' : {}".format(share_filename)
sys.exit(1)
# Command to open a share on top of your current workspace
jscmd = "Signal.load(\"{}\")".format(share_filename)
else:
print usage_help
sys.exit(1)
if verbose:
print 'Receiving signal: {} - share_filename: {}'.format(signal, share_filename)
# TODO: We need to cover the rest of Kano apps (see kano-profile/rules)
for APP in ["make-pong", "make-minecraft", "make-music", "make-light", "kano-draw"]:
if is_running(APP):
app = APP
if app == "make-music":
# Make Music is registered as "sonicpi" in dbus
app = "sonicpi"
break
if app is None:
if verbose:
print "no valid app is running, returning error"
sys.exit(1)
else:
if verbose:
print 'Currently running app found: {}'.format(app)
# if there is no pipe, webkit is not running
fifo_exists = False
try:
if stat.S_ISFIFO(os.stat(pipe_name).st_mode):
fifo_exists = True
except:
# ignore exception when fifo does not exist
pass
# Set user input focus to the app receiving the load_share signal.
# Needs to happen before sending the signal, because DBus is synchronous
# - a confirmation message box will block kano-signal until the user confirms.
if signal == 'load_share':
if verbose:
print 'setting focus to app', app
set_focus(app)
if fifo_exists:
# This means we are talking to Minecraft and Pong,
# because kano-blocks webkit talks receives signals through the pipe.
pipe = open(pipe_name, "w")
# FIXME: This is a special case for Kano Draw signal,
# temporary solution is to send a javasript code to redirect it to downloaded creation.
if app=='kano-draw':
jscmd='window.location="http://localhost:8000/localLoad/{}"'.format(share_filename.strip('/'))
if verbose:
print 'Sending app {} a webkit signal "{}"'.format(app, jscmd)
if not dry_run:
print >> pipe, jscmd
pipe.close()
else:
# Pass on event to dbus
def do_send_dbus(app, signal, share_filename=None):
import dbus
app = app.replace('-', '_') # DBus doesn't behave well with '-'
session_bus = dbus.SessionBus()
proxy = session_bus.get_object("me.kano.{}".format(app), "/me/kano/{}".format(app))
sig_pfn = proxy.get_dbus_method(signal, dbus_interface="me.kano.{}.Actions".format(app))
if share_filename:
sig_pfn(share_filename)
else:
sig_pfn()
if verbose:
print 'Sending dbus signal {} to app {}, filename {}'.format(signal, app, share_filename)
if not dry_run:
try:
# In the case of launch-share, we send the share file as an extra string parameter on the signal
if signal == "load_share":
do_send_dbus(app, signal, share_filename)
else:
do_send_dbus(app, signal)
except:
# make sure to return 1 on error
import traceback
from kano.logging import logger
logger.error('Unexpected error when sending dbus signal.\n{}'
.format(traceback.format_exc()))
sys.exit(1)
sys.exit(0)