mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-03-09 08:58:27 +03:00
console: Make API used by vmmDetails explicit
And hide everything else. Similar to what we did with the Viewers, this should help clarify what the boundaries are here.
This commit is contained in:
parent
f589f01665
commit
03dbbac806
@ -34,6 +34,10 @@ from .sshtunnels import ConnectionInfo
|
||||
from .viewers import SpiceViewer, VNCViewer
|
||||
|
||||
|
||||
class vmmConsolePages(vmmGObjectUI):
|
||||
"""
|
||||
Handles all the complex UI handling dictated by the spice/vnc widgets
|
||||
"""
|
||||
# Console pages
|
||||
(CONSOLE_PAGE_UNAVAILABLE,
|
||||
CONSOLE_PAGE_AUTHENTICATE,
|
||||
@ -41,10 +45,6 @@ from .viewers import SpiceViewer, VNCViewer
|
||||
CONSOLE_PAGE_OFFSET) = range(4)
|
||||
|
||||
|
||||
class vmmConsolePages(vmmGObjectUI):
|
||||
"""
|
||||
Handles all the complex UI handling dictated by the spice/vnc widgets
|
||||
"""
|
||||
def __init__(self, vm, builder, topwin):
|
||||
vmmGObjectUI.__init__(self, None, None, builder=builder, topwin=topwin)
|
||||
|
||||
@ -52,12 +52,12 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self._pointer_is_grabbed = False
|
||||
self._change_title()
|
||||
self.vm.connect("config-changed", self._change_title)
|
||||
self.force_resize = False
|
||||
self._force_resize = False
|
||||
|
||||
# State for disabling modifiers when keyboard is grabbed
|
||||
self.accel_groups = Gtk.accel_groups_from_object(self.topwin)
|
||||
self.gtk_settings_accel = None
|
||||
self.gtk_settings_mnemonic = None
|
||||
self._accel_groups = Gtk.accel_groups_from_object(self.topwin)
|
||||
self._gtk_settings_accel = None
|
||||
self._gtk_settings_mnemonic = None
|
||||
|
||||
# Initialize display widget
|
||||
self._viewer = None
|
||||
@ -67,40 +67,40 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self._viewer_is_connecting = False
|
||||
|
||||
# Fullscreen toolbar
|
||||
self.send_key_button = None
|
||||
self.fs_toolbar = None
|
||||
self.fs_drawer = None
|
||||
self.keycombo_menu = self.build_keycombo_menu(self.send_key)
|
||||
self.init_fs_toolbar()
|
||||
self._send_key_button = None
|
||||
self._fs_toolbar = None
|
||||
self._fs_drawer = None
|
||||
self._keycombo_menu = self._build_keycombo_menu(self._do_send_key)
|
||||
self._init_fs_toolbar()
|
||||
|
||||
# Make viewer widget background always be black
|
||||
black = Gdk.Color(0, 0, 0)
|
||||
self.widget("console-gfx-viewport").modify_bg(Gtk.StateType.NORMAL,
|
||||
black)
|
||||
|
||||
self.serial_tabs = []
|
||||
self.last_gfx_page = 0
|
||||
self._serial_tabs = []
|
||||
self._last_gfx_page = 0
|
||||
self._init_menus()
|
||||
|
||||
# Signals are added by vmmDetails. Don't use connect_signals here
|
||||
# or it changes will be overwritten
|
||||
|
||||
self.refresh_can_fullscreen()
|
||||
self.refresh_scaling_from_settings()
|
||||
self._refresh_can_fullscreen()
|
||||
self._refresh_scaling_from_settings()
|
||||
self.add_gsettings_handle(
|
||||
self.vm.on_console_scaling_changed(
|
||||
self.refresh_scaling_from_settings))
|
||||
self._refresh_scaling_from_settings))
|
||||
self._refresh_resizeguest_from_settings()
|
||||
self.add_gsettings_handle(
|
||||
self.vm.on_console_resizeguest_changed(
|
||||
self._refresh_resizeguest_from_settings))
|
||||
|
||||
scroll = self.widget("console-gfx-scroll")
|
||||
scroll.connect("size-allocate", self.scroll_size_allocate)
|
||||
scroll.connect("size-allocate", self._scroll_size_allocate)
|
||||
self.add_gsettings_handle(
|
||||
self.config.on_console_accels_changed(self._refresh_enable_accel))
|
||||
|
||||
self.page_changed()
|
||||
self._page_changed()
|
||||
|
||||
|
||||
def is_visible(self):
|
||||
@ -116,24 +116,23 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self._viewer.cleanup()
|
||||
self._viewer = None
|
||||
|
||||
self.keycombo_menu.destroy()
|
||||
self.keycombo_menu = None
|
||||
self.fs_drawer.destroy()
|
||||
self.fs_drawer = None
|
||||
self.fs_toolbar.destroy()
|
||||
self.fs_toolbar = None
|
||||
self._keycombo_menu.destroy()
|
||||
self._keycombo_menu = None
|
||||
self._fs_drawer.destroy()
|
||||
self._fs_drawer = None
|
||||
self._fs_toolbar.destroy()
|
||||
self._fs_toolbar = None
|
||||
|
||||
for serial in self.serial_tabs:
|
||||
for serial in self._serial_tabs:
|
||||
serial.cleanup()
|
||||
self.serial_tabs = []
|
||||
self._serial_tabs = []
|
||||
|
||||
|
||||
##########################
|
||||
# Initialization helpers #
|
||||
##########################
|
||||
|
||||
@staticmethod
|
||||
def build_keycombo_menu(cb):
|
||||
def _build_keycombo_menu(self, cb):
|
||||
# Shared with vmmDetails
|
||||
menu = Gtk.Menu()
|
||||
|
||||
@ -156,22 +155,22 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
menu.show_all()
|
||||
return menu
|
||||
|
||||
def init_fs_toolbar(self):
|
||||
def _init_fs_toolbar(self):
|
||||
scroll = self.widget("console-gfx-scroll")
|
||||
pages = self.widget("console-pages")
|
||||
pages.remove(scroll)
|
||||
|
||||
self.fs_toolbar = Gtk.Toolbar()
|
||||
self.fs_toolbar.set_show_arrow(False)
|
||||
self.fs_toolbar.set_no_show_all(True)
|
||||
self.fs_toolbar.set_style(Gtk.ToolbarStyle.BOTH_HORIZ)
|
||||
self._fs_toolbar = Gtk.Toolbar()
|
||||
self._fs_toolbar.set_show_arrow(False)
|
||||
self._fs_toolbar.set_no_show_all(True)
|
||||
self._fs_toolbar.set_style(Gtk.ToolbarStyle.BOTH_HORIZ)
|
||||
|
||||
# Exit fullscreen button
|
||||
button = Gtk.ToolButton.new_from_stock(Gtk.STOCK_LEAVE_FULLSCREEN)
|
||||
button.set_tooltip_text(_("Leave fullscreen"))
|
||||
button.show()
|
||||
self.fs_toolbar.add(button)
|
||||
button.connect("clicked", self.leave_fullscreen)
|
||||
self._fs_toolbar.add(button)
|
||||
button.connect("clicked", self._leave_fullscreen)
|
||||
|
||||
def keycombo_menu_clicked(src):
|
||||
ignore = src
|
||||
@ -182,32 +181,32 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
return x, y + height, True
|
||||
|
||||
self.keycombo_menu.popup(None, None, menu_location,
|
||||
self.fs_toolbar, 0,
|
||||
self._keycombo_menu.popup(None, None, menu_location,
|
||||
self._fs_toolbar, 0,
|
||||
Gtk.get_current_event_time())
|
||||
|
||||
self.send_key_button = Gtk.ToolButton()
|
||||
self.send_key_button.set_icon_name(
|
||||
self._send_key_button = Gtk.ToolButton()
|
||||
self._send_key_button.set_icon_name(
|
||||
"preferences-desktop-keyboard-shortcuts")
|
||||
self.send_key_button.set_tooltip_text(_("Send key combination"))
|
||||
self.send_key_button.show_all()
|
||||
self.send_key_button.connect("clicked", keycombo_menu_clicked)
|
||||
self.fs_toolbar.add(self.send_key_button)
|
||||
self._send_key_button.set_tooltip_text(_("Send key combination"))
|
||||
self._send_key_button.show_all()
|
||||
self._send_key_button.connect("clicked", keycombo_menu_clicked)
|
||||
self._fs_toolbar.add(self._send_key_button)
|
||||
|
||||
self.fs_drawer = AutoDrawer()
|
||||
self.fs_drawer.set_active(False)
|
||||
self.fs_drawer.set_over(self.fs_toolbar)
|
||||
self.fs_drawer.set_under(scroll)
|
||||
self.fs_drawer.set_offset(-1)
|
||||
self.fs_drawer.set_fill(False)
|
||||
self.fs_drawer.set_overlap_pixels(1)
|
||||
self.fs_drawer.set_nooverlap_pixels(0)
|
||||
self.fs_drawer.period = 20
|
||||
self.fs_drawer.step = .1
|
||||
self._fs_drawer = AutoDrawer()
|
||||
self._fs_drawer.set_active(False)
|
||||
self._fs_drawer.set_over(self._fs_toolbar)
|
||||
self._fs_drawer.set_under(scroll)
|
||||
self._fs_drawer.set_offset(-1)
|
||||
self._fs_drawer.set_fill(False)
|
||||
self._fs_drawer.set_overlap_pixels(1)
|
||||
self._fs_drawer.set_nooverlap_pixels(0)
|
||||
self._fs_drawer.period = 20
|
||||
self._fs_drawer.step = .1
|
||||
|
||||
self.fs_drawer.show_all()
|
||||
self._fs_drawer.show_all()
|
||||
|
||||
pages.add(self.fs_drawer)
|
||||
pages.add(self._fs_drawer)
|
||||
|
||||
def _init_menus(self):
|
||||
# Serial list menu
|
||||
@ -215,6 +214,11 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
smenu.connect("show", self._populate_serial_menu)
|
||||
self.widget("details-menu-view-serial-list").set_submenu(smenu)
|
||||
|
||||
|
||||
#################
|
||||
# Internal APIs #
|
||||
#################
|
||||
|
||||
def _change_title(self, ignore1=None):
|
||||
title = self.vm.get_name() + " " + _("Virtual Machine")
|
||||
|
||||
@ -226,61 +230,122 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
self.topwin.set_title(title)
|
||||
|
||||
def someone_has_focus(self):
|
||||
def _someone_has_focus(self):
|
||||
if (self._viewer and
|
||||
self._viewer.console_has_focus() and
|
||||
self._viewer_is_connected):
|
||||
return True
|
||||
|
||||
for serial in self.serial_tabs:
|
||||
for serial in self._serial_tabs:
|
||||
if (serial.terminal and
|
||||
serial.terminal.get_property("has-focus")):
|
||||
return True
|
||||
|
||||
def viewer_is_visible(self):
|
||||
return bool(self._viewer and self._viewer.console_get_visible())
|
||||
def viewer_has_usb_redirection(self):
|
||||
return bool(self._viewer and
|
||||
self._viewer.console_has_usb_redirection())
|
||||
def viewer_get_usb_widget(self):
|
||||
return self._viewer.console_get_usb_widget()
|
||||
def viewer_get_pixbuf(self):
|
||||
return self._viewer.console_get_pixbuf()
|
||||
|
||||
def _disable_modifiers(self):
|
||||
if self.gtk_settings_accel is not None:
|
||||
if self._gtk_settings_accel is not None:
|
||||
return
|
||||
|
||||
for g in self.accel_groups:
|
||||
for g in self._accel_groups:
|
||||
self.topwin.remove_accel_group(g)
|
||||
|
||||
settings = Gtk.Settings.get_default()
|
||||
self.gtk_settings_accel = settings.get_property('gtk-menu-bar-accel')
|
||||
self._gtk_settings_accel = settings.get_property('gtk-menu-bar-accel')
|
||||
settings.set_property('gtk-menu-bar-accel', None)
|
||||
|
||||
self.gtk_settings_mnemonic = settings.get_property(
|
||||
self._gtk_settings_mnemonic = settings.get_property(
|
||||
"gtk-enable-mnemonics")
|
||||
settings.set_property("gtk-enable-mnemonics", False)
|
||||
|
||||
def _enable_modifiers(self):
|
||||
if self.gtk_settings_accel is None:
|
||||
if self._gtk_settings_accel is None:
|
||||
return
|
||||
|
||||
settings = Gtk.Settings.get_default()
|
||||
settings.set_property('gtk-menu-bar-accel', self.gtk_settings_accel)
|
||||
self.gtk_settings_accel = None
|
||||
settings.set_property('gtk-menu-bar-accel', self._gtk_settings_accel)
|
||||
self._gtk_settings_accel = None
|
||||
|
||||
if self.gtk_settings_mnemonic is not None:
|
||||
if self._gtk_settings_mnemonic is not None:
|
||||
settings.set_property("gtk-enable-mnemonics",
|
||||
self.gtk_settings_mnemonic)
|
||||
self._gtk_settings_mnemonic)
|
||||
|
||||
for g in self.accel_groups:
|
||||
for g in self._accel_groups:
|
||||
self.topwin.add_accel_group(g)
|
||||
|
||||
def _refresh_enable_accel(self):
|
||||
# Make sure modifiers are up to date
|
||||
self._viewer_focus_changed()
|
||||
|
||||
def _do_send_key(self, src, keys):
|
||||
ignore = src
|
||||
|
||||
if keys is not None:
|
||||
self._viewer.console_send_keys(keys)
|
||||
|
||||
|
||||
###########################
|
||||
# Resize and scaling APIs #
|
||||
###########################
|
||||
|
||||
def _scroll_size_allocate(self, src_ignore, req):
|
||||
if (not self._viewer or
|
||||
not self._viewer.console_get_desktop_resolution()):
|
||||
return
|
||||
|
||||
scroll = self.widget("console-gfx-scroll")
|
||||
is_scale = self._viewer.console_get_scaling()
|
||||
is_resizeguest = self._viewer.console_get_resizeguest()
|
||||
|
||||
dx = 0
|
||||
dy = 0
|
||||
align_ratio = float(req.width) / float(req.height)
|
||||
|
||||
# pylint: disable=unpacking-non-sequence
|
||||
desktop_w, desktop_h = self._viewer.console_get_desktop_resolution()
|
||||
if desktop_h == 0:
|
||||
return
|
||||
desktop_ratio = float(desktop_w) / float(desktop_h)
|
||||
|
||||
if is_scale or self._force_resize:
|
||||
# Make sure we never show scrollbars when scaling
|
||||
scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER)
|
||||
else:
|
||||
scroll.set_policy(Gtk.PolicyType.AUTOMATIC,
|
||||
Gtk.PolicyType.AUTOMATIC)
|
||||
|
||||
if not self._force_resize and is_resizeguest:
|
||||
# With resize guest, we don't want to maintain aspect ratio,
|
||||
# since the guest can resize to arbitrary resolutions.
|
||||
self._viewer.console_set_size_request(req.width, req.height)
|
||||
return
|
||||
|
||||
if not is_scale or self._force_resize:
|
||||
# Scaling disabled is easy, just force the VNC widget size. Since
|
||||
# we are inside a scrollwindow, it shouldn't cause issues.
|
||||
self._force_resize = False
|
||||
self._viewer.console_set_size_request(desktop_w, desktop_h)
|
||||
return
|
||||
|
||||
# Make sure there is no hard size requirement so we can scale down
|
||||
self._viewer.console_set_size_request(-1, -1)
|
||||
|
||||
# Make sure desktop aspect ratio is maintained
|
||||
if align_ratio > desktop_ratio:
|
||||
desktop_w = int(req.height * desktop_ratio)
|
||||
desktop_h = req.height
|
||||
dx = (req.width - desktop_w) / 2
|
||||
|
||||
else:
|
||||
desktop_w = req.width
|
||||
desktop_h = int(req.width / desktop_ratio)
|
||||
dy = (req.height - desktop_h) / 2
|
||||
|
||||
viewer_alloc = Gdk.Rectangle()
|
||||
viewer_alloc.x = dx
|
||||
viewer_alloc.y = dy
|
||||
viewer_alloc.width = desktop_w
|
||||
viewer_alloc.height = desktop_h
|
||||
self._viewer.console_size_allocate(viewer_alloc)
|
||||
|
||||
def _refresh_resizeguest_from_settings(self):
|
||||
tooltip = ""
|
||||
if self._viewer:
|
||||
@ -298,18 +363,9 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
if not tooltip:
|
||||
self.widget("details-menu-view-resizeguest").set_active(bool(val))
|
||||
|
||||
self.sync_resizeguest_with_display()
|
||||
self._sync_resizeguest_with_display()
|
||||
|
||||
def resizeguest_ui_changed_cb(self, src):
|
||||
# Called from details.py
|
||||
if not src.get_sensitive():
|
||||
return
|
||||
|
||||
val = int(self.widget("details-menu-view-resizeguest").get_active())
|
||||
self.vm.set_console_resizeguest(val)
|
||||
self.sync_resizeguest_with_display()
|
||||
|
||||
def sync_resizeguest_with_display(self):
|
||||
def _sync_resizeguest_with_display(self):
|
||||
if not self._viewer:
|
||||
return
|
||||
|
||||
@ -317,7 +373,32 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self._viewer.console_set_resizeguest(val)
|
||||
self.widget("console-gfx-scroll").queue_resize()
|
||||
|
||||
def refresh_scaling_from_settings(self):
|
||||
def _resizeguest_ui_changed_cb(self, src):
|
||||
if not src.get_sensitive():
|
||||
return
|
||||
|
||||
val = int(self.widget("details-menu-view-resizeguest").get_active())
|
||||
self.vm.set_console_resizeguest(val)
|
||||
self._sync_resizeguest_with_display()
|
||||
|
||||
def _do_size_to_vm(self, src_ignore):
|
||||
# Resize the console to best fit the VM resolution
|
||||
if not self._viewer:
|
||||
return
|
||||
if not self._viewer.console_get_desktop_resolution():
|
||||
return
|
||||
|
||||
self.topwin.unmaximize()
|
||||
self.topwin.resize(1, 1)
|
||||
self._force_resize = True
|
||||
self.widget("console-gfx-scroll").queue_resize()
|
||||
|
||||
|
||||
################
|
||||
# Scaling APIs #
|
||||
################
|
||||
|
||||
def _refresh_scaling_from_settings(self):
|
||||
scale_type = self.vm.get_console_scaling()
|
||||
self.widget("details-menu-view-scale-always").set_active(
|
||||
scale_type == self.config.CONSOLE_SCALE_ALWAYS)
|
||||
@ -328,7 +409,7 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
self._sync_scaling_with_display()
|
||||
|
||||
def scaling_ui_changed_cb(self, src):
|
||||
def _scaling_ui_changed_cb(self, src):
|
||||
# Called from details.py
|
||||
if not src.get_active():
|
||||
return
|
||||
@ -365,16 +446,24 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
# Refresh viewer size
|
||||
self.widget("console-gfx-scroll").queue_resize()
|
||||
|
||||
def details_auth_login(self, ignore):
|
||||
self.widget("console-pages").set_current_page(CONSOLE_PAGE_UNAVAILABLE)
|
||||
self.set_credentials()
|
||||
self.activate_viewer_page()
|
||||
|
||||
def toggle_fullscreen(self, src):
|
||||
do_fullscreen = src.get_active()
|
||||
self._change_fullscreen(do_fullscreen)
|
||||
###################
|
||||
# Fullscreen APIs #
|
||||
###################
|
||||
|
||||
def leave_fullscreen(self, ignore=None):
|
||||
def _refresh_can_fullscreen(self):
|
||||
cpage = self.widget("console-pages").get_current_page()
|
||||
dpage = self.widget("details-pages").get_current_page()
|
||||
|
||||
allow_fullscreen = (dpage == DETAILS_PAGE_CONSOLE and
|
||||
cpage == self.CONSOLE_PAGE_VIEWER and
|
||||
self._viewer_is_connected)
|
||||
|
||||
self.widget("control-fullscreen").set_sensitive(allow_fullscreen)
|
||||
self.widget("details-menu-view-fullscreen").set_sensitive(
|
||||
allow_fullscreen)
|
||||
|
||||
def _leave_fullscreen(self, ignore=None):
|
||||
self._change_fullscreen(False)
|
||||
|
||||
def _change_fullscreen(self, do_fullscreen):
|
||||
@ -382,13 +471,13 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
if do_fullscreen:
|
||||
self.topwin.fullscreen()
|
||||
self.fs_toolbar.show()
|
||||
self.fs_drawer.set_active(True)
|
||||
self._fs_toolbar.show()
|
||||
self._fs_drawer.set_active(True)
|
||||
self.widget("toolbar-box").hide()
|
||||
self.widget("details-menubar").hide()
|
||||
else:
|
||||
self.fs_toolbar.hide()
|
||||
self.fs_drawer.set_active(False)
|
||||
self._fs_toolbar.hide()
|
||||
self._fs_drawer.set_active(False)
|
||||
self.topwin.unfullscreen()
|
||||
|
||||
if self.widget("details-menu-view-toolbar").get_active():
|
||||
@ -397,41 +486,23 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
self._sync_scaling_with_display()
|
||||
|
||||
def size_to_vm(self, src_ignore):
|
||||
# Resize the console to best fit the VM resolution
|
||||
if not self._viewer:
|
||||
return
|
||||
if not self._viewer.console_get_desktop_resolution():
|
||||
return
|
||||
|
||||
self.topwin.unmaximize()
|
||||
self.topwin.resize(1, 1)
|
||||
self.force_resize = True
|
||||
self.widget("console-gfx-scroll").queue_resize()
|
||||
|
||||
def send_key(self, src, keys):
|
||||
ignore = src
|
||||
|
||||
if keys is not None:
|
||||
self._viewer.console_send_keys(keys)
|
||||
|
||||
|
||||
##########################
|
||||
# State tracking methods #
|
||||
##########################
|
||||
|
||||
def view_vm_status(self):
|
||||
def _view_vm_status(self):
|
||||
if not self.vm:
|
||||
# window has been closed and no pages to update are available.
|
||||
return
|
||||
status = self.vm.status()
|
||||
if status == libvirt.VIR_DOMAIN_SHUTOFF:
|
||||
self.activate_unavailable_page(_("Guest not running"))
|
||||
self._activate_unavailable_page(_("Guest not running"))
|
||||
else:
|
||||
if status == libvirt.VIR_DOMAIN_CRASHED:
|
||||
self.activate_unavailable_page(_("Guest has crashed"))
|
||||
self._activate_unavailable_page(_("Guest has crashed"))
|
||||
|
||||
def close_viewer(self):
|
||||
def _close_viewer(self):
|
||||
if self._viewer is None:
|
||||
return
|
||||
|
||||
@ -445,30 +516,33 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
viewer.close()
|
||||
self._viewer_is_connected = False
|
||||
self.refresh_can_fullscreen()
|
||||
self.leave_fullscreen()
|
||||
self._refresh_can_fullscreen()
|
||||
self._leave_fullscreen()
|
||||
|
||||
for serial in self.serial_tabs:
|
||||
for serial in self._serial_tabs:
|
||||
serial.close()
|
||||
|
||||
def update_widget_states(self, vm, status_ignore):
|
||||
def _update_widget_states(self, vm, status_ignore):
|
||||
runable = vm.is_runable()
|
||||
paused = vm.is_paused()
|
||||
pages = self.widget("console-pages")
|
||||
page = pages.get_current_page()
|
||||
|
||||
self._send_key_button.set_sensitive(not (runable or paused))
|
||||
|
||||
if runable:
|
||||
if page != CONSOLE_PAGE_UNAVAILABLE:
|
||||
pages.set_current_page(CONSOLE_PAGE_UNAVAILABLE)
|
||||
if page != self.CONSOLE_PAGE_UNAVAILABLE:
|
||||
pages.set_current_page(self.CONSOLE_PAGE_UNAVAILABLE)
|
||||
|
||||
self.view_vm_status()
|
||||
self._view_vm_status()
|
||||
|
||||
elif page in [CONSOLE_PAGE_UNAVAILABLE, CONSOLE_PAGE_VIEWER]:
|
||||
elif page in [self.CONSOLE_PAGE_UNAVAILABLE, self.CONSOLE_PAGE_VIEWER]:
|
||||
if self._viewer and self._viewer.console_is_open():
|
||||
self.activate_viewer_page()
|
||||
self._activate_viewer_page()
|
||||
else:
|
||||
self._viewerRetriesScheduled = 0
|
||||
self._viewerRetryDelay = 125
|
||||
self.try_login()
|
||||
self._try_login()
|
||||
|
||||
return
|
||||
|
||||
@ -477,18 +551,19 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
# Page Navigation #
|
||||
###################
|
||||
|
||||
def activate_unavailable_page(self, msg):
|
||||
def _activate_unavailable_page(self, msg):
|
||||
"""
|
||||
This function is passed to serialcon.py at least, so change
|
||||
with care
|
||||
"""
|
||||
self.close_viewer()
|
||||
self.widget("console-pages").set_current_page(CONSOLE_PAGE_UNAVAILABLE)
|
||||
self._close_viewer()
|
||||
self.widget("console-pages").set_current_page(
|
||||
self.CONSOLE_PAGE_UNAVAILABLE)
|
||||
self.widget("details-menu-vm-screenshot").set_sensitive(False)
|
||||
self.widget("details-menu-usb-redirection").set_sensitive(False)
|
||||
self.widget("console-unavailable").set_label("<b>" + msg + "</b>")
|
||||
|
||||
def activate_auth_page(self, withPassword, withUsername):
|
||||
def _activate_auth_page(self, withPassword, withUsername):
|
||||
(pw, username) = self.config.get_console_password(self.vm)
|
||||
self.widget("details-menu-vm-screenshot").set_sensitive(False)
|
||||
self.widget("details-menu-usb-redirection").set_sensitive(False)
|
||||
@ -514,11 +589,10 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
username))
|
||||
|
||||
self.widget("console-pages").set_current_page(
|
||||
CONSOLE_PAGE_AUTHENTICATE)
|
||||
self.CONSOLE_PAGE_AUTHENTICATE)
|
||||
|
||||
|
||||
def activate_viewer_page(self):
|
||||
self.widget("console-pages").set_current_page(CONSOLE_PAGE_VIEWER)
|
||||
def _activate_viewer_page(self):
|
||||
self.widget("console-pages").set_current_page(self.CONSOLE_PAGE_VIEWER)
|
||||
self.widget("details-menu-vm-screenshot").set_sensitive(True)
|
||||
if self._viewer:
|
||||
self._viewer.console_grab_focus()
|
||||
@ -528,7 +602,7 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self.widget("details-menu-usb-redirection").set_sensitive(True)
|
||||
return
|
||||
|
||||
def page_changed(self, ignore1=None, ignore2=None, newpage=None):
|
||||
def _page_changed(self, ignore1=None, ignore2=None, newpage=None):
|
||||
pagenum = self.widget("console-pages").get_current_page()
|
||||
|
||||
if newpage is not None:
|
||||
@ -536,57 +610,51 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
w = self.widget("console-pages").get_nth_page(i)
|
||||
w.set_visible(i == newpage)
|
||||
|
||||
if pagenum < CONSOLE_PAGE_OFFSET:
|
||||
self.last_gfx_page = pagenum
|
||||
self.refresh_can_fullscreen()
|
||||
if pagenum < self.CONSOLE_PAGE_OFFSET:
|
||||
self._last_gfx_page = pagenum
|
||||
self._refresh_can_fullscreen()
|
||||
|
||||
def refresh_can_fullscreen(self):
|
||||
cpage = self.widget("console-pages").get_current_page()
|
||||
dpage = self.widget("details-pages").get_current_page()
|
||||
|
||||
allow_fullscreen = (dpage == DETAILS_PAGE_CONSOLE and
|
||||
cpage == CONSOLE_PAGE_VIEWER and
|
||||
self._viewer_is_connected)
|
||||
#########################
|
||||
# Viewer login attempts #
|
||||
#########################
|
||||
|
||||
self.widget("control-fullscreen").set_sensitive(allow_fullscreen)
|
||||
self.widget("details-menu-view-fullscreen").set_sensitive(allow_fullscreen)
|
||||
|
||||
def schedule_retry(self):
|
||||
def _schedule_retry(self):
|
||||
if self._viewerRetriesScheduled >= 10:
|
||||
logging.error("Too many connection failures, not retrying again")
|
||||
return
|
||||
|
||||
self.timeout_add(self._viewerRetryDelay, self.try_login)
|
||||
self.timeout_add(self._viewerRetryDelay, self._try_login)
|
||||
|
||||
if self._viewerRetryDelay < 2000:
|
||||
self._viewerRetryDelay = self._viewerRetryDelay * 2
|
||||
|
||||
def skip_connect_attempt(self):
|
||||
def _skip_connect_attempt(self):
|
||||
return (self._viewer or
|
||||
not self.is_visible())
|
||||
|
||||
def guest_not_avail(self):
|
||||
def _guest_not_avail(self):
|
||||
return (self.vm.is_shutoff() or self.vm.is_crashed())
|
||||
|
||||
def try_login(self, src_ignore=None):
|
||||
def _try_login(self, src_ignore=None):
|
||||
if self._viewer_is_connecting:
|
||||
return
|
||||
|
||||
try:
|
||||
self._viewer_is_connecting = True
|
||||
self._try_login()
|
||||
self._do_try_login()
|
||||
finally:
|
||||
self._viewer_is_connecting = False
|
||||
|
||||
def _try_login(self):
|
||||
if self.skip_connect_attempt():
|
||||
def _do_try_login(self):
|
||||
if self._skip_connect_attempt():
|
||||
# Don't try and login for these cases
|
||||
return
|
||||
|
||||
if self.guest_not_avail():
|
||||
if self._guest_not_avail():
|
||||
# Guest isn't running, schedule another try
|
||||
self.activate_unavailable_page(_("Guest not running"))
|
||||
self.schedule_retry()
|
||||
self._activate_unavailable_page(_("Guest not running"))
|
||||
self._schedule_retry()
|
||||
return
|
||||
|
||||
ginfo = None
|
||||
@ -603,7 +671,7 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
if ginfo is None:
|
||||
logging.debug("No graphics configured for guest")
|
||||
self.activate_unavailable_page(
|
||||
self._activate_unavailable_page(
|
||||
_("Graphical console not configured for guest"))
|
||||
return
|
||||
|
||||
@ -614,11 +682,11 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
msg = (_("Cannot display graphical console type '%s'")
|
||||
% ginfo.gtype)
|
||||
|
||||
self.activate_unavailable_page(msg)
|
||||
self._activate_unavailable_page(msg)
|
||||
return
|
||||
|
||||
if ginfo.is_bad_localhost():
|
||||
self.activate_unavailable_page(
|
||||
self._activate_unavailable_page(
|
||||
_("Guest is on a remote host with transport '%s'\n"
|
||||
"but is only configured to listen on locally.\n"
|
||||
"Connect using 'ssh' transport or change the\n"
|
||||
@ -626,12 +694,12 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
return
|
||||
|
||||
if not ginfo.console_active():
|
||||
self.activate_unavailable_page(
|
||||
self._activate_unavailable_page(
|
||||
_("Graphical console is not yet active for guest"))
|
||||
self.schedule_retry()
|
||||
self._schedule_retry()
|
||||
return
|
||||
|
||||
self.activate_unavailable_page(
|
||||
self._activate_unavailable_page(
|
||||
_("Connecting to graphical console for guest"))
|
||||
|
||||
logging.debug("Starting connect process for %s", ginfo.logstring())
|
||||
@ -649,10 +717,10 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self._viewer.console_open_ginfo(ginfo)
|
||||
except Exception, e:
|
||||
logging.exception("Error connection to graphical console")
|
||||
self.activate_unavailable_page(
|
||||
self._activate_unavailable_page(
|
||||
_("Error connecting to graphical console") + ":\n%s" % e)
|
||||
|
||||
def set_credentials(self, src_ignore=None):
|
||||
def _set_credentials(self, src_ignore=None):
|
||||
passwd = self.widget("console-auth-password")
|
||||
username = self.widget("console-auth-username")
|
||||
|
||||
@ -665,66 +733,6 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self.config.set_console_password(self.vm, passwd.get_text(),
|
||||
username.get_text())
|
||||
|
||||
def scroll_size_allocate(self, src_ignore, req):
|
||||
if (not self._viewer or
|
||||
not self._viewer.console_get_desktop_resolution()):
|
||||
return
|
||||
|
||||
scroll = self.widget("console-gfx-scroll")
|
||||
is_scale = self._viewer.console_get_scaling()
|
||||
is_resizeguest = self._viewer.console_get_resizeguest()
|
||||
|
||||
dx = 0
|
||||
dy = 0
|
||||
align_ratio = float(req.width) / float(req.height)
|
||||
|
||||
# pylint: disable=unpacking-non-sequence
|
||||
desktop_w, desktop_h = self._viewer.console_get_desktop_resolution()
|
||||
if desktop_h == 0:
|
||||
return
|
||||
desktop_ratio = float(desktop_w) / float(desktop_h)
|
||||
|
||||
if is_scale or self.force_resize:
|
||||
# Make sure we never show scrollbars when scaling
|
||||
scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER)
|
||||
else:
|
||||
scroll.set_policy(Gtk.PolicyType.AUTOMATIC,
|
||||
Gtk.PolicyType.AUTOMATIC)
|
||||
|
||||
if not self.force_resize and is_resizeguest:
|
||||
# With resize guest, we don't want to maintain aspect ratio,
|
||||
# since the guest can resize to arbitrary resolutions.
|
||||
self._viewer.console_set_size_request(req.width, req.height)
|
||||
return
|
||||
|
||||
if not is_scale or self.force_resize:
|
||||
# Scaling disabled is easy, just force the VNC widget size. Since
|
||||
# we are inside a scrollwindow, it shouldn't cause issues.
|
||||
self.force_resize = False
|
||||
self._viewer.console_set_size_request(desktop_w, desktop_h)
|
||||
return
|
||||
|
||||
# Make sure there is no hard size requirement so we can scale down
|
||||
self._viewer.console_set_size_request(-1, -1)
|
||||
|
||||
# Make sure desktop aspect ratio is maintained
|
||||
if align_ratio > desktop_ratio:
|
||||
desktop_w = int(req.height * desktop_ratio)
|
||||
desktop_h = req.height
|
||||
dx = (req.width - desktop_w) / 2
|
||||
|
||||
else:
|
||||
desktop_w = req.width
|
||||
desktop_h = int(req.width / desktop_ratio)
|
||||
dy = (req.height - desktop_h) / 2
|
||||
|
||||
viewer_alloc = Gdk.Rectangle()
|
||||
viewer_alloc.x = dx
|
||||
viewer_alloc.y = dy
|
||||
viewer_alloc.width = desktop_w
|
||||
viewer_alloc.height = desktop_h
|
||||
self._viewer.console_size_allocate(viewer_alloc)
|
||||
|
||||
|
||||
##########################
|
||||
# Viewer signal handling #
|
||||
@ -753,17 +761,17 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
if force_accel:
|
||||
self._enable_modifiers()
|
||||
elif self.someone_has_focus():
|
||||
elif self._someone_has_focus():
|
||||
self._disable_modifiers()
|
||||
else:
|
||||
self._enable_modifiers()
|
||||
|
||||
def _viewer_auth_error(self, viewer, errmsg):
|
||||
viewer.close()
|
||||
self.activate_unavailable_page(errmsg)
|
||||
self._activate_unavailable_page(errmsg)
|
||||
|
||||
def _viewer_need_auth(self, ignore, withPassword, withUsername):
|
||||
self.activate_auth_page(withPassword, withUsername)
|
||||
self._activate_auth_page(withPassword, withUsername)
|
||||
|
||||
def _viewer_agent_connected(self, ignore):
|
||||
self._refresh_resizeguest_from_settings()
|
||||
@ -777,16 +785,17 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
if self._viewer:
|
||||
errout = self._viewer.console_reset_tunnels()
|
||||
|
||||
self.widget("console-pages").set_current_page(CONSOLE_PAGE_UNAVAILABLE)
|
||||
self.close_viewer()
|
||||
self.widget("console-pages").set_current_page(
|
||||
self.CONSOLE_PAGE_UNAVAILABLE)
|
||||
self._close_viewer()
|
||||
logging.debug("Viewer disconnected")
|
||||
|
||||
# Make sure modifiers are set correctly
|
||||
self._viewer_focus_changed()
|
||||
|
||||
if self.guest_not_avail():
|
||||
if self._guest_not_avail():
|
||||
# Exit was probably for legitimate reasons
|
||||
self.view_vm_status()
|
||||
self._view_vm_status()
|
||||
return
|
||||
|
||||
error = _("Error: viewer connection to hypervisor host got refused "
|
||||
@ -795,15 +804,15 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
logging.debug("Error output from closed console: %s", errout)
|
||||
error += "\n\nError: %s" % errout
|
||||
|
||||
self.activate_unavailable_page(error)
|
||||
self._activate_unavailable_page(error)
|
||||
self._refresh_resizeguest_from_settings()
|
||||
|
||||
def _viewer_connected(self, ignore):
|
||||
self._viewer_is_connected = True
|
||||
self.refresh_can_fullscreen()
|
||||
self._refresh_can_fullscreen()
|
||||
|
||||
logging.debug("Viewer connected")
|
||||
self.activate_viewer_page()
|
||||
self._activate_viewer_page()
|
||||
|
||||
# Had a successful connect, so reset counters now
|
||||
self._viewerRetriesScheduled = 0
|
||||
@ -832,7 +841,7 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
# Serial console handling #
|
||||
###########################
|
||||
|
||||
def activate_default_console_page(self):
|
||||
def _activate_default_console_page(self):
|
||||
if self.vm.get_graphics_devices() or not self.vm.get_serial_devs():
|
||||
return
|
||||
|
||||
@ -847,14 +856,14 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
def _selected_serial_dev(self):
|
||||
current_page = self.widget("console-pages").get_current_page()
|
||||
if not current_page >= CONSOLE_PAGE_OFFSET:
|
||||
if not current_page >= self.CONSOLE_PAGE_OFFSET:
|
||||
return
|
||||
|
||||
serial_idx = current_page - CONSOLE_PAGE_OFFSET
|
||||
if len(self.serial_tabs) < serial_idx:
|
||||
serial_idx = current_page - self.CONSOLE_PAGE_OFFSET
|
||||
if len(self._serial_tabs) < serial_idx:
|
||||
return
|
||||
|
||||
return self.serial_tabs[serial_idx]
|
||||
return self._serial_tabs[serial_idx]
|
||||
|
||||
def _make_serial_menu_label(self, dev):
|
||||
if dev.virtual_device_type == "console":
|
||||
@ -866,13 +875,13 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
self.widget("details-pages").set_current_page(DETAILS_PAGE_CONSOLE)
|
||||
|
||||
if dev.virtual_device_type == "graphics":
|
||||
self.widget("console-pages").set_current_page(self.last_gfx_page)
|
||||
self.widget("console-pages").set_current_page(self._last_gfx_page)
|
||||
return
|
||||
|
||||
target_port = dev.vmmindex
|
||||
name = self._make_serial_menu_label(dev)
|
||||
serial = None
|
||||
for s in self.serial_tabs:
|
||||
for s in self._serial_tabs:
|
||||
if s.name == name:
|
||||
serial = s
|
||||
break
|
||||
@ -886,10 +895,10 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
|
||||
title = Gtk.Label(label=name)
|
||||
self.widget("console-pages").append_page(serial.box, title)
|
||||
self.serial_tabs.append(serial)
|
||||
self._serial_tabs.append(serial)
|
||||
|
||||
serial.open_console()
|
||||
page_idx = self.serial_tabs.index(serial) + CONSOLE_PAGE_OFFSET
|
||||
page_idx = self._serial_tabs.index(serial) + self.CONSOLE_PAGE_OFFSET
|
||||
self.widget("console-pages").set_current_page(page_idx)
|
||||
|
||||
def _build_serial_menu_items(self, menu_item_cb):
|
||||
@ -916,7 +925,7 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
def _build_graphical_menu_items(self, menu_item_cb):
|
||||
showing_graphics = (
|
||||
self.widget("console-pages").get_current_page() ==
|
||||
CONSOLE_PAGE_VIEWER)
|
||||
self.CONSOLE_PAGE_VIEWER)
|
||||
|
||||
# Populate graphical devices
|
||||
devs = self.vm.get_graphics_devices()
|
||||
@ -972,3 +981,54 @@ class vmmConsolePages(vmmGObjectUI):
|
||||
src.add(Gtk.SeparatorMenuItem())
|
||||
self._build_graphical_menu_items(menu_item_cb)
|
||||
src.show_all()
|
||||
|
||||
|
||||
##########################
|
||||
# API used by vmmDetails #
|
||||
##########################
|
||||
|
||||
def details_viewer_is_visible(self):
|
||||
return bool(self._viewer and self._viewer.console_get_visible())
|
||||
def details_viewer_has_usb_redirection(self):
|
||||
return bool(self._viewer and
|
||||
self._viewer.console_has_usb_redirection())
|
||||
def details_viewer_get_usb_widget(self):
|
||||
return self._viewer.console_get_usb_widget()
|
||||
def details_viewer_get_pixbuf(self):
|
||||
return self._viewer.console_get_pixbuf()
|
||||
|
||||
def details_close_viewer(self):
|
||||
return self._close_viewer()
|
||||
|
||||
def details_activate_default_console_page(self):
|
||||
return self._activate_default_console_page()
|
||||
|
||||
def details_update_widget_states(self, *args, **kwargs):
|
||||
return self._update_widget_states(*args, **kwargs)
|
||||
|
||||
def details_build_keycombo_menu(self, *args, **kwargs):
|
||||
return self._build_keycombo_menu(*args, **kwargs)
|
||||
|
||||
def details_refresh_can_fullscreen(self):
|
||||
return self._refresh_can_fullscreen()
|
||||
def details_resizeguest_ui_changed_cb(self, *args, **kwargs):
|
||||
return self._resizeguest_ui_changed_cb(*args, **kwargs)
|
||||
def details_send_key(self, *args, **kwargs):
|
||||
return self._do_send_key(*args, **kwargs)
|
||||
|
||||
def details_page_changed(self, *args, **kwargs):
|
||||
return self._page_changed(*args, **kwargs)
|
||||
def details_scaling_ui_changed_cb(self, *args, **kwargs):
|
||||
return self._scaling_ui_changed_cb(*args, **kwargs)
|
||||
def details_size_to_vm(self, *args, **kwargs):
|
||||
return self._do_size_to_vm(*args, **kwargs)
|
||||
|
||||
def details_toggle_fullscreen(self, src):
|
||||
do_fullscreen = src.get_active()
|
||||
self._change_fullscreen(do_fullscreen)
|
||||
|
||||
def details_auth_login(self, ignore):
|
||||
self.widget("console-pages").set_current_page(
|
||||
self.CONSOLE_PAGE_UNAVAILABLE)
|
||||
self._set_credentials()
|
||||
self._activate_viewer_page()
|
||||
|
@ -520,6 +520,8 @@ class vmmDetails(vmmGObjectUI):
|
||||
|
||||
"on_hostdev_rombar_toggled": lambda *x: self.enable_apply(
|
||||
x, EDIT_HOSTDEV_ROMBAR),
|
||||
"on_controller_model_combo_changed": (lambda *x:
|
||||
self.enable_apply(x, EDIT_CONTROLLER_MODEL)),
|
||||
|
||||
"on_config_apply_clicked": self.config_apply,
|
||||
"on_config_cancel_clicked": self.config_cancel,
|
||||
@ -531,18 +533,25 @@ class vmmDetails(vmmGObjectUI):
|
||||
"on_hw_list_button_press_event": self.popup_addhw_menu,
|
||||
|
||||
# Listeners stored in vmmConsolePages
|
||||
"on_details_menu_view_fullscreen_activate": self.console.toggle_fullscreen,
|
||||
"on_details_menu_view_size_to_vm_activate": self.console.size_to_vm,
|
||||
"on_details_menu_view_scale_always_toggled": self.console.scaling_ui_changed_cb,
|
||||
"on_details_menu_view_scale_fullscreen_toggled": self.console.scaling_ui_changed_cb,
|
||||
"on_details_menu_view_scale_never_toggled": self.console.scaling_ui_changed_cb,
|
||||
"on_details_menu_view_resizeguest_toggled": self.console.resizeguest_ui_changed_cb,
|
||||
"on_details_menu_view_fullscreen_activate": (
|
||||
self.console.details_toggle_fullscreen),
|
||||
"on_details_menu_view_size_to_vm_activate": (
|
||||
self.console.details_size_to_vm),
|
||||
"on_details_menu_view_scale_always_toggled": (
|
||||
self.console.details_scaling_ui_changed_cb),
|
||||
"on_details_menu_view_scale_fullscreen_toggled": (
|
||||
self.console.details_scaling_ui_changed_cb),
|
||||
"on_details_menu_view_scale_never_toggled": (
|
||||
self.console.details_scaling_ui_changed_cb),
|
||||
"on_details_menu_view_resizeguest_toggled": (
|
||||
self.console.details_resizeguest_ui_changed_cb),
|
||||
|
||||
"on_console_pages_switch_page": self.console.page_changed,
|
||||
"on_console_auth_password_activate": self.console.details_auth_login,
|
||||
"on_console_auth_login_clicked": self.console.details_auth_login,
|
||||
"on_controller_model_combo_changed": lambda *x: self.enable_apply(x,
|
||||
EDIT_CONTROLLER_MODEL),
|
||||
"on_console_pages_switch_page": (
|
||||
self.console.details_page_changed),
|
||||
"on_console_auth_password_activate": (
|
||||
self.console.details_auth_login),
|
||||
"on_console_auth_login_clicked": (
|
||||
self.console.details_auth_login),
|
||||
})
|
||||
|
||||
# Deliberately keep all this after signal connection
|
||||
@ -618,9 +627,9 @@ class vmmDetails(vmmGObjectUI):
|
||||
return
|
||||
|
||||
self.topwin.hide()
|
||||
if self.console.viewer_is_visible():
|
||||
if self.console.details_viewer_is_visible():
|
||||
try:
|
||||
self.console.close_viewer()
|
||||
self.console.details_close_viewer()
|
||||
except:
|
||||
logging.error("Failure when disconnecting from desktop server")
|
||||
|
||||
@ -688,8 +697,8 @@ class vmmDetails(vmmGObjectUI):
|
||||
self.config.get_details_show_toolbar())
|
||||
|
||||
# Keycombo menu (ctrl+alt+del etc.)
|
||||
self.keycombo_menu = self.console.build_keycombo_menu(
|
||||
self.console.send_key)
|
||||
self.keycombo_menu = self.console.details_build_keycombo_menu(
|
||||
self.console.details_send_key)
|
||||
self.widget("details-menu-send-key").set_submenu(self.keycombo_menu)
|
||||
|
||||
|
||||
@ -1252,7 +1261,7 @@ class vmmDetails(vmmGObjectUI):
|
||||
self.page_refresh(newpage)
|
||||
|
||||
self.sync_details_console_view(newpage)
|
||||
self.console.refresh_can_fullscreen()
|
||||
self.console.details_refresh_can_fullscreen()
|
||||
|
||||
def change_run_text(self, can_restore):
|
||||
if can_restore:
|
||||
@ -1297,12 +1306,11 @@ class vmmDetails(vmmGObjectUI):
|
||||
self.widget("config-maxmem").set_sensitive(not ro)
|
||||
|
||||
# Disable send key menu entries for offline VM
|
||||
self.console.send_key_button.set_sensitive(not (run or paused))
|
||||
send_key = self.widget("details-menu-send-key")
|
||||
for c in send_key.get_submenu().get_children():
|
||||
c.set_sensitive(not (run or paused))
|
||||
|
||||
self.console.update_widget_states(vm, status)
|
||||
self.console.details_update_widget_states(vm, status)
|
||||
if not run:
|
||||
self.activate_default_console_page()
|
||||
|
||||
@ -1346,7 +1354,7 @@ class vmmDetails(vmmGObjectUI):
|
||||
# when the user runs a VM while they are focused on the details page,
|
||||
# and we don't want to switch pages out from under them.
|
||||
origpage = pages.get_current_page()
|
||||
self.console.activate_default_console_page()
|
||||
self.console.details_activate_default_console_page()
|
||||
pages.set_current_page(origpage)
|
||||
|
||||
# activate_* are called from engine.py via CLI options
|
||||
@ -1413,7 +1421,7 @@ class vmmDetails(vmmGObjectUI):
|
||||
self.vm.get_connkey())
|
||||
|
||||
def control_vm_menu(self, src_ignore):
|
||||
can_usb = bool(self.console.viewer_has_usb_redirection() and
|
||||
can_usb = bool(self.console.details_viewer_has_usb_redirection() and
|
||||
self.vm.has_spicevmc_type_redirdev())
|
||||
self.widget("details-menu-usb-redirection").set_sensitive(can_usb)
|
||||
|
||||
@ -1464,7 +1472,7 @@ class vmmDetails(vmmGObjectUI):
|
||||
ignore = src
|
||||
spice_usbdev_dialog = self.err
|
||||
|
||||
spice_usbdev_widget = self.console.viewer_get_usb_widget()
|
||||
spice_usbdev_widget = self.console.details_viewer_get_usb_widget()
|
||||
if not spice_usbdev_widget:
|
||||
self.err.show_err(_("Error initializing spice USB device widget"))
|
||||
return
|
||||
@ -1474,7 +1482,7 @@ class vmmDetails(vmmGObjectUI):
|
||||
widget=spice_usbdev_widget)
|
||||
|
||||
def _take_screenshot(self):
|
||||
image = self.console.viewer_get_pixbuf()
|
||||
image = self.console.details_viewer_get_pixbuf()
|
||||
|
||||
metadata = {
|
||||
'tEXt::Hypervisor URI': self.vm.conn.get_uri(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user