1 # Copyright (C) 2008, Vincent Povirk for CodeWeavers
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Lesser General Public License for more details.
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the
15 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 # Boston, MA 02111-1307, USA.
18 from sugar
.activity
import activity
28 def mime_to_extension(mimetype
):
29 # Sugar's metadata does not typically provide a file extension, and the
30 # filename tends to be unusable. Windows depends on extensions so we need
31 # a conversion function. This one is pretty lame but should work for now.
32 if mimetype
== 'application/x-msi':
37 class WineActivity(activity
.Activity
):
38 def __init__(self
, handle
):
39 activity
.Activity
.__init
__(self
, handle
)
41 self
.bundle_path
= activity
.get_bundle_path()
44 activity_root
= activity
.get_activity_root()
45 wine_prefix
= os
.path
.join(activity_root
, 'data', 'wine')
46 except AttributeError:
48 activity_root
= os
.environ
['SUGAR_ACTIVITY_ROOT']
49 wine_prefix
= os
.path
.join(activity_root
, 'data', 'wine')
52 wine_prefix
= os
.path
.expanduser('~/.wine')
55 f
= open(os
.path
.join(self
.bundle_path
, 'activity', 'wine.info'), 'U')
56 for line
in f
.readlines():
58 key
, value
= line
.rstrip('\n').split('=')
59 self
.settings
[key
] = value
63 self
.desktop_parent
= gtk
.EventBox()
64 self
.desktop_parent
.show()
65 self
.set_canvas(self
.desktop_parent
)
66 except AttributeError:
67 # remove any children of the window that Sugar may have added
68 for widget
in self
.get_children():
71 self
.desktop_parent
= self
73 os
.environ
['LD_LIBRARY_PATH'] = "%s:%s" % (os
.path
.join(self
.bundle_path
, 'lib'), os
.environ
.get('LD_LIBRARY_PATH', ''))
74 os
.environ
['PATH'] = "%s:%s" % (os
.path
.join(self
.bundle_path
, 'bin'), os
.environ
.get('PATH', ''))
75 os
.environ
['WINEPREFIX'] = wine_prefix
76 os
.environ
['WINELOADER'] = os
.path
.join(self
.bundle_path
, 'bin/wine')
77 os
.environ
['WINESERVER'] = os
.path
.join(self
.bundle_path
, 'bin/wineserver')
78 os
.environ
['WINEDLLPATH'] = os
.path
.join(self
.bundle_path
, 'lib/wine')
80 self
.desktop_name
= str(os
.getpid())
81 os
.environ
['WINE_DESKTOP_NAME'] = self
.desktop_name
83 firstrun
= not os
.path
.exists(wine_prefix
)
85 self
.setup_prefix(firstrun
)
87 self
.desktop_parent
.connect('map', self
.on_parent_map
)
94 self
.set_title("Wine")
96 def on_parent_map(self
, widget
):
97 os
.environ
['WINE_DESKTOP_PARENT'] = str(self
.desktop_parent
.window
.xid
)
98 os
.environ
['SUGARED_WINE_TOPLEVEL'] = str(self
.window
.xid
)
102 os
.chdir(self
.get_unix_path('c:\\'))
104 width
= gtk
.gdk
.screen_width()
105 height
= gtk
.gdk
.screen_height()
107 cmdline
= ('wine', 'explorer', '/desktop=%s,%sx%s' % (self
.desktop_name
, width
, height
))
109 args
= self
.settings
['exec'].split(' ')
113 cmdline
+= ('start', '/unix')
114 cmdline
+= (os
.path
.join(self
.bundle_path
, args
[0]),)
115 cmdline
+= tuple(args
[1:])
117 self
.wine_pid
, stdin
, stdout
, stderr
= gobject
.spawn_async(cmdline
,
118 flags
=gobject
.SPAWN_SEARCH_PATH|gobject
.SPAWN_DO_NOT_REAP_CHILD
)
119 gobject
.child_watch_add(self
.wine_pid
, self
.on_wine_quit
, None)
121 for cmdline
in self
.to_run
:
122 self
.start_wine(*cmdline
)
124 def start_wine(self
, *args
):
126 logging
.info("running command line: %s" % ' '.join(str(x
) for x
in args
))
128 ['wine', 'explorer', '/desktop=%s' % self
.desktop_name
] + [str(x
) for x
in args
],
129 flags
=gobject
.SPAWN_SEARCH_PATH
)
131 self
.to_run
.append(args
)
133 def run_cmd(self
, *args
):
134 pid
, stdin
, stdout
, stderr
= gobject
.spawn_async(
136 flags
=gobject
.SPAWN_SEARCH_PATH
,
137 standard_output
=True)
140 s
= os
.read(stdout
, 4096)
143 s
= os
.read(stdout
, 4096)
145 result
= ''.join(result
)
149 def get_unix_path(self
, windowspath
):
150 return self
.run_cmd('winepath', '--unix', windowspath
).rstrip('\n')
152 def setup_prefix(self
, firstrun
):
154 self
.run_cmd('wine', 'start', '/unix', os
.path
.join(self
.bundle_path
, self
.settings
['init']))
156 self
.run_cmd('wineboot', '--update')
160 background_file
= os
.path
.join(self
.bundle_path
, self
.settings
['background'])
164 #set up desktop background
165 winini
= self
.get_unix_path(r
'c:\windows\win.ini')
167 f
= open(winini
, 'w')
168 f
.write("\r\n\r\n[desktop]\r\nWallPaper=c:\\windows\\background.bmp")
171 landscapebmp
= self
.get_unix_path(r
'c:\windows\background.bmp')
172 os
.symlink(background_file
, landscapebmp
)
174 def on_wine_quit(self
, pid
, condition
, data
):
177 def read_file(self
, file_path
):
178 #the file is read-only and will be deleted so make a copy
180 fd
, filename
= tempfile
.mkstemp(suffix
=mime_to_extension(self
.metadata
['mime_type']))
181 except (AttributeError, KeyError):
182 logging
.error("can't start file without a mime type")
183 os
.chmod(filename
, int('0770', 8))
184 shutil
.copyfile(file_path
, filename
)
186 atexit
.register(os
.unlink
, filename
)
187 self
.start_wine('start', '/unix', filename
)