2009-07-27 22:30:01 -04:00
#
2013-10-27 21:59:46 +01:00
# Copyright (C) 2009, 2013 Red Hat, Inc.
2009-07-27 22:30:01 -04:00
# 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
2014-09-12 16:10:45 -04:00
from . import vmmenu
from . baseclass import vmmGObject
from . error import vmmErrorDialog
2010-11-23 20:13:50 -05:00
2010-02-28 20:28:51 -05:00
try :
2016-04-18 16:42:12 -04:00
# pylint: disable=no-name-in-module
# pylint: disable=wrong-import-order
from gi . repository import AppIndicator3
2017-07-24 09:26:48 +01:00
except Exception :
2013-06-13 16:56:01 -07:00
AppIndicator3 = None
2010-02-28 20:28:51 -05:00
2013-04-13 14:34:52 -04:00
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 ] ) ,
2013-09-22 13:24:59 -04:00
" action-save-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
2013-09-22 15:13:41 -04:00
" action-migrate-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-delete-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
" action-clone-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
2012-05-14 14:24:56 +01:00
" action-show-host " : ( GObject . SignalFlags . RUN_FIRST , None , [ str ] ) ,
2013-09-22 15:13:41 -04:00
" action-show-domain " : ( GObject . SignalFlags . RUN_FIRST , None , [ str , str ] ) ,
2012-05-14 14:24:56 +01:00
" action-exit-app " : ( GObject . SignalFlags . RUN_FIRST , None , [ ] ) ,
}
2015-09-20 14:20:50 -04:00
def __init__ ( self ) :
2010-12-09 14:06:00 -05:00
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
# Are we using Application Indicators?
2013-06-13 16:56:01 -07:00
if AppIndicator3 is not None :
2010-02-28 20:28:51 -05:00
self . systray_indicator = True
2015-11-18 18:54:17 -05:00
logging . debug ( " Using AppIndicator3 for systray " )
2009-07-27 22:30:01 -04:00
self . init_systray_menu ( )
2014-09-28 13:37:16 +02:00
self . add_gsettings_handle (
2011-04-13 09:27:02 -04:00
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
2015-09-20 14:20:50 -04:00
self . conn_menuitems = None
self . conn_vm_menuitems = None
self . vm_action_dict = None
2011-04-13 09:27:02 -04:00
2015-09-20 14:20:50 -04:00
###########################
# Initialization routines #
###########################
2009-07-27 22:30:01 -04:00
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 :
2013-07-29 14:38:24 -04:00
hide_item = Gtk . MenuItem . new_with_mnemonic (
_ ( " _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 :
2014-03-22 11:21:19 -04:00
# pylint: disable=maybe-no-member
2013-07-29 14:38:24 -04:00
self . systray_icon = AppIndicator3 . Indicator . new ( " virt-manager " ,
2015-11-18 18:48:30 -05:00
" virt-manager " ,
2017-10-18 18:50:42 -04:00
AppIndicator3 . IndicatorCategory . APPLICATION_STATUS )
2013-07-29 14:38:24 -04:00
self . systray_icon . set_status ( AppIndicator3 . IndicatorStatus . ACTIVE )
2010-12-10 11:47:07 -05:00
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
2013-04-17 17:39:25 -04:00
def show_systray ( self ) :
2009-07-27 22:30:01 -04:00
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 :
2014-03-22 11:21:19 -04:00
# pylint: disable=maybe-no-member
status = AppIndicator3 . IndicatorStatus . PASSIVE
2010-02-28 20:28:51 -05:00
if do_show :
2014-03-22 11:21:19 -04:00
status = AppIndicator3 . IndicatorStatus . ACTIVE
self . systray_icon . set_status ( status )
2010-02-28 20:28:51 -05:00
else :
self . systray_icon . set_visible ( do_show )
2009-07-27 22:30:01 -04:00
# Helper functions
def _get_vm_menu_item ( self , vm ) :
2014-06-02 17:17:47 -04:00
connkey = vm . get_connkey ( )
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 :
2014-06-02 17:17:47 -04:00
if connkey in self . conn_vm_menuitems [ uri ] :
return self . conn_vm_menuitems [ uri ] [ connkey ]
2009-07-27 22:30:01 -04:00
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
2014-07-04 18:20:08 -04:00
menu_item = Gtk . MenuItem . new_with_label ( conn . get_pretty_desc ( ) )
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 ) :
2014-05-02 10:20:59 -04:00
if uri not 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 ) :
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 = { }
2014-06-02 17:17:47 -04:00
for vm in conn . list_vms ( ) :
vm_mappings [ vm . get_name ( ) ] = vm . get_connkey ( )
2009-07-27 22:30:01 -04:00
vm_names = vm_mappings . keys ( )
vm_names . sort ( )
if len ( vm_names ) == 0 :
2014-02-25 15:57:38 -05:00
menu_item = Gtk . MenuItem . new_with_label ( _ ( " No virtual machines " ) )
2009-07-27 22:30:01 -04:00
menu_item . set_sensitive ( False )
vm_submenu . insert ( menu_item , 0 )
return
2017-10-11 12:36:03 +01:00
for i , name in enumerate ( vm_names ) :
2014-06-02 17:17:47 -04:00
connkey = vm_mappings [ name ]
if connkey in self . conn_vm_menuitems [ uri ] :
vm_item = self . conn_vm_menuitems [ uri ] [ connkey ]
2009-07-27 22:30:01 -04:00
vm_submenu . insert ( vm_item , i )
2014-06-02 17:17:47 -04:00
def vm_added ( self , conn , connkey ) :
2011-07-22 13:54:40 -04:00
uri = conn . get_uri ( )
2014-06-02 17:17:47 -04:00
vm = conn . get_vm ( connkey )
2009-07-27 22:30:01 -04:00
if not vm :
return
2015-04-09 18:02:42 -04:00
vm . connect ( " state-changed " , self . vm_state_changed )
2009-07-27 22:30:01 -04:00
vm_mappings = self . conn_vm_menuitems [ uri ]
2014-06-02 17:17:47 -04:00
if connkey in vm_mappings :
2009-07-27 22:30:01 -04:00
return
# Build VM list entry
2014-02-25 15:57:38 -05:00
menu_item = Gtk . ImageMenuItem . new_with_label ( vm . get_name ( ) )
menu_item . set_use_underline ( False )
2014-06-02 17:17:47 -04:00
vm_mappings [ connkey ] = menu_item
2014-01-28 18:04:46 -05:00
vm_action_menu = vmmenu . VMActionMenu ( self , lambda : vm )
2009-07-27 22:30:01 -04:00
menu_item . set_submenu ( vm_action_menu )
2014-06-02 17:17:47 -04:00
self . vm_action_dict [ connkey ] = vm_action_menu
2009-07-27 22:30:01 -04:00
# Add VM to menu list
self . populate_vm_list ( conn )
# Update state
self . vm_state_changed ( vm )
menu_item . show ( )
2014-06-02 17:17:47 -04:00
def vm_removed ( self , conn , connkey ) :
2011-07-22 13:54:40 -04:00
uri = conn . get_uri ( )
2009-07-27 22:30:01 -04:00
vm_mappings = self . conn_vm_menuitems [ uri ]
if not vm_mappings :
return
2014-06-02 17:17:47 -04:00
if connkey not in vm_mappings :
return
conn_item = self . conn_menuitems [ uri ]
vm_menu_item = vm_mappings [ connkey ]
vm_menu = conn_item . get_submenu ( )
vm_menu . remove ( vm_menu_item )
vm_menu_item . destroy ( )
del ( vm_mappings [ connkey ] )
if len ( vm_menu . get_children ( ) ) == 0 :
placeholder = Gtk . MenuItem . new_with_label (
_ ( " No virtual machines " ) )
placeholder . show ( )
placeholder . set_sensitive ( False )
vm_menu . add ( placeholder )
2009-07-27 22:30:01 -04:00
2015-04-09 16:07:09 -04:00
def vm_state_changed ( self , vm ) :
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
2014-06-02 17:17:47 -04:00
menu = self . vm_action_dict [ vm . get_connkey ( ) ]
2013-09-22 15:13:41 -04:00
menu . update_widget_states ( vm )
2009-07-27 22:30:01 -04:00
def exit_app ( self , ignore ) :
self . emit ( " action-exit-app " )