Repository URL to install this package:
|
Version:
15.1.0-1 ▾
|
# (c) Copyright 2009-2013, 2015. CodeWeavers, Inc.
import os
import subprocess
import traceback
import gobject
gobject.threads_init()
import gtk
import cxutils
import bottlequery
import cxobservable
import bottlecollection
import createshortcutdlg
import cxguilog
import cxguitools
import pyop
# for localization
from cxutils import cxgettext as _
# These are the observable events
DIALOG_CLOSED = 'dialog_closed'
#
# Dialog instance
#
class RunCommandController(cxobservable.Object):
observable_events = frozenset((DIALOG_CLOSED,))
def __init__(self, inBottleName):
cxobservable.Object.__init__(self)
# Setup the GUI
self.xml = gtk.Builder()
self.xml.set_translation_domain("crossover")
self.xml.add_from_file(cxguitools.get_ui_path("cxrun"))
self.xml.connect_signals(self)
# Add indents to debug channel menu items
for item in self.xml.get_object("DebugChannelMenu").get_children()[3:]:
item.set_label(' '+item.get_label())
#----------------------------------------------------------------------------
# Set up progress bar
#----------------------------------------------------------------------------
progbar = self.xml.get_object("ProgBar")
progbar.set_pulse_step(.05)
progbar.hide()
#----------------------------------------------------------------------------
# Fill Bottle popup list
#----------------------------------------------------------------------------
bottlePopupWidget = self.xml.get_object("BottlePopup")
self.bottleListStore = gtk.ListStore(str, object) #display name, internal name
bottlePopupWidget.set_model(self.bottleListStore)
selectIter = 0
collection = bottlecollection.sharedCollection()
if len(collection.bottleList()) > 0:
for bottleName in sorted(collection.bottleList()):
newrow = self.bottleListStore.append()
self.bottleListStore.set_value(newrow, 0, bottleName)
self.bottleListStore.set_value(newrow, 1, bottleName)
if bottleName == inBottleName:
selectIter = newrow
else:
newrow = self.bottleListStore.append()
self.bottleListStore.set_value(newrow, 0, _("(No bottles)"))
self.bottleListStore.set_value(newrow, 1, None)
if selectIter:
bottlePopupWidget.set_active_iter(selectIter)
else:
bottlePopupWidget.set_active_iter(self.bottleListStore.get_iter_first())
self.add_menu_open = False
self.commandOp = None
self.animateEvent = None
self.set_widget_sensitivities(self)
def set_command(self, command):
commandEntry = self.xml.get_object("CommandEntry")
commandEntry.set_text(command)
def cancel_clicked(self, caller):
self.xml.get_object("RunCommandDialog").destroy()
self.quit_requested(caller)
def quit_requested(self, _caller):
self.emit_event(DIALOG_CLOSED)
cxguitools.toplevel_quit()
def progbar_pulse(self):
progBar = self.xml.get_object("ProgBar")
progBar.pulse()
return True
def set_widget_sensitivities(self, _caller):
progBar = self.xml.get_object("ProgBar")
collection = bottlecollection.sharedCollection()
if self.commandOp != None or len(collection.bottleList()) == 0:
self.xml.get_object("RunCommandButton").set_sensitive(False)
self.xml.get_object("CommandEntry").set_sensitive(False)
self.xml.get_object("BottlePopup").set_sensitive(False)
self.xml.get_object("DebugOptionsFrame").set_sensitive(False)
self.xml.get_object("CommandBrowseButton").set_sensitive(False)
progBar.show()
else:
if self.xml.get_object("CommandEntry").get_text():
self.xml.get_object("RunCommandButton").set_sensitive(True)
else:
self.xml.get_object("RunCommandButton").set_sensitive(False)
self.xml.get_object("CommandEntry").set_sensitive(True)
self.xml.get_object("BottlePopup").set_sensitive(True)
self.xml.get_object("DebugOptionsFrame").set_sensitive(True)
self.xml.get_object("CommandBrowseButton").set_sensitive(True)
progBar.hide()
if self.xml.get_object("CommandEntry").get_text():
self.xml.get_object("CreateIconButton").set_sensitive(True)
else:
self.xml.get_object("CreateIconButton").set_sensitive(False)
if len(collection.bottleList()) == 0:
self.xml.get_object("ProgBar").hide()
def present(self):
self.xml.get_object("RunCommandDialog").present()
def run_command(self, _caller):
logFileName = ""
loggingChannels = ""
if self.xml.get_object("LogFileCheckbox").get_active():
fileSaver = gtk.FileChooserDialog(_("Specify where to save the log file"), self.xml.get_object("RunCommandDialog"), gtk.FILE_CHOOSER_ACTION_SAVE)
fileFilter = gtk.FileFilter()
fileFilter.add_pattern("*.cxlog")
fileFilter.set_name(_("CrossOver Log Files"))
fileSaver.add_filter(fileFilter)
fileSaver.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
fileSaver.add_button(gtk.STOCK_SAVE, gtk.RESPONSE_OK)
fileSaver.set_do_overwrite_confirmation(True)
cxguitools.set_default_extension(fileSaver, 'cxlog')
if fileSaver.run() == gtk.RESPONSE_OK:
logFileName = fileSaver.get_filename()
fileSaver.destroy()
else:
fileSaver.destroy()
return
loggingChannels = self.xml.get_object("DbgChannelEntry").get_text()
self.animateEvent = gobject.timeout_add(100, self.progbar_pulse)
command_line = self.xml.get_object("CommandEntry").get_text()
if logFileName:
log_file = cxguilog.create_log_file(logFileName, "Running command: %s\nBottle: %s\nDebug channels: %s\n\n" % (command_line, self.get_selected_bottle().name, loggingChannels))
else:
log_file = None
self.commandOp = RunWineCommandOperation(self, command_line, self.get_selected_bottle().name, log_file, loggingChannels)
self.set_widget_sensitivities(self)
pyop.sharedOperationQueue.enqueue(self.commandOp)
def toggle_logfile(self, widget):
self.xml.get_object("ExtraLoggingChannelsFrame").set_sensitive(
widget.get_active())
def run_command_finished(self, _runCommandOp):
self.commandOp = None
self.set_widget_sensitivities(self)
gobject.source_remove(self.animateEvent)
def get_selected_bottle(self):
collection = bottlecollection.sharedCollection()
bottlePopup = self.xml.get_object("BottlePopup")
activeIndex = bottlePopup.get_active_iter()
selectedBottleName = self.bottleListStore.get_value(activeIndex, 1)
if selectedBottleName:
bottleObj = collection.bottleObject(selectedBottleName)
return bottleObj
def browse_for_command(self, _caller):
selectedBottle = self.get_selected_bottle()
filePicker = gtk.FileChooserDialog(_("Choose a File to Run"), self.xml.get_object("RunCommandDialog"), gtk.FILE_CHOOSER_ACTION_OPEN)
cxguitools.add_filters(filePicker, cxguitools.FILTERS_RUNNABLE | cxguitools.FILTERS_ALLFILES)
environ = bottlequery.get_win_environ(selectedBottle.name, ("SystemDrive",))
drive = bottlequery.expand_win_string(environ, "%SystemDrive%")
drive = bottlequery.get_native_path(selectedBottle.name, drive)
filePicker.set_current_folder(drive)
filePicker.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
filePicker.add_button(gtk.STOCK_OPEN, gtk.RESPONSE_OK)
if filePicker.run() == gtk.RESPONSE_OK:
commandEntry = self.xml.get_object("CommandEntry")
filename = cxutils.argvtocmdline((filePicker.get_filename(),))
commandEntry.set_text(filename)
filePicker.destroy()
def create_icon(self, _widget):
bottlename = self.get_selected_bottle().name
command = self.xml.get_object("CommandEntry").get_text()
createshortcutdlg.CreateShortcutDialog(bottlename=bottlename, command=command)
def add_button_pos(self, menu):
_menu_width, menu_height = menu.size_request()
button = self.xml.get_object("DbgChannelButton")
button_x, button_y = button.window.get_origin()
button_allocation = button.get_allocation()
button_x += button_allocation.x
button_y += button_allocation.y
button_height = button_allocation.height
button_screen = button.window.get_screen()
monitor_frame = button_screen.get_monitor_geometry(button_screen.get_monitor_at_window(button.window))
fits_below = (button_y + button_height + menu_height <= monitor_frame.y + monitor_frame.height)
fits_above = (button_y - menu_height >= monitor_frame.y)
if fits_below:
return button_x, button_y + button_height, True
elif fits_above:
return button_x, button_y - menu_height, True
else:
return button_x, button_y + button_height, False
def on_DbgChannelButton_button_press_event(self, widget, event):
if self.add_menu_open or event.button != 1:
return
menu = self.xml.get_object("DebugChannelMenu")
menu.popup(None, None, self.add_button_pos, event.button, event.time)
self.add_menu_open = True
widget.set_active(True)
return True
def on_DbgChannelButton_clicked(self, widget):
if self.add_menu_open or not widget.get_active():
return
menu = self.xml.get_object("DebugChannelMenu")
menu.popup(None, None, self.add_button_pos, 0, 0)
self.add_menu_open = True
def on_DebugChannelMenu_deactivate(self, _menushell):
self.add_menu_open = False
button = self.xml.get_object("DbgChannelButton")
button.set_active(False)
def on_DbgClearMenu_activate(self, _menu):
self.xml.get_object("DbgChannelEntry").set_text('')
def add_debug_channels(self, menu):
channels = self.xml.get_object("DbgChannelEntry").get_text().split(',')
for channel in menu.get_tooltip_text().split(','):
if channel not in channels:
channels.append(channel)
self.xml.get_object("DbgChannelEntry").set_text(','.join(x for x in channels if x))
#
# Global dialog management
#
DIALOG = None
def _dialog_closed(_event=None, _data=None, *_args):
# pylint: disable=W0603
global DIALOG
DIALOG = None
def open_or_show(*args, **kwargs):
# pylint: disable=W0603
global DIALOG
if DIALOG is None:
DIALOG = RunCommandController(*args, **kwargs)
DIALOG.add_observer(DIALOG_CLOSED, _dialog_closed)
else:
DIALOG.present()
return DIALOG
#
# Operations
#
class RunWineCommandOperation(pyop.PythonOperation):
def __init__(self, inCommandController, inCommand, inBottleName, inLogFile=None, inDebugChannels=""):
pyop.PythonOperation.__init__(self)
self.bottlename = inBottleName
self.commandController = inCommandController
self.argArray = [os.path.join(cxutils.CX_ROOT, "bin", "cxstart")]
self.argArray.extend(["--bottle", inBottleName, '--new-console'])
self.log_file = inLogFile
if inDebugChannels != "":
self.argArray.append("--debugmsg")
self.argArray.append(inDebugChannels)
cmdline_array = cxutils.cmdlinetoargv(inCommand)
dirname = cxutils.dirname(cmdline_array[0])
if dirname:
self.argArray.append('--workdir')
self.argArray.append(dirname)
self.argArray.append("--")
self.argArray.extend(cxutils.cmdlinetoargv(inCommand))
def __unicode__(self):
return "RunWineCommandOperation for " + self.bottlename
def main(self):
try:
if self.log_file:
env = os.environ.copy()
env['CX_LOG'] = '-'
stderr = self.log_file
else:
env = None
stderr = subprocess.PIPE
subp = subprocess.Popen(self.argArray, stdout=subprocess.PIPE, stderr=stderr, env=env, universal_newlines=True, close_fds=True)
if self.log_file:
self.log_file.close()
subp.communicate()
except:
traceback.print_exc()
def finish(self):
self.commandController.run_command_finished(self)
pyop.PythonOperation.finish(self)