2019-05-05 16:25:35 -04:00
# Copyright (C) 2006-2008, 2013, 2014 Red Hat, Inc.
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
from gi . repository import Gdk
from gi . repository import Gtk
2019-06-16 21:12:39 -04:00
from virtinst import log
2019-05-05 16:25:35 -04:00
from . import vmmenu
from . baseclass import vmmGObjectUI
from . engine import vmmEngine
2020-09-09 15:14:05 -04:00
from . details . console import vmmConsolePages
2019-06-16 21:56:34 -04:00
from . details . details import vmmDetails
from . details . snapshots import vmmSnapshotPage
2019-05-05 16:25:35 -04:00
# Main tab pages
( DETAILS_PAGE_DETAILS ,
DETAILS_PAGE_CONSOLE ,
DETAILS_PAGE_SNAPSHOTS ) = range ( 3 )
class vmmVMWindow ( vmmGObjectUI ) :
__gsignals__ = {
2019-05-08 16:13:40 -04:00
" customize-finished " : ( vmmGObjectUI . RUN_FIRST , None , [ object ] ) ,
2019-05-05 16:25:35 -04:00
" closed " : ( vmmGObjectUI . RUN_FIRST , None , [ ] ) ,
}
@classmethod
def get_instance ( cls , parentobj , vm ) :
try :
# Maintain one dialog per VM
key = " %s + %s " % ( vm . conn . get_uri ( ) , vm . get_uuid ( ) )
if cls . _instances is None :
cls . _instances = { }
if key not in cls . _instances :
cls . _instances [ key ] = vmmVMWindow ( vm )
return cls . _instances [ key ]
2020-08-22 15:42:08 -04:00
except Exception as e : # pragma: no cover
2019-05-05 16:25:35 -04:00
if not parentobj :
raise
parentobj . err . show_err (
_ ( " Error launching details: %s " ) % str ( e ) )
def __init__ ( self , vm , parent = None ) :
vmmGObjectUI . __init__ ( self , " vmwindow.ui " , " vmm-vmwindow " )
self . vm = vm
self . is_customize_dialog = False
if parent :
# Details window is being abused as a 'configure before install'
# dialog, set things as appropriate
self . is_customize_dialog = True
self . topwin . set_type_hint ( Gdk . WindowTypeHint . DIALOG )
self . topwin . set_transient_for ( parent )
2022-08-01 09:44:48 -04:00
self . topwin . set_deletable ( False )
2019-05-05 16:25:35 -04:00
self . widget ( " toolbar-box " ) . show ( )
self . widget ( " customize-toolbar " ) . show ( )
self . widget ( " details-toolbar " ) . hide ( )
self . widget ( " details-menubar " ) . hide ( )
pages = self . widget ( " details-pages " )
pages . set_current_page ( DETAILS_PAGE_DETAILS )
else :
2020-09-01 11:54:10 -04:00
self . conn . connect ( " vm-removed " , self . _vm_removed_cb )
2019-05-05 16:25:35 -04:00
self . ignoreDetails = False
2020-09-09 15:14:05 -04:00
self . _console = vmmConsolePages ( self . vm , self . builder , self . topwin )
self . widget ( " console-placeholder " ) . add ( self . _console . top_box )
self . _console . connect ( " page-changed " , self . _console_page_changed_cb )
self . _console . connect ( " leave-fullscreen " ,
self . _console_leave_fullscreen_cb )
2020-09-20 22:53:30 -04:00
self . _console . connect ( " change-title " ,
self . _console_change_title_cb )
2020-09-09 15:14:05 -04:00
2020-09-20 21:55:05 -04:00
self . _snapshots = vmmSnapshotPage ( self . vm , self . builder , self . topwin )
self . widget ( " snapshot-placeholder " ) . add ( self . _snapshots . top_box )
2020-09-09 15:14:05 -04:00
2019-05-05 16:25:35 -04:00
self . _details = vmmDetails ( self . vm , self . builder , self . topwin ,
self . is_customize_dialog )
self . widget ( " details-placeholder " ) . add ( self . _details . top_box )
# Set default window size
w , h = self . vm . get_details_window_size ( )
2020-09-09 12:58:20 -04:00
if w < = 0 or h < = 0 :
self . _set_initial_window_size ( )
else :
self . topwin . set_default_size ( w , h )
2019-05-05 16:25:35 -04:00
self . _window_size = None
self . _shutdownmenu = None
self . _vmmenu = None
self . init_menus ( )
self . builder . connect_signals ( {
" on_close_details_clicked " : self . close ,
" on_details_menu_close_activate " : self . close ,
" on_vmm_details_delete_event " : self . _window_delete_event ,
" on_vmm_details_configure_event " : self . window_resized ,
" on_details_menu_quit_activate " : self . exit_app ,
" on_control_vm_details_toggled " : self . details_console_changed ,
" on_control_vm_console_toggled " : self . details_console_changed ,
" on_control_snapshots_toggled " : self . details_console_changed ,
" on_control_run_clicked " : self . control_vm_run ,
" on_control_shutdown_clicked " : self . control_vm_shutdown ,
" on_control_pause_toggled " : self . control_vm_pause ,
" on_control_fullscreen_toggled " : self . control_fullscreen ,
" on_details_customize_finish_clicked " : self . customize_finish ,
" on_details_cancel_customize_clicked " : self . _customize_cancel_clicked ,
" on_details_menu_virtual_manager_activate " : self . control_vm_menu ,
" on_details_menu_screenshot_activate " : self . control_vm_screenshot ,
" on_details_menu_usb_redirection " : self . control_vm_usb_redirection ,
" on_details_menu_view_toolbar_activate " : self . toggle_toolbar ,
" on_details_menu_view_manager_activate " : self . view_manager ,
" on_details_menu_view_details_toggled " : self . details_console_changed ,
" on_details_menu_view_console_toggled " : self . details_console_changed ,
" on_details_menu_view_snapshots_toggled " : self . details_console_changed ,
2020-09-20 21:55:05 -04:00
" on_details_pages_switch_page " : self . _details_page_switch_cb ,
2019-05-05 16:25:35 -04:00
2020-09-09 15:14:05 -04:00
" on_details_menu_view_fullscreen_activate " : self . _fullscreen_changed_cb ,
" on_details_menu_view_size_to_vm_activate " : self . _size_to_vm_cb ,
" on_details_menu_view_scale_always_toggled " : self . _scaling_ui_changed_cb ,
" on_details_menu_view_scale_fullscreen_toggled " : self . _scaling_ui_changed_cb ,
" on_details_menu_view_scale_never_toggled " : self . _scaling_ui_changed_cb ,
" on_details_menu_view_resizeguest_toggled " : self . _resizeguest_ui_changed_cb ,
2020-09-09 19:04:44 -04:00
" on_details_menu_view_autoconnect_activate " : self . _autoconnect_ui_changed_cb ,
2019-05-05 16:25:35 -04:00
} )
# Deliberately keep all this after signal connection
2020-09-20 21:55:05 -04:00
self . vm . connect ( " state-changed " , self . _vm_state_changed_cb )
self . vm . connect ( " resources-sampled " , self . _resources_sampled_cb )
2019-05-05 16:25:35 -04:00
2020-09-20 21:55:05 -04:00
self . _sync_console_page_menu_state ( )
2020-09-09 15:14:05 -04:00
self . _console_refresh_scaling_from_settings ( )
self . add_gsettings_handle (
self . vm . on_console_scaling_changed (
self . _console_refresh_scaling_from_settings ) )
self . _console_refresh_resizeguest_from_settings ( )
self . add_gsettings_handle (
self . vm . on_console_resizeguest_changed (
self . _console_refresh_resizeguest_from_settings ) )
2020-09-09 19:04:44 -04:00
self . _console_refresh_autoconnect_from_settings ( )
self . add_gsettings_handle (
self . vm . on_console_autoconnect_changed (
self . _console_refresh_autoconnect_from_settings ) )
2020-09-09 15:14:05 -04:00
2020-09-20 21:55:05 -04:00
self . _refresh_vm_state ( )
2019-05-05 16:25:35 -04:00
self . activate_default_page ( )
@property
def conn ( self ) :
return self . vm . conn
def _cleanup ( self ) :
2020-09-09 15:14:05 -04:00
self . _console . cleanup ( )
self . _console = None
2020-09-20 21:55:05 -04:00
self . _snapshots . cleanup ( )
self . _snapshots = None
2019-05-23 17:01:44 -04:00
self . _details . cleanup ( )
self . _details = None
2019-05-05 16:25:35 -04:00
self . _shutdownmenu . destroy ( )
self . _shutdownmenu = None
self . _vmmenu . destroy ( )
self . _vmmenu = None
if self . _window_size :
self . vm . set_details_window_size ( * self . _window_size )
self . conn . disconnect_by_obj ( self )
self . vm = None
def show ( self ) :
2019-06-16 21:12:39 -04:00
log . debug ( " Showing VM details: %s " , self . vm )
2019-05-05 16:25:35 -04:00
vis = self . is_visible ( )
self . topwin . present ( )
if vis :
return
vmmEngine . get_instance ( ) . increment_window_counter ( )
2020-09-20 21:55:05 -04:00
self . _refresh_vm_state ( )
2019-05-05 16:25:35 -04:00
def customize_finish ( self , src ) :
ignore = src
if self . _details . vmwindow_has_unapplied_changes ( ) :
return
2019-05-08 16:13:40 -04:00
self . emit ( " customize-finished " , self . vm )
2019-05-05 16:25:35 -04:00
2020-09-09 12:58:20 -04:00
def _set_initial_window_size ( self ) :
"""
We want the window size for new windows to be 1024 x768 viewer
size , plus whatever it takes to fit the toolbar + menubar , etc .
To achieve this , we force the display box to the desired size
with set_size_request , wait for the window to report it has
been resized , and then unset the hardcoded size request so
the user can manually resize the window however they want .
"""
w = 1024
h = 768
hid = [ ]
def win_cb ( src , event ) :
self . widget ( " details-pages " ) . set_size_request ( - 1 , - 1 )
self . topwin . disconnect ( hid [ 0 ] )
self . widget ( " details-pages " ) . set_size_request ( w , h )
hid . append ( self . topwin . connect ( " configure-event " , win_cb ) )
2020-09-01 11:54:10 -04:00
def _vm_removed_cb ( self , _conn , vm ) :
if self . vm == vm :
2019-05-05 16:25:35 -04:00
self . cleanup ( )
def _customize_cancel ( self ) :
2019-06-16 21:12:39 -04:00
log . debug ( " Asking to cancel customization " )
2019-05-05 16:25:35 -04:00
result = self . err . yes_no (
_ ( " This will abort the installation. Are you sure? " ) )
if not result :
2019-06-16 21:12:39 -04:00
log . debug ( " Customize cancel aborted " )
2019-05-05 16:25:35 -04:00
return
2019-06-16 21:12:39 -04:00
log . debug ( " Canceling customization " )
2019-05-05 16:25:35 -04:00
return self . _close ( )
def _customize_cancel_clicked ( self , src ) :
ignore = src
return self . _customize_cancel ( )
def _window_delete_event ( self , ignore1 = None , ignore2 = None ) :
return self . close ( )
def close ( self , ignore1 = None , ignore2 = None ) :
if self . is_visible ( ) :
2019-06-16 21:12:39 -04:00
log . debug ( " Closing VM details: %s " , self . vm )
2019-05-05 16:25:35 -04:00
return self . _close ( )
def _close ( self ) :
fs = self . widget ( " details-menu-view-fullscreen " )
if fs . get_active ( ) :
2020-08-26 18:01:02 -04:00
fs . set_active ( False ) # pragma: no cover
2019-05-05 16:25:35 -04:00
if not self . is_visible ( ) :
return
self . topwin . hide ( )
2020-09-20 21:55:27 -04:00
self . _console . vmwindow_close ( )
self . _details . vmwindow_close ( )
2019-05-05 16:25:35 -04:00
self . emit ( " closed " )
vmmEngine . get_instance ( ) . decrement_window_counter ( )
return 1
##########################
# Initialization helpers #
##########################
def init_menus ( self ) :
# Virtual Machine menu
self . _shutdownmenu = vmmenu . VMShutdownMenu ( self , lambda : self . vm )
self . widget ( " control-shutdown " ) . set_menu ( self . _shutdownmenu )
self . widget ( " control-shutdown " ) . set_icon_name ( " system-shutdown " )
topmenu = self . widget ( " details-vm-menu " )
submenu = topmenu . get_submenu ( )
self . _vmmenu = vmmenu . VMActionMenu (
self , lambda : self . vm , show_open = False )
for child in submenu . get_children ( ) :
submenu . remove ( child )
self . _vmmenu . add ( child )
topmenu . set_submenu ( self . _vmmenu )
topmenu . show_all ( )
self . widget ( " details-pages " ) . set_show_tabs ( False )
self . widget ( " details-menu-view-toolbar " ) . set_active (
self . config . get_details_show_toolbar ( ) )
2020-09-09 15:14:05 -04:00
# Keycombo menu (ctrl+alt+del etc.)
self . widget ( " details-menu-send-key " ) . set_submenu (
self . _console . vmwindow_get_keycombo_menu ( ) )
# Serial list menu
self . widget ( " details-menu-view-console-list " ) . set_submenu (
self . _console . vmwindow_get_console_list_menu ( ) )
2019-05-05 16:25:35 -04:00
##########################
# Window state listeners #
##########################
def window_resized ( self , ignore , ignore2 ) :
if not self . is_visible ( ) :
2020-08-26 18:01:02 -04:00
return # pragma: no cover
2019-05-05 16:25:35 -04:00
self . _window_size = self . topwin . get_size ( )
def control_fullscreen ( self , src ) :
menu = self . widget ( " details-menu-view-fullscreen " )
if src . get_active ( ) != menu . get_active ( ) :
menu . set_active ( src . get_active ( ) )
def toggle_toolbar ( self , src ) :
if self . is_customize_dialog :
return
active = src . get_active ( )
self . config . set_details_show_toolbar ( active )
2020-08-26 18:01:02 -04:00
fsactive = self . widget ( " details-menu-view-fullscreen " ) . get_active ( )
self . widget ( " toolbar-box " ) . set_visible ( active and not fsactive )
2019-05-05 16:25:35 -04:00
def details_console_changed ( self , src ) :
if self . ignoreDetails :
return
if not src . get_active ( ) :
return
is_details = ( src == self . widget ( " control-vm-details " ) or
src == self . widget ( " details-menu-view-details " ) )
is_snapshot = ( src == self . widget ( " control-snapshots " ) or
src == self . widget ( " details-menu-view-snapshots " ) )
pages = self . widget ( " details-pages " )
if pages . get_current_page ( ) == DETAILS_PAGE_DETAILS :
if self . _details . vmwindow_has_unapplied_changes ( ) :
2020-09-20 21:55:05 -04:00
self . _sync_toolbar_page_buttons ( pages . get_current_page ( ) )
2019-05-05 16:25:35 -04:00
return
if is_details :
pages . set_current_page ( DETAILS_PAGE_DETAILS )
elif is_snapshot :
pages . set_current_page ( DETAILS_PAGE_SNAPSHOTS )
else :
pages . set_current_page ( DETAILS_PAGE_CONSOLE )
2020-09-20 21:55:05 -04:00
def _sync_toolbar_page_buttons ( self , newpage ) :
2019-05-05 16:25:35 -04:00
details = self . widget ( " control-vm-details " )
details_menu = self . widget ( " details-menu-view-details " )
console = self . widget ( " control-vm-console " )
console_menu = self . widget ( " details-menu-view-console " )
snapshot = self . widget ( " control-snapshots " )
snapshot_menu = self . widget ( " details-menu-view-snapshots " )
is_details = newpage == DETAILS_PAGE_DETAILS
is_snapshot = newpage == DETAILS_PAGE_SNAPSHOTS
is_console = not is_details and not is_snapshot
try :
self . ignoreDetails = True
details . set_active ( is_details )
details_menu . set_active ( is_details )
snapshot . set_active ( is_snapshot )
snapshot_menu . set_active ( is_snapshot )
console . set_active ( is_console )
console_menu . set_active ( is_console )
finally :
self . ignoreDetails = False
2020-09-20 21:55:05 -04:00
def _details_page_switch_cb ( self , notebook , pagewidget , newpage ) :
2019-05-05 16:25:35 -04:00
for i in range ( notebook . get_n_pages ( ) ) :
w = notebook . get_nth_page ( i )
w . set_visible ( i == newpage )
2020-09-20 21:55:05 -04:00
self . _refresh_current_page ( newpage )
self . _sync_toolbar_page_buttons ( newpage )
self . _sync_console_page_menu_state ( )
2019-05-05 16:25:35 -04:00
def change_run_text ( self , can_restore ) :
if can_restore :
text = _ ( " _Restore " )
else :
text = _ ( " _Run " )
strip_text = text . replace ( " _ " , " " )
self . widget ( " details-vm-menu " ) . get_submenu ( ) . change_run_text ( text )
self . widget ( " control-run " ) . set_label ( strip_text )
2020-09-20 22:53:30 -04:00
def _refresh_title ( self ) :
title = ( _ ( " % (vm-name)s on % (connection-name)s " ) % {
" vm-name " : self . vm . get_name_or_title ( ) ,
" connection-name " : self . vm . conn . get_pretty_desc ( ) ,
} )
grabmsg = self . _console . vmwindow_get_title_message ( )
if grabmsg :
title = grabmsg + " " + title
self . topwin . set_title ( title )
2020-09-20 21:55:05 -04:00
def _refresh_vm_state ( self ) :
2019-05-05 16:25:35 -04:00
vm = self . vm
2020-09-20 22:53:30 -04:00
self . _refresh_title ( )
2019-05-05 16:25:35 -04:00
self . widget ( " details-menu-view-toolbar " ) . set_active (
self . config . get_details_show_toolbar ( ) )
self . toggle_toolbar ( self . widget ( " details-menu-view-toolbar " ) )
run = vm . is_runable ( )
stop = vm . is_stoppable ( )
paused = vm . is_paused ( )
if vm . managedsave_supported :
self . change_run_text ( vm . has_managed_save ( ) )
self . widget ( " control-run " ) . set_sensitive ( run )
self . widget ( " control-shutdown " ) . set_sensitive ( stop )
self . widget ( " control-shutdown " ) . get_menu ( ) . update_widget_states ( vm )
self . widget ( " control-pause " ) . set_sensitive ( stop )
if paused :
pauseTooltip = _ ( " Resume the virtual machine " )
else :
pauseTooltip = _ ( " Pause the virtual machine " )
self . widget ( " control-pause " ) . set_tooltip_text ( pauseTooltip )
self . widget ( " details-vm-menu " ) . get_submenu ( ) . update_widget_states ( vm )
self . set_pause_state ( paused )
errmsg = self . vm . snapshots_supported ( )
cansnap = not bool ( errmsg )
self . widget ( " control-snapshots " ) . set_sensitive ( cansnap )
self . widget ( " details-menu-view-snapshots " ) . set_sensitive ( cansnap )
tooltip = _ ( " Manage VM snapshots " )
if not cansnap :
tooltip + = " \n " + errmsg
self . widget ( " control-snapshots " ) . set_tooltip_text ( tooltip )
2020-09-20 21:55:05 -04:00
self . _refresh_current_page ( )
2019-05-05 16:25:35 -04:00
#############################
# External action listeners #
#############################
def view_manager ( self , _src ) :
from . manager import vmmManager
vmmManager . get_instance ( self ) . show ( )
def exit_app ( self , _src ) :
vmmEngine . get_instance ( ) . exit_app ( )
def activate_default_console_page ( self ) :
2020-09-09 15:14:05 -04:00
self . _console . vmwindow_activate_default_console_page ( )
2019-05-05 16:25:35 -04:00
# activate_* are called from engine.py via CLI options
def activate_default_page ( self ) :
if self . is_customize_dialog :
return
pages = self . widget ( " details-pages " )
pages . set_current_page ( DETAILS_PAGE_CONSOLE )
self . activate_default_console_page ( )
def activate_console_page ( self ) :
pages = self . widget ( " details-pages " )
pages . set_current_page ( DETAILS_PAGE_CONSOLE )
def activate_performance_page ( self ) :
self . widget ( " details-pages " ) . set_current_page ( DETAILS_PAGE_DETAILS )
self . _details . vmwindow_activate_performance_page ( )
def activate_config_page ( self ) :
self . widget ( " details-pages " ) . set_current_page ( DETAILS_PAGE_DETAILS )
def set_pause_state ( self , state ) :
src = self . widget ( " control-pause " )
try :
src . handler_block_by_func ( self . control_vm_pause )
src . set_active ( state )
finally :
src . handler_unblock_by_func ( self . control_vm_pause )
def control_vm_pause ( self , src ) :
do_pause = src . get_active ( )
# Set button state back to original value: just let the status
# update function fix things for us
self . set_pause_state ( not do_pause )
if do_pause :
vmmenu . VMActionUI . suspend ( self , self . vm )
else :
vmmenu . VMActionUI . resume ( self , self . vm )
def control_vm_menu ( self , src_ignore ) :
2020-08-27 16:37:15 -04:00
can_usb = bool ( self . vm . has_spicevmc_type_redirdev ( ) and
2020-09-09 15:14:05 -04:00
self . _console . vmwindow_viewer_has_usb_redirection ( ) )
2019-05-05 16:25:35 -04:00
self . widget ( " details-menu-usb-redirection " ) . set_sensitive ( can_usb )
def control_vm_run ( self , src_ignore ) :
if self . _details . vmwindow_has_unapplied_changes ( ) :
return
vmmenu . VMActionUI . run ( self , self . vm )
def control_vm_shutdown ( self , src_ignore ) :
vmmenu . VMActionUI . shutdown ( self , self . vm )
def control_vm_screenshot ( self , src ) :
ignore = src
try :
return self . _take_screenshot ( )
2020-08-22 15:42:08 -04:00
except Exception as e : # pragma: no cover
2019-05-05 16:25:35 -04:00
self . err . show_err ( _ ( " Error taking screenshot: %s " ) % str ( e ) )
def control_vm_usb_redirection ( self , src ) :
ignore = src
spice_usbdev_dialog = self . err
2020-09-09 15:14:05 -04:00
spice_usbdev_widget = self . _console . vmwindow_viewer_get_usb_widget ( )
2020-08-22 15:42:08 -04:00
if not spice_usbdev_widget : # pragma: no cover
2019-05-05 16:25:35 -04:00
self . err . show_err ( _ ( " Error initializing spice USB device widget " ) )
return
spice_usbdev_widget . show ( )
spice_usbdev_dialog . show_info ( _ ( " Select USB devices for redirection " ) ,
widget = spice_usbdev_widget ,
buttons = Gtk . ButtonsType . CLOSE )
def _take_screenshot ( self ) :
2020-09-09 15:14:05 -04:00
image = self . _console . vmwindow_viewer_get_pixbuf ( )
2019-05-05 16:25:35 -04:00
metadata = {
' tEXt::Hypervisor URI ' : self . vm . conn . get_uri ( ) ,
' tEXt::Domain Name ' : self . vm . get_name ( ) ,
' tEXt::Domain UUID ' : self . vm . get_uuid ( ) ,
' tEXt::Generator App ' : self . config . get_appname ( ) ,
' tEXt::Generator Version ' : self . config . get_appversion ( ) ,
}
ret = image . save_to_bufferv (
' png ' , list ( metadata . keys ( ) ) , list ( metadata . values ( ) )
)
# On Fedora 19, ret is (bool, str)
# Someday the bindings might be fixed to just return the str, try
# and future proof it a bit
if isinstance ( ret , tuple ) and len ( ret ) > = 2 :
ret = ret [ 1 ]
# F24 rawhide, ret[1] is a named tuple with a 'buffer' element...
if hasattr ( ret , " buffer " ) :
2020-08-22 15:42:08 -04:00
ret = ret . buffer # pragma: no cover
2019-05-05 16:25:35 -04:00
import datetime
2022-12-13 15:09:35 -05:00
import os
2019-05-05 16:25:35 -04:00
now = str ( datetime . datetime . now ( ) ) . split ( " . " ) [ 0 ] . replace ( " " , " _ " )
default = " Screenshot_ %s _ %s .png " % ( self . vm . get_name ( ) , now )
2022-12-13 15:09:35 -05:00
start_folder = self . config . get_default_directory ( " screenshot " )
filename = self . err . browse_local (
_ ( " Save Virtual Machine Screenshot " ) ,
2019-05-05 16:25:35 -04:00
_type = ( " png " , _ ( " PNG files " ) ) ,
dialog_type = Gtk . FileChooserAction . SAVE ,
2022-12-13 15:09:35 -05:00
choose_button = Gtk . STOCK_SAVE ,
start_folder = start_folder ,
default_name = default ,
confirm_overwrite = True )
if not filename : # pragma: no cover
2019-06-16 21:12:39 -04:00
log . debug ( " No screenshot path given, skipping save. " )
2019-05-05 16:25:35 -04:00
return
if not filename . endswith ( " .png " ) :
2020-08-26 18:01:02 -04:00
filename + = " .png " # pragma: no cover
2019-05-05 16:25:35 -04:00
open ( filename , " wb " ) . write ( ret )
2022-12-13 15:09:35 -05:00
self . config . set_default_directory (
" screenshot " , os . path . dirname ( filename ) )
2019-05-05 16:25:35 -04:00
########################
# Details page refresh #
########################
2020-09-20 21:55:05 -04:00
def _refresh_resources ( self ) :
2019-05-05 16:25:35 -04:00
details = self . widget ( " details-pages " )
page = details . get_current_page ( )
if page == DETAILS_PAGE_DETAILS :
self . _details . vmwindow_resources_refreshed ( )
2020-09-20 21:55:05 -04:00
def _refresh_current_page ( self , newpage = None ) :
2020-09-20 21:55:27 -04:00
newpage = newpage or self . widget ( " details-pages " ) . get_current_page ( )
is_details = newpage == DETAILS_PAGE_DETAILS
self . _details . vmwindow_refresh_vm_state ( is_details )
if newpage == DETAILS_PAGE_CONSOLE :
self . _console . vmwindow_refresh_vm_state ( )
elif newpage == DETAILS_PAGE_SNAPSHOTS :
self . _snapshots . vmwindow_refresh_vm_state ( )
2020-09-09 15:14:05 -04:00
#########################
# Console page handling #
#########################
2020-09-20 21:55:05 -04:00
def _sync_console_page_menu_state ( self ) :
2020-09-09 15:14:05 -04:00
if not self . vm :
# This is triggered via cleanup + idle_add, so vm might
# disappear and spam the logs
return # pragma: no cover
paused = self . vm . is_paused ( )
is_viewer = self . _console . vmwindow_get_viewer_is_visible ( )
can_usb = self . _console . vmwindow_get_can_usb_redirect ( )
self . widget ( " details-menu-vm-screenshot " ) . set_sensitive ( is_viewer )
self . widget ( " details-menu-usb-redirection " ) . set_sensitive ( can_usb )
keycombo_menu = self . _console . vmwindow_get_keycombo_menu ( )
can_sendkey = ( is_viewer and not paused )
for c in keycombo_menu . get_children ( ) :
c . set_sensitive ( can_sendkey )
self . _console_refresh_can_fullscreen ( )
self . _console_refresh_resizeguest_from_settings ( )
def _console_refresh_can_fullscreen ( self ) :
allow_fullscreen = self . _console . vmwindow_get_viewer_is_visible ( )
self . widget ( " control-fullscreen " ) . set_sensitive ( allow_fullscreen )
self . widget ( " details-menu-view-fullscreen " ) . set_sensitive (
allow_fullscreen )
def _console_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 )
self . widget ( " details-menu-view-scale-never " ) . set_active (
scale_type == self . config . CONSOLE_SCALE_NEVER )
self . widget ( " details-menu-view-scale-fullscreen " ) . set_active (
scale_type == self . config . CONSOLE_SCALE_FULLSCREEN )
self . _console . vmwindow_sync_scaling_with_display ( )
def _scaling_ui_changed_cb ( self , src ) :
# Called from details.py
if not src . get_active ( ) :
return
scale_type = 0
if src == self . widget ( " details-menu-view-scale-always " ) :
scale_type = self . config . CONSOLE_SCALE_ALWAYS
elif src == self . widget ( " details-menu-view-scale-fullscreen " ) :
scale_type = self . config . CONSOLE_SCALE_FULLSCREEN
elif src == self . widget ( " details-menu-view-scale-never " ) :
scale_type = self . config . CONSOLE_SCALE_NEVER
self . vm . set_console_scaling ( scale_type )
def _fullscreen_changed_cb ( self , src ) :
do_fullscreen = src . get_active ( )
self . widget ( " control-fullscreen " ) . set_active ( do_fullscreen )
self . _console . vmwindow_set_fullscreen ( do_fullscreen )
self . widget ( " details-menubar " ) . set_visible ( not do_fullscreen )
show_toolbar = not do_fullscreen
if not self . widget ( " details-menu-view-toolbar " ) . get_active ( ) :
show_toolbar = False # pragma: no cover
self . widget ( " toolbar-box " ) . set_visible ( show_toolbar )
def _resizeguest_ui_changed_cb ( self , src ) :
if not src . get_sensitive ( ) :
return # pragma: no cover
val = int ( self . widget ( " details-menu-view-resizeguest " ) . get_active ( ) )
self . vm . set_console_resizeguest ( val )
self . _console . vmwindow_sync_resizeguest_with_display ( )
def _console_refresh_resizeguest_from_settings ( self ) :
tooltip = self . _console . vmwindow_get_resizeguest_tooltip ( )
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 ) )
self . _console . vmwindow_sync_resizeguest_with_display ( )
2020-09-09 19:04:44 -04:00
def _autoconnect_ui_changed_cb ( self , src ) :
val = int ( self . widget ( " details-menu-view-autoconnect " ) . get_active ( ) )
self . vm . set_console_autoconnect ( val )
def _console_refresh_autoconnect_from_settings ( self ) :
val = self . vm . get_console_autoconnect ( )
self . widget ( " details-menu-view-autoconnect " ) . set_active ( val )
2020-09-09 15:14:05 -04:00
def _size_to_vm_cb ( self , src ) :
self . _console . vmwindow_set_size_to_vm ( )
def _console_leave_fullscreen_cb ( self , src ) :
# This will trigger de-fullscreening in a roundabout way
self . widget ( " control-fullscreen " ) . set_active ( False )
2020-09-20 21:55:05 -04:00
2020-09-20 22:53:30 -04:00
def _console_change_title_cb ( self , src ) :
self . _refresh_title ( )
2020-09-20 21:55:05 -04:00
def _vm_state_changed_cb ( self , src ) :
2020-09-20 21:55:27 -04:00
if self . is_visible ( ) :
self . _refresh_vm_state ( )
2020-09-20 21:55:05 -04:00
def _resources_sampled_cb ( self , src ) :
2020-09-20 21:55:27 -04:00
if self . is_visible ( ) :
self . _refresh_resources ( )
2020-09-20 21:55:05 -04:00
def _console_page_changed_cb ( self , src ) :
self . _sync_console_page_menu_state ( )