2014-01-28 18:44:40 -05:00
# Copyright (C) 2006-2007, 2013, 2014 Red Hat, Inc.
# Copyright (C) 2006 Hugh O. Brock <hbrock@redhat.com>
# Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
2018-04-04 14:35:41 +01:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 15:00:02 -04:00
# See the COPYING file in the top-level directory.
2014-01-28 18:44:40 -05:00
from gi . repository import Gtk
import virtinst
2014-09-12 16:10:45 -04:00
from . import uiutil
from . baseclass import vmmGObjectUI
2014-01-28 18:44:40 -05:00
class vmmGraphicsDetails ( vmmGObjectUI ) :
__gsignals__ = {
2018-03-15 08:10:09 -04:00
" changed-password " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
" changed-port " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
" changed-tlsport " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
" changed-type " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
" changed-listen " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
" changed-address " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
" changed-keymap " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
" changed-opengl " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
" changed-rendernode " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
2014-01-28 18:44:40 -05:00
}
def __init__ ( self , vm , builder , topwin ) :
vmmGObjectUI . __init__ ( self , " gfxdetails.ui " ,
None , builder = builder , topwin = topwin )
self . vm = vm
self . conn = vm . conn
self . builder . connect_signals ( {
" on_graphics_type_changed " : self . _change_graphics_type ,
" on_graphics_port_auto_toggled " : self . _change_port_auto ,
" on_graphics_tlsport_auto_toggled " : self . _change_tlsport_auto ,
" on_graphics_use_password " : self . _change_password_chk ,
2017-07-19 11:09:28 +08:00
" on_graphics_show_password " : self . _show_password_chk ,
2014-01-28 18:44:40 -05:00
2017-02-21 17:00:59 +04:00
" on_graphics_listen_type_changed " : self . _change_graphics_listen ,
2014-01-28 18:44:40 -05:00
" on_graphics_password_changed " : lambda ignore : self . emit ( " changed-password " ) ,
" on_graphics_address_changed " : lambda ignore : self . emit ( " changed-address " ) ,
" on_graphics_tlsport_changed " : lambda ignore : self . emit ( " changed-tlsport " ) ,
" on_graphics_port_changed " : lambda ignore : self . emit ( " changed-port " ) ,
" on_graphics_keymap_changed " : lambda ignore : self . emit ( " changed-keymap " ) ,
2017-02-21 17:01:01 +04:00
" on_graphics_opengl_toggled " : self . _change_opengl ,
" on_graphics_rendernode_changed " : lambda ignore : self . emit ( " changed-rendernode " )
2014-01-28 18:44:40 -05:00
} )
self . _init_ui ( )
self . top_box = self . widget ( " graphics-box " )
def _cleanup ( self ) :
self . vm = None
self . conn = None
##########################
# Initialization methods #
##########################
def _init_ui ( self ) :
graphics_list = self . widget ( " graphics-type " )
graphics_model = Gtk . ListStore ( str , str )
graphics_list . set_model ( graphics_model )
2015-04-10 13:04:02 -04:00
uiutil . init_combo_text_column ( graphics_list , 1 )
2014-01-28 18:44:40 -05:00
graphics_model . clear ( )
graphics_model . append ( [ " spice " , _ ( " Spice server " ) ] )
graphics_model . append ( [ " vnc " , _ ( " VNC server " ) ] )
2017-02-21 17:00:59 +04:00
graphics_listen_list = self . widget ( " graphics-listen-type " )
graphics_listen_model = Gtk . ListStore ( str , str )
graphics_listen_list . set_model ( graphics_listen_model )
uiutil . init_combo_text_column ( graphics_listen_list , 1 )
graphics_listen_model . clear ( )
graphics_listen_model . append ( [ " address " , _ ( " Address " ) ] )
graphics_listen_model . append ( [ " none " , _ ( " None " ) ] )
2014-01-28 18:44:40 -05:00
self . widget ( " graphics-address " ) . set_model ( Gtk . ListStore ( str , str ) )
2015-04-10 13:04:02 -04:00
uiutil . init_combo_text_column ( self . widget ( " graphics-address " ) , 1 )
2014-01-28 18:44:40 -05:00
model = self . widget ( " graphics-address " ) . get_model ( )
model . clear ( )
model . append ( [ None , _ ( " Hypervisor default " ) ] )
model . append ( [ " 127.0.0.1 " , _ ( " Localhost only " ) ] )
model . append ( [ " 0.0.0.0 " , _ ( " All interfaces " ) ] )
# Keymap
combo = self . widget ( " graphics-keymap " )
model = Gtk . ListStore ( str , str )
combo . set_model ( model )
2015-04-10 13:04:02 -04:00
uiutil . init_combo_text_column ( combo , 1 )
2014-01-28 18:44:40 -05:00
2016-02-05 16:18:16 +01:00
model . append ( [ " auto " , _ ( " Auto " ) ] )
2018-03-20 12:18:35 -04:00
model . append ( [ virtinst . DeviceGraphics . KEYMAP_LOCAL ,
2016-02-05 16:18:16 +01:00
_ ( " Copy local keymap " ) ] )
2018-03-20 12:18:35 -04:00
for k in virtinst . DeviceGraphics . valid_keymaps ( ) :
2014-01-28 18:44:40 -05:00
model . append ( [ k , k ] )
2017-02-21 17:01:01 +04:00
# Host GPU rendernode
combo = self . widget ( " graphics-rendernode " )
model = Gtk . ListStore ( str , str )
combo . set_model ( model )
uiutil . init_combo_text_column ( combo , 1 )
model . append ( [ None , _ ( " Auto " ) ] )
devs = self . conn . filter_nodedevs ( " drm " )
for i in devs :
drm = i . xmlobj
if drm . drm_type != ' render ' :
continue
rendernode = drm . get_devnode ( ) . path
2017-11-25 16:32:30 -05:00
model . append ( [ rendernode ,
i . xmlobj . drm_pretty_name ( self . conn . get_backend ( ) ) ] )
2017-02-21 17:01:01 +04:00
2014-01-28 18:44:40 -05:00
def _get_config_graphics_ports ( self ) :
port = uiutil . spin_get_helper ( self . widget ( " graphics-port " ) )
tlsport = uiutil . spin_get_helper ( self . widget ( " graphics-tlsport " ) )
2015-05-19 17:17:53 -04:00
gtype = uiutil . get_list_selection ( self . widget ( " graphics-type " ) )
2014-01-28 18:44:40 -05:00
if self . widget ( " graphics-port-auto " ) . get_active ( ) :
port = - 1
if self . widget ( " graphics-tlsport-auto " ) . get_active ( ) :
tlsport = - 1
if gtype != " spice " :
tlsport = None
return port , tlsport
##############
# Public API #
##############
def reset_state ( self ) :
uiutil . set_grid_row_visible ( self . widget ( " graphics-display " ) , False )
uiutil . set_grid_row_visible ( self . widget ( " graphics-xauth " ) , False )
self . widget ( " graphics-type " ) . set_active ( 0 )
2017-02-21 17:00:59 +04:00
self . widget ( " graphics-listen-type " ) . set_active ( 0 )
2014-01-28 18:44:40 -05:00
self . widget ( " graphics-address " ) . set_active ( 0 )
self . widget ( " graphics-keymap " ) . set_active ( 0 )
2017-11-25 16:32:30 -05:00
# Select last entry in the list, which should be a rendernode path
rendermodel = self . widget ( " graphics-rendernode " ) . get_model ( )
self . widget ( " graphics-rendernode " ) . set_active_iter ( rendermodel [ - 1 ] . iter )
2014-01-28 18:44:40 -05:00
self . _change_ports ( )
self . widget ( " graphics-port-auto " ) . set_active ( True )
self . widget ( " graphics-tlsport-auto " ) . set_active ( True )
self . widget ( " graphics-password " ) . set_text ( " " )
self . widget ( " graphics-password " ) . set_sensitive ( False )
self . widget ( " graphics-password-chk " ) . set_active ( False )
def get_values ( self ) :
2015-05-19 17:17:53 -04:00
gtype = uiutil . get_list_selection ( self . widget ( " graphics-type " ) )
2014-01-28 18:44:40 -05:00
port , tlsport = self . _get_config_graphics_ports ( )
2017-02-21 17:00:59 +04:00
listen = uiutil . get_list_selection ( self . widget ( " graphics-listen-type " ) )
2015-05-19 17:17:53 -04:00
addr = uiutil . get_list_selection ( self . widget ( " graphics-address " ) )
2015-05-19 17:54:53 -04:00
keymap = uiutil . get_list_selection ( self . widget ( " graphics-keymap " ) )
2014-01-28 18:44:40 -05:00
if keymap == " auto " :
keymap = None
passwd = self . widget ( " graphics-password " ) . get_text ( )
if not self . widget ( " graphics-password-chk " ) . get_active ( ) :
passwd = None
2017-02-21 17:00:56 +04:00
gl = self . widget ( " graphics-opengl " ) . get_active ( )
2017-02-21 17:01:01 +04:00
rendernode = uiutil . get_list_selection ( self . widget ( " graphics-rendernode " ) )
2017-02-21 17:00:56 +04:00
2017-02-21 17:01:01 +04:00
return gtype , port , tlsport , listen , addr , passwd , keymap , gl , rendernode
2014-01-28 18:44:40 -05:00
def set_dev ( self , gfx ) :
self . reset_state ( )
def set_port ( basename , val ) :
auto = self . widget ( basename + " -auto " )
widget = self . widget ( basename )
2014-03-22 18:25:53 -04:00
auto . set_inconsistent ( False )
2014-03-30 17:34:26 -04:00
label = auto . get_label ( ) . split ( " ( " ) [ 0 ]
2014-03-22 18:25:53 -04:00
2014-01-28 18:44:40 -05:00
if val == - 1 or gfx . autoport :
auto . set_active ( True )
2014-03-30 17:34:26 -04:00
if val and val != - 1 :
label + = " ( %s %s ) " % ( _ ( " Port " ) , val )
2014-01-28 18:44:40 -05:00
elif val is None :
auto . set_inconsistent ( True )
else :
auto . set_active ( False )
widget . set_value ( val )
2014-03-30 17:34:26 -04:00
auto . set_label ( label )
2014-01-28 18:44:40 -05:00
gtype = gfx . type
is_vnc = ( gtype == " vnc " )
is_sdl = ( gtype == " sdl " )
is_spice = ( gtype == " spice " )
title = ( _ ( " %(graphicstype)s Server " ) %
2017-08-05 14:39:32 +08:00
{ " graphicstype " : gfx . pretty_type_simple ( gtype ) } )
2014-01-28 18:44:40 -05:00
if is_vnc or is_spice :
use_passwd = gfx . passwd is not None
set_port ( " graphics-port " , gfx . port )
2017-02-21 17:00:59 +04:00
listentype = gfx . get_first_listen_type ( )
if listentype and listentype == ' none ' :
uiutil . set_list_selection ( self . widget ( " graphics-listen-type " ) , ' none ' )
else :
uiutil . set_list_selection ( self . widget ( " graphics-listen-type " ) , ' address ' )
uiutil . set_list_selection (
self . widget ( " graphics-address " ) , gfx . listen )
2015-05-19 18:22:49 -04:00
uiutil . set_list_selection (
2015-05-19 17:17:53 -04:00
self . widget ( " graphics-keymap " ) , gfx . keymap or None )
2014-01-28 18:44:40 -05:00
self . widget ( " graphics-password " ) . set_text ( gfx . passwd or " " )
self . widget ( " graphics-password-chk " ) . set_active ( use_passwd )
self . widget ( " graphics-password " ) . set_sensitive ( use_passwd )
if is_spice :
set_port ( " graphics-tlsport " , gfx . tlsPort )
2017-03-08 16:01:59 -05:00
opengl_warning = " "
rendernode_warning = " "
opengl_supported = self . conn . check_support (
self . conn . SUPPORT_CONN_SPICE_GL )
rendernode_supported = self . conn . check_support (
self . conn . SUPPORT_CONN_SPICE_RENDERNODE )
# * If spicegl isn't supported, show a warning icon and
# and desensitive everything
# * If qemu:///system and rendernode isn't supported,
# show a warning icon and desensitize everything, since
# rendernode support is needed for it to work out of the box.
# * Otherwise, enable all UI, but show warning icons anyways
# for potential config issues
glval = False
renderval = None
glsensitive = False
if not opengl_supported :
opengl_warning = (
_ ( " Hypervisor/libvirt does not support spice GL " ) )
elif not rendernode_supported :
rendernode_warning = (
_ ( " Hypervisor/libvirt does not support manual rendernode " ) )
if self . conn . is_qemu_system ( ) :
opengl_warning = rendernode_warning
if not opengl_warning :
glval = bool ( gfx . gl )
glsensitive = True
if not rendernode_warning :
renderval = gfx . rendernode or None
if opengl_warning :
pass
2018-03-20 17:23:34 -04:00
elif not [ v for v in self . vm . xmlobj . devices . video if
2017-03-08 16:01:59 -05:00
( v . model == " virtio " and v . accel3d ) ] :
opengl_warning = _ ( " Spice GL requires "
" virtio graphics configured with accel3d. " )
elif gfx . get_first_listen_type ( ) not in [ " none " , " socket " ] :
opengl_warning = _ ( " Graphics listen type does not support "
" spice GL. " )
self . widget ( " graphics-opengl " ) . set_active ( glval )
2017-11-25 16:32:30 -05:00
if glval :
# Only sync rendernode UI with XML, if gl=on, otherwise
# we want to preserve the suggested rendernode already
# selected in the UI
uiutil . set_list_selection (
self . widget ( " graphics-rendernode " ) , renderval )
2017-03-08 16:01:59 -05:00
self . widget ( " graphics-opengl " ) . set_sensitive ( glsensitive )
self . widget ( " graphics-opengl-warn " ) . set_tooltip_text (
opengl_warning or None )
self . widget ( " graphics-opengl-warn " ) . set_visible (
bool ( opengl_warning ) )
self . widget ( " graphics-rendernode " ) . set_sensitive (
rendernode_supported )
self . widget ( " graphics-rendernode-warn " ) . set_tooltip_text (
rendernode_warning or None )
self . widget ( " graphics-rendernode-warn " ) . set_visible (
bool ( rendernode_warning ) )
2014-01-28 18:44:40 -05:00
if is_sdl :
title = _ ( " Local SDL Window " )
self . widget ( " graphics-display " ) . set_text (
gfx . display or _ ( " Unknown " ) )
self . widget ( " graphics-xauth " ) . set_text (
gfx . xauth or _ ( " Unknown " ) )
2015-05-19 18:22:49 -04:00
uiutil . set_list_selection ( self . widget ( " graphics-type " ) , gtype )
2014-01-28 18:44:40 -05:00
return title
#############
# Listeners #
#############
def _show_rows_from_type ( self ) :
hide_all = [ " graphics-xauth " , " graphics-display " , " graphics-address " ,
" graphics-password-box " , " graphics-keymap " , " graphics-port-box " ,
2017-03-08 16:01:59 -05:00
" graphics-tlsport-box " , " graphics-opengl-box " ]
2014-01-28 18:44:40 -05:00
2015-05-19 17:17:53 -04:00
gtype = uiutil . get_list_selection ( self . widget ( " graphics-type " ) )
2017-02-21 17:00:59 +04:00
listen = uiutil . get_list_selection ( self . widget ( " graphics-listen-type " ) )
2014-01-28 18:44:40 -05:00
sdl_rows = [ " graphics-xauth " , " graphics-display " ]
2017-02-21 17:00:59 +04:00
vnc_rows = [ " graphics-password-box " , " graphics-keymap " ]
if listen == ' address ' :
vnc_rows . extend ( [ " graphics-port-box " , " graphics-address " ] )
spice_rows = vnc_rows [ : ]
if listen == ' address ' :
spice_rows . extend ( [ " graphics-tlsport-box " ] )
2017-03-08 16:01:59 -05:00
spice_rows . extend ( [ " graphics-opengl-box " ] )
2014-01-28 18:44:40 -05:00
rows = [ ]
if gtype == " sdl " :
rows = sdl_rows
elif gtype == " vnc " :
rows = vnc_rows
elif gtype == " spice " :
rows = spice_rows
for row in hide_all :
uiutil . set_grid_row_visible ( self . widget ( row ) , row in rows )
def _change_graphics_type ( self , ignore ) :
self . _show_rows_from_type ( )
self . emit ( " changed-type " )
2017-02-21 17:00:59 +04:00
def _change_graphics_listen ( self , ignore ) :
self . _show_rows_from_type ( )
self . emit ( " changed-listen " )
2017-02-21 17:01:01 +04:00
def _change_opengl ( self , ignore ) :
2017-03-08 16:01:59 -05:00
uiutil . set_grid_row_visible (
self . widget ( " graphics-rendernode-box " ) ,
self . widget ( " graphics-opengl " ) . get_active ( ) )
2017-02-21 17:01:01 +04:00
self . emit ( " changed-opengl " )
2014-01-28 18:44:40 -05:00
def _change_port_auto ( self , ignore ) :
2014-03-22 18:25:53 -04:00
self . widget ( " graphics-port-auto " ) . set_inconsistent ( False )
2014-01-28 18:44:40 -05:00
self . _change_ports ( )
self . emit ( " changed-port " )
def _change_tlsport_auto ( self , ignore ) :
2014-03-22 18:25:53 -04:00
self . widget ( " graphics-tlsport-auto " ) . set_inconsistent ( False )
2014-01-28 18:44:40 -05:00
self . _change_ports ( )
self . emit ( " changed-tlsport " )
def _change_ports ( self ) :
is_auto = ( self . widget ( " graphics-port-auto " ) . get_active ( ) or
self . widget ( " graphics-port-auto " ) . get_inconsistent ( ) )
is_tlsauto = ( self . widget ( " graphics-tlsport-auto " ) . get_active ( ) or
self . widget ( " graphics-tlsport-auto " ) . get_inconsistent ( ) )
self . widget ( " graphics-port " ) . set_visible ( not is_auto )
self . widget ( " graphics-tlsport " ) . set_visible ( not is_tlsauto )
def _change_password_chk ( self , ignore = None ) :
if self . widget ( " graphics-password-chk " ) . get_active ( ) :
self . widget ( " graphics-password " ) . set_sensitive ( True )
else :
self . widget ( " graphics-password " ) . set_text ( " " )
self . widget ( " graphics-password " ) . set_sensitive ( False )
self . emit ( " changed-password " )
2017-07-19 11:09:28 +08:00
def _show_password_chk ( self , ignore = None ) :
if self . widget ( " graphics-visiblity-chk " ) . get_active ( ) :
self . widget ( " graphics-password " ) . set_visibility ( True )
else :
self . widget ( " graphics-password " ) . set_visibility ( False )