2009-07-27 22:30:01 -04:00
#
# Copyright (C) 2009 Red Hat, Inc.
# Copyright (C) 2009 Cole Robinson <crobinso@redhat.com>
#
# 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-01-31 18:16:54 -05:00
import logging
2012-05-14 14:24:56 +01:00
from gi . repository import GObject
from gi . repository import Gtk
2009-07-27 22:30:01 -04:00
2010-12-09 14:06:00 -05:00
from virtManager . baseclass import vmmGObject
2010-11-23 20:13:50 -05:00
from virtManager . error import vmmErrorDialog
2010-02-28 20:28:51 -05:00
try :
import appindicator
except :
appindicator = None
2010-08-23 11:16:48 -04:00
def build_image_menu_item ( label ) :
2012-05-14 14:24:56 +01:00
hasfunc = hasattr ( Gtk . ImageMenuItem , " set_use_underline " )
2010-08-23 11:16:48 -04:00
if hasfunc :
label . replace ( " _ " , " __ " )
2012-05-14 14:24:56 +01:00
menu_item = Gtk . ImageMenuItem ( label )
2010-08-23 11:16:48 -04:00
if hasfunc :
menu_item . set_use_underline ( False )
return menu_item
2010-12-09 14:06:00 -05:00
class vmmSystray ( vmmGObject ) :
2012-05-14 14:24:56 +01:00
__gsignals__ = {
" action-toggle-manager " : ( GObject . SignalFlags . RUN_FIRST , None , [ ] ) ,
" action-view-manager " : ( GObject . SignalFlags . RUN_FIRST , None , [ ] ) ,
" action-suspend-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-resume-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-run-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-shutdown-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-reset-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-reboot-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-destroy-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-show-host " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
" action-show-vm " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-exit-app " : ( GObject . SignalFlags . RUN_FIRST , None , [ ] ) ,
}
2010-12-09 14:06:00 -05:00
def __init__ ( self , engine ) :
vmmGObject . __init__ ( self )
2009-07-27 22:30:01 -04:00
2010-11-23 20:13:50 -05:00
self . topwin = None
2010-11-30 14:33:21 -05:00
self . err = vmmErrorDialog ( )
2009-07-27 22:30:01 -04:00
self . conn_menuitems = { }
self . conn_vm_menuitems = { }
self . vm_action_dict = { }
self . systray_menu = None
self . systray_icon = None
2010-02-28 20:28:51 -05:00
self . systray_indicator = False
2011-07-22 16:43:26 -04:00
engine . connect ( " conn-added " , self . conn_added )
engine . connect ( " conn-removed " , self . conn_removed )
2010-12-09 14:06:00 -05:00
2010-02-28 20:28:51 -05:00
# Are we using Application Indicators?
if appindicator is not None :
self . systray_indicator = True
2009-07-27 22:30:01 -04:00
self . init_systray_menu ( )
2011-04-13 09:27:02 -04:00
self . add_gconf_handle (
self . config . on_view_system_tray_changed ( self . show_systray ) )
2009-07-27 22:30:01 -04:00
self . show_systray ( )
2009-11-10 11:56:15 -05:00
def is_visible ( self ) :
2010-02-28 20:28:51 -05:00
if self . systray_indicator :
return ( self . config . get_view_system_tray ( ) and
self . systray_icon )
else :
return ( self . config . get_view_system_tray ( ) and
self . systray_icon and
self . systray_icon . is_embedded ( ) )
2009-11-10 11:56:15 -05:00
2011-07-23 21:16:54 -04:00
def _cleanup ( self ) :
self . err = None
2011-04-13 09:27:02 -04:00
2011-07-23 21:16:54 -04:00
if self . systray_menu :
self . systray_menu . destroy ( )
self . systray_menu = None
2011-04-13 09:27:02 -04:00
2011-07-23 21:16:54 -04:00
self . systray_icon = None
2011-04-13 09:27:02 -04:00
2009-07-27 22:30:01 -04:00
# Initialization routines
def init_systray_menu ( self ) :
"""
Do we want notifications ?
Close App
Hide app ? As in , only have systray active ? is that possible ?
Have one of those ' minimize to tray ' notifications ?
"""
2012-05-14 14:24:56 +01:00
self . systray_menu = Gtk . Menu ( )
2009-07-27 22:30:01 -04:00
2012-05-14 14:24:56 +01:00
self . systray_menu . add ( Gtk . SeparatorMenuItem ( ) )
2010-02-28 20:28:51 -05:00
if self . systray_indicator :
2012-05-14 14:24:56 +01:00
hide_item = Gtk . MenuItem ( " _Show Virtual Machine Manager " )
2010-02-28 20:28:51 -05:00
hide_item . connect ( " activate " , self . systray_activate )
self . systray_menu . add ( hide_item )
2012-05-14 14:24:56 +01:00
exit_item = Gtk . ImageMenuItem . new_from_stock ( Gtk . STOCK_QUIT , None )
2009-07-27 22:30:01 -04:00
exit_item . connect ( " activate " , self . exit_app )
self . systray_menu . add ( exit_item )
self . systray_menu . show_all ( )
2009-11-10 12:00:01 -05:00
def init_systray ( self ) :
2009-07-27 22:30:01 -04:00
# Build the systray icon
if self . systray_icon :
return
2010-02-28 20:28:51 -05:00
if self . systray_indicator :
2010-12-10 11:47:07 -05:00
self . systray_icon = appindicator . Indicator ( " virt-manager " ,
2010-02-28 20:28:51 -05:00
" virt-manager-icon " ,
appindicator . CATEGORY_OTHER )
2010-12-10 11:47:07 -05:00
self . systray_icon . set_status ( appindicator . STATUS_ACTIVE )
self . systray_icon . set_menu ( self . systray_menu )
2010-02-28 20:28:51 -05:00
else :
2012-05-14 14:24:56 +01:00
self . systray_icon = Gtk . StatusIcon ( )
2010-02-28 20:28:51 -05:00
self . systray_icon . set_visible ( True )
2011-07-13 18:48:02 -04:00
self . systray_icon . set_property ( " icon-name " , " virt-manager " )
2010-02-28 20:28:51 -05:00
self . systray_icon . connect ( " activate " , self . systray_activate )
self . systray_icon . connect ( " popup-menu " , self . systray_popup )
2012-05-14 14:24:56 +01:00
self . systray_icon . set_tooltip_text ( _ ( " Virtual Machine Manager " ) )
2009-07-27 22:30:01 -04:00
def show_systray ( self , ignore1 = None , ignore2 = None , ignore3 = None ,
ignore4 = None ) :
do_show = self . config . get_view_system_tray ( )
2012-01-31 18:16:54 -05:00
logging . debug ( " Showing systray: %s " , do_show )
2009-07-27 22:30:01 -04:00
if not self . systray_icon :
2009-11-10 12:00:01 -05:00
if do_show :
self . init_systray ( )
2009-07-27 22:30:01 -04:00
else :
2010-02-28 20:28:51 -05:00
if self . systray_indicator :
if do_show :
2010-12-10 11:47:07 -05:00
self . systray_icon . set_status ( appindicator . STATUS_ACTIVE )
2010-02-28 20:28:51 -05:00
else :
2010-12-10 11:47:07 -05:00
self . systray_icon . set_status ( appindicator . STATUS_PASSIVE )
2010-02-28 20:28:51 -05:00
else :
self . systray_icon . set_visible ( do_show )
2009-07-27 22:30:01 -04:00
def build_vm_menu ( self , vm ) :
2012-05-14 14:24:56 +01:00
icon_size = Gtk . IconSize . MENU
2009-07-27 22:30:01 -04:00
2012-05-14 14:24:56 +01:00
pause_item = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Pause " ) )
pause_img = Gtk . Image . new_from_stock ( Gtk . STOCK_MEDIA_PAUSE , icon_size )
2009-07-27 22:30:01 -04:00
pause_item . set_image ( pause_img )
pause_item . connect ( " activate " , self . run_vm_action ,
" action-suspend-domain " , vm . get_uuid ( ) )
2012-05-14 14:24:56 +01:00
resume_item = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Resume " ) )
resume_img = Gtk . Image . new_from_stock ( Gtk . STOCK_MEDIA_PAUSE ,
2009-07-27 22:30:01 -04:00
icon_size )
resume_item . set_image ( resume_img )
resume_item . connect ( " activate " , self . run_vm_action ,
" action-resume-domain " , vm . get_uuid ( ) )
2012-05-14 14:24:56 +01:00
run_item = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Run " ) )
run_img = Gtk . Image . new_from_stock ( Gtk . STOCK_MEDIA_PLAY , icon_size )
2009-07-27 22:30:01 -04:00
run_item . set_image ( run_img )
run_item . connect ( " activate " , self . run_vm_action ,
" action-run-domain " , vm . get_uuid ( ) )
# Shutdown menu
2012-05-14 14:24:56 +01:00
reboot_item = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Reboot " ) )
2013-01-13 14:41:25 -05:00
reboot_img = Gtk . Image . new_from_icon_name ( " system-shutdown " , icon_size )
2009-07-27 22:30:01 -04:00
reboot_item . set_image ( reboot_img )
reboot_item . connect ( " activate " , self . run_vm_action ,
" action-reboot-domain " , vm . get_uuid ( ) )
reboot_item . show ( )
2012-05-14 14:24:56 +01:00
shutdown_item = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Shut Down " ) )
2013-01-13 14:41:25 -05:00
shutdown_img = Gtk . Image . new_from_icon_name ( " system-shutdown " ,
icon_size )
2009-07-27 22:30:01 -04:00
shutdown_item . set_image ( shutdown_img )
shutdown_item . connect ( " activate " , self . run_vm_action ,
" action-shutdown-domain " , vm . get_uuid ( ) )
shutdown_item . show ( )
2012-05-14 14:24:56 +01:00
reset_item = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Force Reset " ) )
2013-01-13 14:41:25 -05:00
reset_img = Gtk . Image . new_from_icon_name ( " system-shutdown " , icon_size )
2013-03-16 17:59:32 -04:00
reset_item . set_image ( reset_img )
reset_item . show ( )
reset_item . connect ( " activate " , self . run_vm_action ,
2012-05-14 14:24:56 +01:00
" action-reset-domain " , vm . get_uuid ( ) )
2013-03-16 17:59:32 -04:00
2012-05-14 14:24:56 +01:00
destroy_item = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Force Off " ) )
2013-01-13 14:41:25 -05:00
destroy_img = Gtk . Image . new_from_icon_name ( " system-shutdown " ,
icon_size )
2009-07-27 22:30:01 -04:00
destroy_item . set_image ( destroy_img )
destroy_item . show ( )
destroy_item . connect ( " activate " , self . run_vm_action ,
" action-destroy-domain " , vm . get_uuid ( ) )
2012-05-14 14:24:56 +01:00
shutdown_menu = Gtk . Menu ( )
2009-07-27 22:30:01 -04:00
shutdown_menu . add ( reboot_item )
shutdown_menu . add ( shutdown_item )
2013-03-16 17:59:32 -04:00
shutdown_menu . add ( reset_item )
2009-07-27 22:30:01 -04:00
shutdown_menu . add ( destroy_item )
2012-05-14 14:24:56 +01:00
shutdown_menu_item = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Shut Down " ) )
2013-01-13 14:41:25 -05:00
shutdown_menu_img = Gtk . Image . new_from_icon_name ( " system-shutdown " ,
icon_size )
2009-07-27 22:30:01 -04:00
shutdown_menu_item . set_image ( shutdown_menu_img )
shutdown_menu_item . set_submenu ( shutdown_menu )
2012-05-14 14:24:56 +01:00
sep = Gtk . SeparatorMenuItem ( )
2009-07-27 22:30:01 -04:00
2012-05-14 14:24:56 +01:00
open_item = Gtk . ImageMenuItem . new_from_stock ( " gtk-open " , None )
2009-07-27 22:30:01 -04:00
open_item . show ( )
open_item . connect ( " activate " , self . run_vm_action ,
2011-06-08 16:33:20 -04:00
" action-show-vm " , vm . get_uuid ( ) )
2009-07-27 22:30:01 -04:00
vm_action_dict = { }
vm_action_dict [ " run " ] = run_item
vm_action_dict [ " pause " ] = pause_item
vm_action_dict [ " resume " ] = resume_item
vm_action_dict [ " shutdown_menu " ] = shutdown_menu_item
vm_action_dict [ " reboot " ] = reboot_item
vm_action_dict [ " shutdown " ] = shutdown_item
2013-03-16 17:59:32 -04:00
vm_action_dict [ " reset " ] = reset_item
2009-07-27 22:30:01 -04:00
vm_action_dict [ " destroy " ] = destroy_item
vm_action_dict [ " sep " ] = sep
vm_action_dict [ " open " ] = open_item
2012-05-14 14:24:56 +01:00
menu = Gtk . Menu ( )
2009-07-27 22:30:01 -04:00
for key in [ " run " , " pause " , " resume " , " shutdown_menu " , " sep " , " open " ] :
item = vm_action_dict [ key ]
item . show_all ( )
menu . add ( vm_action_dict [ key ] )
return menu , vm_action_dict
# Helper functions
def _get_vm_menu_item ( self , vm ) :
uuid = vm . get_uuid ( )
2011-07-22 16:43:26 -04:00
uri = vm . conn . get_uri ( )
2009-07-27 22:30:01 -04:00
2010-12-10 11:47:07 -05:00
if uri in self . conn_vm_menuitems :
if uuid in self . conn_vm_menuitems [ uri ] :
2009-07-27 22:30:01 -04:00
return self . conn_vm_menuitems [ uri ] [ uuid ]
return None
def _set_vm_status_icon ( self , vm , menu_item ) :
2012-05-14 14:24:56 +01:00
image = Gtk . Image ( )
2011-07-12 11:50:11 -04:00
image . set_from_icon_name ( vm . run_status_icon_name ( ) ,
2012-05-14 14:24:56 +01:00
Gtk . IconSize . MENU )
2009-07-27 22:30:01 -04:00
image . set_sensitive ( vm . is_active ( ) )
menu_item . set_image ( image )
# Listeners
2010-12-09 11:22:35 -05:00
def systray_activate ( self , widget_ignore ) :
2009-10-29 11:08:40 -04:00
self . emit ( " action-toggle-manager " )
2009-07-27 22:30:01 -04:00
2010-12-09 11:22:35 -05:00
def systray_popup ( self , widget_ignore , button , event_time ) :
2009-07-27 22:30:01 -04:00
if button != 3 :
return
2012-05-14 14:24:56 +01:00
self . systray_menu . popup ( None , None , Gtk . StatusIcon . position_menu ,
self . systray_icon , 0 , event_time )
2009-07-27 22:30:01 -04:00
2010-03-24 10:58:17 -04:00
def repopulate_menu_list ( self ) :
# Build sorted connection list
connsort = self . conn_menuitems . keys ( )
connsort . sort ( )
connsort . reverse ( )
# Empty conn list
for child in self . systray_menu . get_children ( ) :
if child in self . conn_menuitems . values ( ) :
self . systray_menu . remove ( child )
# Build sorted conn list
for uri in connsort :
self . systray_menu . insert ( self . conn_menuitems [ uri ] , 0 )
2010-12-09 11:22:35 -05:00
def conn_added ( self , engine_ignore , conn ) :
2009-07-27 22:30:01 -04:00
conn . connect ( " vm-added " , self . vm_added )
conn . connect ( " vm-removed " , self . vm_removed )
conn . connect ( " state-changed " , self . conn_state_changed )
2010-12-10 11:47:07 -05:00
if conn . get_uri ( ) in self . conn_menuitems :
2009-07-27 22:30:01 -04:00
return
2012-05-14 14:24:56 +01:00
menu_item = Gtk . MenuItem . new_with_label ( conn . get_pretty_desc_inactive ( ) )
2009-07-27 22:30:01 -04:00
menu_item . show ( )
2012-05-14 14:24:56 +01:00
vm_submenu = Gtk . Menu ( )
2009-07-27 22:30:01 -04:00
vm_submenu . show ( )
menu_item . set_submenu ( vm_submenu )
self . conn_menuitems [ conn . get_uri ( ) ] = menu_item
self . conn_vm_menuitems [ conn . get_uri ( ) ] = { }
2010-03-24 10:58:17 -04:00
self . repopulate_menu_list ( )
2009-07-27 22:30:01 -04:00
self . conn_state_changed ( conn )
self . populate_vm_list ( conn )
2011-04-12 11:50:10 -04:00
def conn_removed ( self , engine_ignore , uri ) :
if not uri in self . conn_menuitems :
2009-07-27 22:30:01 -04:00
return
2011-04-12 11:50:10 -04:00
menu_item = self . conn_menuitems [ uri ]
2009-07-27 22:30:01 -04:00
self . systray_menu . remove ( menu_item )
2011-04-14 13:26:44 -04:00
menu_item . destroy ( )
2011-04-12 11:50:10 -04:00
del ( self . conn_menuitems [ uri ] )
self . conn_vm_menuitems [ uri ] = { }
2009-07-27 22:30:01 -04:00
2010-03-24 10:58:17 -04:00
self . repopulate_menu_list ( )
2009-07-27 22:30:01 -04:00
def conn_state_changed ( self , conn ) :
# XXX: Even 'paused' conn?
sensitive = conn . is_active ( )
menu_item = self . conn_menuitems [ conn . get_uri ( ) ]
menu_item . set_sensitive ( sensitive )
def populate_vm_list ( self , conn ) :
uri = conn . get_uri ( )
conn_menu_item = self . conn_menuitems [ uri ]
vm_submenu = conn_menu_item . get_submenu ( )
# Empty conn menu
for c in vm_submenu . get_children ( ) :
vm_submenu . remove ( c )
vm_mappings = { }
for vm in conn . vms . values ( ) :
vm_mappings [ vm . get_name ( ) ] = vm . get_uuid ( )
vm_names = vm_mappings . keys ( )
vm_names . sort ( )
if len ( vm_names ) == 0 :
2012-05-14 14:24:56 +01:00
menu_item = Gtk . MenuItem ( _ ( " No virtual machines " ) )
2009-07-27 22:30:01 -04:00
menu_item . set_sensitive ( False )
vm_submenu . insert ( menu_item , 0 )
return
for i in range ( 0 , len ( vm_names ) ) :
name = vm_names [ i ]
uuid = vm_mappings [ name ]
2010-12-10 11:47:07 -05:00
if uuid in self . conn_vm_menuitems [ uri ] :
2009-07-27 22:30:01 -04:00
vm_item = self . conn_vm_menuitems [ uri ] [ uuid ]
vm_submenu . insert ( vm_item , i )
2011-07-22 13:54:40 -04:00
def vm_added ( self , conn , uuid ) :
uri = conn . get_uri ( )
2009-07-27 22:30:01 -04:00
vm = conn . get_vm ( uuid )
if not vm :
return
vm . connect ( " status-changed " , self . vm_state_changed )
vm_mappings = self . conn_vm_menuitems [ uri ]
2010-12-10 11:47:07 -05:00
if uuid in vm_mappings :
2009-07-27 22:30:01 -04:00
return
# Build VM list entry
2010-08-23 11:16:48 -04:00
menu_item = build_image_menu_item ( vm . get_name ( ) )
2009-07-27 22:30:01 -04:00
vm_mappings [ uuid ] = menu_item
vm_action_menu , vm_action_dict = self . build_vm_menu ( vm )
menu_item . set_submenu ( vm_action_menu )
self . vm_action_dict [ uuid ] = vm_action_dict
# Add VM to menu list
self . populate_vm_list ( conn )
# Update state
self . vm_state_changed ( vm )
menu_item . show ( )
2011-07-22 13:54:40 -04:00
def vm_removed ( self , conn , uuid ) :
uri = conn . get_uri ( )
2009-07-27 22:30:01 -04:00
vm_mappings = self . conn_vm_menuitems [ uri ]
if not vm_mappings :
return
2010-12-10 11:47:07 -05:00
if uuid in vm_mappings :
2009-07-27 22:30:01 -04:00
conn_item = self . conn_menuitems [ uri ]
vm_menu_item = vm_mappings [ uuid ]
vm_menu = conn_item . get_submenu ( )
vm_menu . remove ( vm_menu_item )
2011-04-14 13:26:44 -04:00
vm_menu_item . destroy ( )
2009-07-27 22:30:01 -04:00
del ( vm_mappings [ uuid ] )
if len ( vm_menu . get_children ( ) ) == 0 :
2012-05-14 14:24:56 +01:00
placeholder = Gtk . MenuItem ( _ ( " No virtual machines " ) )
2009-07-27 22:30:01 -04:00
placeholder . show ( )
placeholder . set_sensitive ( False )
vm_menu . add ( placeholder )
2010-02-27 10:42:43 -05:00
def vm_state_changed ( self , vm , ignore = None , ignore2 = None ) :
2009-07-27 22:30:01 -04:00
menu_item = self . _get_vm_menu_item ( vm )
if not menu_item :
return
self . _set_vm_status_icon ( vm , menu_item )
# Update action widget states
actions = self . vm_action_dict [ vm . get_uuid ( ) ]
is_paused = vm . is_paused ( )
actions [ " run " ] . set_sensitive ( vm . is_runable ( ) )
actions [ " pause " ] . set_sensitive ( vm . is_pauseable ( ) )
actions [ " resume " ] . set_sensitive ( vm . is_paused ( ) )
actions [ " shutdown_menu " ] . set_sensitive ( vm . is_active ( ) )
actions [ " shutdown " ] . set_sensitive ( vm . is_stoppable ( ) )
actions [ " reboot " ] . set_sensitive ( vm . is_stoppable ( ) )
2013-03-16 17:59:32 -04:00
actions [ " reset " ] . set_sensitive ( vm . is_destroyable ( ) )
2009-07-27 22:30:01 -04:00
actions [ " destroy " ] . set_sensitive ( vm . is_destroyable ( ) )
actions [ " pause " ] . set_property ( " visible " , not is_paused )
actions [ " resume " ] . set_property ( " visible " , is_paused )
def run_vm_action ( self , ignore , signal_name , uuid ) :
uri = None
for tmpuri , vm_mappings in self . conn_vm_menuitems . items ( ) :
if vm_mappings . get ( uuid ) :
uri = tmpuri
break
if not uri :
return
self . emit ( signal_name , uri , uuid )
def exit_app ( self , ignore ) :
self . emit ( " action-exit-app " )