Design Document Actions

From Openbox

(Difference between revisions)
Jump to: navigation, search
(New page: singleword = action key:value = set option for last seen action { } = for placing an action (or list of) in an action " " = is a string, not an action can use \" \{ and \} inside any strin...)
 
Line 1: Line 1:
singleword = action
+
* singleword = action
key:value = set option for last seen action
+
* key:value = set option for last seen action
{ } = for placing an action (or list of) in an action
+
* { } = for placing an action (or list of) in an action
" " = is a string, not an action
+
* " " = is a string, not an action
can use \" \{ and \} inside any string
+
* can use \" \{ and \} inside any string
[ ] = setting target(s) for an action, tries them left to right until it finds one that matches
+
== Filters ==
      at least 1 window.
+
* [ ] = setting target(s) for an action, tries them left to right until it finds one that matches at least 1 window. separate target options by ",".  all options inside one set of [] must apply to choose a window.
      separate target options by ",".  all options inside one set of [] must apply to choose a
+
**      some targets are:
      window.
+
***        target - is the focused window, or the window targetted by an interractive action
      some targets are:
+
***        focus - is the focused window (ignores the fact you're targetting something else in alt-tab for instance
        @target - the focused window, or window targetted by an interractive action
+
***        title="foo" - pattern match foo against all titles
        @focus - focused window (ignores the fact you're targetting something else in alt-tab
+
***        type="foo" - pattern match foo against all types
                for instance
+
***        (basically anything we test in the app-specific rules..)
        title="foo" - pattern match foo against all titles
+
***        desktop=1 - match against the window's current desktop (a number or "all")
        type="foo" - pattern match foo against all types
+
***        ifviewing=3 - match against current desktop (filters all or none)
        (basically anything we test in the app-specific rules..)
+
***        visible - a flag that the window is on the currently visible desktop
        desktop=1 - match against the window's current desktop (a number or "all")
+
***        not<test> - inverts the other test  (maybe not <test>)
        ifviewing=3 - match against current desktop (filters all or none)
+
        visible - a flag that the window is on the currently visible desktop
+
        not<test> - inverts the other test  (maybe not <test>)
+
  
 
for bind action, chroot means when a breakchroot is hit, any bindings inside are removed
 
for bind action, chroot means when a breakchroot is hit, any bindings inside are removed
  
bind key:C-A-a chroot:yes actions:{ bind key:Escape actions:breakchroot
+
bind key:C-A-a chroot:yes actions:{ bind key:Escape actions:breakchroot
                                    bind key:Left actions:{moverelative x:-5}
+
                                    bind key:Left actions:{moverelative x:-5}
                                    bind key:Right actions:{moverelative x:5}
+
                                    bind key:Right actions:{moverelative x:5}
                                    bind key:Up actions:{moverelative y:-5}
+
                                    bind key:Up actions:{moverelative y:-5}
                                    bind key:Down actions:{moverelative y:5}
+
                                    bind key:Down actions:{moverelative y:5}
                                  }
+
                                  }
  
bind -key=A-Tab -actions={nextwindow -finalactions={focus unshade raise -app=yes}}
+
Possible -unixcommand syntax
 +
bind -key=A-Tab -actions={nextwindow -finalactions={focus unshade raise -app=yes}}
  
 +
Examples..
 +
bind key:W-a actions:togglemaximizefull
 +
bind key:A-Escape actions:{lower app:yes focustobottom unfocus}
 +
bind key:A-Tab actions:{nextwindow finalactions:{focus unshade raise app:yes}}
 +
bind key:A-S-Tab actions:{previouswindow finalactions:{focus unshade raise app:yes}}
 +
bind key:W-Tab actions:{showmenu menu:client-list-combined-menu}
 +
bind key:W-F10 actions:{execute command:"gnome-screensaver-command -l"}
 +
bind key:W-F11 actions:reconfigure
 +
bind key:W-F12 actions:restart
 +
bind key:C-A-Left actions:{desktopleft dialog:no wrap:no}
 +
bind key:C-A-Up actions:{desktopup dialog:no wrap:no}
 +
bind key:S-A-Up actions:{sendtodesktopup dialog:no wrap:no follow:yes}
 +
bind key:A-F4 actions:{close}
 +
bind key:A-F4 actions:{close [target]}  # target = default
 +
bind key:A-S-F4 actions:{close [title="*Google Chrome", desktop=2]}  # chrome windows on desktop 2
 +
bind key:A-S-F4 actions:{close [desktop=1] [desktop=2]}  # all windows on desktop 1. if none match, then all windows on desktop 2
 +
bind key:Print actions:{execute command:"gnome-screenshot"}
 +
bind key:W-d actions:{toggleshowdesktop}
 +
bind key:W-S-Right actions:{directionalcyclewindows direction:right}
 +
bind key:W-S-Left  actions:{directionalcyclewindows direction:left}
 +
bind key:W-S-Up    actions:{directionalcyclewindows direction:up}
 +
bind key:W-S-Down  actions:{directionalcyclewindows direction:down}
  
bind key:W-a actions:togglemaximizefull
+
reconfigure  # an action with no options
bind key:A-Escape actions:{lower app:yes focustobottom unfocus}
+
restart command:"metacitylol"  # an action with one option
bind key:A-Tab actions:{nextwindow finalactions:{focus unshade raise app:yes}}
+
nextwindow finalactions:{focus unshade raise app:yes} # nested actions
bind key:A-S-Tab actions:{previouswindow finalactions:{focus unshade raise app:yes}}
+
# execute action outside of a bind action
bind key:W-Tab actions:{showmenu menu:client-list-combined-menu}
+
  execute startupnotify:true startupname:Konqueror command:"kfmclient openProfile filemanagement# multiple options
bind key:W-F10 actions:{execute command:"gnome-screensaver-command -l"}
+
bind key:W-F11 actions:reconfigure
+
bind key:W-F12 actions:restart
+
bind key:C-A-Left actions:{desktopleft dialog:no wrap:no}
+
bind key:C-A-Up actions:{desktopup dialog:no wrap:no}
+
bind key:S-A-Up actions:{sendtodesktopup dialog:no wrap:no follow:yes}
+
bind key:A-F4 actions:{close}
+
bind key:A-F4 actions:{close [target]}  # target = default
+
bind key:A-S-F4 actions:{close [title="*Google Chrome", desktop=2]} # chrome windows on desktop 2
+
bind key:A-S-F4 actions:{close [desktop=1] [desktop=2]}  # all windows on desktop 1. if none match, then all windows on desktop 2
+
bind key:Print actions:{execute command:"gnome-screenshot"}
+
bind key:W-d actions:{toggleshowdesktop}
+
bind key:W-S-Right actions:{directionalcyclewindows direction:right}
+
bind key:W-S-Left actions:{directionalcyclewindows direction:left}
+
bind key:W-S-Up    actions:{directionalcyclewindows direction:up}
+
bind key:W-S-Down  actions:{directionalcyclewindows direction:down}
+
  
reconfigure # an action with no options
+
  close [target]  # target = default
restart command:"metacitylol"  # an action with one option
+
close [title="*Google Chrome", desktop=2] # chrome windows on desktop 2
nextwindow finalactions:{focus unshade raise app:yes} # nested actions
+
  close [desktop=1] [desktop=2] # all windows on desktop 1. if none match, then all windows on desktop 2
# execute action outside of a bind action
+
execute startupnotify:true startupname:Konqueror command:"kfmclient openProfile filemanagement" # multiple options
+
  
close [target]  # target = default
+
togglemaximizefull
close [title="*Google Chrome", desktop=2] # chrome windows on desktop 2
+
moverelative x:-5
close [desktop=1] [desktop=2] # all windows on desktop 1. if none match, then all windows on desktop 2
+
moverelative y:-5
 +
  moverelative y:-5
 +
  moverelative y:-5
  
 +
Have alias action to build composite actions (macros)
 +
alias name:_foo actions:{foo bar baz}
  
 +
if [title="* GIMP", desktop=8, viewing=8] actions:{foo bar}
  
togglemaximizefull
+
alias name:_myif actions:
moverelative x:-5
+
  [viewing=8, desktop=8] {
moverelative y:-5
+
    [title="* GIMP"] {
moverelative y:-5
+
      moveresizeto x:69 y:0 width:1373 height:1005
moverelative y:-5
+
      sendkeyevent usetarget:no key:C-j
 +
    }
 +
    [locked=no, notitle="* GIMP" title="Toolbox - *"]
 +
      lock
 +
  }
  
alias name:_foo actions:{foo bar baz}
+
Attempt at an Else:
 +
[viewing=8, desktop=8] {
 +
  [title="* GIMP"] nextwindow
 +
}
 +
| [visible] nextwindow
  
 +
alias name:_myif actions:{
 +
  moveresizeto [viewing=8, desktop=8, title="* GIMP"] x:69 y:0 width:1373 height:1005
 +
  sendkeyevent [viewing=8, desktop=8, title="* GIMP"] usetarget:no key:C-j
 +
  lock        [locked=no notitle="* GIMP" title="Toolbox - *"]}
 +
}
  
 +
Attempt to group filters on actions by use of a chain action:
 +
chain [viewing=8,desktop=8] a:{chain [title="* GIMP"] a:{moveresizeto x:69 y:0 width:1373 height:1005 sendkeyevent usetarget:no key:C-j} | lock [locked=no, title="Toolbox - *]}
  
if [title="* GIMP", desktop=8, viewing=8] actions:{foo bar}
+
[target] {moveresizeto a:foo} | stuff
 +
[desktop=2] movetodesktop desktop:4 | [desktop=1] {stuff otherstuff}
 +
[foo] bar | baz
  
alias name:_myif actions:
+
Do filters stack as parsing continues on a line?  We decided no.
  [viewing=8, desktop=8] {
+
[foo] bar | [lal] bar | baz => [foo | lal] bar | baz
    [title="* GIMP"] {
+
      moveresizeto x:69 y:0 width:1373 height:1005
+
      sendkeyevent usetarget:no key:C-j
+
    }
+
    [locked=no, notitle="* GIMP" title="Toolbox - *"]
+
      lock
+
  }
+
  
[viewing=8, desktop=8] {
+
What about OR in filters?
  [title="* GIMP"] nextwindow
+
[a,b | c,d] foo | bar
}
+
[a, (b|c), d] foo | bar
| [visible] nextwindow
+
  
alias name:_myif actions:{
+
= PROPOSED ACTION LANGUAGE =
  moveresizeto [viewing=8, desktop=8, title="* GIMP"] x:69 y:0 width:1373 height:1005
+
  sendkeyevent [viewing=8, desktop=8, title="* GIMP"] usetarget:no key:C-j
+
  lock        [locked=no notitle="* GIMP" title="Toolbox - *"]}
+
}
+
  
chain [viewing=8,desktop=8] a:{chain [title="* GIMP"] a:{moveresizeto x:69 y:0 width:1373 height:1005 sendkeyevent usetarget:no key:C-j} | lock [locked=no, title="Toolbox - *]}
+
In BNF like thing:
 +
TEST      := KEY=VALUE | KEY  # eg. locked or desktop=1. See [[#Filters|Filters]].
 +
ACTION    := [FILTER] ACTION | ACTIONNAME ACTIONOPTS ELSE | {ACTIONLIST}
 +
ACTIONLIST := ACTION ACTIONLIST | ACTION
 +
ELSE      := nil | \| ACTION
 +
FILTER    := FILTERORS
 +
FILTERORS  := FILTERANDS \| FILTERORS | FILTERANDS
 +
FILTERANDS := TEST, FILTERANDS | TEST
 +
ACTIONOPTS := ACTIONOPT ACTIONOPTS | ACTIONOPT
 +
ACTIONOPT  := ATTRIBUTE:TEXTWORD | ATTRIBUTE:TEXTSTRING | ATTRIBUTE:{ACTIONLIST}
 +
TEXTWORD  := strings not starting with " or ( or {
 +
TEXTSTRING := "TEXT" | (TEXT) where TEXT is a string, where ')' or '"' (depending how it is quoted) must be escaped by an '\'. \\ \( \) and \" are all valid escaped characters.
  
 +
In English like thing:
 +
an ACTIONSPOT can hold an ACTION, an ACTIONLIST, or a FILTER. it may be followed by a | ELSE, where ELSE is an ACTIONSPOT which is only run if the prior action spot's filter returned an empty list of windows.
 +
an ACTIONLIST is a list of 1 or more space-separated ACTIONSPOTS inside {}.
 +
a FILTER is a [] with tests (eg foo=bar) inside delimited by , for AND and | for OR. AND has higher precedence.
 +
an ACTION is a name (no spaces) and a space-separated list of key:value pairs to assign to the ACTION.  the value is a WORD, a STRING or an ACTIONLIST.
 +
a WORD is a string of text with no space and does not start with a '(' '"' or '{' character.
 +
a STRING is a string of text quoted with "" or ().  the ending quoting character and '\' must be escaped inside the STRING, and \( \) \" or \\ are all valid escaped characters.
 +
  Unrecognized escape sequences are simply dropped from the string with a warning to the user.
  
 +
Example using bind to also be an action:
 +
bind key:M-r actions:{[la] foo | {bar etc:(yay)}
 +
                      morethings
 +
                      }
  
 +
Bind actions should not persist though! Need to be recreated at startup, tho they can be injected at runtime.
  
 +
note: OR precedence can be achived by splitting into nested filters:
 +
  [a,b] [c|d] foo  => if a&b&(c|d) then foo
  
moveresiveto a:foo b:56
+
Examples:
 +
execute startupnotify:true startupname:Konqueror command:(kfmclient openProfile filemanagement)
 +
execute startupnotify:true startupname:Konqueror command:"kfmclient openProfile filemanagement"
  
 +
[ifviewing=8, desktop=8] {
 +
  [title="* GIMP"] {moveresize sendkey}
 +
  [title="Toolbox - *", nottitle="* GIMP", locked=no] lock
 +
}
  
[target] {moveresizeto a:foo} | stuff
+
== Functionality ==
[desktop=2] movetodesktop desktop:4 | [desktop=1] {stuff otherstuff}
+
[foo] bar | baz
+
 
+
[foo] bar | [lal] bar | baz => [foo | lal] bar | baz
+
 
+
[a,b | c,d] foo | bar
+
[a, (b|c), d] foo | bar
+
 
+
===============================================================================================
+
ACTION LANGUAGE
+
 
+
TEST      := KEY=VALUE | KEY  # eg. locked=no
+
ACTION    := [FILTER] ACTION | ACTIONNAME ACTIONOPTS ELSE | {ACTIONLIST}
+
ACTIONLIST := ACTION ACTIONLIST | ACTION
+
ELSE      := nil | \| ACTION
+
FILTER    := FILTERORS
+
FILTERORS  := FILTERANDS \| FILTERORS | FILTERANDS
+
FILTERANDS := TEST, FILTERANDS | TEST
+
ACTIONOPTS := ACTIONOPT ACTIONOPTS | ACTIONOPT
+
ACTIONOPT  := ATTRIBUTE:TEXTWORD | ATTRIBUTE:TEXTSTRING | ATTRIBUTE:{ACTIONLIST}
+
TEXTWORD  := strings not starting with " or ( or {
+
TEXTSTRING := "TEXT" | (TEXT) where TEXT is a string, where ')' or '"' (depending how it is quoted) must be escaped by an '\'. \\ \( \) and \" are all valid escaped characters.
+
 
+
 
+
an ACTIONSPOT can hold an ACTION, an ACTIONLIST, or a FILTER. it may be followed by a | ELSE,
+
  where ELSE is an ACTIONSPOT which is only run if the prior action spot's filter returned an
+
  empty list of windows.
+
an ACTIONLIST is a list of 1 or more space-separated ACTIONSPOTS inside {}.
+
a FILTER is a [] with tests (eg foo=bar) inside delimited by , for AND and | for OR. AND has higher precedence.
+
an ACTION is a name (no spaces) and a space-separated list of key:value pairs to assign to the ACTION.  the value is a WORD, a STRING or an ACTIONLIST.
+
a WORD is a string of text with no space and does not start with a '(' '"' or '{' character.
+
a STRING is a string of text quoted with "" or ().  the ending quoting character and '\' must be
+
  escaped inside the STRING, and \( \) \" or \\ are all valid escaped characters.
+
  Unrecognized escape sequences are simply dropped from the string with a warning to the user.
+
 
+
bind key:M-r actions:{[la] foo | {bar etc:(yay)}
+
                      morethings
+
                    }
+
 
+
note, or precedence can be achived by splitting into nested filters:
+
  [a,b] [c|d] foo  => if a&b&(c|d) then foo
+
 
+
execute startupnotify:true startupname:Konqueror command:(kfmclient openProfile filemanagement)
+
  
[ifviewing=8, desktop=8] {
+
[[#Filters|Filters]] are used to create a list of windows.  The default filter is ''[target]'' meaning only the targetted window is matched.  Each action is run and passed a list of windows matched by the filters applied to it.
  [title="* GIMP"] {moveresize sendkey}
+
  [title="Toolbox - *", nottitle="* GIMP", locked=no] lock
+
}
+

Revision as of 19:06, 28 January 2011

  • singleword = action
  • key:value = set option for last seen action
  • { } = for placing an action (or list of) in an action
  • " " = is a string, not an action
  • can use \" \{ and \} inside any string

Filters

  • [ ] = setting target(s) for an action, tries them left to right until it finds one that matches at least 1 window. separate target options by ",". all options inside one set of [] must apply to choose a window.
    • some targets are:
      • target - is the focused window, or the window targetted by an interractive action
      • focus - is the focused window (ignores the fact you're targetting something else in alt-tab for instance
      • title="foo" - pattern match foo against all titles
      • type="foo" - pattern match foo against all types
      • (basically anything we test in the app-specific rules..)
      • desktop=1 - match against the window's current desktop (a number or "all")
      • ifviewing=3 - match against current desktop (filters all or none)
      • visible - a flag that the window is on the currently visible desktop
      • not<test> - inverts the other test (maybe not <test>)

for bind action, chroot means when a breakchroot is hit, any bindings inside are removed

bind key:C-A-a chroot:yes actions:{ bind key:Escape actions:breakchroot
                                    bind key:Left actions:{moverelative x:-5}
                                    bind key:Right actions:{moverelative x:5}
                                    bind key:Up actions:{moverelative y:-5}
                                    bind key:Down actions:{moverelative y:5}
                                  }

Possible -unixcommand syntax

bind -key=A-Tab -actions={nextwindow -finalactions={focus unshade raise -app=yes}}

Examples..

bind key:W-a actions:togglemaximizefull
bind key:A-Escape actions:{lower app:yes focustobottom unfocus}
bind key:A-Tab actions:{nextwindow finalactions:{focus unshade raise app:yes}}
bind key:A-S-Tab actions:{previouswindow finalactions:{focus unshade raise app:yes}}
bind key:W-Tab actions:{showmenu menu:client-list-combined-menu}
bind key:W-F10 actions:{execute command:"gnome-screensaver-command -l"}
bind key:W-F11 actions:reconfigure
bind key:W-F12 actions:restart
bind key:C-A-Left actions:{desktopleft dialog:no wrap:no}
bind key:C-A-Up actions:{desktopup dialog:no wrap:no}
bind key:S-A-Up actions:{sendtodesktopup dialog:no wrap:no follow:yes}
bind key:A-F4 actions:{close}
bind key:A-F4 actions:{close [target]}   # target = default
bind key:A-S-F4 actions:{close [title="*Google Chrome", desktop=2]}  # chrome windows on desktop 2
bind key:A-S-F4 actions:{close [desktop=1] [desktop=2]}  # all windows on desktop 1. if none match, then all windows on desktop 2
bind key:Print actions:{execute command:"gnome-screenshot"}
bind key:W-d actions:{toggleshowdesktop}
bind key:W-S-Right actions:{directionalcyclewindows direction:right}
bind key:W-S-Left  actions:{directionalcyclewindows direction:left}
bind key:W-S-Up    actions:{directionalcyclewindows direction:up}
bind key:W-S-Down  actions:{directionalcyclewindows direction:down}
reconfigure  # an action with no options
restart command:"metacitylol"  # an action with one option
nextwindow finalactions:{focus unshade raise app:yes}  # nested actions
# execute action outside of a bind action
execute startupnotify:true startupname:Konqueror command:"kfmclient openProfile filemanagement"  # multiple options
close [target]   # target = default
close [title="*Google Chrome", desktop=2]  # chrome windows on desktop 2
close [desktop=1] [desktop=2]  # all windows on desktop 1. if none match, then all windows on desktop 2
togglemaximizefull
moverelative x:-5
moverelative y:-5
moverelative y:-5
moverelative y:-5

Have alias action to build composite actions (macros)

alias name:_foo actions:{foo bar baz}
if [title="* GIMP", desktop=8, viewing=8] actions:{foo bar}
alias name:_myif actions:
  [viewing=8, desktop=8] {
    [title="* GIMP"] {
      moveresizeto x:69 y:0 width:1373 height:1005
      sendkeyevent usetarget:no key:C-j
    }
    [locked=no, notitle="* GIMP" title="Toolbox - *"]
      lock
  }

Attempt at an Else:

[viewing=8, desktop=8] {
  [title="* GIMP"] nextwindow
}
| [visible] nextwindow
alias name:_myif actions:{
  moveresizeto [viewing=8, desktop=8, title="* GIMP"] x:69 y:0 width:1373 height:1005
  sendkeyevent [viewing=8, desktop=8, title="* GIMP"] usetarget:no key:C-j
  lock         [locked=no notitle="* GIMP" title="Toolbox - *"]}
}

Attempt to group filters on actions by use of a chain action:

chain [viewing=8,desktop=8] a:{chain [title="* GIMP"] a:{moveresizeto x:69 y:0 width:1373 height:1005 sendkeyevent usetarget:no key:C-j} | lock [locked=no, title="Toolbox - *]}
[target] {moveresizeto a:foo} | stuff
[desktop=2] movetodesktop desktop:4 | [desktop=1] {stuff otherstuff}
[foo] bar | baz

Do filters stack as parsing continues on a line? We decided no.

[foo] bar | [lal] bar | baz => [foo | lal] bar | baz

What about OR in filters?

[a,b | c,d] foo | bar
[a, (b|c), d] foo | bar

PROPOSED ACTION LANGUAGE

In BNF like thing:

TEST       := KEY=VALUE | KEY   # eg. locked or desktop=1. See Filters.
ACTION     := [FILTER] ACTION | ACTIONNAME ACTIONOPTS ELSE | {ACTIONLIST}
ACTIONLIST := ACTION ACTIONLIST | ACTION
ELSE       := nil | \| ACTION
FILTER     := FILTERORS
FILTERORS  := FILTERANDS \| FILTERORS | FILTERANDS
FILTERANDS := TEST, FILTERANDS | TEST
ACTIONOPTS := ACTIONOPT ACTIONOPTS | ACTIONOPT
ACTIONOPT  := ATTRIBUTE:TEXTWORD | ATTRIBUTE:TEXTSTRING | ATTRIBUTE:{ACTIONLIST}
TEXTWORD   := strings not starting with " or ( or {
TEXTSTRING := "TEXT" | (TEXT) where TEXT is a string, where ')' or '"' (depending how it is quoted) must be escaped by an '\'. \\ \( \) and \" are all valid escaped characters.

In English like thing:

an ACTIONSPOT can hold an ACTION, an ACTIONLIST, or a FILTER. it may be followed by a | ELSE, where ELSE is an ACTIONSPOT which is only run if the prior action spot's filter returned an empty list of windows.
an ACTIONLIST is a list of 1 or more space-separated ACTIONSPOTS inside {}.
a FILTER is a [] with tests (eg foo=bar) inside delimited by , for AND and | for OR. AND has higher precedence.
an ACTION is a name (no spaces) and a space-separated list of key:value pairs to assign to the ACTION.  the value is a WORD, a STRING or an ACTIONLIST.
a WORD is a string of text with no space and does not start with a '(' '"' or '{' character.
a STRING is a string of text quoted with "" or ().  the ending quoting character and '\' must be escaped inside the STRING, and \( \) \" or \\ are all valid escaped characters.
 Unrecognized escape sequences are simply dropped from the string with a warning to the user.

Example using bind to also be an action:

bind key:M-r actions:{[la] foo | {bar etc:(yay)}
                      morethings
                     }

Bind actions should not persist though! Need to be recreated at startup, tho they can be injected at runtime.

note: OR precedence can be achived by splitting into nested filters:

 [a,b] [c|d] foo   => if a&b&(c|d) then foo

Examples:

execute startupnotify:true startupname:Konqueror command:(kfmclient openProfile filemanagement)
execute startupnotify:true startupname:Konqueror command:"kfmclient openProfile filemanagement"
[ifviewing=8, desktop=8] {
  [title="* GIMP"] {moveresize sendkey}
  [title="Toolbox - *", nottitle="* GIMP", locked=no] lock
}

Functionality

Filters are used to create a list of windows. The default filter is [target] meaning only the targetted window is matched. Each action is run and passed a list of windows matched by the filters applied to it.

Personal tools