diff --git a/src/virt-manager.glade b/src/virt-manager.glade index 6b28d5bd..228ee895 100644 --- a/src/virt-manager.glade +++ b/src/virt-manager.glade @@ -3289,6 +3289,22 @@ Máirín Duffy <duffy@redhat.com> True + + + + True + Take screenshot + True + True + True + False + + + + False + True + + 0 @@ -3358,8 +3374,8 @@ Máirín Duffy <duffy@redhat.com> True True - GTK_POLICY_ALWAYS - GTK_POLICY_ALWAYS + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC GTK_SHADOW_NONE GTK_CORNER_TOP_LEFT @@ -3371,8 +3387,8 @@ Máirín Duffy <duffy@redhat.com> True - 0.5 - 0.5 + 0 + 0 0 0 diff --git a/src/virt-manager.py.in b/src/virt-manager.py.in index 7ad74bd4..e2437433 100755 --- a/src/virt-manager.py.in +++ b/src/virt-manager.py.in @@ -76,39 +76,46 @@ gtk.window_set_default_icon_from_file(icon_dir + "/" + appname + "-icon.svg") def main(): optParser = OptionParser() optParser.add_option("-c", "--connect", dest="uri", help="Connect to hypervisor at URI", metavar="URI") + optParser.add_option("--no-dbus", action="store_true", dest="nodbus", help="Disable DBus service for controlling UI") (options, args) = optParser.parse_args() config = vmmConfig(appname, appversion, gconf_dir, glade_dir, icon_dir) engine = vmmEngine(config) - bus = None - try: - bus = dbus.SessionBus() - - dbusProxy = bus.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus") - dbusObj = dbus.Interface(dbusProxy, "org.freedesktop.DBus") - - # If we're already running, then just talk to existing process - if os.getenv("DBUS_STARTER_ADDRESS"): - name = dbus.service.BusName("com.redhat.virt.manager", bus=bus) - remote = vmmRemote(engine, name) - else: - managerProxy = bus.get_object("com.redhat.virt.manager", "/com/redhat/virt/manager") - managerObj = dbus.Interface(managerProxy, "com.redhat.virt.manager") - - if options.uri != None: - managerObj.show_host_summary(options.uri) - else: - managerObj.show_connect() - # yes, we exit completely now - remote service is in charge - return - except: - print str(sys.exc_info()[0]) + " " + str(sys.exc_info()[1]) - print _("Could not connection to session bus, disabling DBus service") + if options.nodbus: if options.uri != None: engine.show_manager(options.uri) else: engine.show_connect() + else: + bus = None + try: + bus = dbus.SessionBus() + + dbusProxy = bus.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus") + dbusObj = dbus.Interface(dbusProxy, "org.freedesktop.DBus") + + # If we're already running, then just talk to existing process + if os.getenv("DBUS_STARTER_ADDRESS"): + name = dbus.service.BusName("com.redhat.virt.manager", bus=bus) + remote = vmmRemote(engine, name) + else: + managerProxy = bus.get_object("com.redhat.virt.manager", "/com/redhat/virt/manager") + managerObj = dbus.Interface(managerProxy, "com.redhat.virt.manager") + + if options.uri != None: + managerObj.show_host_summary(options.uri) + else: + managerObj.show_connect() + # yes, we exit completely now - remote service is in charge + return + except: + print str(sys.exc_info()[0]) + " " + str(sys.exc_info()[1]) + print _("Could not connection to session bus, disabling DBus service") + if options.uri != None: + engine.show_manager(options.uri) + else: + engine.show_connect() gtk.main() if __name__ == "__main__": diff --git a/src/virtManager/console.py b/src/virtManager/console.py index b7b9f6f8..819dbd8d 100644 --- a/src/virtManager/console.py +++ b/src/virtManager/console.py @@ -64,6 +64,7 @@ class vmmConsole(gobject.GObject): self.vncViewer = GRFBViewer() scrolledWin = gtk.ScrolledWindow() + scrolledWin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) vp = gtk.Viewport() vp.set_shadow_type(gtk.SHADOW_NONE) @@ -74,6 +75,7 @@ class vmmConsole(gobject.GObject): self.window.get_widget("console-pages").append_page(scrolledWin, gtk.Label("VNC")) scrolledWin.show() + self.vncViewer.connect("size-request", self.autosize, vp) self.vncViewer.show() self.ignorePause = False @@ -108,6 +110,23 @@ class vmmConsole(gobject.GObject): self.vncViewer.connect("disconnected", self._vnc_disconnected) + # Auto-increase the window size to fit the console - within reason + # though, cos we don't want a min window size greater than the screen + # the user has scrollbars anyway if they want it smaller / it can't fit + def autosize(self, src, size, vp): + rootWidth = gtk.gdk.screen_width() + rootHeight = gtk.gdk.screen_height() + + vncWidth, vncHeight = src.get_size_request() + + if vncWidth > (rootWidth-200): + vncWidth = rootWidth - 200 + if vncHeight > (rootHeight-200): + vncHeight = rootHeight - 200 + + vp.set_size_request(vncWidth+3, vncHeight+3) + + def show(self): dialog = self.window.get_widget("vmm-console") dialog.show_all() @@ -319,12 +338,12 @@ class vmmConsole(gobject.GObject): if screenshot != None: cr = screenshot.cairo_create() width, height = screenshot.get_size() - - # Set 60% gray overlayed - cr.set_source_rgba(0, 0, 0, 0.6) + + # Set 50% gray overlayed + cr.set_source_rgba(0, 0, 0, 0.5) cr.rectangle(0, 0, width, height) cr.fill() - + # Render a big text 'paused' across it cr.set_source_rgba(1, 1,1, 1) cr.set_font_size(80) @@ -335,7 +354,7 @@ class vmmConsole(gobject.GObject): y = height/2 - (extents[3]/2) cr.move_to(x, y) cr.show_text(overlay) - + self.window.get_widget("console-screenshot").set_from_pixmap(screenshot, None) self.activate_screenshot_page() else: diff --git a/src/vncViewer/rfb.py b/src/vncViewer/rfb.py index bc3d5e30..6699d45f 100644 --- a/src/vncViewer/rfb.py +++ b/src/vncViewer/rfb.py @@ -43,7 +43,16 @@ class RFBError(Exception): pass class RFBAuthError(RFBError): pass class RFBProtocolError(RFBError): pass - +ENCODING_RAW = 0 +ENCODING_COPY_RECT = 1 +ENCODING_RRE = 2 +ENCODING_CORRE = 4 +ENCODING_HEXTILE = 5 +ENCODING_ZRLE = 16 +ENCODING_DESKTOP_RESIZE = -223 +ENCODING_CURSOR_POS = -232 +ENCODING_RICH_CURSOR = -239 +ENCODING_XCURSOR = -240 ## RFBFrameBuffer ## @@ -53,6 +62,9 @@ class RFBFrameBuffer: #print >>stderr, 'init_screen: %dx%d, name=%r' % (width, height, name) raise NotImplementedError + def resize_screen(self, width, height): + raise NotImplementedError + def set_converter(self, convert_pixels, convert_color1): self.convert_pixels = convert_pixels self.convert_color1 = convert_color1 @@ -88,7 +100,7 @@ class RFBFrameBuffer: class RFBProxy: "Abstract class of RFB clients." - def __init__(self, fb=None, preferred_encoding=(5,0), debug=0): + def __init__(self, fb=None, preferred_encoding=(ENCODING_RAW,ENCODING_HEXTILE), debug=0): self.fb = fb self.debug = debug self.preferred_encoding = preferred_encoding @@ -274,19 +286,19 @@ class RFBProxy: (x0, y0, width, height, t) = unpack('>HHHHl', self.recv_relay(12)) if self.debug: print >>stderr, ' %d: %d x %d at (%d,%d), type=%d' % (rectindex, width, height, x0, y0, t) - # RawEncoding - if t == 0: + + if t == ENCODING_RAW: l = width*height*self.bytesperpixel data = self.recv_relay(l) if self.debug: print >>stderr, ' RawEncoding: len=%d, received=%d' % (l, len(data)) if self.fb: self.fb.process_pixels(x0, y0, width, height, data) - # CopyRectEncoding - elif t == 1: + + elif t == ENCODING_COPY_RECT: raise RFBProtocolError('unsupported: CopyRectEncoding') - # RREEncoding - elif t == 2: + + elif t == ENCODING_RRE: (nsubrects,) = unpack('>L', self.recv_relay(4)) bgcolor = self.recv_relay(self.bytesperpixel) if self.debug: @@ -300,8 +312,8 @@ class RFBProxy: self.fb.process_solid(x0+x, y0+y, w, h, fgcolor) if 2 <= self.debug: print >>stderr, ' RREEncoding: ', (x,y,w,h,fgcolor) - # CoRREEncoding - elif t == 4: + + elif t == ENCODING_CORRE: (nsubrects,) = unpack('>L', self.recv_relay(4)) bgcolor = self.recv_relay(self.bytesperpixel) if self.debug: @@ -315,8 +327,8 @@ class RFBProxy: self.fb.process_solid(x0+x, y0+y, w, h, fgcolor) if 2 <= self.debug: print >>stderr, ' CoRREEncoding: ', (x,y,w,h,fgcolor) - # HextileEncoding - elif t == 5: + + elif t == ENCODING_HEXTILE: if self.debug: print >>stderr, ' HextileEncoding' (fgcolor, bgcolor) = (None, None) @@ -368,11 +380,14 @@ class RFBProxy: self.fb.process_solid(x0+x+(xy>>4), y0+y+(xy&15), (wh>>4)+1, (wh&15)+1, fgcolor) if 3 <= self.debug: print >>stderr, ' ', (xy,wh) - # ZRLEEncoding - elif t == 16: + + elif t == ENCODING_ZRLE: raise RFBProtocolError('unsupported: ZRLEEncoding') - # RichCursor - elif t == -239: + + elif t == ENCODING_DESKTOP_RESIZE: + self.clipping = self.fb.resize_screen(width, height) + + elif t == ENCODING_RICH_CURSOR: if width and height: rowbytes = (width + 7) / 8; # Cursor image RGB @@ -392,8 +407,8 @@ class RFBProxy: return '\x00\x00\x00\x00' data = ''.join([ conv1(i) for i in xrange(0, len(data), 4) ]) self.fb.change_cursor(width, height, x0, y0, data) - # XCursor - elif t == -240: + + elif t == ENCODING_XCURSOR: if width and height: rowbytes = (width + 7) / 8; # Foreground RGB @@ -419,8 +434,8 @@ class RFBProxy: return '\x00\x00\x00\x00' data = ''.join([ conv1(i) for i in xrange(len(data)) ]) self.fb.change_cursor(width, height, x0, y0, data) - # CursorPos -> only change the cursor position - elif t == -232: + + elif t == ENCODING_CURSOR_POS: if self.debug: print >>stderr, 'CursorPos: %d,%d' % (x0,y0) if self.fb: @@ -467,7 +482,7 @@ class RFBProxy: class RFBNetworkClient(RFBProxy): def __init__(self, host, port, fb=None, pwdfile=None, - preferred_encoding=(0,5), debug=0): + preferred_encoding=(ENCODING_RAW,ENCODING_HEXTILE), debug=0): RFBProxy.__init__(self, fb=fb, preferred_encoding=preferred_encoding, debug=debug) self.host = host self.port = port @@ -478,8 +493,6 @@ class RFBNetworkClient(RFBProxy): def init(self): self.sock.connect((self.host, self.port)) x = RFBProxy.init(self) - print >>stderr, 'Connected: %s:%d, protocol_version=3.%d, preferred_encoding=%s' % \ - (self.host, self.port, self.protocol_version, self.preferred_encoding) return x def recv(self, n): diff --git a/src/vncViewer/vnc.py b/src/vncViewer/vnc.py index 54661eb7..b63bb57b 100755 --- a/src/vncViewer/vnc.py +++ b/src/vncViewer/vnc.py @@ -29,10 +29,6 @@ stderr = sys.stderr from time import time -#host = "courgette" -host = "localhost" -port = 5901 - class GRFBFrameBuffer(rfb.RFBFrameBuffer, gobject.GObject): __gsignals__= { "resize": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [int,int]), @@ -43,6 +39,10 @@ class GRFBFrameBuffer(rfb.RFBFrameBuffer, gobject.GObject): self.__gobject_init__() self.canvas = canvas self.pixmap = None + self.name = "VNC" + + def get_name(self): + return self.name def get_pixmap(self): return self.pixmap @@ -57,8 +57,11 @@ class GRFBFrameBuffer(rfb.RFBFrameBuffer, gobject.GObject): return clone def init_screen(self, width, height, name): - self.pixmap = gtk.gdk.Pixmap(self.canvas.window, width, height) + self.name = name + return self.resize_screen(width, height) + def resize_screen(self, width, height): + self.pixmap = gtk.gdk.Pixmap(self.canvas.window, width, height) self.emit("resize", width, height) return (0, 0, width, height) @@ -92,8 +95,8 @@ class GRFBNetworkClient(rfb.RFBNetworkClient, gobject.GObject): "disconnected": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []) } - def __init__(self, host, port, converter): - rfb.RFBNetworkClient.__init__(self, host, port, converter) + def __init__(self, host, port, converter, debug=0): + rfb.RFBNetworkClient.__init__(self, host, port, converter, debug=debug,preferred_encoding=(rfb.ENCODING_RAW,rfb.ENCODING_DESKTOP_RESIZE)) self.__gobject_init__() self.watch = None @@ -177,6 +180,9 @@ class GRFBViewer(gtk.DrawingArea): self.set_property("can-focus", True) + def get_framebuffer_name(self): + return self.fb.get_name() + def connect_to_host(self, host, port): if self.client != None: self.disconnect_from_host() @@ -249,16 +255,19 @@ class GRFBViewer(gtk.DrawingArea): return self.fb.clone_pixmap() def update_pointer(self, win, event): - x, y, state = event.window.get_pointer() - self.client.update_pointer(self.state_to_mask(state), x, y) + if self.client != None: + x, y, state = event.window.get_pointer() + self.client.update_pointer(self.state_to_mask(state), x, y) return True def key_press(self, win, event): - self.client.update_key(1, event.keyval) + if self.client != None: + self.client.update_key(1, event.keyval) return True def key_release(self, win, event): - self.client.update_key(0, event.keyval) + if self.client != None: + self.client.update_key(0, event.keyval) return True def get_frame_buffer(self): @@ -283,7 +292,10 @@ gobject.type_register(GRFBViewer) def main(): - + host = sys.argv[1] + port = int(sys.argv[2]) + password = sys.argv[3] + win = gtk.Window() win.set_name("VNC") win.connect("destroy", lambda w: gtk.main_quit()) @@ -291,31 +303,39 @@ def main(): pane = gtk.ScrolledWindow() pane.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) win.add(pane) - pane.show() vp = gtk.Viewport() pane.add(vp) - vp.show() - - vnc = GRFBWidget() - vp.add(vnc) - vnc.show() + vnc = GRFBViewer() + vp.add(vnc) + + win.show_all() win.present() vnc.connect_to_host(host, port) + vnc.authenticate(password) + vnc.activate() + win.set_title(vnc.get_framebuffer_name()) - rootWidth = gtk.gdk.screen_width() - rootHeight = gtk.gdk.screen_height() + def autosize(): + rootWidth = gtk.gdk.screen_width() + rootHeight = gtk.gdk.screen_height() - vncWidth, vncHeight = vnc.get_size_request() + vncWidth, vncHeight = vnc.get_size_request() + + if vncWidth > (rootWidth-200): + vncWidth = rootWidth - 200 + if vncHeight > (rootHeight-200): + vncHeight = rootHeight - 200 + + vp.set_size_request(vncWidth+3, vncHeight+3) + + def resize(src, size): + autosize() + + vnc.connect('size-request', resize) - if vncWidth > (rootWidth-200): - vncWidth = rootWidth - 200 - if vncHeight > (rootHeight-200): - vncHeight = rootHeight - 200 - - vp.set_size_request(vncWidth+2, vncHeight+2) gtk.main() vnc.disconnect_from_host() diff --git a/virt-manager.spec.in b/virt-manager.spec.in index 2392fb7f..97ba989f 100644 --- a/virt-manager.spec.in +++ b/virt-manager.spec.in @@ -31,6 +31,8 @@ Requires: gnome-keyring >= 0.4.9 Requires: gnome-python2-gnomekeyring >= 2.15.4 # Minimum we've tested with Requires: libxml2-python >= 2.6.23 +# Required to install Xen guests +Requires: python-xeninst >= 0.90.0 # Earlier vte hand broken python binding module Requires: vte >= 0.12.2