Logging sms/dial; logging device info; added Ctrl+r; fixing a bug with shutdown/settings
[gc-dialer] / src / hildonize.py
1 #!/usr/bin/env python
2
3 """
4 Open Issues
5         @bug not all of a message is shown
6         @bug Buttons are too small
7 """
8
9
10 import gobject
11 import gtk
12 import dbus
13
14
15 class _NullHildonModule(object):
16         pass
17
18
19 try:
20         import hildon as _hildon
21         hildon  = _hildon # Dumb but gets around pyflakiness
22 except (ImportError, OSError):
23         hildon = _NullHildonModule
24
25
26 IS_HILDON_SUPPORTED = hildon is not _NullHildonModule
27
28
29 class _NullHildonProgram(object):
30
31         def add_window(self, window):
32                 pass
33
34
35 def _hildon_get_app_class():
36         return hildon.Program
37
38
39 def _null_get_app_class():
40         return _NullHildonProgram
41
42
43 try:
44         hildon.Program
45         get_app_class = _hildon_get_app_class
46 except AttributeError:
47         get_app_class = _null_get_app_class
48
49
50 def _hildon_set_application_title(window, title):
51         pass
52
53
54 def _null_set_application_title(window, title):
55         window.set_title(title)
56
57
58 if IS_HILDON_SUPPORTED:
59         set_application_title = _hildon_set_application_title
60 else:
61         set_application_title = _null_set_application_title
62
63
64 def _fremantle_hildonize_window(app, window):
65         oldWindow = window
66         newWindow = hildon.StackableWindow()
67         oldWindow.get_child().reparent(newWindow)
68         app.add_window(newWindow)
69         return newWindow
70
71
72 def _hildon_hildonize_window(app, window):
73         oldWindow = window
74         newWindow = hildon.Window()
75         oldWindow.get_child().reparent(newWindow)
76         app.add_window(newWindow)
77         return newWindow
78
79
80 def _null_hildonize_window(app, window):
81         return window
82
83
84 try:
85         hildon.StackableWindow
86         hildonize_window = _fremantle_hildonize_window
87 except AttributeError:
88         try:
89                 hildon.Window
90                 hildonize_window = _hildon_hildonize_window
91         except AttributeError:
92                 hildonize_window = _null_hildonize_window
93
94
95 def _fremantle_hildonize_menu(window, gtkMenu, buttons):
96         appMenu = hildon.AppMenu()
97         for button in buttons:
98                 appMenu.append(button)
99         window.set_app_menu(appMenu)
100         gtkMenu.get_parent().remove(gtkMenu)
101         return appMenu
102
103
104 def _hildon_hildonize_menu(window, gtkMenu, ignoredButtons):
105         hildonMenu = gtk.Menu()
106         for child in gtkMenu.get_children():
107                 child.reparent(hildonMenu)
108         window.set_menu(hildonMenu)
109         gtkMenu.destroy()
110         return hildonMenu
111
112
113 def _null_hildonize_menu(window, gtkMenu, ignoredButtons):
114         return gtkMenu
115
116
117 try:
118         hildon.AppMenu
119         GTK_MENU_USED = False
120         IS_FREMANTLE_SUPPORTED = True
121         hildonize_menu = _fremantle_hildonize_menu
122 except AttributeError:
123         GTK_MENU_USED = True
124         IS_FREMANTLE_SUPPORTED = False
125         if IS_HILDON_SUPPORTED:
126                 hildonize_menu = _hildon_hildonize_menu
127         else:
128                 hildonize_menu = _null_hildonize_menu
129
130
131 def _hildon_set_button_auto_selectable(button):
132         button.set_theme_size(hildon.HILDON_SIZE_AUTO_HEIGHT)
133
134
135 def _null_set_button_auto_selectable(button):
136         pass
137
138
139 try:
140         hildon.HILDON_SIZE_AUTO_HEIGHT
141         gtk.Button.set_theme_size
142         set_button_auto_selectable = _hildon_set_button_auto_selectable
143 except AttributeError:
144         set_button_auto_selectable = _null_set_button_auto_selectable
145
146
147 def _hildon_set_button_finger_selectable(button):
148         button.set_theme_size(hildon.HILDON_SIZE_FINGER_HEIGHT)
149
150
151 def _null_set_button_finger_selectable(button):
152         pass
153
154
155 try:
156         hildon.HILDON_SIZE_FINGER_HEIGHT
157         gtk.Button.set_theme_size
158         set_button_finger_selectable = _hildon_set_button_finger_selectable
159 except AttributeError:
160         set_button_finger_selectable = _null_set_button_finger_selectable
161
162
163 def _hildon_set_button_thumb_selectable(button):
164         button.set_theme_size(hildon.HILDON_SIZE_THUMB_HEIGHT)
165
166
167 def _null_set_button_thumb_selectable(button):
168         pass
169
170
171 try:
172         hildon.HILDON_SIZE_THUMB_HEIGHT
173         gtk.Button.set_theme_size
174         set_button_thumb_selectable = _hildon_set_button_thumb_selectable
175 except AttributeError:
176         set_button_thumb_selectable = _null_set_button_thumb_selectable
177
178
179 def _hildon_set_cell_thumb_selectable(renderer):
180         renderer.set_property("scale", 1.5)
181
182
183 def _null_set_cell_thumb_selectable(renderer):
184         pass
185
186
187 if IS_HILDON_SUPPORTED:
188         set_cell_thumb_selectable = _hildon_set_cell_thumb_selectable
189 else:
190         set_cell_thumb_selectable = _null_set_cell_thumb_selectable
191
192
193 def _hildon_set_pix_cell_thumb_selectable(renderer):
194         renderer.set_property("stock-size", 48)
195
196
197 def _null_set_pix_cell_thumb_selectable(renderer):
198         pass
199
200
201 if IS_HILDON_SUPPORTED:
202         set_pix_cell_thumb_selectable = _hildon_set_pix_cell_thumb_selectable
203 else:
204         set_pix_cell_thumb_selectable = _null_set_pix_cell_thumb_selectable
205
206
207 def _fremantle_show_information_banner(parent, message):
208         hildon.hildon_banner_show_information(parent, "", message)
209
210
211 def _hildon_show_information_banner(parent, message):
212         hildon.hildon_banner_show_information(parent, None, message)
213
214
215 def _null_show_information_banner(parent, message):
216         pass
217
218
219 if IS_FREMANTLE_SUPPORTED:
220         show_information_banner = _fremantle_show_information_banner
221 else:
222         try:
223                 hildon.hildon_banner_show_information
224                 show_information_banner = _hildon_show_information_banner
225         except AttributeError:
226                 show_information_banner = _null_show_information_banner
227
228
229 def _fremantle_show_busy_banner_start(parent, message):
230         hildon.hildon_gtk_window_set_progress_indicator(parent, True)
231         return parent
232
233
234 def _fremantle_show_busy_banner_end(banner):
235         hildon.hildon_gtk_window_set_progress_indicator(banner, False)
236
237
238 def _hildon_show_busy_banner_start(parent, message):
239         return hildon.hildon_banner_show_animation(parent, None, message)
240
241
242 def _hildon_show_busy_banner_end(banner):
243         banner.destroy()
244
245
246 def _null_show_busy_banner_start(parent, message):
247         return None
248
249
250 def _null_show_busy_banner_end(banner):
251         assert banner is None
252
253
254 try:
255         hildon.hildon_gtk_window_set_progress_indicator
256         show_busy_banner_start = _fremantle_show_busy_banner_start
257         show_busy_banner_end = _fremantle_show_busy_banner_end
258 except AttributeError:
259         try:
260                 hildon.hildon_banner_show_animation
261                 show_busy_banner_start = _hildon_show_busy_banner_start
262                 show_busy_banner_end = _hildon_show_busy_banner_end
263         except AttributeError:
264                 show_busy_banner_start = _null_show_busy_banner_start
265                 show_busy_banner_end = _null_show_busy_banner_end
266
267
268 def _hildon_hildonize_text_entry(textEntry):
269         textEntry.set_property('hildon-input-mode', 7)
270
271
272 def _null_hildonize_text_entry(textEntry):
273         pass
274
275
276 if IS_HILDON_SUPPORTED:
277         hildonize_text_entry = _hildon_hildonize_text_entry
278 else:
279         hildonize_text_entry = _null_hildonize_text_entry
280
281
282 def _hildon_mark_window_rotatable(window):
283         # gtk documentation is unclear whether this does a "=" or a "|="
284         window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT)
285
286
287 def _null_mark_window_rotatable(window):
288         pass
289
290
291 try:
292         hildon.HILDON_PORTRAIT_MODE_SUPPORT
293         mark_window_rotatable = _hildon_mark_window_rotatable
294 except AttributeError:
295         mark_window_rotatable = _null_mark_window_rotatable
296
297
298 def _hildon_window_to_portrait(window):
299         # gtk documentation is unclear whether this does a "=" or a "|="
300         window.set_flags(hildon.HILDON_PORTRAIT_MODE_SUPPORT)
301
302
303 def _hildon_window_to_landscape(window):
304         # gtk documentation is unclear whether this does a "=" or a "&= ~"
305         window.unset_flags(hildon.HILDON_PORTRAIT_MODE_REQUEST)
306
307
308 def _null_window_to_portrait(window):
309         pass
310
311
312 def _null_window_to_landscape(window):
313         pass
314
315
316 try:
317         hildon.HILDON_PORTRAIT_MODE_SUPPORT
318         hildon.HILDON_PORTRAIT_MODE_REQUEST
319
320         window_to_portrait = _hildon_window_to_portrait
321         window_to_landscape = _hildon_window_to_landscape
322 except AttributeError:
323         window_to_portrait = _null_window_to_portrait
324         window_to_landscape = _null_window_to_landscape
325
326
327 def get_device_orientation():
328         bus = dbus.SystemBus()
329         try:
330                 rawMceRequest = bus.get_object("com.nokia.mce", "/com/nokia/mce/request")
331                 mceRequest = dbus.Interface(rawMceRequest, dbus_interface="com.nokia.mce.request")
332                 orientation, standState, faceState, xAxis, yAxis, zAxis = mceRequest.get_device_orientation()
333         except dbus.exception.DBusException:
334                 # catching for documentation purposes that when a system doesn't
335                 # support this, this is what to expect
336                 raise
337
338         if orientation == "":
339                 return gtk.ORIENTATION_HORIZONTAL
340         elif orientation == "":
341                 return gtk.ORIENTATION_VERTICAL
342         else:
343                 raise RuntimeError("Unknown orientation: %s" % orientation)
344
345
346 def _hildon_hildonize_password_entry(textEntry):
347         textEntry.set_property('hildon-input-mode', 7 | (1 << 29))
348
349
350 def _null_hildonize_password_entry(textEntry):
351         pass
352
353
354 if IS_HILDON_SUPPORTED:
355         hildonize_password_entry = _hildon_hildonize_password_entry
356 else:
357         hildonize_password_entry = _null_hildonize_password_entry
358
359
360 def _hildon_hildonize_combo_entry(comboEntry):
361         comboEntry.set_property('hildon-input-mode', 1 << 4)
362
363
364 def _null_hildonize_combo_entry(textEntry):
365         pass
366
367
368 if IS_HILDON_SUPPORTED:
369         hildonize_combo_entry = _hildon_hildonize_combo_entry
370 else:
371         hildonize_combo_entry = _null_hildonize_combo_entry
372
373
374 def _fremantle_hildonize_scrollwindow(scrolledWindow):
375         pannableWindow = hildon.PannableArea()
376
377         child = scrolledWindow.get_child()
378         scrolledWindow.remove(child)
379         pannableWindow.add(child)
380
381         parent = scrolledWindow.get_parent()
382         if parent is not None:
383                 parent.remove(scrolledWindow)
384                 parent.add(pannableWindow)
385
386         return pannableWindow
387
388
389 def _hildon_hildonize_scrollwindow(scrolledWindow):
390         hildon.hildon_helper_set_thumb_scrollbar(scrolledWindow, True)
391         return scrolledWindow
392
393
394 def _null_hildonize_scrollwindow(scrolledWindow):
395         return scrolledWindow
396
397
398 try:
399         hildon.PannableArea
400         hildonize_scrollwindow = _fremantle_hildonize_scrollwindow
401         hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
402 except AttributeError:
403         try:
404                 hildon.hildon_helper_set_thumb_scrollbar
405                 hildonize_scrollwindow = _hildon_hildonize_scrollwindow
406                 hildonize_scrollwindow_with_viewport = _hildon_hildonize_scrollwindow
407         except AttributeError:
408                 hildonize_scrollwindow = _null_hildonize_scrollwindow
409                 hildonize_scrollwindow_with_viewport = _null_hildonize_scrollwindow
410
411
412 def _hildon_request_number(parent, title, range, default):
413         spinner = hildon.NumberEditor(*range)
414         spinner.set_value(default)
415
416         dialog = gtk.Dialog(
417                 title,
418                 parent,
419                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
420                 (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
421         )
422         dialog.set_default_response(gtk.RESPONSE_CANCEL)
423         dialog.get_child().add(spinner)
424
425         try:
426                 dialog.show_all()
427                 response = dialog.run()
428
429                 if response == gtk.RESPONSE_OK:
430                         return spinner.get_value()
431                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
432                         raise RuntimeError("User cancelled request")
433                 else:
434                         raise RuntimeError("Unrecognized response %r", response)
435         finally:
436                 dialog.hide()
437                 dialog.destroy()
438
439
440 def _null_request_number(parent, title, range, default):
441         adjustment = gtk.Adjustment(default, range[0], range[1], 1, 5, 0)
442         spinner = gtk.SpinButton(adjustment, 0, 0)
443         spinner.set_wrap(False)
444
445         dialog = gtk.Dialog(
446                 title,
447                 parent,
448                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
449                 (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
450         )
451         dialog.set_default_response(gtk.RESPONSE_CANCEL)
452         dialog.get_child().add(spinner)
453
454         try:
455                 dialog.show_all()
456                 response = dialog.run()
457
458                 if response == gtk.RESPONSE_OK:
459                         return spinner.get_value_as_int()
460                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
461                         raise RuntimeError("User cancelled request")
462                 else:
463                         raise RuntimeError("Unrecognized response %r", response)
464         finally:
465                 dialog.hide()
466                 dialog.destroy()
467
468
469 try:
470         hildon.NumberEditor # TODO deprecated in fremantle
471         request_number = _hildon_request_number
472 except AttributeError:
473         request_number = _null_request_number
474
475
476 def _hildon_touch_selector(parent, title, items, defaultIndex):
477         model = gtk.ListStore(gobject.TYPE_STRING)
478         for item in items:
479                 model.append((item, ))
480
481         selector = hildon.TouchSelector()
482         selector.append_text_column(model, True)
483         selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
484         selector.set_active(0, defaultIndex)
485
486         dialog = hildon.PickerDialog(parent)
487         dialog.set_selector(selector)
488
489         try:
490                 dialog.show_all()
491                 response = dialog.run()
492
493                 if response == gtk.RESPONSE_OK:
494                         return selector.get_active(0)
495                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
496                         raise RuntimeError("User cancelled request")
497                 else:
498                         raise RuntimeError("Unrecognized response %r", response)
499         finally:
500                 dialog.hide()
501                 dialog.destroy()
502
503
504 def _on_null_touch_selector_activated(treeView, path, column, dialog, pathData):
505         dialog.response(gtk.RESPONSE_OK)
506         pathData[0] = path
507
508
509 def _null_touch_selector(parent, title, items, defaultIndex = -1):
510         parentSize = parent.get_size()
511
512         model = gtk.ListStore(gobject.TYPE_STRING)
513         for item in items:
514                 model.append((item, ))
515
516         cell = gtk.CellRendererText()
517         set_cell_thumb_selectable(cell)
518         column = gtk.TreeViewColumn(title)
519         column.pack_start(cell, expand=True)
520         column.add_attribute(cell, "text", 0)
521
522         treeView = gtk.TreeView()
523         treeView.set_model(model)
524         treeView.append_column(column)
525         selection = treeView.get_selection()
526         selection.set_mode(gtk.SELECTION_SINGLE)
527         if 0 < defaultIndex:
528                 selection.select_path((defaultIndex, ))
529
530         scrolledWin = gtk.ScrolledWindow()
531         scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
532         scrolledWin.add(treeView)
533
534         dialog = gtk.Dialog(
535                 title,
536                 parent,
537                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
538                 (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
539         )
540         dialog.set_default_response(gtk.RESPONSE_CANCEL)
541         dialog.get_child().add(scrolledWin)
542         dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
543
544         scrolledWin = hildonize_scrollwindow(scrolledWin)
545         pathData = [None]
546         treeView.connect("row-activated", _on_null_touch_selector_activated, dialog, pathData)
547
548         try:
549                 dialog.show_all()
550                 response = dialog.run()
551
552                 if response == gtk.RESPONSE_OK:
553                         if pathData[0] is None:
554                                 raise RuntimeError("No selection made")
555                         return pathData[0][0]
556                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
557                         raise RuntimeError("User cancelled request")
558                 else:
559                         raise RuntimeError("Unrecognized response %r", response)
560         finally:
561                 dialog.hide()
562                 dialog.destroy()
563
564
565 try:
566         hildon.PickerDialog
567         hildon.TouchSelector
568         touch_selector = _hildon_touch_selector
569 except AttributeError:
570         touch_selector = _null_touch_selector
571
572
573 def _hildon_touch_selector_entry(parent, title, items, defaultItem):
574         # Got a segfault when using append_text_column with TouchSelectorEntry, so using this way
575         try:
576                 selector = hildon.TouchSelectorEntry(text=True)
577         except TypeError:
578                 selector = hildon.hildon_touch_selector_entry_new_text()
579         defaultIndex = -1
580         for i, item in enumerate(items):
581                 selector.append_text(item)
582                 if item == defaultItem:
583                         defaultIndex = i
584
585         dialog = hildon.PickerDialog(parent)
586         dialog.set_selector(selector)
587
588         if 0 < defaultIndex:
589                 selector.set_active(0, defaultIndex)
590         else:
591                 selector.get_entry().set_text(defaultItem)
592
593         try:
594                 dialog.show_all()
595                 response = dialog.run()
596         finally:
597                 dialog.hide()
598
599         if response == gtk.RESPONSE_OK:
600                 return selector.get_entry().get_text()
601         elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
602                 raise RuntimeError("User cancelled request")
603         else:
604                 raise RuntimeError("Unrecognized response %r", response)
605
606
607 def _on_null_touch_selector_entry_entry_changed(entry, result, selection, defaultIndex):
608         custom = entry.get_text().strip()
609         if custom:
610                 result[0] = custom
611                 selection.unselect_all()
612         else:
613                 result[0] = None
614                 selection.select_path((defaultIndex, ))
615
616
617 def _on_null_touch_selector_entry_entry_activated(customEntry, dialog, result):
618         dialog.response(gtk.RESPONSE_OK)
619         result[0] = customEntry.get_text()
620
621
622 def _on_null_touch_selector_entry_tree_activated(treeView, path, column, dialog, result):
623         dialog.response(gtk.RESPONSE_OK)
624         model = treeView.get_model()
625         itr = model.get_iter(path)
626         if itr is not None:
627                 result[0] = model.get_value(itr, 0)
628
629
630 def _null_touch_selector_entry(parent, title, items, defaultItem):
631         parentSize = parent.get_size()
632
633         model = gtk.ListStore(gobject.TYPE_STRING)
634         defaultIndex = -1
635         for i, item in enumerate(items):
636                 model.append((item, ))
637                 if item == defaultItem:
638                         defaultIndex = i
639
640         cell = gtk.CellRendererText()
641         set_cell_thumb_selectable(cell)
642         column = gtk.TreeViewColumn(title)
643         column.pack_start(cell, expand=True)
644         column.add_attribute(cell, "text", 0)
645
646         treeView = gtk.TreeView()
647         treeView.set_model(model)
648         treeView.append_column(column)
649         selection = treeView.get_selection()
650         selection.set_mode(gtk.SELECTION_SINGLE)
651
652         scrolledWin = gtk.ScrolledWindow()
653         scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
654         scrolledWin.add(treeView)
655
656         customEntry = gtk.Entry()
657
658         layout = gtk.VBox()
659         layout.pack_start(customEntry, expand=False)
660         layout.pack_start(scrolledWin)
661
662         dialog = gtk.Dialog(
663                 title,
664                 parent,
665                 gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
666                 (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL),
667         )
668         dialog.set_default_response(gtk.RESPONSE_CANCEL)
669         dialog.get_child().add(layout)
670         dialog.resize(parentSize[0], max(parentSize[1]-100, 100))
671
672         scrolledWin = hildonize_scrollwindow(scrolledWin)
673
674         result = [None]
675         if 0 < defaultIndex:
676                 selection.select_path((defaultIndex, ))
677                 result[0] = defaultItem
678         else:
679                 customEntry.set_text(defaultItem)
680
681         customEntry.connect("activate", _on_null_touch_selector_entry_entry_activated, dialog, result)
682         customEntry.connect("changed", _on_null_touch_selector_entry_entry_changed, result, selection, defaultIndex)
683         treeView.connect("row-activated", _on_null_touch_selector_entry_tree_activated, dialog, result)
684
685         try:
686                 dialog.show_all()
687                 response = dialog.run()
688
689                 if response == gtk.RESPONSE_OK:
690                         _, itr = selection.get_selected()
691                         if itr is not None:
692                                 return model.get_value(itr, 0)
693                         else:
694                                 enteredText = customEntry.get_text().strip()
695                                 if enteredText:
696                                         return enteredText
697                                 elif result[0] is not None:
698                                         return result[0]
699                                 else:
700                                         raise RuntimeError("No selection made")
701                 elif response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
702                         raise RuntimeError("User cancelled request")
703                 else:
704                         raise RuntimeError("Unrecognized response %r", response)
705         finally:
706                 dialog.hide()
707                 dialog.destroy()
708
709
710 try:
711         hildon.PickerDialog
712         hildon.TouchSelectorEntry
713         touch_selector_entry = _hildon_touch_selector_entry
714 except AttributeError:
715         touch_selector_entry = _null_touch_selector_entry
716
717
718 if __name__ == "__main__":
719         app = get_app_class()()
720
721         label = gtk.Label("Hello World from a Label!")
722
723         win = gtk.Window()
724         win.add(label)
725         win = hildonize_window(app, win)
726         if False:
727                 print touch_selector(win, "Test", ["A", "B", "C", "D"], 2)
728         if True:
729                 print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "C")
730                 print touch_selector_entry(win, "Test", ["A", "B", "C", "D"], "Blah")
731         if False:
732                 import pprint
733                 name, value = "", ""
734                 goodLocals = [
735                         (name, value) for (name, value) in locals().iteritems()
736                         if not name.startswith("_")
737                 ]
738                 pprint.pprint(goodLocals)
739         if False:
740                 import time
741                 show_information_banner(win, "Hello World")
742                 time.sleep(5)
743         if False:
744                 import time
745                 banner = show_busy_banner_start(win, "Hello World")
746                 time.sleep(5)
747                 show_busy_banner_end(banner)