Ion3
Uno degli elementi caratterizzanti prestazione e velocità di un desktop linux è naturalmente l'interfaccia grafica.
L'incidenza è duplice: da una parte ci sono le prestazioni del software che si sta utilizzando, e dall'altra l'usabilità di questo software. Non basta infatti avere un desktop composto da pochi, leggeri, elementi per eseguire le operazioni desiderate: l'importante è che l'utilizzo sia quanto più immediato. Più il software è veloce nell'eseguire operazione, più rapidamente restituirà il controllo all'utente. Quindi, una volta ottimizzato il sistema, il collo di bottiglia si sposta verso il layer che sta tra la macchina e l'uomo.
Lo studio di un'interfaccia grafica ottimizzata per la rapidità d'uso non può quindi prescindere dal parametro della usability. Lo sanno, o almeno l'hanno tenuto in considerazione per molto tempo anche alla Microsoft: Windows è stato per anni fornito di un'efficace alternativa all'utilizzo del mouse per compiere le operazioni: gli shortcut da tastiera, praticamente onnipresenti fino a Windows 2000, e che solo ultimamente con la moda delle interfacce ricche di effetti speciali hanno visto ridursi la loro importanza ed efficacia costringendo gli utenti, in molti casi, ad usare necessariamente il mouse per operazioni anche banali, come spostarsi su un'altra directory o indicare il nome di un file. Un vero passo indietro, considerando che il tempo per muovere ripetutamente il polso dalla tastiera al mouse è tempo perso, e i movimenti stessi distraggono e rendono impreciso quello che vorrebbe essere un veloce e fluido scambio di informazioni con la macchina.
Purtroppo la maggior parte degli window manager disponibili per Linux non fanno eccezione, nonostante i più evoluti (per quanto riguarda le feature) come Gnome e KDE facciano qualche sforzo in più, per donare all'utente il controllo della propria interfaccia anche tramite l'uso della tastiera. Presto o tardi, anche se imparate tutti gli shortcut a memoria (perchè non sono immediatamente visibili) o personalizzate fino all'eccesso gli shortcut, vi ritrovete a dover spostare il puntatore sopra quel particolare pulsante, o slider, perchè irraggiungibile in altri modi, o raggiungibile in maniera farraginosa. Paradossalmente, ma neanche tanto, sono quelli più essenziali (come Window Maker) a donare più spazio operativo ai tasti. Ma anche in questo caso il problema si ripresenta ogniqualvolta si utilizzi quella tal applicazione che sì, ti fa aprire la finestra di dialogo per salvare un file, ma subito dopo, per scegliere la directory, dopo diversi tentativi falliti perchè sulla root non si può salvare nulla, ti costringe nuovamente ad acchiappare quel simpatico topino così indispensabile in certi casi quanto superfluo in altri.
Dal lato delle applicazioni, quindi, non è pensabile di poter risolvere il problema definitivamente, o perlomeno non senza rinunciare a qualche killer application a cui ci siamo ben volentieri abituati. Sul fronte del window manager, invece, qualcosa si può fare: usare Ion
Configurazione
La prima parte è semplice: si tratta di modificare il cfg_ion.lua per impostare il tasto Windows come tasto Mod4+ da utilizzare nella configurazione con la costante META
cfg_ion.lua
--
-- Ion main configuration file
--
-- This file only includes some settings that are rather frequently altered.
-- The rest of the settings are in cfg_ioncore.lua and individual modules'
-- configuration files (cfg_modulename.lua).
--
-- Set default modifiers. Alt should usually be mapped to Mod1 on
-- XFree86-based systems. The flying window keys are probably Mod3
-- or Mod4; see the output of 'xmodmap'.
--META="Mod1+"
--ALTMETA=""
-- Terminal emulator
--XTERM="xterm"
-- Debian sets the META and ALTMETA keys in /etc/default/ion3.
dopath("cfg_debian")
-- MAX forza META e ALT ad essere Windows e ALT
META="Mod4+" --Windows Key
ALT="Mod1+" --Alt Key
-- Some basic settings
ioncore.set{
-- Maximum delay between clicks in milliseconds to be considered a
-- double click.
--dblclick_delay=250,
-- For keyboard resize, time (in milliseconds) to wait after latest
-- key press before automatically leaving resize mode (and doing
-- the resize in case of non-opaque move).
--kbresize_delay=1500,
-- Opaque resize?
opaque_resize=true,
-- Movement commands warp the pointer to frames instead of just
-- changing focus. Enabled by default.
warp=true,
}
-- cfg_ioncore contains configuration of the Ion 'core'
dopath("cfg_ioncore")
-- Load some kludges to make apps behave better.
dopath("cfg_kludges")
-- Load some modules. Disable the loading of cfg_modules by commenting out
-- the corresponding line with -- if you don't want the whole default set
-- (everything except mod_dock). Then uncomment the lines for the modules
-- you want.
dopath("cfg_modules")
-- Deprecated.
dopath("cfg_user", true)
La seconda parte è più corposa: si tratta di una rivisitazione totale del file cfg_ioncore.lua, ovvero il file di configurazione dei "comportamenti" di Ion. Ovvero: tutti gli shortcut passano da qui.
cfg_ioncore.lua
defbindings("WScreen", {
bdoc("Switch to n:th object (workspace, full screen client window) "..
"within current screen."),
kpress(META.."F1", "WScreen.switch_nth(_, 0)"),
kpress(META.."F2", "WScreen.switch_nth(_, 1)"),
kpress(META.."F3", "WScreen.switch_nth(_, 2)"),
kpress(META.."F4", "WScreen.switch_nth(_, 3)"),
kpress(META.."F5", "WScreen.switch_nth(_, 4)"),
kpress(META.."F6", "WScreen.switch_nth(_, 5)"),
kpress(META.."F7", "WScreen.switch_nth(_, 6)"),
kpress(META.."F8", "WScreen.switch_nth(_, 7)"),
kpress(META.."F9", "WScreen.switch_nth(_, 8)"),
kpress(META.."F10", "WScreen.switch_nth(_, 9)"),
bdoc("Switch to next/previous object within current screen."),
kpress(ALT.."Control+Left", "WScreen.switch_prev(_)"),
kpress(ALT.."Control+Right", "WScreen.switch_next(_)"),
bdoc("Go to first region demanding attention or previously active one."),
kpress(META.."I", "ioncore.goto_activity() or ioncore.goto_previous()"),
bdoc("Clear all tags."),
kpress(META.."T", "ioncore.clear_tags()"),
bdoc("Create a new workspace of chosen default type."),
kpress(META.."Control+N", "ioncore.create_ws(_)"),
bdoc("Display the main menu."),
kpress(ALT..META.."F1", "mod_query.query_menu(_, 'mainmenu', 'Main menu: ')"),
kpress(ALT.."F1", "mod_menu.menu(_, _sub, 'mainmenu', {big=true})"),
mpress("Button3", "mod_menu.pmenu(_, _sub, 'mainmenu')"),
bdoc("Display the window list menu."),
mpress("Button2", "mod_menu.pmenu(_, _sub, 'windowlist')"),
bdoc("Forward-circulate focus."),
-- '_chld' used here stands to for an actual child window that may not
-- be managed by the screen itself, unlike '_sub', that is likely to be
-- the managing group of that window. The right/left directions are
-- used instead of next/prev, because they work better in conjunction
-- with tilings.
kpress(ALT.."Tab", "ioncore.goto_next(_chld, 'right')",
"_chld:non-nil"),
bdoc("Backward-circulate focus."),
kpress(ALT.."Shift+Tab", "ioncore.goto_next(_chld, 'left')",
"_chld:non-nil"),
})
-- Client window bindings
--
-- These bindings affect client windows directly.
defbindings("WClientWin", {
bdoc("Nudge the client window. This might help with some "..
"programs' resizing problems."),
kpress_wait(META.."L", "WClientWin.nudge(_)"),
bdoc("Kill client owning the client window."),
kpress(ALT.."Shift+F4", "WClientWin.kill(_)"),
bdoc("Save winprop for current window."),
kpress(META.."Shift+W", "autoprop(_sub, _, false)", "_sub:WClientWin"),
kpress(META..ALT.."W", "autoprop(_sub, _, true)", "_sub:WClientWin"),
})
-- Client window group bindings
defbindings("WGroupCW", {
bdoc("Toggle client window group full-screen mode"),
kpress_wait(META.."Return", "WGroup.set_fullscreen(_, 'toggle')"),
})
-- WMPlex context bindings
--
-- These bindings work in frames and on screens. The innermost of such
-- contexts/objects always gets to handle the key press. Most of these
-- bindings define actions on client windows. (Remember that client windows
-- can be put in fullscreen mode and therefore may not have a frame.)
defbindings("WMPlex", {
bdoc("Close current object."),
kpress_wait(ALT.."F4", "WRegion.rqclose_propagate(_, _sub)"),
})
-- Frames for transient windows ignore this bindmap
defbindings("WMPlex.toplevel", {
bdoc("Query for manual page to be displayed."),
kpress(ALT.."Shift+F1", "mod_query.query_man(_, ':man')"),
bdoc("Query for Lua code to execute."),
kpress(ALT..META.."F2", "mod_query.query_lua(_)"),
bdoc("Query for command line to execute."),
kpress(ALT.."F2", "mod_query.query_exec(_)"),
-- frame_client_menu.lua
bdoc("Query for command line to execute."),
kpress(ALT.."F3", "clientlist_menu(_, _sub, true)"),
bdoc("Display context menu."),
--kpress(META.."M", "mod_menu.menu(_, _sub, 'ctxmenu')"),
kpress(ALT..META.."F3", "mod_query.query_menu(_, 'ctxmenu', 'Context menu:')"),
bdoc("Run a terminal emulator."),
kpress(ALT.."F5", "ioncore.exec_on(_, XTERM or 'xterm' or 'x-terminal-emulator')"),
bdoc("Run Rox."),
kpress(ALT.."F6", "ioncore.exec_on(_, 'rox')"),
bdoc("Query for workspace to go to or create a new one."),
kpress(ALT.."F9", "mod_query.query_workspace(_)"),
bdoc("Query for a client window to go to."),
kpress(META.."Shift+G", "mod_query.query_gotoclient(_)"),
bdoc("Query for a client window to attach."),
kpress(META.."Shift+A", "mod_query.query_attachclient(_)"),
})
-- WFrame context bindings
--
-- These bindings are common to all types of frames. The rest of frame
-- bindings that differ between frame types are defined in the modules'
-- configuration files.
defbindings("WFrame", {
bdoc("Maximize the frame horizontally/vertically."),
kpress(META..ALT.."Right", "WFrame.maximize_horiz(_)"),
kpress(META..ALT.."Up", "WFrame.maximize_vert(_)"),
bdoc("Display context menu."),
mpress("Button3", "mod_menu.pmenu(_, _sub, 'ctxmenu')"),
bdoc("Begin move/resize mode."),
kpress(META.."R", "WFrame.begin_kbresize(_)"),
bdoc("Switch the frame to display the object indicated by the tab."),
mclick("Button1@tab", "WFrame.p_switch_tab(_)"),
mclick("Button2@tab", "WFrame.p_switch_tab(_)"),
bdoc("Resize the frame."),
mdrag("Button1@border", "WFrame.p_resize(_)"),
mdrag(META.."Button3", "WFrame.p_resize(_)"),
bdoc("Move the frame."),
mdrag(META.."Button1", "WFrame.p_move(_)"),
bdoc("Move objects between frames by dragging and dropping the tab."),
mdrag("Button1@tab", "WFrame.p_tabdrag(_)"),
mdrag("Button2@tab", "WFrame.p_tabdrag(_)"),
})
-- Frames for transient windows ignore this bindmap
defbindings("WFrame.toplevel", {
bdoc("Switch to next/previous object within the frame."),
kpress(ALT.."Tab", "WFrame.switch_next(_)"),
kpress(ALT.."Shift+Tab", "WFrame.switch_prev(_)"),
bdoc("Move current object within the frame left/right."),
kpress(META.."comma", "WFrame.dec_index(_, _sub)", "_sub:non-nil"),
kpress(META.."period", "WFrame.inc_index(_, _sub)", "_sub:non-nil"),
bdoc("Switch to n:th object within the frame."),
kpress(META.."1", "WFrame.switch_nth(_, 0)"),
kpress(META.."2", "WFrame.switch_nth(_, 1)"),
kpress(META.."3", "WFrame.switch_nth(_, 2)"),
kpress(META.."4", "WFrame.switch_nth(_, 3)"),
kpress(META.."5", "WFrame.switch_nth(_, 4)"),
kpress(META.."6", "WFrame.switch_nth(_, 5)"),
kpress(META.."7", "WFrame.switch_nth(_, 6)"),
kpress(META.."8", "WFrame.switch_nth(_, 7)"),
kpress(META.."9", "WFrame.switch_nth(_, 8)"),
kpress(META.."0", "WFrame.switch_nth(_, 9)"),
-- bdoc("Maximize the frame horizontally/vertically."),
-- kpress(META.."H", "WFrame.maximize_horiz(_)"),
-- kpress(META.."V", "WFrame.maximize_vert(_)"),
bdoc("Tag current object within the frame."),
kpress(META.."X", "WRegion.set_tagged(_sub, 'toggle')", "_sub:non-nil"),
bdoc("Attach tagged objects to this frame."),
kpress(META.."V", "ioncore.tagged_attach(_)"),
})
-- Bindings for floating frames.
defbindings("WFrame.floating", {
bdoc("Toggle shade mode"),
mdblclick("Button1@tab", "WFrame.set_shaded(_, 'toggle')"),
bdoc("Raise the frame."),
mpress("Button1@tab", "WRegion.rqorder(_, 'front')"),
mpress("Button1@border", "WRegion.rqorder(_, 'front')"),
mclick(META.."Button1", "WRegion.rqorder(_, 'front')"),
bdoc("Lower the frame."),
mclick(META.."Button3", "WRegion.rqorder(_, 'back')"),
bdoc("Move the frame."),
mdrag("Button1@tab", "WFrame.p_move(_)"),
})
-- WMoveresMode context bindings
--
-- These bindings are available keyboard move/resize mode. The mode
-- is activated on frames with the command begin_kbresize (bound to
-- META.."R" above by default).
defbindings("WMoveresMode", {
bdoc("Cancel the resize mode."),
kpress("AnyModifier+Escape","WMoveresMode.cancel(_)"),
bdoc("End the resize mode."),
kpress("AnyModifier+Return","WMoveresMode.finish(_)"),
bdoc("Grow in specified direction."),
kpress("Left", "WMoveresMode.resize(_, 1, 0, 0, 0)"),
kpress("Right", "WMoveresMode.resize(_, 0, 1, 0, 0)"),
kpress("Up", "WMoveresMode.resize(_, 0, 0, 1, 0)"),
kpress("Down", "WMoveresMode.resize(_, 0, 0, 0, 1)"),
kpress("F", "WMoveresMode.resize(_, 1, 0, 0, 0)"),
kpress("B", "WMoveresMode.resize(_, 0, 1, 0, 0)"),
kpress("P", "WMoveresMode.resize(_, 0, 0, 1, 0)"),
kpress("N", "WMoveresMode.resize(_, 0, 0, 0, 1)"),
bdoc("Shrink in specified direction."),
kpress("Shift+Left", "WMoveresMode.resize(_,-1, 0, 0, 0)"),
kpress("Shift+Right", "WMoveresMode.resize(_, 0,-1, 0, 0)"),
kpress("Shift+Up", "WMoveresMode.resize(_, 0, 0,-1, 0)"),
kpress("Shift+Down", "WMoveresMode.resize(_, 0, 0, 0,-1)"),
kpress("Shift+F", "WMoveresMode.resize(_,-1, 0, 0, 0)"),
kpress("Shift+B", "WMoveresMode.resize(_, 0,-1, 0, 0)"),
kpress("Shift+P", "WMoveresMode.resize(_, 0, 0,-1, 0)"),
kpress("Shift+N", "WMoveresMode.resize(_, 0, 0, 0,-1)"),
bdoc("Move in specified direction."),
kpress(META.."Left", "WMoveresMode.move(_,-1, 0)"),
kpress(META.."Right", "WMoveresMode.move(_, 1, 0)"),
kpress(META.."Up", "WMoveresMode.move(_, 0,-1)"),
kpress(META.."Down", "WMoveresMode.move(_, 0, 1)"),
kpress(META.."F", "WMoveresMode.move(_,-1, 0)"),
kpress(META.."B", "WMoveresMode.move(_, 1, 0)"),
kpress(META.."P", "WMoveresMode.move(_, 0,-1)"),
kpress(META.."N", "WMoveresMode.move(_, 0, 1)"),
})
--
-- Menu definitions
--
-- Main menu
defmenu("mainmenu", {
submenu("Programs", "appmenu"),
menuentry("Lock screen", "ioncore.exec_on(_, 'xlock')"),
menuentry("Lock screen",
"ioncore.exec_on(_, ioncore.lookup_script('ion-lock'))"),
menuentry("Help", "mod_query.query_man(_)"),
menuentry("About Ion", "mod_query.show_about_ion(_)"),
submenu("Styles", "stylemenu"),
submenu("Debian", "Debian"),
submenu("Session", "sessionmenu"),
})
-- Application menu
defmenu("appmenu", {
menuentry("Terminal", "ioncore.exec_on(_, 'x-terminal-emulator')"),
menuentry("Browser", "ioncore.exec_on(_, 'sensible-browser')"),
menuentry("Run...", "mod_query.query_exec(_)"),
})
-- Session control menu
defmenu("sessionmenu", {
menuentry("Save", "ioncore.snapshot()"),
menuentry("Restart", "ioncore.restart()"),
menuentry("Restart TWM", "ioncore.restart_other('twm')"),
menuentry("Exit", "ioncore.shutdown()"),
})
-- Context menu (frame/client window actions)
defctxmenu("WFrame", "Frame", {
menuentry("Close", "WRegion.rqclose_propagate(_, _sub)"),
menuentry("Kill", "WClientWin.kill(_sub)",
"_sub:WClientWin"),
menuentry("Toggle tag", "WRegion.set_tagged(_sub, 'toggle')",
"_sub:non-nil"),
menuentry("Attach tagged", "WFrame.attach_tagged(_)"),
menuentry("Clear tags", "ioncore.clear_tags()"),
menuentry("Window info", "mod_query.show_tree(_, _sub)"),
})
-- Context menu for screens
defctxmenu("WScreen", "Screen", {
menuentry("New workspace", "ioncore.create_ws(_)"),
menuentry("New empty workspace",
"ioncore.create_ws(_, nil, true)"),
menuentry("Close workspace","WRegion.rqclose(_sub)"),
})
-- Auto-generated Debian menu definitions
if os.execute("test -x /usr/bin/update-menus") == 0 then
if ioncore.is_i18n() then
dopath("debian-menu-i18n")
else
dopath("debian-menu")
end
end
Keyboard Shortcut
WIN+Fx: go to desktop x
WIN+x: go to tab x inside a frame
CTRL-ALT+left: go to previous desktop
CTRL-ALT+right: go to next deskto
WIN+s: split horizontally
WIN+ALT+s: split vertically
WIN+X: tag focused window
WIN+V: paste tagged windows into selected frame
WIN+Enter: full screen
ALT+F1: menu
ALT+Shift+F1: dmenu
ALT+F2: run
ALT+Shift+F2: run ion kludges
ALT+F3: run lua
ALT+F4: close
ALT+F5: run terminal
ALT+F6: run rox
+ altre che ora non ricordo...
allego il file contenente l'intera cartella .ion3, con tutti i plugin inclusi per il corretto funzionamento degli shortcut