This email list is read-only. Emails sent to this list will be discarded ---------------------------------- src/Makefile.am | 2 +- src/hint_window.py | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/kvm-launcher | 65 ++++++++++++--------- src/sample_utils.py | 49 ---------------- 4 files changed, 197 insertions(+), 78 deletions(-)
New commits: commit 13ad29257b5b0ab6501ff7a0f39d75c7a0f40747 Author: Bob Spencer <[email protected]> Date: Wed Jan 14 20:25:23 2009 -0700 Monitor spawned processes Show error message in dialog (not console) Added hint_window for launching Diff in this email is a maximum of 400 lines. diff --git a/src/Makefile.am b/src/Makefile.am index 7196f2d..1220996 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,7 +5,7 @@ bin_SCRIPTS = kvm-launcher # Utility files # create .pyc and .pyo (byte-compile) # and place files in /usr/lib/python<ver>/<pkg>/site-packages -python_PYTHON = sample_utils.py +python_PYTHON = hint_window.py desktopentry_DATA = kvm-launcher.desktop icon_DATA = kvm-launcher32.png diff --git a/src/hint_window.py b/src/hint_window.py new file mode 100644 index 0000000..d0ddb4e --- /dev/null +++ b/src/hint_window.py @@ -0,0 +1,159 @@ +#!/usr/bin/python -ttu +# vim: ai ts=4 sts=4 et sw=4 +# +# hint_window.py: A simple window that shows a hint to the user +# +# Copyright 2009 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + + +import gc +import gobject +import gtk +import gtk.gdk +import gtk.glade +import os +import sys +import time +import pango + +# Import our app's libraries +#import utils + +DEFAULT_DISPLAY_TIME = 2000 # 2 sec to show window if not overridden +TEXT_OFFSET = 40 # text offset from edge +LINE_OFFSET = 3 # border offset from edge +COLOR_BLACK = "#000000" # color of background +COLOR_LTGRAY = "#E2E2E2" # color of text +COLOR_GRAY = "#ADADAD" # color of border line +COLOR_DKGRAY = "#404040" # color of border line2 + +# Show image in a borderless window for display_time milliseconds. +# FIXME: Do we know that this works correctly? One question I have is are we +# just counting on garbage collection not happening while the hint is being +# displayed since the object is being created and then immediately discarded in +# our current usage? + +"""Note: This class is a singleton. See remarks at bottom""" +class _HintWindow(object): + """A borderless window with message to user""" + def __init__(self): + self.__timeout_id = None + + #Display short status window centered (e.g. 'Sorting by name') + self.ht_window = gtk.Window(type=gtk.WINDOW_POPUP) + self.ht_window.set_position(gtk.WIN_POS_CENTER_ALWAYS) + self.ht_window.set_decorated(True) + self.ht_window.set_modal(False) + self.ht_window.set_default_size(0,0) + + self.area = gtk.DrawingArea() + #self.area.set_size_request (0,0) #self.width, self.height) + self.ht_window.add(self.area) + self.area.connect('expose_event', self.expose_event) + + # set bkgd color + self.area.modify_bg(gtk.STATE_NORMAL , + gtk.gdk.color_parse(COLOR_BLACK)) + + # create colors for lines and text + self.ltgray = self.area.get_colormap().alloc_color(COLOR_LTGRAY) + self.gray = self.area.get_colormap().alloc_color(COLOR_GRAY) + self.dkgray = self.area.get_colormap().alloc_color(COLOR_DKGRAY) + + def show_hint(self, msg, display_time=DEFAULT_DISPLAY_TIME): + self.msg = msg #used in expose_event method + self.timer_start(display_time) + + self.ht_window.hide() + #self.area.hide() + self.ht_window.show() + self.area.show() + + def hide_hint(self): + self.timer_stop() + self.ht_window.hide() + #self.area.hide() + + def timer_start(self, time): + self.timer_stop() + self.__timeout_id = gobject.timeout_add(time, self.timer_callback) + return True + + def timer_stop(self): + if self.__timeout_id: + gobject.source_remove(self.__timeout_id) + self.__timeout_id = None + return True + return False + + def timer_callback(self): + self.ht_window.hide() + return False #stop timer + + + '''expose_event occurs when drawarea exposed''' + def expose_event(self, area, event): + # get graphics context (gc) and drawing window + gc = event.window.new_gc() + drawwnd = area.window + + # set text, font, get text width/height + layout = area.create_pango_layout(self.msg) + layout.set_font_description(pango.FontDescription('Sans')) + tw, th = layout.get_pixel_size() + + # size window according to size of text + offset + w = tw + TEXT_OFFSET #width of parent window + h = th + TEXT_OFFSET #height of parent window + self.ht_window.resize(w,h) + self.area.set_size_request(w,h) + + # draw text + gc.foreground = self.ltgray #dkwhite + x = (w - tw) / 2 + y = (h - th) / 2 + drawwnd.draw_layout(gc, x, y, layout=layout) + + # create simple double line border + o = LINE_OFFSET #save me some typing + gc.foreground = self.dkgray + drawwnd.draw_line(gc, o, o+1, w-o-2,o+1 ) #top + drawwnd.draw_line(gc, w-o-2,o+1, w-o-2,h-o) #right + drawwnd.draw_line(gc, w-o-2,h-o, o, h-o) #bottom + drawwnd.draw_line(gc, o, h-o, o, o+1 ) #left + gc.foreground = self.gray + drawwnd.draw_line(gc, o+1, o, w-o-1,o ) #top + drawwnd.draw_line(gc, w-o-1,o, w-o-1,h-o-1)#right + drawwnd.draw_line(gc, w-o-1,h-o-1,o+1, h-o-1)#bottom + drawwnd.draw_line(gc, o+1, h-o-1,o+1, o ) #left + + return True + + +""" +The HintWindow is a Singleton. (granted a little awkward in python) +This ensures callers get the same instance of the HintWindow and +if they sort repeatedly a bunch of new windows aren't created. +It also prevents two windows from showing at the same time. +""" + +_hintwindow = _HintWindow() +def HintWindow (): return _hintwindow diff --git a/src/kvm-launcher b/src/kvm-launcher index 7dd5dab..eb935d6 100755 --- a/src/kvm-launcher +++ b/src/kvm-launcher @@ -22,19 +22,11 @@ import sys import gnome import gtk import gtk.glade - -import popen2 - -#import gobject -#import pygtk -#import re -#import shutil -#import time -#import traceback -#import signal +import time +import subprocess import webbrowser -import hint_window +import hint_window debug = False @@ -110,7 +102,8 @@ class App(object): buttons=gtk.BUTTONS_OK_CANCEL, message_format="Do you want to exit?") if dialog.run() == gtk.RESPONSE_OK: - gtk.main_quit() + #gtk.main_quit() + sys.exit() #if spawned a child process and user wants to exit now dialog.destroy() def link_clicked(self, widget): @@ -149,30 +142,46 @@ class App(object): def launch_kvm_clicked(self, widget): image_path = self.image_path_entry.get_text() - print "Launching KVM: %s" % image_path cmd = "kvm -no-acpi -m 512 -hda " + image_path + \ " -hdb /var/lib/moblin-image-creator/kvm/mic_vm_share.img " + \ "-boot c &" - self.launch_app(cmd) - + self.launch_app(self.widgets.get_widget("launch_kvm"), + cmd, "Starting KVM...") + def launch_qemu_clicked(self, widget): image_path = self.image_path_entry.get_text() - print "Launching QEMU: %s" % image_path cmd = "qemu-kvm -no-acpi -m 512 -hda " + image_path + \ " -hdb /var/lib/moblin-image-creator/kvm/mic_vm_share.img " + \ "-boot c &" - self.launch_app(cmd) - - def launch_app(self, cmd): - os.popen(cmd) - - #TBD: capture error without blocking - # the following gets the error, but blocks if no error - #p = popen2.popen3(cmd) - #err = p[2].read() - #if err: - # self.show_message(gtk.MESSAGE_ERROR, err) - + self.launch_app(self.widgets.get_widget("launch_qemu"), + cmd, "Starting QEMU...") + + def launch_app(self, widget, cmd, splash_prompt=""): + '''Launch app but allow user to exit''' + #disable action buttons for 2sec + if splash_prompt != "": + hint_window.HintWindow().show_hint (splash_prompt) + widget.set_sensitive(False) + + p = subprocess.Popen(cmd, shell=True, close_fds=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + i=0 + while p.poll() == None: + time.sleep(0.1) + while gtk.events_pending(): + gtk.main_iteration(False) + i=i+1 + if i==20: + widget.set_sensitive(True) + #process has exited + hint_window.HintWindow().hide_hint () + + (stdoutdata, stderrdata) = p.communicate(None) + if stderrdata != "": + self.show_message (gtk.MESSAGE_ERROR, "Error: " + stderrdata) + print stdoutdata + widget.set_sensitive(True) + def show_message (self, msg_type, msg): dialog = gtk.MessageDialog(type=msg_type, buttons=gtk.BUTTONS_OK, diff --git a/src/sample_utils.py b/src/sample_utils.py deleted file mode 100644 index b0d6227..0000000 --- a/src/sample_utils.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/python -tt -# vim: ai ts=4 sts=4 et sw=4 -# -# sample_utils.py contains utility methods used by kvm-launcher -# -# Copyright (C) 2009, Intel Corporation. -# -# Author: Praj Karur Mohan <[email protected]>\nBob Spencer <[email protected]> -# -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the PG_ORGANIZATION nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS-IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -import sys - -def printUserInfo(name,age): - """Display user name and age""" - if name == "" or age < 0 or age > 200: - return False - print ("\nYour name is %s and you are %d years old\n") % (name,age) - return True - -# Add fn to exercise code -def main(): - printUserInfo("fooname",0) - -if '__main__' == __name__: - sys.exit(main()) _______________________________________________ Commits mailing list [email protected] https://lists.moblin.org/mailman/listinfo/commits
