2 # Copyright (C) 2007, One Laptop Per Child
3 # Copyright (C) 2008, Vincent Povirk for CodeWeavers
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
20 # This sucks. To get the object chooser to work outside the main activity
21 # process, I had to cpoy the class from the sugar library and remove parts of
22 # it, apparently because I'm not getting some glib magic right.
24 # Hopefully the API won't change drastically.
30 import dbus
.mainloop
.glib
32 dbus
.mainloop
.glib
.DBusGMainLoop(set_as_default
=True)
36 J_DBUS_SERVICE
= 'org.laptop.Journal'
37 J_DBUS_INTERFACE
= 'org.laptop.Journal'
38 J_DBUS_PATH
= '/org/laptop/Journal'
44 class ObjectChooser(object):
45 def __init__(self
, parent
=None):
48 elif hasattr(parent
, 'window') and hasattr(parent
.window
, 'xid'):
49 parent_xid
= parent
.window
.xid
53 self
._parent
_xid
= parent_xid
54 self
._object
_id
= None
56 self
._chooser
_id
= None
57 self
._response
_code
= RESPONSE_NONE
60 self
._object
_id
= None
62 self
._main
_loop
= gobject
.MainLoop()
64 self
._bus
= dbus
.SessionBus()
65 self
._bus
.add_signal_receiver(
66 self
.__name
_owner
_changed
_cb
,
67 signal_name
="NameOwnerChanged",
68 dbus_interface
="org.freedesktop.DBus",
71 obj
= self
._bus
.get_object(J_DBUS_SERVICE
, J_DBUS_PATH
)
72 journal
= dbus
.Interface(obj
, J_DBUS_INTERFACE
)
73 journal
.connect_to_signal('ObjectChooserResponse',
74 self
.__chooser
_response
_cb
)
75 journal
.connect_to_signal('ObjectChooserCancelled',
76 self
.__chooser
_cancelled
_cb
)
77 self
._chooser
_id
= journal
.ChooseObject(self
._parent
_xid
)
81 self
._main
_loop
= None
83 return self
._response
_code
85 def get_selected_object(self
):
86 if self
._object
_id
is None:
89 from sugar
.datastore
import datastore
90 return datastore
.get(self
._object
_id
)
96 if self
._main
_loop
is not None:
97 self
._main
_loop
.quit()
98 self
._main
_loop
= None
101 def __chooser_response_cb(self
, chooser_id
, object_id
):
102 if chooser_id
!= self
._chooser
_id
:
104 print('ObjectChooser.__chooser_response_cb: %r' % object_id
)
105 self
._response
_code
= RESPONSE_ACCEPT
106 self
._object
_id
= object_id
109 def __chooser_cancelled_cb(self
, chooser_id
):
110 if chooser_id
!= self
._chooser
_id
:
112 print('ObjectChooser.__chooser_cancelled_cb: %r' % chooser_id
)
113 self
._response
_code
= RESPONSE_CANCEL
116 def __name_owner_changed_cb(self
, name
, old
, new
):
117 print('ObjectChooser.__name_owner_changed_cb')
118 # Journal service disappeared from the bus
119 self
._response
_code
= RESPONSE_CANCEL
122 def start_wine(*args
):
124 ['wine', 'explorer', '/desktop=%s' % os
.environ
['WINE_DESKTOP_NAME']] + [str(x
) for x
in args
],
125 flags
=gobject
.SPAWN_SEARCH_PATH
)
127 def start_object(dsobject
):
130 from sugar
.activity
import activity
131 sys
.path
.insert(0, activity
.get_bundle_path())
133 file_path
= dsobject
.get_file_path()
134 fd
, filename
= filenames
.create_dsobject_file(dsobject
.metadata
)
135 os
.chmod(filename
, int('0770', 8))
136 shutil
.copyfile(file_path
, filename
)
138 # FIXME: delete the file when this activity instance exits?
139 start_wine('start', '/unix', filename
)
142 def start_chooser_object(chooser
):
144 response
= chooser
.run()
145 if int(response
) == RESPONSE_ACCEPT
:
146 dsobject
= chooser
.get_selected_object()
148 start_object(dsobject
)
154 def on_chooser_realize(widget
):
155 # If ObjectChooser is a subclass of gtk.Dialog (old sugar-toolkit), we can't
156 # use an XID for the transient parent. Instead, we set it through gdk when
157 # the window is realized.
160 widget
.window
.set_transient_for(gtk
.gdk
.window_foreign_new(int(os
.environ
['SUGARED_WINE_TOPLEVEL'])))
162 traceback
.print_exc()
165 chooser
= ObjectChooser(parent
=int(os
.environ
['SUGARED_WINE_TOPLEVEL']))
166 start_chooser_object(chooser
)
168 traceback
.print_exc()
169 import sugar
.graphics
.objectchooser
170 chooser
= sugar
.graphics
.objectchooser
.ObjectChooser()
172 chooser
.connect('realize', on_chooser_realize
)
174 traceback
.print_exc()
175 start_chooser_object(chooser
)