2009-11-20 11:39:22 -05: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.
#
2009-11-20 13:12:24 -05:00
import logging
2010-12-10 11:47:07 -05:00
import os
import statvfs
2009-11-20 13:12:24 -05:00
2012-05-14 14:24:56 +01:00
from gi . repository import Gtk
2009-11-20 11:39:22 -05:00
2010-03-04 15:31:33 -05:00
import virtinst
2009-11-20 11:39:22 -05:00
from virtinst import VirtualNetworkInterface
2009-12-01 12:23:19 -05:00
from virtinst import VirtualDisk
2009-11-20 11:39:22 -05:00
2010-03-04 15:31:33 -05:00
from virtManager import util
2009-11-20 13:12:24 -05:00
from virtManager . error import vmmErrorDialog
2009-11-30 16:22:20 -05:00
OPTICAL_DEV_PATH = 0
2009-11-30 16:21:04 -05:00
OPTICAL_LABEL = 1
OPTICAL_IS_MEDIA_PRESENT = 2
2009-11-30 16:22:20 -05:00
OPTICAL_DEV_KEY = 3
OPTICAL_MEDIA_KEY = 4
2010-02-12 13:52:33 -05:00
OPTICAL_IS_VALID = 5
2009-11-30 16:21:04 -05:00
##############################################################
# Initialize an error object to use for validation functions #
##############################################################
2010-11-30 14:33:21 -05:00
err_dial = vmmErrorDialog ( )
2009-11-20 13:12:24 -05:00
def set_error_parent ( parent ) :
global err_dial
err_dial . set_parent ( parent )
err_dial = err_dial
2011-04-13 09:27:02 -04:00
def cleanup ( ) :
global err_dial
err_dial = None
2011-07-19 14:02:39 -04:00
def spin_get_helper ( widget ) :
adj = widget . get_adjustment ( )
txt = widget . get_text ( )
try :
ret = int ( txt )
except :
2012-05-14 14:24:56 +01:00
ret = adj . get_value ( )
2011-07-19 14:02:39 -04:00
return ret
2010-03-04 15:31:33 -05:00
############################################################
# Helpers for shared storage UI between create/addhardware #
############################################################
def set_sparse_tooltip ( widget ) :
2010-04-05 12:17:25 -04:00
sparse_str = _ ( " Fully allocating storage may take longer now, "
2010-03-04 15:31:33 -05:00
" but the OS install phase will be quicker. \n \n "
" Skipping allocation can also cause space issues on "
" the host machine, if the maximum image size exceeds "
2013-02-21 13:27:55 +08:00
" available storage space. \n \n "
" Tip: Storage format qcow2 and qed "
" do not support full allocation. " )
2012-05-14 14:24:56 +01:00
widget . set_tooltip_text ( sparse_str )
2010-03-04 15:31:33 -05:00
2010-12-09 14:06:00 -05:00
def host_disk_space ( conn ) :
2010-03-04 15:31:33 -05:00
pool = util . get_default_pool ( conn )
2010-12-09 14:06:00 -05:00
path = util . get_default_dir ( conn )
2010-03-04 15:31:33 -05:00
avail = 0
2011-04-09 19:25:40 -04:00
if pool and pool . is_active ( ) :
2010-03-04 15:31:33 -05:00
# FIXME: make sure not inactive?
# FIXME: use a conn specific function after we send pool-added
2011-04-09 19:25:40 -04:00
pool . refresh ( )
2011-04-10 17:08:23 -04:00
avail = int ( util . xpath ( pool . get_xml ( ) , " /pool/available " ) )
2010-03-04 15:31:33 -05:00
2011-07-07 13:38:04 -04:00
elif not conn . is_remote ( ) and os . path . exists ( path ) :
2010-03-04 15:31:33 -05:00
vfs = os . statvfs ( os . path . dirname ( path ) )
avail = vfs [ statvfs . F_FRSIZE ] * vfs [ statvfs . F_BAVAIL ]
return float ( avail / 1024.0 / 1024.0 / 1024.0 )
2010-12-09 14:06:00 -05:00
def host_space_tick ( conn , widget ) :
2010-12-13 16:12:55 -05:00
try :
max_storage = host_disk_space ( conn )
except :
logging . exception ( " Error determining host disk space " )
return 0
2010-03-04 15:31:33 -05:00
def pretty_storage ( size ) :
return " %.1f Gb " % float ( size )
hd_label = ( " %s available in the default location " %
pretty_storage ( max_storage ) )
hd_label = ( " <span color= ' #484848 ' > %s </span> " % hd_label )
widget . set_markup ( hd_label )
return 1
2010-05-13 10:37:46 -04:00
def check_default_pool_active ( topwin , conn ) :
default_pool = util . get_default_pool ( conn )
if default_pool and not default_pool . is_active ( ) :
res = err_dial . yes_no ( _ ( " Default pool is not active. " ) ,
_ ( " Storage pool ' %s ' is not active. "
" Would you like to start the pool "
" now? " ) % default_pool . get_name ( ) )
if not res :
return False
# Try to start the pool
try :
default_pool . start ( )
2012-01-16 22:04:40 -05:00
logging . info ( " Started pool ' %s ' " , default_pool . get_name ( ) )
2010-05-13 10:37:46 -04:00
except Exception , e :
return topwin . err . show_err ( _ ( " Could not start storage_pool "
" ' %s ' : %s " ) %
2011-04-06 11:22:03 -04:00
( default_pool . get_name ( ) , str ( e ) ) )
2010-05-13 10:37:46 -04:00
return True
2010-03-23 22:15:53 -04:00
#####################################################
# Hardware model list building (for details, addhw) #
#####################################################
2011-07-22 13:00:36 -04:00
def build_video_combo ( vm , video_dev , no_default = None ) :
2012-05-14 14:24:56 +01:00
video_dev_model = Gtk . ListStore ( str , str )
2010-03-23 22:15:53 -04:00
video_dev . set_model ( video_dev_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-03-23 22:15:53 -04:00
video_dev . pack_start ( text , True )
2012-10-28 16:32:23 -04:00
video_dev . add_attribute ( text , ' text ' , 1 )
2012-05-14 14:24:56 +01:00
video_dev_model . set_sort_column_id ( 1 , Gtk . SortType . ASCENDING )
2010-03-23 22:15:53 -04:00
2011-07-22 13:00:36 -04:00
populate_video_combo ( vm , video_dev , no_default )
def populate_video_combo ( vm , video_dev , no_default = None ) :
video_dev_model = video_dev . get_model ( )
has_spice = any ( map ( lambda g : g . type == g . TYPE_SPICE ,
vm . get_graphics_devices ( ) ) )
has_qxl = any ( map ( lambda v : v . model_type == " qxl " ,
vm . get_video_devices ( ) ) )
video_dev_model . clear ( )
2011-07-22 16:43:26 -04:00
tmpdev = virtinst . VirtualVideoDevice ( vm . conn . vmm )
2010-03-23 22:15:53 -04:00
for m in tmpdev . model_types :
2011-07-22 13:13:26 -04:00
if not vm . rhel6_defaults ( ) :
2011-07-22 13:00:36 -04:00
if m == " qxl " and not has_spice and not has_qxl :
# Only list QXL video option when VM has SPICE video
continue
2010-03-23 22:15:53 -04:00
if m == tmpdev . MODEL_DEFAULT and no_default :
continue
2012-10-28 16:32:23 -04:00
video_dev_model . append ( [ m , tmpdev . pretty_model ( m ) ] )
2011-07-22 13:00:36 -04:00
2010-03-23 22:15:53 -04:00
if len ( video_dev_model ) > 0 :
video_dev . set_active ( 0 )
def build_sound_combo ( vm , combo , no_default = False ) :
2012-05-14 14:24:56 +01:00
dev_model = Gtk . ListStore ( str )
2010-03-23 22:15:53 -04:00
combo . set_model ( dev_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-03-23 22:15:53 -04:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 0 )
2012-05-14 14:24:56 +01:00
dev_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2010-03-23 22:15:53 -04:00
2011-07-22 13:13:26 -04:00
disable_rhel = not vm . rhel6_defaults ( )
2011-03-08 11:17:11 -05:00
rhel6_soundmodels = [ " ich6 " , " ac97 " , " es1370 " ]
2010-12-13 14:31:27 -05:00
2010-03-23 22:15:53 -04:00
for m in virtinst . VirtualAudio . MODELS :
if m == virtinst . VirtualAudio . MODEL_DEFAULT and no_default :
continue
2010-05-13 12:41:27 -04:00
2010-12-13 14:31:27 -05:00
if ( disable_rhel and m not in rhel6_soundmodels ) :
2010-05-13 12:41:27 -04:00
continue
2010-03-23 22:15:53 -04:00
dev_model . append ( [ m ] )
if len ( dev_model ) > 0 :
2010-03-24 00:22:17 -04:00
combo . set_active ( 0 )
def build_watchdogmodel_combo ( vm , combo , no_default = False ) :
2010-12-09 11:22:35 -05:00
ignore = vm
2012-05-14 14:24:56 +01:00
dev_model = Gtk . ListStore ( str )
2010-03-24 00:22:17 -04:00
combo . set_model ( dev_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-03-24 00:22:17 -04:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 0 )
2012-05-14 14:24:56 +01:00
dev_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2010-03-24 00:22:17 -04:00
for m in virtinst . VirtualWatchdog . MODELS :
if m == virtinst . VirtualAudio . MODEL_DEFAULT and no_default :
continue
dev_model . append ( [ m ] )
if len ( dev_model ) > 0 :
combo . set_active ( 0 )
def build_watchdogaction_combo ( vm , combo , no_default = False ) :
2010-12-09 11:22:35 -05:00
ignore = vm
2012-05-14 14:24:56 +01:00
dev_model = Gtk . ListStore ( str , str )
2010-03-24 00:22:17 -04:00
combo . set_model ( dev_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-03-24 00:22:17 -04:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 1 )
2012-05-14 14:24:56 +01:00
dev_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2010-03-24 00:22:17 -04:00
for m in virtinst . VirtualWatchdog . ACTIONS :
if m == virtinst . VirtualWatchdog . ACTION_DEFAULT and no_default :
continue
dev_model . append ( [ m , virtinst . VirtualWatchdog . get_action_desc ( m ) ] )
if len ( dev_model ) > 0 :
2010-03-23 22:15:53 -04:00
combo . set_active ( 0 )
2011-04-19 13:08:15 +02:00
def build_source_mode_combo ( vm , combo ) :
2012-05-14 14:24:56 +01:00
source_mode = Gtk . ListStore ( str , str )
2011-04-19 13:08:15 +02:00
combo . set_model ( source_mode )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2011-04-19 13:08:15 +02:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 1 )
populate_source_mode_combo ( vm , combo )
combo . set_active ( 0 )
def populate_source_mode_combo ( vm , combo ) :
2011-04-28 14:23:50 -04:00
ignore = vm
2011-04-19 13:08:15 +02:00
model = combo . get_model ( )
model . clear ( )
# [xml value, label]
2012-01-29 16:21:39 -05:00
model . append ( [ None , " Default " ] )
2011-05-19 12:13:20 -04:00
model . append ( [ " vepa " , " VEPA " ] )
model . append ( [ " bridge " , " Bridge " ] )
model . append ( [ " private " , " Private " ] )
model . append ( [ " passthrough " , " Passthrough " ] )
2011-04-19 13:08:15 +02:00
2011-06-23 17:42:03 +02:00
def build_smartcard_mode_combo ( vm , combo ) :
2012-05-14 14:24:56 +01:00
dev_model = Gtk . ListStore ( str , str )
2011-06-23 17:42:03 +02:00
combo . set_model ( dev_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2011-06-23 17:42:03 +02:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 1 )
2012-05-14 14:24:56 +01:00
dev_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2011-06-23 17:42:03 +02:00
populate_smartcard_mode_combo ( vm , combo )
idx = - 1
for rowid in range ( len ( combo . get_model ( ) ) ) :
idx = 0
row = combo . get_model ( ) [ rowid ]
if row [ 0 ] == virtinst . VirtualSmartCardDevice . MODE_DEFAULT :
idx = rowid
break
combo . set_active ( idx )
def populate_smartcard_mode_combo ( vm , combo ) :
ignore = vm
model = combo . get_model ( )
model . clear ( )
# [xml value, label]
model . append ( [ " passthrough " , " Passthrough " ] )
model . append ( [ " host " , " Host " ] )
# TODO
# model.append(["host-certificates", "Host Certificates"])
2011-09-02 03:23:27 +02:00
def build_redir_type_combo ( vm , combo ) :
2012-05-14 14:24:56 +01:00
source_mode = Gtk . ListStore ( str , str , bool )
2011-09-02 03:23:27 +02:00
combo . set_model ( source_mode )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2011-09-02 03:23:27 +02:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 1 )
populate_redir_type_combo ( vm , combo )
combo . set_active ( 0 )
def populate_redir_type_combo ( vm , combo ) :
ignore = vm
model = combo . get_model ( )
model . clear ( )
# [xml value, label, conn details]
model . append ( [ " spicevmc " , " Spice channel " , False ] )
model . append ( [ " tcp " , " TCP " , True ] )
2010-03-23 22:15:53 -04:00
def build_netmodel_combo ( vm , combo ) :
2012-05-14 14:24:56 +01:00
dev_model = Gtk . ListStore ( str , str )
2010-03-23 22:15:53 -04:00
combo . set_model ( dev_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-03-23 22:15:53 -04:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 1 )
2012-05-14 14:24:56 +01:00
dev_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2010-03-23 22:15:53 -04:00
populate_netmodel_combo ( vm , combo )
combo . set_active ( 0 )
def populate_netmodel_combo ( vm , combo ) :
model = combo . get_model ( )
model . clear ( )
# [xml value, label]
model . append ( [ None , _ ( " Hypervisor default " ) ] )
if vm . is_hvm ( ) :
2010-12-10 19:01:08 -05:00
mod_list = [ " rtl8139 " , " ne2k_pci " , " pcnet " , " e1000 " ]
2011-05-09 09:07:36 -04:00
if vm . get_hv_type ( ) in [ " kvm " , " qemu " , " test " ] :
2010-03-23 22:15:53 -04:00
mod_list . append ( " virtio " )
2012-03-05 16:10:15 +08:00
if ( vm . get_hv_type ( ) == " kvm " and
vm . get_machtype ( ) == " pseries " ) :
mod_list . append ( " spapr-vlan " )
2011-05-09 09:07:36 -04:00
if vm . get_hv_type ( ) in [ " xen " , " test " ] :
2010-12-10 19:01:08 -05:00
mod_list . append ( " netfront " )
2010-03-23 22:15:53 -04:00
mod_list . sort ( )
for m in mod_list :
model . append ( [ m , m ] )
2010-05-20 08:34:32 -04:00
def build_cache_combo ( vm , combo , no_default = False ) :
2010-12-09 11:22:35 -05:00
ignore = vm
2012-05-14 14:24:56 +01:00
dev_model = Gtk . ListStore ( str , str )
2010-05-20 08:34:32 -04:00
combo . set_model ( dev_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-05-20 08:34:32 -04:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 1 )
2012-05-14 14:24:56 +01:00
dev_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2010-05-20 08:34:32 -04:00
combo . set_active ( - 1 )
for m in virtinst . VirtualDisk . cache_types :
dev_model . append ( [ m , m ] )
if not no_default :
dev_model . append ( [ None , " default " ] )
combo . set_active ( 0 )
2009-11-30 16:21:04 -05:00
2011-07-23 20:41:35 -04:00
def build_io_combo ( vm , combo , no_default = False ) :
ignore = vm
2012-05-14 14:24:56 +01:00
dev_model = Gtk . ListStore ( str , str )
2011-07-23 20:41:35 -04:00
combo . set_model ( dev_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2011-07-23 20:41:35 -04:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 1 )
2012-05-14 14:24:56 +01:00
dev_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2011-07-23 20:41:35 -04:00
combo . set_active ( - 1 )
for m in virtinst . VirtualDisk . io_modes :
dev_model . append ( [ m , m ] )
if not no_default :
dev_model . append ( [ None , " default " ] )
combo . set_active ( 0 )
2010-12-10 20:33:41 -05:00
def build_disk_bus_combo ( vm , combo , no_default = False ) :
ignore = vm
2012-05-14 14:24:56 +01:00
dev_model = Gtk . ListStore ( str , str )
2010-12-10 20:33:41 -05:00
combo . set_model ( dev_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-12-10 20:33:41 -05:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 1 )
2012-05-14 14:24:56 +01:00
dev_model . set_sort_column_id ( 0 , Gtk . SortType . ASCENDING )
2010-12-10 20:33:41 -05:00
if not no_default :
dev_model . append ( [ None , " default " ] )
combo . set_active ( - 1 )
2010-12-10 19:20:14 -05:00
2010-12-11 20:54:48 -05:00
def build_vnc_keymap_combo ( vm , combo , no_default = False ) :
ignore = vm
2012-05-14 14:24:56 +01:00
model = Gtk . ListStore ( str , str )
2010-12-11 20:54:48 -05:00
combo . set_model ( model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-12-11 20:54:48 -05:00
combo . pack_start ( text , True )
combo . add_attribute ( text , ' text ' , 1 )
if not no_default :
model . append ( [ None , " default " ] )
else :
model . append ( [ None , " Auto " ] )
model . append ( [ virtinst . VirtualGraphics . KEYMAP_LOCAL ,
" Copy local keymap " ] )
for k in virtinst . VirtualGraphics . valid_keymaps ( ) :
model . append ( [ k , k ] )
combo . set_active ( - 1 )
2010-12-10 19:20:14 -05:00
#####################################
# Storage format list/combo helpers #
#####################################
def build_storage_format_combo ( vm , combo ) :
2012-05-14 14:24:56 +01:00
dev_model = Gtk . ListStore ( str )
2010-12-10 19:20:14 -05:00
combo . set_model ( dev_model )
2012-05-14 14:24:56 +01:00
combo . set_entry_text_column ( 0 )
2010-12-10 19:20:14 -05:00
2012-03-01 18:08:13 -05:00
formats = [ " raw " , " qcow2 " , " qed " ]
2011-07-22 13:13:26 -04:00
if vm . rhel6_defaults ( ) :
2011-07-22 12:22:09 -04:00
formats . append ( " vmdk " )
2012-02-07 17:13:59 -05:00
formats . append ( " vdi " )
2011-07-22 12:22:09 -04:00
for m in formats :
2010-12-10 19:20:14 -05:00
dev_model . append ( [ m ] )
combo . set_active ( 0 )
2009-11-30 16:21:04 -05:00
#######################################################################
# Widgets for listing network device options (in create, addhardware) #
#######################################################################
2009-12-02 09:54:29 -05:00
def pretty_network_desc ( nettype , source = None , netobj = None ) :
if nettype == VirtualNetworkInterface . TYPE_USER :
return _ ( " Usermode networking " )
extra = None
if nettype == VirtualNetworkInterface . TYPE_BRIDGE :
ret = _ ( " Bridge " )
elif nettype == VirtualNetworkInterface . TYPE_VIRTUAL :
ret = _ ( " Virtual network " )
if netobj :
extra = " : %s " % netobj . pretty_forward_mode ( )
else :
ret = nettype . capitalize ( )
if source :
ret + = " ' %s ' " % source
if extra :
ret + = " %s " % extra
return ret
2011-04-28 14:23:50 -04:00
def init_network_list ( net_list , bridge_box ,
source_mode_box = None , source_mode_label = None ,
vport_expander = None ) :
2010-03-20 18:35:47 -04:00
# [ network type, source name, label, sensitive?, net is active,
2010-12-04 12:28:44 -05:00
# manual bridge, net instance]
2012-05-14 14:24:56 +01:00
net_model = Gtk . ListStore ( str , str , str , bool , bool , bool , object )
2009-11-20 11:39:22 -05:00
net_list . set_model ( net_model )
2009-11-24 13:14:55 -05:00
2011-04-28 14:23:50 -04:00
net_list . connect ( " changed " , net_list_changed , bridge_box , source_mode_box ,
source_mode_label , vport_expander )
2009-11-24 13:14:55 -05:00
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-03-20 18:35:47 -04:00
net_list . pack_start ( text , True )
net_list . add_attribute ( text , ' text ' , 2 )
net_list . add_attribute ( text , ' sensitive ' , 3 )
2011-04-28 14:23:50 -04:00
def net_list_changed ( net_list , bridge_box ,
source_mode_box , source_mode_label , vport_expander ) :
2010-03-20 18:35:47 -04:00
active = net_list . get_active ( )
if active < 0 :
return
2011-03-17 16:33:40 -04:00
if not bridge_box :
return
2010-03-20 18:35:47 -04:00
row = net_list . get_model ( ) [ active ]
2011-04-19 13:08:15 +02:00
2012-11-08 14:15:02 +01:00
if source_mode_box is not None :
2011-04-19 13:08:15 +02:00
show_source_mode = ( row [ 0 ] == VirtualNetworkInterface . TYPE_DIRECT )
source_mode_box . set_property ( " visible " , show_source_mode )
source_mode_label . set_property ( " visible " , show_source_mode )
vport_expander . set_property ( " visible " , show_source_mode )
2010-03-20 18:35:47 -04:00
show_bridge = row [ 5 ]
bridge_box . set_property ( " visible " , show_bridge )
def get_network_selection ( net_list , bridge_entry ) :
2011-03-17 16:33:40 -04:00
idx = net_list . get_active ( )
if idx == - 1 :
return None , None
2010-03-20 18:35:47 -04:00
row = net_list . get_model ( ) [ net_list . get_active ( ) ]
net_type = row [ 0 ]
net_src = row [ 1 ]
net_check_bridge = row [ 5 ]
2011-03-17 16:33:40 -04:00
if net_check_bridge and bridge_entry :
2010-03-20 18:35:47 -04:00
net_type = VirtualNetworkInterface . TYPE_BRIDGE
net_src = bridge_entry . get_text ( )
return net_type , net_src
2009-11-20 11:39:22 -05:00
2011-04-06 16:07:12 +02:00
def populate_network_list ( net_list , conn , show_direct_interfaces = True ) :
2009-11-20 11:39:22 -05:00
model = net_list . get_model ( )
model . clear ( )
2009-12-02 09:18:05 -05:00
vnet_bridges = [ ]
2009-11-25 16:12:45 -05:00
vnet_dict = { }
bridge_dict = { }
iface_dict = { }
2010-03-20 18:35:47 -04:00
def build_row ( nettype , name , label , is_sensitive , is_running ,
2011-04-11 19:42:17 -04:00
manual_bridge = False , key = None ) :
2010-12-04 12:28:44 -05:00
return [ nettype , name , label ,
is_sensitive , is_running , manual_bridge ,
2011-04-11 19:42:17 -04:00
key ]
2010-02-12 13:37:04 -05:00
2009-11-24 13:14:55 -05:00
def set_active ( idx ) :
2010-03-20 18:35:47 -04:00
net_list . set_active ( idx )
2009-11-24 13:14:55 -05:00
2009-11-25 16:12:45 -05:00
def add_dict ( indict , model ) :
keylist = indict . keys ( )
keylist . sort ( )
rowlist = map ( lambda key : indict [ key ] , keylist )
for row in rowlist :
model . append ( row )
2009-11-20 11:39:22 -05:00
# For qemu:///session
if conn . is_qemu_session ( ) :
2009-12-02 09:54:29 -05:00
nettype = VirtualNetworkInterface . TYPE_USER
2010-07-26 15:15:28 -04:00
r = build_row ( nettype , None , pretty_network_desc ( nettype ) , True , True )
model . append ( r )
2009-11-24 13:14:55 -05:00
set_active ( 0 )
2009-11-20 11:39:22 -05:00
return
hasNet = False
2009-11-25 16:12:45 -05:00
netIdxLabel = None
2009-11-20 11:39:22 -05:00
# Virtual Networks
for uuid in conn . list_net_uuids ( ) :
net = conn . get_net ( uuid )
2009-12-02 09:54:29 -05:00
nettype = VirtualNetworkInterface . TYPE_VIRTUAL
2009-11-20 11:39:22 -05:00
2009-12-02 09:54:29 -05:00
label = pretty_network_desc ( nettype , net . get_name ( ) , net )
2009-11-20 11:39:22 -05:00
if not net . is_active ( ) :
2010-12-10 11:47:07 -05:00
label + = " ( %s ) " % _ ( " Inactive " )
2009-11-20 11:39:22 -05:00
hasNet = True
2009-11-25 16:12:45 -05:00
# FIXME: Should we use 'default' even if it's inactive?
2009-11-20 11:39:22 -05:00
# FIXME: This preference should be configurable
if net . get_name ( ) == " default " :
2009-11-25 16:12:45 -05:00
netIdxLabel = label
2009-11-20 11:39:22 -05:00
2010-02-12 13:37:04 -05:00
vnet_dict [ label ] = build_row ( nettype , net . get_name ( ) , label , True ,
2011-04-11 19:42:17 -04:00
net . is_active ( ) , key = net . get_uuid ( ) )
2009-12-02 09:18:05 -05:00
# Build a list of vnet bridges, so we know not to list them
# in the physical interface list
vnet_bridge = net . get_bridge_device ( )
if vnet_bridge :
vnet_bridges . append ( vnet_bridge )
2009-11-20 11:39:22 -05:00
if not hasNet :
2009-11-25 16:12:45 -05:00
label = _ ( " No virtual networks available " )
2010-02-12 13:37:04 -05:00
vnet_dict [ label ] = build_row ( None , None , label , False , False )
2009-11-20 11:39:22 -05:00
# Physical devices
hasShared = False
2009-11-25 16:12:45 -05:00
brIdxLabel = None
for name in conn . list_net_device_paths ( ) :
br = conn . get_net_device ( name )
bridge_name = br . get_bridge ( )
2009-12-02 09:54:29 -05:00
nettype = VirtualNetworkInterface . TYPE_BRIDGE
2009-11-25 16:12:45 -05:00
2009-12-02 09:18:05 -05:00
if ( bridge_name in vnet_bridges ) or ( br . get_name ( ) in vnet_bridges ) :
# Don't list this, as it is basically duplicating virtual net info
continue
2009-11-25 16:12:45 -05:00
if br . is_shared ( ) :
sensitive = True
if br . get_bridge ( ) :
2009-12-02 09:58:31 -05:00
hasShared = True
2009-12-02 09:54:29 -05:00
brlabel = " ( %s ) " % pretty_network_desc ( nettype , bridge_name )
2009-11-20 11:39:22 -05:00
else :
2009-11-25 16:12:45 -05:00
bridge_name = name
brlabel = _ ( " (Empty bridge) " )
else :
2011-04-06 16:07:12 +02:00
if ( show_direct_interfaces and virtinst . support . check_conn_support ( conn . vmm ,
virtinst . support . SUPPORT_CONN_HV_DIRECT_INTERFACE ) ) :
sensitive = True
nettype = VirtualNetworkInterface . TYPE_DIRECT
bridge_name = name
brlabel = " : %s " % _ ( " macvtap " )
else :
sensitive = False
brlabel = " ( %s ) " % _ ( " Not bridged " )
2009-11-25 16:12:45 -05:00
label = _ ( " Host device %s %s " ) % ( br . get_name ( ) , brlabel )
if hasShared and not brIdxLabel :
brIdxLabel = label
2011-04-11 19:42:17 -04:00
row = build_row ( nettype , bridge_name , label , sensitive , True ,
key = br . get_name ( ) )
2009-11-20 11:39:22 -05:00
2009-11-25 16:12:45 -05:00
if sensitive :
bridge_dict [ label ] = row
else :
iface_dict [ label ] = row
add_dict ( bridge_dict , model )
add_dict ( vnet_dict , model )
add_dict ( iface_dict , model )
2009-11-20 11:39:22 -05:00
# If there is a bridge device, default to that
# If not, use 'default' network
# If not present, use first list entry
# If list empty, use no network devices
2010-02-12 13:37:04 -05:00
return_warn = False
2009-11-25 16:12:45 -05:00
label = brIdxLabel or netIdxLabel
2010-02-12 13:37:04 -05:00
2009-12-02 10:03:03 -05:00
for idx in range ( len ( model ) ) :
row = model [ idx ]
2010-02-12 13:37:04 -05:00
is_inactive = not row [ 4 ]
2009-12-02 10:03:03 -05:00
if label :
2009-11-25 16:12:45 -05:00
if row [ 2 ] == label :
default = idx
2010-02-12 13:37:04 -05:00
return_warn = is_inactive
2009-11-25 16:12:45 -05:00
break
2009-12-02 10:03:03 -05:00
else :
2012-11-08 14:15:02 +01:00
if row [ 3 ] is True :
2009-12-02 10:03:03 -05:00
default = idx
2010-02-12 13:37:04 -05:00
return_warn = is_inactive
2009-12-02 10:03:03 -05:00
break
2009-11-20 11:39:22 -05:00
else :
2010-02-12 13:37:04 -05:00
return_warn = True
2011-04-15 15:34:54 -04:00
row = build_row ( None , None , _ ( " No networking " ) , True , False )
2010-03-20 18:35:47 -04:00
model . insert ( 0 , row )
2009-11-20 11:39:22 -05:00
default = 0
2011-04-06 16:07:12 +02:00
# After all is said and done, add a manual bridge option
manual_row = build_row ( None , None , _ ( " Specify shared device name " ) ,
True , False , manual_bridge = True )
model . append ( manual_row )
2010-03-20 18:35:47 -04:00
2009-11-24 13:14:55 -05:00
set_active ( default )
2010-02-12 13:37:04 -05:00
return return_warn
2009-11-20 13:12:24 -05:00
def validate_network ( parent , conn , nettype , devname , macaddr , model = None ) :
set_error_parent ( parent )
net = None
2012-03-05 16:10:15 +08:00
addr = None
2009-11-20 13:12:24 -05:00
if nettype is None :
return None
# Make sure VirtualNetwork is running
if ( nettype == VirtualNetworkInterface . TYPE_VIRTUAL and
devname not in conn . vmm . listNetworks ( ) ) :
res = err_dial . yes_no ( _ ( " Virtual Network is not active. " ) ,
_ ( " Virtual Network ' %s ' is not active. "
" Would you like to start the network "
" now? " ) % devname )
if not res :
return False
# Try to start the network
try :
virnet = conn . vmm . networkLookupByName ( devname )
virnet . create ( )
2012-01-16 22:04:40 -05:00
logging . info ( " Started network ' %s ' " , devname )
2009-11-20 13:12:24 -05:00
except Exception , e :
return err_dial . show_err ( _ ( " Could not start virtual network "
2011-04-06 11:22:03 -04:00
" ' %s ' : %s " ) % ( devname , str ( e ) ) )
2009-11-20 13:12:24 -05:00
# Create network device
try :
bridge = None
netname = None
if nettype == VirtualNetworkInterface . TYPE_VIRTUAL :
netname = devname
elif nettype == VirtualNetworkInterface . TYPE_BRIDGE :
bridge = devname
2011-04-06 16:07:12 +02:00
elif nettype == VirtualNetworkInterface . TYPE_DIRECT :
bridge = devname
2009-11-20 13:12:24 -05:00
elif nettype == VirtualNetworkInterface . TYPE_USER :
pass
2010-12-10 11:47:07 -05:00
net = VirtualNetworkInterface ( conn = conn . vmm ,
type = nettype ,
bridge = bridge ,
network = netname ,
macaddr = macaddr ,
model = model )
2012-03-05 16:10:15 +08:00
if net . model == " spapr-vlan " :
addr = " spapr-vio "
net . set_address ( addr )
2009-11-20 13:12:24 -05:00
except Exception , e :
2011-08-30 14:50:50 -04:00
return err_dial . val_err ( _ ( " Error with network parameters. " ) , e )
2009-11-20 13:12:24 -05:00
# Make sure there is no mac address collision
isfatal , errmsg = net . is_conflict_net ( conn . vmm )
if isfatal :
return err_dial . val_err ( _ ( " Mac address collision. " ) , errmsg )
elif errmsg is not None :
retv = err_dial . yes_no ( _ ( " Mac address collision. " ) ,
_ ( " %s Are you sure you want to use this "
" address? " ) % errmsg )
if not retv :
return False
return net
2009-11-24 13:14:55 -05:00
def generate_macaddr ( conn ) :
newmac = " "
try :
net = VirtualNetworkInterface ( conn = conn . vmm )
net . setup ( conn . vmm )
newmac = net . macaddr
except :
pass
return newmac
2009-11-28 20:49:44 -05:00
2009-11-30 16:21:04 -05:00
2009-12-10 20:04:26 -05:00
############################################
# Populate media widget (choosecd, create) #
############################################
2009-11-30 16:21:04 -05:00
2010-02-12 13:52:33 -05:00
def init_mediadev_combo ( widget ) :
2009-11-30 16:22:20 -05:00
# [Device path, pretty label, has_media?, device key, media key,
2010-02-12 13:52:33 -05:00
# vmmMediaDevice, is valid device]
2012-05-14 14:24:56 +01:00
model = Gtk . ListStore ( str , str , bool , str , str , bool )
2009-11-30 16:21:04 -05:00
widget . set_model ( model )
model . clear ( )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2009-11-30 16:21:04 -05:00
widget . pack_start ( text , True )
2010-02-12 13:52:33 -05:00
widget . add_attribute ( text , ' text ' , OPTICAL_LABEL )
widget . add_attribute ( text , ' sensitive ' , OPTICAL_IS_VALID )
2009-11-30 16:21:04 -05:00
2009-12-10 20:04:26 -05:00
def populate_mediadev_combo ( conn , widget , devtype ) :
2009-11-30 11:56:41 -05:00
sigs = [ ]
2010-02-12 13:52:33 -05:00
model = widget . get_model ( )
model . clear ( )
set_mediadev_default ( model )
2009-11-30 11:56:41 -05:00
2009-12-10 20:04:26 -05:00
sigs . append ( conn . connect ( " mediadev-added " , mediadev_added , widget , devtype ) )
sigs . append ( conn . connect ( " mediadev-removed " , mediadev_removed , widget ) )
2009-11-30 16:21:04 -05:00
widget . set_active ( - 1 )
2009-12-10 20:04:26 -05:00
mediadev_set_default_selection ( widget )
2009-11-30 16:21:04 -05:00
2009-11-30 11:56:41 -05:00
return sigs
2010-02-12 13:52:33 -05:00
def set_mediadev_default ( model ) :
if len ( model ) == 0 :
model . append ( [ None , _ ( " No device present " ) , False , None , None , False ] )
2009-11-30 16:16:43 -05:00
def set_row_from_object ( row , obj ) :
2009-11-30 16:22:20 -05:00
row [ OPTICAL_DEV_PATH ] = obj . get_path ( )
2009-11-30 16:21:04 -05:00
row [ OPTICAL_LABEL ] = obj . pretty_label ( )
2009-11-30 16:16:43 -05:00
row [ OPTICAL_IS_MEDIA_PRESENT ] = obj . has_media ( )
2009-11-30 16:22:20 -05:00
row [ OPTICAL_DEV_KEY ] = obj . get_key ( )
row [ OPTICAL_MEDIA_KEY ] = obj . get_media_key ( )
2010-02-12 13:52:33 -05:00
row [ OPTICAL_IS_VALID ] = True
2009-11-30 16:21:04 -05:00
2009-12-10 20:04:26 -05:00
def mediadev_removed ( ignore_helper , key , widget ) :
2009-11-30 16:21:04 -05:00
model = widget . get_model ( )
active = widget . get_active ( )
idx = 0
2009-11-30 16:22:20 -05:00
2009-11-30 16:21:04 -05:00
for row in model :
2009-11-30 10:50:04 -05:00
if row [ OPTICAL_DEV_KEY ] == key :
2009-11-30 16:22:20 -05:00
# Whole device removed
del ( model [ idx ] )
2009-11-30 11:56:41 -05:00
if idx > active and active != - 1 :
2010-12-10 11:47:07 -05:00
widget . set_active ( active - 1 )
2009-11-30 11:56:41 -05:00
elif idx == active :
widget . set_active ( - 1 )
2009-11-30 16:22:20 -05:00
idx + = 1
2009-11-30 16:21:04 -05:00
2010-02-12 13:52:33 -05:00
set_mediadev_default ( model )
2009-12-10 20:04:26 -05:00
mediadev_set_default_selection ( widget )
2009-11-30 16:21:04 -05:00
2009-12-10 20:04:26 -05:00
def mediadev_added ( ignore_helper , newobj , widget , devtype ) :
2009-11-30 16:21:04 -05:00
model = widget . get_model ( )
2009-11-30 16:22:20 -05:00
2009-12-10 20:04:26 -05:00
if newobj . get_media_type ( ) != devtype :
return
2012-11-08 14:15:02 +01:00
if len ( model ) == 1 and model [ 0 ] [ OPTICAL_IS_VALID ] is False :
2010-02-12 13:52:33 -05:00
# Only entry is the 'No device' entry
model . clear ( )
2009-12-10 20:04:26 -05:00
newobj . connect ( " media-added " , mediadev_media_changed , widget )
newobj . connect ( " media-removed " , mediadev_media_changed , widget )
2009-11-30 10:50:04 -05:00
2009-11-30 16:22:20 -05:00
# Brand new device
2010-02-12 13:52:33 -05:00
row = [ None , None , None , None , None , None ]
2009-11-30 16:16:43 -05:00
set_row_from_object ( row , newobj )
2009-11-30 16:22:20 -05:00
model . append ( row )
2009-12-10 20:04:26 -05:00
mediadev_set_default_selection ( widget )
2009-11-30 16:16:43 -05:00
2009-12-10 20:04:26 -05:00
def mediadev_media_changed ( newobj , widget ) :
2009-11-30 16:22:20 -05:00
model = widget . get_model ( )
active = widget . get_active ( )
idx = 0
2009-11-30 16:21:04 -05:00
# Search for the row with matching device node and
# fill in info about inserted media. If model has no current
# selection, select the new media.
for row in model :
2009-11-30 16:22:20 -05:00
if row [ OPTICAL_DEV_PATH ] == newobj . get_path ( ) :
2009-11-30 16:16:43 -05:00
set_row_from_object ( row , newobj )
2009-11-30 10:50:04 -05:00
has_media = row [ OPTICAL_IS_MEDIA_PRESENT ]
2009-11-30 16:21:04 -05:00
2009-11-30 10:50:04 -05:00
if has_media and active == - 1 :
2009-11-30 16:21:04 -05:00
widget . set_active ( idx )
2009-11-30 10:50:04 -05:00
elif not has_media and active == idx :
widget . set_active ( - 1 )
2009-11-30 16:21:04 -05:00
idx = idx + 1
2009-12-10 20:04:26 -05:00
mediadev_set_default_selection ( widget )
2009-11-30 16:16:43 -05:00
2009-12-10 20:04:26 -05:00
def mediadev_set_default_selection ( widget ) :
2009-11-30 16:21:04 -05:00
# Set the first active cdrom device as selected, otherwise none
model = widget . get_model ( )
idx = 0
active = widget . get_active ( )
if active != - 1 :
# already a selection, don't change it
return
for row in model :
2012-11-08 14:15:02 +01:00
if row [ OPTICAL_IS_MEDIA_PRESENT ] is True :
2009-11-30 16:21:04 -05:00
widget . set_active ( idx )
return
idx + = 1
widget . set_active ( - 1 )
####################################################################
# Build toolbar shutdown button menu (manager and details toolbar) #
####################################################################
2013-03-16 17:59:32 -04:00
def build_shutdown_button_menu ( widget , shutdown_cb , reboot_cb , reset_cb ,
2010-05-12 11:42:59 -04:00
destroy_cb , save_cb ) :
2013-01-13 14:41:25 -05:00
widget . set_icon_name ( " system-shutdown " )
2012-05-14 14:24:56 +01:00
menu = Gtk . Menu ( )
2009-11-28 20:49:44 -05:00
widget . set_menu ( menu )
2013-01-13 14:41:25 -05:00
rebootimg = Gtk . Image . new_from_icon_name ( " system-shutdown " ,
Gtk . IconSize . MENU )
shutdownimg = Gtk . Image . new_from_icon_name ( " system-shutdown " ,
Gtk . IconSize . MENU )
destroyimg = Gtk . Image . new_from_icon_name ( " system-shutdown " ,
Gtk . IconSize . MENU )
resetimg = Gtk . Image . new_from_icon_name ( " system-shutdown " ,
Gtk . IconSize . MENU )
2012-05-14 14:24:56 +01:00
saveimg = Gtk . Image . new_from_icon_name ( Gtk . STOCK_SAVE , Gtk . IconSize . MENU )
2009-11-28 20:49:44 -05:00
2012-05-14 14:24:56 +01:00
reboot = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Reboot " ) )
2009-11-28 20:49:44 -05:00
reboot . set_image ( rebootimg )
reboot . show ( )
reboot . connect ( " activate " , reboot_cb )
menu . add ( reboot )
2012-05-14 14:24:56 +01:00
shutdown = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Shut Down " ) )
2009-11-28 20:49:44 -05:00
shutdown . set_image ( shutdownimg )
shutdown . show ( )
shutdown . connect ( " activate " , shutdown_cb )
menu . add ( shutdown )
2012-05-14 14:24:56 +01:00
reset = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Force Reset " ) )
2013-03-16 17:59:32 -04:00
reset . set_image ( resetimg )
reset . show ( )
reset . connect ( " activate " , reset_cb )
menu . add ( reset )
2012-05-14 14:24:56 +01:00
destroy = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " _Force Off " ) )
2009-11-28 20:49:44 -05:00
destroy . set_image ( destroyimg )
destroy . show ( )
destroy . connect ( " activate " , destroy_cb )
menu . add ( destroy )
2009-12-01 12:23:19 -05:00
2012-05-14 14:24:56 +01:00
sep = Gtk . SeparatorMenuItem ( )
2010-05-12 11:42:59 -04:00
sep . show ( )
menu . add ( sep )
2012-05-14 14:24:56 +01:00
save = Gtk . ImageMenuItem . new_with_mnemonic ( _ ( " Sa_ve " ) )
2010-05-12 11:42:59 -04:00
save . set_image ( saveimg )
save . show ( )
save . connect ( " activate " , save_cb )
menu . add ( save )
2009-12-01 12:23:19 -05:00
#####################################
# Path permissions checker for qemu #
#####################################
2010-12-09 14:06:00 -05:00
def check_path_search_for_qemu ( parent , conn , path ) :
2009-12-01 12:23:19 -05:00
set_error_parent ( parent )
if conn . is_remote ( ) or not conn . is_qemu_system ( ) :
return
2011-04-18 13:19:39 -04:00
user = util . running_config . default_qemu_user
2009-12-01 12:23:19 -05:00
2011-04-18 13:19:39 -04:00
skip_paths = util . running_config . get_perms_fix_ignore ( )
2009-12-01 12:23:19 -05:00
broken_paths = VirtualDisk . check_path_search_for_user ( conn . vmm , path , user )
for p in broken_paths :
if p in skip_paths :
broken_paths . remove ( p )
if not broken_paths :
return
2012-01-16 22:04:40 -05:00
logging . debug ( " No search access for dirs: %s " , broken_paths )
2009-12-01 12:23:19 -05:00
resp , chkres = err_dial . warn_chkbox (
_ ( " The emulator may not have search permissions "
" for the path ' %s ' . " ) % path ,
_ ( " Do you want to correct this now? " ) ,
2010-02-28 20:49:16 -05:00
_ ( " Don ' t ask about these directories again. " ) ,
2012-05-14 14:24:56 +01:00
buttons = Gtk . ButtonsType . YES_NO )
2009-12-01 12:23:19 -05:00
if chkres :
2011-04-18 13:19:39 -04:00
util . running_config . add_perms_fix_ignore ( broken_paths )
2009-12-01 12:23:19 -05:00
if not resp :
return
logging . debug ( " Attempting to correct permission issues. " )
errors = VirtualDisk . fix_path_search_for_user ( conn . vmm , path , user )
if not errors :
return
errmsg = _ ( " Errors were encountered changing permissions for the "
" following directories: " )
details = " "
for path , error in errors . items ( ) :
if path not in broken_paths :
continue
details + = " %s : %s \n " % ( path , error )
2012-01-16 22:04:40 -05:00
logging . debug ( " Permission errors: \n %s " , details )
2009-12-01 12:23:19 -05:00
ignore , chkres = err_dial . err_chkbox ( errmsg , details ,
_ ( " Don ' t ask about these directories again. " ) )
if chkres :
2011-04-18 13:19:39 -04:00
util . running_config . add_perms_fix_ignore ( errors . keys ( ) )
2009-12-01 12:23:19 -05:00
2010-02-08 17:13:36 -05:00
######################################
# Interface startmode widget builder #
######################################
def build_startmode_combo ( start_list ) :
2012-05-14 14:24:56 +01:00
start_model = Gtk . ListStore ( str )
2010-02-08 17:13:36 -05:00
start_list . set_model ( start_model )
2012-05-14 14:24:56 +01:00
text = Gtk . CellRendererText ( )
2010-02-08 17:13:36 -05:00
start_list . pack_start ( text , True )
start_list . add_attribute ( text , ' text ' , 0 )
start_model . append ( [ " none " ] )
start_model . append ( [ " onboot " ] )
start_model . append ( [ " hotplug " ] )
2011-05-18 18:54:27 -04:00
#########################
# Console keycombo menu #
#########################
def build_keycombo_menu ( cb ) :
2012-05-14 14:24:56 +01:00
menu = Gtk . Menu ( )
2011-05-18 18:54:27 -04:00
def make_item ( name , combo ) :
2012-05-14 14:24:56 +01:00
item = Gtk . MenuItem . new_with_mnemonic ( name )
2011-05-18 18:54:27 -04:00
item . connect ( " activate " , cb , combo )
menu . add ( item )
make_item ( " Ctrl+Alt+_Backspace " , [ " Control_L " , " Alt_L " , " BackSpace " ] )
make_item ( " Ctrl+Alt+_Delete " , [ " Control_L " , " Alt_L " , " Delete " ] )
2012-05-14 14:24:56 +01:00
menu . add ( Gtk . SeparatorMenuItem ( ) )
2011-05-18 18:54:27 -04:00
for i in range ( 1 , 13 ) :
make_item ( " Ctrl+Alt+F_ %d " % i , [ " Control_L " , " Alt_L " , " F %d " % i ] )
2012-05-14 14:24:56 +01:00
menu . add ( Gtk . SeparatorMenuItem ( ) )
2011-05-18 18:54:27 -04:00
make_item ( " _Printscreen " , [ " Print " ] )
menu . show_all ( )
return menu