Expose XWarpPointer to lua as rootwin:warp_pointer, for region_do_warp_alt
[notion.git] / contrib / scripts / xkbion.lua
blob4e5aae493af195dc47ffafbd77867d172746ac6e
1 -- Authors: Sergey Redin <sergey@redin.info>
2 -- License: Public domain
3 -- Last Changed: Unknown
4 --
5 -- xkbion.lua
6 -- TODO: make xkbion_set understand some simple presets
8 -- Author: Sergey Redin <sergey at redin.info>
9 -- This software is in the public domain.
11 -- Thanks:
12 -- smersh at users.sf.net (author of xkbind) for the original idea
14 --[[
16 -- This script allows you to use independent keyboard layouts for different windows in Ion3.
17 -- It uses a window property to store the XKB groups, so you can restart Ion without losing
18 -- settings for each window.
20 -- Example usage. This is what I have in my cfg_ion.lua:
22 dopath("mod_xkb")
23 dopath("xkbion.lua")
24 xkbion_set {
25 {name="EN", hint="", action = function() mod_xkb.lock_group(0) end},
26 {name="RU", hint="important", action = function() mod_xkb.lock_group(1) end},
27 key="Caps_Lock",
28 statusname = "xkbion",
30 xkbion_set {
31 {name="num", command="numlockx on"},
32 {name="<->", command="numlockx off"},
33 key="Num_Lock",
34 statusname="num",
35 atomname="XKBION_NUM",
37 xkbion_set {
38 {name="----", hint="", action = function() mod_xkb.lock_modifiers(2, 0) end},
39 {name="CAPS", hint="critical", action = function() mod_xkb.lock_modifiers(2, 2) end},
40 key="Caps_Lock",
41 statusname = "caps",
42 atomname="XKBION_CAPS",
45 -- Edit this to suit your needs.
46 -- Please note, if you want to use Caps_Lock key to change the keyboard groups like I do,
47 -- do not forget to add "grp:caps_toggle" to your XKB settings, just to prevent X from using
48 -- this key also for swiching keyboard registers.
50 -- At least one group definition must be present.
51 -- "name" is only neseccary if you want to use mod_statusbar to indicate current XKB group.
52 -- "hint" is only necessary if you want to highlight your XKB group in statusbar, possible
53 -- values are standard values provided by the mod_statusbar: important, normal, critical
54 -- "command" and "action" are also unneseccary but xkbion.lua is not particulary useful
55 -- without them. :) The same thing for "key".
57 -- The last thing to say about xkbion_set() parameters is that if you call xkbion_set
58 -- more than once (like I do it for XKB groups and NumLock state) you must choose different
59 -- "atomname" values. The default for atomname is XKBION_GROUP.
61 -- The second xkbion_set() call (numlock section) is here mostly for the example. Most users
62 -- will need only one call, for changing XKB group. Please also note that you can define more
63 -- than two groups in call to xkbion_set().
65 -- You can use this line in cfg_statusbar.lua to indicate the current XKB group:
67 template="... %xkbion ...",
69 -- If your Ion does not have mod_xkb, you may try the following:
71 xkbion_set {
72 {name="EN", command="setxkbmap us -option grp:caps_toggle"},
73 {name="RU", command="setxkbmap ru winkeys -option grp:caps_toggle"},
74 key="Caps_Lock",
75 statusname = "xkbion",
80 function xkbion_set (groups) -- the only global created by xkbion.lua
82 if not groups or type(groups) ~= "table" then error("bad args") end
83 if not groups[1] or type(groups[1]) ~= "table" then
84 error("default group is undefined")
85 end
87 -- window_group_prop(w) - get XKBION_GROUP integer property of window `w' (set it to 1 if it's not yet defined)
88 -- window_group_prop(w, group) - set XKBION_GROUP property of window `w' to integer `group'
89 -- "XKBION_GROUP" is just the default name
90 local window_group_prop
92 local XA_INTEGER = 19
93 local atom = ioncore.x_intern_atom( tostring( groups.atomname or "XKBION_GROUP" ) )
94 if not atom or type(atom) ~= "number" then
95 error("Cannot intern atom " .. atomname)
96 end
97 window_group_prop = function(w, gnum)
98 if not w or type(w) ~= "userdata" or not w.xid or type(w.xid) ~= "function" then return 1 end
99 local xid = tonumber( w:xid() )
100 if gnum == nil then
101 local t = ioncore.x_get_window_property( xid, atom, XA_INTEGER, 1, true )
102 if t and type(t) == "table" and t[1] ~= nil then
103 do return tonumber(t[1]) end
104 else
105 gnum = 1
107 else
108 gnum = tonumber(gnum)
110 -- we're here if the second argument is set or if the window does not have our property yet
111 ioncore.defer( function()
112 ioncore.x_change_property( xid, atom, XA_INTEGER, 32, "replace", {gnum} )
113 end )
114 return gnum
118 local set_group
120 local current_gnum = 1
121 local first_time = true
122 local statusname = groups.statusname
123 if statusname and type(statusname) ~= "string" then statusname = nil end
124 set_group = function(w, do_increment)
125 local gnum
126 if w then
127 gnum = window_group_prop(w)
128 else
129 gnum = 1
131 if do_increment then gnum = gnum + 1 end
132 local g = groups[gnum]
133 if not g then gnum, g = 1, groups[1] end
134 if not g then return end -- error in settings, groups[1] not defined
135 if first_time then
136 first_time = false
137 elseif gnum == current_gnum then
138 return
140 window_group_prop(w, gnum) -- it's OK to call it even it `w' is nil
141 if g.command then
142 ioncore.exec(g.command)
144 if g.action then ioncore.defer(g.action) end
145 current_gnum = gnum
146 local group_name = g.name
147 local hint_name = g.hint
148 if statusname and group_name and type(group_name) == "string" then
149 mod_statusbar.inform(statusname, group_name)
150 mod_statusbar.inform(statusname.."_hint", hint_name)
151 ioncore.defer(mod_statusbar.update)
156 ioncore.get_hook("region_notify_hook"):add(
157 function(reg, action)
158 if (obj_typename(reg) == "WClientWin") and (action == "activated") then
159 set_group(reg)
164 local key = groups.key
165 if key and type(key) == "string" then
166 defbindings("WClientWin", {
167 kpress(key, function (_, _sub) set_group(_, true) end, "_sub:WClientWin")
171 set_group() -- initialize
173 end -- xkbion_set()