2009-10-30 20:25:27 +03:00
#
2015-04-04 03:54:38 +03:00
# Copyright (C) 2006-2008, 2015 Red Hat, Inc.
2009-10-30 20:25:27 +03:00
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
2015-03-23 22:56:55 +03:00
# Copyright (C) 2010 Marc-Andre Lureau <marcandre.lureau@redhat.com>
2009-10-30 20:25:27 +03:00
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
2012-05-14 17:24:56 +04:00
from gi . repository import Gtk
from gi . repository import Gdk
2010-02-11 17:32:05 +03:00
2013-09-07 03:36:09 +04:00
import logging
2009-10-30 20:25:27 +03:00
2014-09-13 00:10:45 +04:00
from . autodrawer import AutoDrawer
2015-04-04 03:54:38 +03:00
from . baseclass import vmmGObjectUI
2014-09-13 00:10:45 +04:00
from . details import DETAILS_PAGE_CONSOLE
2014-09-21 21:36:28 +04:00
from . serialcon import vmmSerialConsole
2015-04-04 03:54:38 +03:00
from . sshtunnels import ConnectionInfo
2015-08-13 23:00:33 +03:00
from . viewers import SpiceViewer , VNCViewer , have_spice_gtk
2015-04-04 03:54:38 +03:00
2009-10-30 20:25:27 +03:00
2015-09-18 18:55:15 +03:00
# console-pages IDs
( _CONSOLE_PAGE_UNAVAILABLE ,
_CONSOLE_PAGE_AUTHENTICATE ,
_CONSOLE_PAGE_SERIAL ,
_CONSOLE_PAGE_VIEWER ) = range ( 4 )
2015-04-04 03:54:38 +03:00
class vmmConsolePages ( vmmGObjectUI ) :
2015-04-04 01:03:58 +03:00
"""
2015-04-04 03:54:38 +03:00
Handles all the complex UI handling dictated by the spice / vnc widgets
2015-04-04 01:03:58 +03:00
"""
2013-02-16 22:31:46 +04:00
def __init__ ( self , vm , builder , topwin ) :
2013-06-09 03:25:36 +04:00
vmmGObjectUI . __init__ ( self , None , None , builder = builder , topwin = topwin )
2009-10-30 20:25:27 +03:00
self . vm = vm
2015-04-04 01:03:58 +03:00
self . _pointer_is_grabbed = False
self . _change_title ( )
2015-04-10 01:02:42 +03:00
self . vm . connect ( " state-changed " , self . _change_title )
2015-04-04 04:34:03 +03:00
self . _force_resize = False
2009-10-30 20:25:27 +03:00
# State for disabling modifiers when keyboard is grabbed
2015-04-04 04:34:03 +03:00
self . _accel_groups = Gtk . accel_groups_from_object ( self . topwin )
self . _gtk_settings_accel = None
self . _gtk_settings_mnemonic = None
2009-10-30 20:25:27 +03:00
# Initialize display widget
2015-04-04 01:03:58 +03:00
self . _viewer = None
2009-10-30 20:25:27 +03:00
2011-05-19 01:22:07 +04:00
# Fullscreen toolbar
2015-04-04 04:34:03 +03:00
self . _send_key_button = None
self . _fs_toolbar = None
self . _fs_drawer = None
2015-09-06 01:23:47 +03:00
self . _keycombo_toolbar = self . _build_keycombo_menu ( )
self . _keycombo_menu = self . _build_keycombo_menu ( )
2015-04-04 04:34:03 +03:00
self . _init_fs_toolbar ( )
2011-05-19 01:22:07 +04:00
2010-12-22 04:13:11 +03:00
# Make viewer widget background always be black
2012-05-14 17:24:56 +04:00
black = Gdk . Color ( 0 , 0 , 0 )
2013-04-21 20:10:14 +04:00
self . widget ( " console-gfx-viewport " ) . modify_bg ( Gtk . StateType . NORMAL ,
2011-07-14 21:13:13 +04:00
black )
2009-11-29 02:48:56 +03:00
2015-09-18 18:55:15 +03:00
self . widget ( " console-pages " ) . set_show_tabs ( False )
self . widget ( " serial-pages " ) . set_show_tabs ( False )
self . _serial_consoles = [ ]
2013-09-02 01:40:38 +04:00
self . _init_menus ( )
2012-02-02 02:26:46 +04:00
# Signals are added by vmmDetails. Don't use connect_signals here
2009-10-30 20:25:27 +03:00
# or it changes will be overwritten
2013-04-18 01:39:25 +04:00
2015-09-18 20:05:41 +03:00
self . widget ( " console-gfx-scroll " ) . connect ( " size-allocate " ,
self . _scroll_size_allocate )
self . _refresh_widget_states ( )
2015-04-04 04:34:03 +03:00
self . _refresh_scaling_from_settings ( )
2015-09-18 20:05:41 +03:00
2014-09-28 15:37:16 +04:00
self . add_gsettings_handle (
2014-01-31 04:15:02 +04:00
self . vm . on_console_scaling_changed (
2015-04-04 04:34:03 +03:00
self . _refresh_scaling_from_settings ) )
2015-04-04 01:03:58 +03:00
self . _refresh_resizeguest_from_settings ( )
2014-09-28 15:37:16 +04:00
self . add_gsettings_handle (
2014-01-31 18:13:53 +04:00
self . vm . on_console_resizeguest_changed (
2015-04-04 01:03:58 +03:00
self . _refresh_resizeguest_from_settings ) )
2014-09-28 15:37:16 +04:00
self . add_gsettings_handle (
2015-04-04 01:03:58 +03:00
self . config . on_console_accels_changed ( self . _refresh_enable_accel ) )
2009-10-30 20:25:27 +03:00
2014-01-27 02:09:07 +04:00
2009-10-30 20:25:27 +03:00
def is_visible ( self ) :
2013-06-18 07:29:20 +04:00
if self . topwin :
return self . topwin . get_visible ( )
else :
return False
2009-10-30 20:25:27 +03:00
2011-07-24 05:16:54 +04:00
def _cleanup ( self ) :
2011-04-12 02:35:21 +04:00
self . vm = None
2011-05-19 01:36:08 +04:00
2015-04-04 01:03:58 +03:00
if self . _viewer :
self . _viewer . cleanup ( )
self . _viewer = None
2011-04-12 02:35:21 +04:00
2015-09-06 01:23:47 +03:00
self . _keycombo_toolbar . destroy ( )
self . _keycombo_toolbar = None
2015-04-04 04:34:03 +03:00
self . _fs_drawer . destroy ( )
self . _fs_drawer = None
self . _fs_toolbar . destroy ( )
self . _fs_toolbar = None
2011-05-19 01:22:07 +04:00
2015-09-18 18:55:15 +03:00
for serial in self . _serial_consoles :
2013-09-02 01:40:38 +04:00
serial . cleanup ( )
2015-09-18 18:55:15 +03:00
self . _serial_consoles = [ ]
2013-09-02 01:40:38 +04:00
2009-10-30 20:25:27 +03:00
##########################
# Initialization helpers #
##########################
2015-09-06 01:23:47 +03:00
def _build_keycombo_menu ( self ) :
2014-01-27 02:09:07 +04:00
# Shared with vmmDetails
menu = Gtk . Menu ( )
def make_item ( name , combo ) :
item = Gtk . MenuItem . new_with_mnemonic ( name )
2015-09-06 01:23:47 +03:00
item . connect ( " activate " , self . _do_send_key , combo )
2014-01-27 02:09:07 +04:00
menu . add ( item )
make_item ( " Ctrl+Alt+_Backspace " , [ " Control_L " , " Alt_L " , " BackSpace " ] )
make_item ( " Ctrl+Alt+_Delete " , [ " Control_L " , " Alt_L " , " Delete " ] )
menu . add ( Gtk . SeparatorMenuItem ( ) )
for i in range ( 1 , 13 ) :
make_item ( " Ctrl+Alt+F_ %d " % i , [ " Control_L " , " Alt_L " , " F %d " % i ] )
menu . add ( Gtk . SeparatorMenuItem ( ) )
make_item ( " _Printscreen " , [ " Print " ] )
menu . show_all ( )
return menu
2015-04-04 04:34:03 +03:00
def _init_fs_toolbar ( self ) :
2013-04-21 20:10:14 +04:00
scroll = self . widget ( " console-gfx-scroll " )
2011-07-14 21:13:13 +04:00
pages = self . widget ( " console-pages " )
2011-05-19 01:22:07 +04:00
pages . remove ( scroll )
2015-04-04 04:34:03 +03:00
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 )
2011-05-19 01:22:07 +04:00
# Exit fullscreen button
2012-05-14 17:24:56 +04:00
button = Gtk . ToolButton . new_from_stock ( Gtk . STOCK_LEAVE_FULLSCREEN )
button . set_tooltip_text ( _ ( " Leave fullscreen " ) )
2011-05-19 01:22:07 +04:00
button . show ( )
2015-04-04 04:34:03 +03:00
self . _fs_toolbar . add ( button )
button . connect ( " clicked " , self . _leave_fullscreen )
2011-05-19 01:22:07 +04:00
2011-05-19 02:54:27 +04:00
def keycombo_menu_clicked ( src ) :
ignore = src
def menu_location ( menu , toolbar ) :
ignore = menu
2013-04-15 20:35:45 +04:00
ignore , x , y = toolbar . get_window ( ) . get_origin ( )
height = toolbar . get_window ( ) . get_height ( )
2011-05-19 02:54:27 +04:00
return x , y + height , True
2015-09-06 01:23:47 +03:00
self . _keycombo_toolbar . popup ( None , None , menu_location ,
2015-04-04 04:34:03 +03:00
self . _fs_toolbar , 0 ,
2013-04-14 21:16:02 +04:00
Gtk . get_current_event_time ( ) )
2011-05-19 02:54:27 +04:00
2015-04-04 04:34:03 +03:00
self . _send_key_button = Gtk . ToolButton ( )
self . _send_key_button . set_icon_name (
2012-01-30 06:56:18 +04:00
" preferences-desktop-keyboard-shortcuts " )
2015-04-04 04:34:03 +03:00
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 . show_all ( )
pages . add ( self . _fs_drawer )
2011-05-19 01:22:07 +04:00
2013-09-02 01:40:38 +04:00
def _init_menus ( self ) :
# Serial list menu
smenu = Gtk . Menu ( )
2014-12-03 20:14:32 +03:00
smenu . connect ( " show " , self . _populate_serial_menu )
2013-09-02 01:40:38 +04:00
self . widget ( " details-menu-view-serial-list " ) . set_submenu ( smenu )
2015-09-06 01:23:47 +03:00
# Keycombo menu (ctrl+alt+del etc.)
self . widget ( " details-menu-send-key " ) . set_submenu ( self . _keycombo_menu )
2015-04-04 04:34:03 +03:00
#################
# Internal APIs #
#################
2015-04-04 01:03:58 +03:00
def _change_title ( self , ignore1 = None ) :
2015-09-01 01:38:05 +03:00
title = ( _ ( " % (vm-name)s on % (connection-name)s " ) % {
" vm-name " : self . vm . get_name_or_title ( ) ,
" connection-name " : self . vm . conn . get_pretty_desc ( ) ,
} )
2011-03-23 23:56:12 +03:00
2015-04-04 01:03:58 +03:00
if self . _pointer_is_grabbed and self . _viewer :
keystr = self . _viewer . console_get_grab_keys ( )
2011-03-23 23:56:12 +03:00
keymsg = _ ( " Press %s to release pointer. " ) % keystr
title = keymsg + " " + title
self . topwin . set_title ( title )
2015-04-04 04:34:03 +03:00
def _someone_has_focus ( self ) :
2015-04-04 01:03:58 +03:00
if ( self . _viewer and
self . _viewer . console_has_focus ( ) and
2015-09-18 20:05:41 +03:00
self . _viewer . console_is_open ( ) ) :
2013-12-19 01:27:33 +04:00
return True
2015-09-18 18:55:15 +03:00
for serial in self . _serial_consoles :
2013-12-19 01:27:33 +04:00
if ( serial . terminal and
serial . terminal . get_property ( " has-focus " ) ) :
return True
2010-04-21 20:59:25 +04:00
def _disable_modifiers ( self ) :
2015-04-04 04:34:03 +03:00
if self . _gtk_settings_accel is not None :
2009-11-02 00:36:44 +03:00
return
2015-04-04 04:34:03 +03:00
for g in self . _accel_groups :
2009-10-30 20:25:27 +03:00
self . topwin . remove_accel_group ( g )
2009-10-30 21:36:17 +03:00
2012-05-14 17:24:56 +04:00
settings = Gtk . Settings . get_default ( )
2015-04-04 04:34:03 +03:00
self . _gtk_settings_accel = settings . get_property ( ' gtk-menu-bar-accel ' )
2009-10-30 20:25:27 +03:00
settings . set_property ( ' gtk-menu-bar-accel ' , None )
2015-04-04 04:34:03 +03:00
self . _gtk_settings_mnemonic = settings . get_property (
2015-03-26 20:10:38 +03:00
" gtk-enable-mnemonics " )
settings . set_property ( " gtk-enable-mnemonics " , False )
2009-10-30 21:36:17 +03:00
2010-04-21 20:59:25 +04:00
def _enable_modifiers ( self ) :
2015-04-04 04:34:03 +03:00
if self . _gtk_settings_accel is None :
2009-10-30 20:25:27 +03:00
return
2009-11-02 00:36:44 +03:00
2012-05-14 17:24:56 +04:00
settings = Gtk . Settings . get_default ( )
2015-04-04 04:34:03 +03:00
settings . set_property ( ' gtk-menu-bar-accel ' , self . _gtk_settings_accel )
self . _gtk_settings_accel = None
2009-10-30 21:36:17 +03:00
2015-04-04 04:34:03 +03:00
if self . _gtk_settings_mnemonic is not None :
2009-10-30 21:36:17 +03:00
settings . set_property ( " gtk-enable-mnemonics " ,
2015-04-04 04:34:03 +03:00
self . _gtk_settings_mnemonic )
2009-10-30 21:36:17 +03:00
2015-04-04 04:34:03 +03:00
for g in self . _accel_groups :
2009-10-30 20:25:27 +03:00
self . topwin . add_accel_group ( g )
2015-04-04 01:03:58 +03:00
def _refresh_enable_accel ( self ) :
2010-12-02 21:41:22 +03:00
# Make sure modifiers are up to date
2015-04-04 01:03:58 +03:00
self . _viewer_focus_changed ( )
2009-10-30 20:25:27 +03:00
2015-04-04 04:34:03 +03:00
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 )
2015-04-04 01:03:58 +03:00
def _refresh_resizeguest_from_settings ( self ) :
2014-01-31 18:13:53 +04:00
tooltip = " "
2015-04-04 01:03:58 +03:00
if self . _viewer :
if self . _viewer . viewer_type != " spice " :
2014-01-31 18:13:53 +04:00
tooltip = (
_ ( " Graphics type ' %s ' does not support auto resize. " ) %
2015-04-04 01:03:58 +03:00
self . _viewer . viewer_type )
elif not self . _viewer . console_has_agent ( ) :
2014-01-31 18:13:53 +04:00
tooltip = _ ( " Guest agent is not available. " )
val = self . vm . get_console_resizeguest ( )
widget = self . widget ( " details-menu-view-resizeguest " )
widget . set_tooltip_text ( tooltip )
widget . set_sensitive ( not bool ( tooltip ) )
if not tooltip :
self . widget ( " details-menu-view-resizeguest " ) . set_active ( bool ( val ) )
2015-04-04 04:34:03 +03:00
self . _sync_resizeguest_with_display ( )
2014-01-31 18:13:53 +04:00
2015-04-04 04:34:03 +03:00
def _sync_resizeguest_with_display ( self ) :
if not self . _viewer :
return
val = bool ( self . vm . get_console_resizeguest ( ) )
self . _viewer . console_set_resizeguest ( val )
self . widget ( " console-gfx-scroll " ) . queue_resize ( )
def _resizeguest_ui_changed_cb ( self , src ) :
2014-02-28 20:46:05 +04:00
if not src . get_sensitive ( ) :
2014-01-31 18:13:53 +04:00
return
val = int ( self . widget ( " details-menu-view-resizeguest " ) . get_active ( ) )
self . vm . set_console_resizeguest ( val )
2015-04-04 04:34:03 +03:00
self . _sync_resizeguest_with_display ( )
2014-01-31 18:13:53 +04:00
2015-04-04 04:34:03 +03:00
def _do_size_to_vm ( self , src_ignore ) :
# Resize the console to best fit the VM resolution
2015-04-04 01:03:58 +03:00
if not self . _viewer :
2014-01-31 18:13:53 +04:00
return
2015-04-04 04:34:03 +03:00
if not self . _viewer . console_get_desktop_resolution ( ) :
return
2014-01-31 18:13:53 +04:00
2015-04-04 04:34:03 +03:00
self . topwin . unmaximize ( )
self . topwin . resize ( 1 , 1 )
self . _force_resize = True
2014-01-31 18:13:53 +04:00
self . widget ( " console-gfx-scroll " ) . queue_resize ( )
2015-04-04 04:34:03 +03:00
################
# Scaling APIs #
################
def _refresh_scaling_from_settings ( self ) :
2014-01-31 04:15:02 +04:00
scale_type = self . vm . get_console_scaling ( )
2011-07-14 21:13:13 +04:00
self . widget ( " details-menu-view-scale-always " ) . set_active (
2014-01-31 04:15:02 +04:00
scale_type == self . config . CONSOLE_SCALE_ALWAYS )
2011-07-14 21:13:13 +04:00
self . widget ( " details-menu-view-scale-never " ) . set_active (
2014-01-31 04:15:02 +04:00
scale_type == self . config . CONSOLE_SCALE_NEVER )
2011-07-14 21:13:13 +04:00
self . widget ( " details-menu-view-scale-fullscreen " ) . set_active (
2014-01-31 04:15:02 +04:00
scale_type == self . config . CONSOLE_SCALE_FULLSCREEN )
2009-10-30 20:25:27 +03:00
2015-04-04 01:03:58 +03:00
self . _sync_scaling_with_display ( )
2009-10-30 20:25:27 +03:00
2015-04-04 04:34:03 +03:00
def _scaling_ui_changed_cb ( self , src ) :
2014-01-31 04:15:02 +04:00
# Called from details.py
2009-10-30 20:25:27 +03:00
if not src . get_active ( ) :
return
2014-01-31 04:15:02 +04:00
scale_type = 0
2011-07-14 21:13:13 +04:00
if src == self . widget ( " details-menu-view-scale-always " ) :
2014-01-31 04:15:02 +04:00
scale_type = self . config . CONSOLE_SCALE_ALWAYS
2011-07-14 21:13:13 +04:00
elif src == self . widget ( " details-menu-view-scale-fullscreen " ) :
2014-01-31 04:15:02 +04:00
scale_type = self . config . CONSOLE_SCALE_FULLSCREEN
2011-07-14 21:13:13 +04:00
elif src == self . widget ( " details-menu-view-scale-never " ) :
2014-01-31 04:15:02 +04:00
scale_type = self . config . CONSOLE_SCALE_NEVER
2009-10-30 20:25:27 +03:00
2014-01-31 04:15:02 +04:00
self . vm . set_console_scaling ( scale_type )
2015-04-04 01:03:58 +03:00
self . _sync_scaling_with_display ( )
2009-10-30 20:25:27 +03:00
2015-04-04 01:03:58 +03:00
def _sync_scaling_with_display ( self ) :
if not self . _viewer :
2010-12-22 04:13:11 +03:00
return
2015-04-04 01:03:58 +03:00
curscale = self . _viewer . console_get_scaling ( )
2011-07-14 21:13:13 +04:00
fs = self . widget ( " control-fullscreen " ) . get_active ( )
2014-01-31 04:15:02 +04:00
scale_type = self . vm . get_console_scaling ( )
2009-10-30 20:25:27 +03:00
2015-07-10 15:07:02 +03:00
if ( scale_type == self . config . CONSOLE_SCALE_NEVER and
curscale is True ) :
2015-04-04 01:03:58 +03:00
self . _viewer . console_set_scaling ( False )
2015-07-10 15:07:02 +03:00
elif ( scale_type == self . config . CONSOLE_SCALE_ALWAYS and
curscale is False ) :
2015-04-04 01:03:58 +03:00
self . _viewer . console_set_scaling ( True )
2015-07-10 15:07:02 +03:00
elif ( scale_type == self . config . CONSOLE_SCALE_FULLSCREEN and
curscale != fs ) :
2015-04-04 01:03:58 +03:00
self . _viewer . console_set_scaling ( fs )
2009-10-30 20:25:27 +03:00
2009-11-29 02:48:56 +03:00
# Refresh viewer size
2014-01-30 01:58:34 +04:00
self . widget ( " console-gfx-scroll " ) . queue_resize ( )
2009-11-29 02:48:56 +03:00
2009-10-30 20:25:27 +03:00
2015-04-04 04:34:03 +03:00
###################
# Fullscreen APIs #
###################
def _refresh_can_fullscreen ( self ) :
cpage = self . widget ( " console-pages " ) . get_current_page ( )
dpage = self . widget ( " details-pages " ) . get_current_page ( )
2015-11-25 02:23:36 +03:00
allow_fullscreen = bool ( dpage == DETAILS_PAGE_CONSOLE and
cpage == _CONSOLE_PAGE_VIEWER and
self . _viewer and self . _viewer . console_is_open ( ) )
2011-05-19 01:22:07 +04:00
2015-04-04 04:34:03 +03:00
self . widget ( " control-fullscreen " ) . set_sensitive ( allow_fullscreen )
self . widget ( " details-menu-view-fullscreen " ) . set_sensitive (
allow_fullscreen )
def _leave_fullscreen ( self , ignore = None ) :
2011-05-19 01:22:07 +04:00
self . _change_fullscreen ( False )
2009-11-23 00:39:38 +03:00
2011-05-19 01:22:07 +04:00
def _change_fullscreen ( self , do_fullscreen ) :
2011-07-14 21:13:13 +04:00
self . widget ( " control-fullscreen " ) . set_active ( do_fullscreen )
2009-11-23 00:39:38 +03:00
if do_fullscreen :
2009-10-30 20:25:27 +03:00
self . topwin . fullscreen ( )
2015-04-04 04:34:03 +03:00
self . _fs_toolbar . show ( )
self . _fs_drawer . set_active ( True )
2011-07-14 21:13:13 +04:00
self . widget ( " toolbar-box " ) . hide ( )
self . widget ( " details-menubar " ) . hide ( )
2009-10-30 20:25:27 +03:00
else :
2015-04-04 04:34:03 +03:00
self . _fs_toolbar . hide ( )
self . _fs_drawer . set_active ( False )
2009-10-30 20:25:27 +03:00
self . topwin . unfullscreen ( )
2011-07-14 21:13:13 +04:00
if self . widget ( " details-menu-view-toolbar " ) . get_active ( ) :
self . widget ( " toolbar-box " ) . show ( )
self . widget ( " details-menubar " ) . show ( )
2009-10-30 20:25:27 +03:00
2015-04-04 01:03:58 +03:00
self . _sync_scaling_with_display ( )
2014-01-30 01:58:34 +04:00
2009-10-30 20:25:27 +03:00
##########################
# State tracking methods #
##########################
2015-04-12 17:24:35 +03:00
def _show_vm_status_unavailable ( self ) :
if self . vm . is_crashed ( ) :
self . _activate_unavailable_page ( _ ( " Guest has crashed " ) )
2009-10-30 20:25:27 +03:00
else :
2015-04-12 17:24:35 +03:00
self . _activate_unavailable_page ( _ ( " Guest not running " ) )
2009-10-30 20:25:27 +03:00
2015-04-04 04:34:03 +03:00
def _close_viewer ( self ) :
2015-04-04 01:03:58 +03:00
if self . _viewer is None :
2011-01-14 19:34:51 +03:00
return
2015-04-12 17:33:41 +03:00
self . _viewer . console_remove_display_from_widget (
self . widget ( " console-gfx-viewport " ) )
self . _viewer . cleanup ( )
2015-04-04 01:03:58 +03:00
self . _viewer = None
2011-01-14 19:34:51 +03:00
2015-04-04 04:34:03 +03:00
self . _leave_fullscreen ( )
2010-12-22 04:13:11 +03:00
2015-09-18 18:55:15 +03:00
for serial in self . _serial_consoles :
2013-11-10 02:54:47 +04:00
serial . close ( )
2015-04-12 20:04:32 +03:00
def _update_vm_widget_states ( self ) :
2015-09-06 01:23:47 +03:00
page = self . widget ( " console-pages " ) . get_current_page ( )
2015-04-04 04:34:03 +03:00
2015-09-06 01:23:47 +03:00
if self . vm . is_runable ( ) :
2015-04-12 17:24:35 +03:00
self . _show_vm_status_unavailable ( )
2009-10-30 20:25:27 +03:00
2015-09-18 18:55:15 +03:00
elif ( page == _CONSOLE_PAGE_UNAVAILABLE or
page == _CONSOLE_PAGE_VIEWER ) :
2015-04-04 01:03:58 +03:00
if self . _viewer and self . _viewer . console_is_open ( ) :
2015-04-04 04:34:03 +03:00
self . _activate_viewer_page ( )
2009-10-30 20:25:27 +03:00
else :
2015-04-12 17:24:35 +03:00
self . _init_viewer ( )
2015-09-12 19:07:56 +03:00
# Update other state
2015-09-18 20:05:41 +03:00
self . _refresh_widget_states ( )
2009-10-30 20:25:27 +03:00
2013-09-02 01:40:38 +04:00
2009-10-30 20:25:27 +03:00
###################
# Page Navigation #
###################
2015-04-04 04:34:03 +03:00
def _activate_unavailable_page ( self , msg ) :
2011-06-21 03:09:31 +04:00
"""
This function is passed to serialcon . py at least , so change
with care
"""
2015-04-04 04:34:03 +03:00
self . _close_viewer ( )
self . widget ( " console-pages " ) . set_current_page (
2015-09-18 18:55:15 +03:00
_CONSOLE_PAGE_UNAVAILABLE )
2011-07-14 21:13:13 +04:00
self . widget ( " console-unavailable " ) . set_label ( " <b> " + msg + " </b> " )
2009-10-30 20:25:27 +03:00
2015-04-04 04:34:03 +03:00
def _activate_auth_page ( self , withPassword , withUsername ) :
2009-10-30 20:25:27 +03:00
( pw , username ) = self . config . get_console_password ( self . vm )
2013-09-02 01:40:38 +04:00
self . widget ( " console-auth-password " ) . set_visible ( withPassword )
self . widget ( " label-auth-password " ) . set_visible ( withPassword )
self . widget ( " console-auth-username " ) . set_visible ( withUsername )
self . widget ( " label-auth-username " ) . set_visible ( withUsername )
2009-10-30 20:25:27 +03:00
2011-07-14 21:13:13 +04:00
self . widget ( " console-auth-username " ) . set_text ( username )
self . widget ( " console-auth-password " ) . set_text ( pw )
2009-10-30 20:25:27 +03:00
2013-09-02 01:40:38 +04:00
self . widget ( " console-auth-remember " ) . set_sensitive (
bool ( self . config . has_keyring ( ) ) )
2009-10-30 20:25:27 +03:00
if self . config . has_keyring ( ) :
2015-04-12 19:43:29 +03:00
self . widget ( " console-auth-remember " ) . set_active (
bool ( pw and username ) )
2013-09-02 01:40:38 +04:00
self . widget ( " console-pages " ) . set_current_page (
2015-09-18 18:55:15 +03:00
_CONSOLE_PAGE_AUTHENTICATE )
2009-10-30 20:25:27 +03:00
2015-04-12 19:43:29 +03:00
if withUsername :
self . widget ( " console-auth-username " ) . grab_focus ( )
else :
self . widget ( " console-auth-password " ) . grab_focus ( )
2015-04-04 04:34:03 +03:00
def _activate_viewer_page ( self ) :
2015-09-18 18:55:15 +03:00
self . widget ( " console-pages " ) . set_current_page ( _CONSOLE_PAGE_VIEWER )
2015-04-04 01:03:58 +03:00
if self . _viewer :
self . _viewer . console_grab_focus ( )
2009-10-30 20:25:27 +03:00
2015-09-18 20:05:41 +03:00
def _page_changed ( self , src , origpage , newpage ) :
ignore = src
ignore = origpage
# Hide the contents of all other pages, so they don't screw
# up window sizing
for i in range ( self . widget ( " console-pages " ) . get_n_pages ( ) ) :
self . widget ( " console-pages " ) . get_nth_page ( i ) . set_visible (
i == newpage )
2014-02-28 22:35:48 +04:00
2015-09-18 20:05:41 +03:00
self . idle_add ( self . _refresh_widget_states )
2014-02-28 22:35:48 +04:00
2015-09-18 20:05:41 +03:00
def _refresh_widget_states ( self ) :
pagenum = self . widget ( " console-pages " ) . get_current_page ( )
2015-09-06 01:23:47 +03:00
paused = self . vm . is_paused ( )
2015-09-18 20:05:41 +03:00
is_viewer = ( pagenum == _CONSOLE_PAGE_VIEWER and
self . _viewer and self . _viewer . console_is_open ( ) )
2015-09-06 01:23:47 +03:00
self . widget ( " details-menu-vm-screenshot " ) . set_sensitive ( is_viewer )
self . widget ( " details-menu-usb-redirection " ) . set_sensitive (
2015-09-12 19:07:56 +03:00
bool ( is_viewer and self . _viewer and
self . _viewer . console_has_usb_redirection ( ) and
self . vm . has_spicevmc_type_redirdev ( ) ) )
2015-09-06 01:23:47 +03:00
2015-09-18 20:05:41 +03:00
can_sendkey = ( is_viewer and not paused )
self . _send_key_button . set_sensitive ( can_sendkey )
2015-09-06 01:23:47 +03:00
for c in self . _keycombo_menu . get_children ( ) :
2015-09-18 20:05:41 +03:00
c . set_sensitive ( can_sendkey )
2015-09-06 01:23:47 +03:00
2015-04-04 04:34:03 +03:00
self . _refresh_can_fullscreen ( )
2011-06-01 20:22:05 +04:00
2015-04-04 04:34:03 +03:00
#########################
# Viewer login attempts #
#########################
2011-06-01 20:22:05 +04:00
2015-04-12 17:24:35 +03:00
def _init_viewer ( self ) :
if self . _viewer or not self . is_visible ( ) :
2010-02-11 18:43:44 +03:00
# Don't try and login for these cases
2009-10-30 20:25:27 +03:00
return
2012-03-13 23:27:23 +04:00
ginfo = None
2010-01-11 18:30:40 +03:00
try :
2012-03-13 23:27:23 +04:00
gdevs = self . vm . get_graphics_devices ( )
gdev = gdevs and gdevs [ 0 ] or None
if gdev :
2016-05-08 01:08:25 +03:00
ginfo = ConnectionInfo ( self . vm . conn , gdev )
2010-01-11 18:30:40 +03:00
except Exception , e :
# We can fail here if VM is destroyed: xen is a bit racy
# and can't handle domain lookups that soon after
2012-01-17 07:04:40 +04:00
logging . exception ( " Getting graphics console failed: %s " , str ( e ) )
2010-01-11 18:30:40 +03:00
return
2012-03-13 23:27:23 +04:00
if ginfo is None :
2011-01-07 22:59:31 +03:00
logging . debug ( " No graphics configured for guest " )
2015-04-04 04:34:03 +03:00
self . _activate_unavailable_page (
_ ( " Graphical console not configured for guest " ) )
2009-10-30 20:25:27 +03:00
return
2012-03-13 23:27:23 +04:00
if ginfo . gtype not in self . config . embeddable_graphics ( ) :
2011-04-10 07:03:32 +04:00
logging . debug ( " Don ' t know how to show graphics type ' %s ' "
2012-03-13 23:27:23 +04:00
" disabling console page " , ginfo . gtype )
2011-01-07 22:59:31 +03:00
msg = ( _ ( " Cannot display graphical console type ' %s ' " )
2012-03-13 23:27:23 +04:00
% ginfo . gtype )
2011-01-07 22:59:31 +03:00
2015-04-04 04:34:03 +03:00
self . _activate_unavailable_page ( msg )
2009-10-30 20:25:27 +03:00
return
2013-06-30 19:44:58 +04:00
if ginfo . is_bad_localhost ( ) :
2015-04-04 04:34:03 +03:00
self . _activate_unavailable_page (
_ ( " Guest is on a remote host with transport ' %s ' \n "
2015-04-11 19:08:57 +03:00
" but is only configured to listen locally. \n "
2015-04-04 04:34:03 +03:00
" Connect using ' ssh ' transport or change the \n "
" guest ' s listen address. " % ginfo . transport ) )
2013-06-30 19:44:58 +04:00
return
2015-04-04 04:34:03 +03:00
self . _activate_unavailable_page (
_ ( " Connecting to graphical console for guest " ) )
2010-02-11 18:43:44 +03:00
2012-03-13 23:27:23 +04:00
logging . debug ( " Starting connect process for %s " , ginfo . logstring ( ) )
2009-10-30 20:25:27 +03:00
try :
2012-03-13 23:27:23 +04:00
if ginfo . gtype == " vnc " :
2015-04-04 01:03:58 +03:00
viewer_class = VNCViewer
2012-03-13 23:27:23 +04:00
elif ginfo . gtype == " spice " :
2015-08-13 23:00:33 +03:00
if have_spice_gtk :
viewer_class = SpiceViewer
else :
raise RuntimeError ( " Error opening Spice console, "
" SpiceClientGtk missing " )
2011-01-14 22:17:35 +03:00
2016-05-08 01:08:25 +03:00
self . _viewer = viewer_class ( self . vm , ginfo )
2015-04-04 01:03:58 +03:00
self . _connect_viewer_signals ( )
2011-01-14 22:17:35 +03:00
2015-04-04 01:03:58 +03:00
self . _refresh_enable_accel ( )
2015-04-12 04:39:24 +03:00
self . _viewer . console_open ( )
2011-01-13 19:26:38 +03:00
except Exception , e :
logging . exception ( " Error connection to graphical console " )
2015-04-04 04:34:03 +03:00
self . _activate_unavailable_page (
2011-01-13 19:26:38 +03:00
_ ( " Error connecting to graphical console " ) + " : \n %s " % e )
2009-10-30 20:25:27 +03:00
2015-04-04 04:34:03 +03:00
def _set_credentials ( self , src_ignore = None ) :
2011-07-14 21:13:13 +04:00
passwd = self . widget ( " console-auth-password " )
username = self . widget ( " console-auth-username " )
2015-04-04 01:03:58 +03:00
if passwd . get_visible ( ) :
self . _viewer . console_set_password ( passwd . get_text ( ) )
2012-05-14 17:24:56 +04:00
if username . get_visible ( ) :
2015-04-04 01:03:58 +03:00
self . _viewer . console_set_username ( username . get_text ( ) )
2009-10-30 20:25:27 +03:00
2011-07-14 21:13:13 +04:00
if self . widget ( " console-auth-remember " ) . get_active ( ) :
2009-10-30 20:25:27 +03:00
self . config . set_console_password ( self . vm , passwd . get_text ( ) ,
username . get_text ( ) )
2015-04-04 01:03:58 +03:00
##########################
# Viewer signal handling #
##########################
def _viewer_add_display ( self , ignore , display ) :
self . widget ( " console-gfx-viewport " ) . add ( display )
# Sync initial settings
self . _sync_scaling_with_display ( )
self . _refresh_resizeguest_from_settings ( )
def _pointer_grabbed ( self , ignore ) :
self . _pointer_is_grabbed = True
self . _change_title ( )
def _pointer_ungrabbed ( self , ignore ) :
self . _pointer_is_grabbed = False
self . _change_title ( )
def _viewer_allocate_cb ( self , src , ignore ) :
self . widget ( " console-gfx-scroll " ) . queue_resize ( )
def _viewer_focus_changed ( self , ignore1 = None , ignore2 = None ) :
force_accel = self . config . get_console_accels ( )
if force_accel :
self . _enable_modifiers ( )
2015-04-04 04:34:03 +03:00
elif self . _someone_has_focus ( ) :
2015-04-04 01:03:58 +03:00
self . _disable_modifiers ( )
else :
self . _enable_modifiers ( )
2015-04-12 20:04:32 +03:00
def _viewer_auth_rejected ( self , ignore , errmsg ) :
self . _close_viewer ( )
2015-04-04 04:34:03 +03:00
self . _activate_unavailable_page ( errmsg )
2015-04-04 01:03:58 +03:00
2015-04-12 20:04:32 +03:00
def _viewer_auth_error ( self , ignore , errmsg , viewer_will_disconnect ) :
errmsg = _ ( " Viewer authentication error: %s " ) % errmsg
self . err . val_err ( errmsg )
if viewer_will_disconnect :
# GtkVNC will disconnect after an auth error, so lets do it for
# them and re-init the viewer (which will be triggered by
# update_vm_widget_states if needed)
self . _close_viewer ( )
self . _activate_unavailable_page ( errmsg )
self . _update_vm_widget_states ( )
2015-04-04 01:03:58 +03:00
def _viewer_need_auth ( self , ignore , withPassword , withUsername ) :
2015-04-04 04:34:03 +03:00
self . _activate_auth_page ( withPassword , withUsername )
2015-04-04 01:03:58 +03:00
def _viewer_agent_connected ( self , ignore ) :
self . _refresh_resizeguest_from_settings ( )
def _viewer_usb_redirect_error ( self , ignore , errstr ) :
self . err . show_err ( _ ( " USB redirection error " ) ,
text2 = str ( errstr ) , modal = True )
def _viewer_disconnected ( self , ignore ) :
errout = " "
if self . _viewer :
2015-04-12 05:30:07 +03:00
errout = self . _viewer . console_get_err_output ( )
2015-04-04 01:03:58 +03:00
2015-04-04 04:34:03 +03:00
self . widget ( " console-pages " ) . set_current_page (
2015-09-18 18:55:15 +03:00
_CONSOLE_PAGE_UNAVAILABLE )
2015-04-04 04:34:03 +03:00
self . _close_viewer ( )
2015-04-04 01:03:58 +03:00
logging . debug ( " Viewer disconnected " )
# Make sure modifiers are set correctly
self . _viewer_focus_changed ( )
2015-04-12 17:24:35 +03:00
if self . vm . is_runable ( ) :
2015-04-04 01:03:58 +03:00
# Exit was probably for legitimate reasons
2015-04-12 17:24:35 +03:00
self . _show_vm_status_unavailable ( )
2015-04-12 20:04:32 +03:00
else :
error = _ ( " Error: viewer connection to hypervisor host got "
" refused or disconnected! " )
if errout :
logging . debug ( " Error output from closed console: %s " , errout )
error + = " \n \n Error: %s " % errout
self . _activate_unavailable_page ( error )
2015-04-04 01:03:58 +03:00
self . _refresh_resizeguest_from_settings ( )
def _viewer_connected ( self , ignore ) :
logging . debug ( " Viewer connected " )
2015-04-04 04:34:03 +03:00
self . _activate_viewer_page ( )
2015-04-04 01:03:58 +03:00
# Make sure modifiers are set correctly
self . _viewer_focus_changed ( )
def _connect_viewer_signals ( self ) :
self . _viewer . connect ( " add-display-widget " , self . _viewer_add_display )
self . _viewer . connect ( " pointer-grab " , self . _pointer_grabbed )
self . _viewer . connect ( " pointer-ungrab " , self . _pointer_ungrabbed )
self . _viewer . connect ( " size-allocate " , self . _viewer_allocate_cb )
self . _viewer . connect ( " focus-in-event " , self . _viewer_focus_changed )
self . _viewer . connect ( " focus-out-event " , self . _viewer_focus_changed )
self . _viewer . connect ( " connected " , self . _viewer_connected )
self . _viewer . connect ( " disconnected " , self . _viewer_disconnected )
self . _viewer . connect ( " auth-error " , self . _viewer_auth_error )
2015-04-12 20:04:32 +03:00
self . _viewer . connect ( " auth-rejected " , self . _viewer_auth_rejected )
2015-04-04 01:03:58 +03:00
self . _viewer . connect ( " need-auth " , self . _viewer_need_auth )
self . _viewer . connect ( " agent-connected " , self . _viewer_agent_connected )
self . _viewer . connect ( " usb-redirect-error " ,
self . _viewer_usb_redirect_error )
2013-09-02 01:40:38 +04:00
###########################
# Serial console handling #
###########################
2015-04-04 04:34:03 +03:00
def _activate_default_console_page ( self ) :
2015-09-18 18:55:15 +03:00
"""
Find the default graphical or serial console for the VM
"""
2013-09-02 01:40:38 +04:00
if self . vm . get_graphics_devices ( ) or not self . vm . get_serial_devs ( ) :
return
2015-09-18 18:55:15 +03:00
# We iterate through the 'console' menu and activate the first
# valid entry... it's the easiest thing to do to hit all the right
# code paths.
2014-12-03 20:14:32 +03:00
self . _populate_serial_menu ( )
menu = self . widget ( " details-menu-view-serial-list " ) . get_submenu ( )
for child in menu . get_children ( ) :
if isinstance ( child , Gtk . SeparatorMenuItem ) :
break
if child . get_sensitive ( ) :
child . toggled ( )
break
2013-09-02 01:40:38 +04:00
2014-12-03 20:14:32 +03:00
def _console_menu_toggled ( self , src , dev ) :
2013-09-02 01:40:38 +04:00
self . widget ( " details-pages " ) . set_current_page ( DETAILS_PAGE_CONSOLE )
2014-12-03 20:14:32 +03:00
if dev . virtual_device_type == " graphics " :
2015-09-18 18:55:15 +03:00
self . widget ( " console-pages " ) . set_current_page ( _CONSOLE_PAGE_VIEWER )
2014-12-03 20:14:32 +03:00
return
2013-09-02 01:40:38 +04:00
2014-12-03 20:14:32 +03:00
target_port = dev . vmmindex
2013-09-02 01:40:38 +04:00
serial = None
2015-09-18 18:55:15 +03:00
name = src . get_label ( )
for s in self . _serial_consoles :
2013-09-02 01:40:38 +04:00
if s . name == name :
serial = s
break
if not serial :
serial = vmmSerialConsole ( self . vm , target_port , name )
2013-12-19 01:27:33 +04:00
serial . terminal . connect ( " focus-in-event " ,
2015-04-04 01:03:58 +03:00
self . _viewer_focus_changed )
2013-12-19 01:27:33 +04:00
serial . terminal . connect ( " focus-out-event " ,
2015-04-04 01:03:58 +03:00
self . _viewer_focus_changed )
2013-09-02 01:40:38 +04:00
title = Gtk . Label ( label = name )
2015-09-18 18:55:15 +03:00
self . widget ( " serial-pages " ) . append_page ( serial . box , title )
self . _serial_consoles . append ( serial )
2013-09-02 01:40:38 +04:00
2013-11-10 02:54:47 +04:00
serial . open_console ( )
2015-09-18 18:55:15 +03:00
page_idx = self . _serial_consoles . index ( serial )
self . widget ( " console-pages " ) . set_current_page ( _CONSOLE_PAGE_SERIAL )
self . widget ( " serial-pages " ) . set_current_page ( page_idx )
2013-09-02 01:40:38 +04:00
2014-12-03 20:14:32 +03:00
def _build_serial_menu_items ( self , menu_item_cb ) :
devs = self . vm . get_serial_devs ( )
if len ( devs ) == 0 :
menu_item_cb ( _ ( " No text console available " ) ,
radio = False , sensitive = False )
return
2013-09-02 01:40:38 +04:00
2015-09-18 18:55:15 +03:00
active_label = None
if ( self . widget ( " console-pages " ) . get_current_page ( ) ==
_CONSOLE_PAGE_SERIAL ) :
serial_page = self . widget ( " serial-pages " ) . get_current_page ( )
if len ( self . _serial_consoles ) > serial_page :
active_label = self . _serial_consoles [ serial_page ] . name
2014-12-03 20:14:32 +03:00
for dev in devs :
2015-09-18 18:55:15 +03:00
if dev . virtual_device_type == " console " :
2016-02-05 18:18:16 +03:00
label = _ ( " Text Console %d " ) % ( dev . vmmindex + 1 )
2015-09-18 18:55:15 +03:00
else :
2016-02-05 18:18:16 +03:00
label = _ ( " Serial %d " ) % ( dev . vmmindex + 1 )
2015-09-18 18:55:15 +03:00
2014-12-03 20:14:32 +03:00
tooltip = vmmSerialConsole . can_connect ( self . vm , dev )
sensitive = not bool ( tooltip )
2013-09-02 01:40:38 +04:00
2015-09-18 18:55:15 +03:00
active = ( sensitive and label == active_label )
2014-12-03 20:14:32 +03:00
menu_item_cb ( label , sensitive = sensitive , active = active ,
tooltip = tooltip , cb = self . _console_menu_toggled , cbdata = dev )
2013-09-02 01:40:38 +04:00
2014-12-03 20:14:32 +03:00
def _build_graphical_menu_items ( self , menu_item_cb ) :
2013-09-02 01:40:38 +04:00
devs = self . vm . get_graphics_devices ( )
if len ( devs ) == 0 :
2014-12-03 20:14:32 +03:00
menu_item_cb ( _ ( " No graphical console available " ) ,
radio = False , sensitive = False )
return
2015-09-18 18:55:15 +03:00
active = ( self . widget ( " console-pages " ) . get_current_page ( ) !=
_CONSOLE_PAGE_SERIAL )
2014-12-03 20:21:57 +03:00
for idx , dev in enumerate ( devs ) :
label = ( _ ( " Graphical Console " ) + " " +
dev . pretty_type_simple ( dev . type ) )
sensitive = True
tooltip = None
if idx > 0 :
label + = " %s " % ( idx + 1 )
sensitive = False
tooltip = _ ( " virt-manager does not support more "
" that one graphical console " )
2015-09-18 18:55:15 +03:00
menu_item_cb ( label , active = active ,
2014-12-03 20:21:57 +03:00
sensitive = sensitive , tooltip = tooltip ,
cb = self . _console_menu_toggled , cbdata = dev )
2014-12-03 20:14:32 +03:00
def _populate_serial_menu ( self , ignore = None ) :
src = self . widget ( " details-menu-view-serial-list " ) . get_submenu ( )
for child in src :
src . remove ( child )
def menu_item_cb ( label , sensitive = True , active = False ,
radio = True , tooltip = None , cb = None , cbdata = None ) :
if radio :
item = Gtk . RadioMenuItem ( menu_item_cb . radio_group )
if menu_item_cb . radio_group is None :
menu_item_cb . radio_group = item
item . set_label ( label )
else :
item = Gtk . MenuItem . new_with_label ( label )
item . set_sensitive ( sensitive )
if active :
2013-09-02 01:40:38 +04:00
item . set_active ( True )
2014-12-03 20:14:32 +03:00
if tooltip :
item . set_tooltip_text ( tooltip )
2014-12-03 20:21:57 +03:00
if cb and sensitive :
2014-12-03 20:14:32 +03:00
item . connect ( " toggled " , cb , cbdata )
2013-09-02 01:40:38 +04:00
src . add ( item )
2014-12-03 20:14:32 +03:00
menu_item_cb . radio_group = None
2013-09-02 01:40:38 +04:00
2014-12-03 20:14:32 +03:00
self . _build_serial_menu_items ( menu_item_cb )
src . add ( Gtk . SeparatorMenuItem ( ) )
self . _build_graphical_menu_items ( menu_item_cb )
2013-09-02 01:40:38 +04:00
src . show_all ( )
2015-04-04 04:34:03 +03:00
##########################
# 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 ( )
2015-04-12 20:04:32 +03:00
def details_update_widget_states ( self ) :
return self . _update_vm_widget_states ( )
2015-04-04 04:34:03 +03:00
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_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 . _set_credentials ( )