948 Commits

Author SHA1 Message Date
op
9eb763ab87 cwm: fix a semi-transparency border issue with some applications
When running with a compositor the border of some applications (firefox,
chromium, zathura...) is not rendered correctly.  Initializing the highest
significant bits of the color fixes it.

diff from Julien Blanchard (julien at typed-hole [dot] org); ok okan@
2023-03-22 08:27:36 +00:00
4a6128d5e4 Fix overlapping menu items as reported by kn@ and probably others at
some point; with op@ and Walter Alejandro Iglesias helping along the
way.  Consistently use font ascent+descent instead of an arbitrary font
height+1 for individual menu item rectangles and placement.

ok kn@ op@
2022-10-15 16:06:07 +00:00
4e73ce533c cycling fix: when no client is active, warp pointer to last active;
from Walter Alejandro Iglesias.
2022-02-27 14:59:55 +00:00
496bcc879d whitespace 2022-02-26 15:19:18 +00:00
5e5221d82d Fix spelling of some unused MWM hints; from Sean C. Farley.
While here, flesh out the rest of the MWM hints.
2022-02-26 15:03:42 +00:00
op
7c22b36a23 Add group-last command that shows only the previously active group; ok okan 2022-01-27 18:45:10 +00:00
81a08ddb89 Allow bare numbers for key and mouse bindings; taken from similar
support in other parse.y's; from Leon Fischer <lfischer@airmail.cc>.
2021-12-24 16:00:47 +00:00
a9eeb04606 sync parse.y changes from base; ok naddy@
original from naddy@:
> Don't declare variables as "unsigned char *" that are passed to
> functions that take "char *" arguments.  Where such chars are
> assigned to int or passed to ctype functions, explicitly cast them
> to unsigned char.
>
> For OpenBSD's clang, -Wpointer-sign has been disabled by default,
> but when the parse.y code was built elsewhere, the compiler would
> complain.
>
> With help from millert@
> ok benno@ deraadt@
2021-11-22 00:51:54 +00:00
055b84f4d4 Do not attempt to grab keys without a keycode; this incidentally allows
XF86 keys support.

found and fix by Luis Henriques <henrix@camandro.org>
2021-11-19 19:13:14 +00:00
kn
d46f34f01e Keep pointer within window on maximize/fullscreen toggle
Spawn a window, maximize it in any way, move the cursor to a window border
that is not on the screen's edge and unmaximize again:  While the window
goes back the cursor stays at the screen's edge, i.e.  focus is lost to the
underlaying window.

Moving, resizing, tiling or snapping windows in any way always moves the
cursor along iff needed, e.g. using MS-[hjkl] to move a small window from
the center to the edge keeps the cursor within window borders -- no matter
what you do with the keyboard, focus stays on that window.

Make CM-f, CM-m, CM-equal and CMS-equal (default bindings) for toggling
full-screen mode, maximization, vertical maximization and horizontal
maximization of the current window drag the cursor along if needed as well.

OK okan kmos dv
2021-04-22 10:02:55 +00:00
91c05f9403 Fixed memory leak in xu_get_strprop.
If a client calls XSetTextProperty for a window to clear all its
properties, then allocated memory within libX11 is not freed.

OK okan@
2020-04-25 20:07:28 +00:00
3ebe04ee8e Prevent out of boundary write with configuration files in which too many
quoted arguments are stored for other window managers.

The quotation handling happens within the while loop without checking if
the "end" limit has been already reached. If this happens, the final
NULL assignment leads to an out of boundary write on stack.

OK okan@
2020-04-16 17:12:49 +00:00
6407eb9bc1 Allow configuring a percentage window size of the master window during
htile/vtile actions. From Uwe Werler, with a few manpage tweaks.
2020-04-16 13:32:35 +00:00
6afdd483c7 zap stray tabs 2020-03-24 14:48:29 +00:00
6c20772841 Instead of using _NET_ACTIVE_WINDOW on restart, use the pointer location
to determine what client to set active. Reduces a round trip for every
window.
2020-03-24 14:47:29 +00:00
0a7d8cc5c4 Add support for SIGINT/SIGTERM. 2020-03-23 20:14:27 +00:00
tim
6c7b8261df Simplify conditional construct.
OK okan@
2020-03-20 18:50:08 +00:00
49f839e194 Trim event_mask to those that the root window actually needs. 2020-03-20 15:16:31 +00:00
207b71ef1c No need to lookup current client early; move to right before it is
needed.
2020-03-20 12:13:20 +00:00
tim
3b9b98c024 Recommit 1.259, but now with TAILQ_FOREACH_SAFE.
From and OK okan@

Original commit message:

Plug two memory leaks. Also get rid of a variable that is no longer
necessary.

OK okan@
2020-03-16 17:50:44 +00:00
tim
b9213d0a02 Revert previous. Causes a crash as reported by Tom Murphy. 2020-03-14 16:11:09 +00:00
tim
146fa08e4d Simplify list markup.
OK okan@ schwarze@
2020-03-13 20:50:07 +00:00
tim
d8c7d87737 Plug two memory leaks. Also get rid of a variable that is no longer
necessary.

OK okan@
2020-03-13 20:49:13 +00:00
3d1a8028c2 Remove ColormaskChange from event-mask since there's no event handler. 2020-02-28 13:38:35 +00:00
96275a835d Unrelated style fixes, consistency changes and sorting, appropriate
dosage/removal of wrappers, simplification of name queue, client cycle joins
other kb/mb bound functions.
2020-02-27 14:56:39 +00:00
7a88b2bdb2 Allow the 'empty' group clients to be window-{h,v}tile'd.
Behaviour (or lack there of) noticed by Raf Czlonka.
2020-02-07 18:53:41 +00:00
d3410dd10d Map ('5') and allow mod5mask (altgr) as a modifier.
From Artturi Alm (though changed from 'm' to '5')
2020-02-03 16:38:02 +00:00
83de84b7f8 add, then use, xvasprintf, checking for appropriate return. 2020-01-22 19:58:35 +00:00
2fc191f978 Ensure the pointer stays within client bounds after a window 'snap' (to edge).
reported by Stefan Hagen.
2020-01-21 15:50:03 +00:00
781af9c998 Because cwm warps the pointer during a client move (to stay within the client),
there's a window of time where an expose or enternotify event will get
generated for a lower client; use a hammer and drain events after keyboard
move/resize, until such a time that cwm doesn't warp the pointer.  Behavior
noticed by kn.

ok kn@
2019-08-13 18:45:38 +00:00
6131e36f8a Fix regression from r1.107 (lost a return); kettenis@ pointed out the high
potential for a use-after-free (true!) where kn@ ran into the regression using
an app that actually exercised the XGrabPointer() failure path.
2019-08-12 00:52:36 +00:00
kn
fdb841c3b0 Add application section
Link what is described as "applications" here to how they are actually
defined in cwmrc(5).

While here, call the configuration file what it is instead of reusing
the default path (already mentioned in the FILES section).

OK okan
2019-07-09 21:38:44 +00:00
kn
40000724cc command uses execvp(3) not execve(2)
util.c:u_exec() has been doing so since import.
2019-07-02 23:37:47 +00:00
tim
25b699b582 Plug a memory leak in log_debug(); OK okan@ 2019-04-29 19:03:20 +00:00
tim
3f1caab46a Handle _NET_WM_NAME changes.
This fixes the problem where cwm's window menu wouldn't show Firefox's current
window title if it contains non-ASCII characters.

OK okan@
2019-04-29 19:02:21 +00:00
9a7528f5b9 Check the atom type on propertynotify before iterating. 2019-03-11 15:25:46 +00:00
e55c0d48fa use screen_find() for xrandr crtc changes 2019-03-10 22:53:11 +00:00
5bc2098c6f Find the managed screen from the parent window for client_current(). 2019-03-10 20:38:28 +00:00
5071baa2aa Print window id in hex; while here, remove unnecessary newline. 2019-03-08 20:33:30 +00:00
4470a247c8 Similar to keypress event, fetch the screen from the event root window in the
buttonpress handler; bail if we don't manage the screen. Allows us to find the
current client based on the screen/event root.
2019-03-08 17:40:43 +00:00
eab4b7e4b5 extend verbose logging for key/button events 2019-03-08 15:04:39 +00:00
bf43b62414 [keypress event] turns out we've been checking the wrong window for a matching
client thus always falling back to client_current(); while the current client
is problaby right in most cases, use event's subwindow (not window) to find the
client. Bail early if this event came to us from a screen we don't manage.
This is result of us grabing all keybindings off the root window instead of
selectively.
2019-03-08 14:48:02 +00:00
2a3c2b5231 add parans for readibility 2019-03-08 13:17:26 +00:00
7c45b87622 Teach client_current() to use a screen to find the current client instead of
iterating over all (fallback if no screen provided for now). Initially convert
trivial uses of client_current().
2019-03-07 14:28:17 +00:00
01be5b4e4a check cc->gc directly 2019-03-07 13:24:44 +00:00
823566a653 zip extra lines 2019-03-07 13:24:10 +00:00
aa79351d2e gc clientq inside groups, instead use the better maintained one per-screen 2019-03-07 13:14:41 +00:00
b26202724a shuffle deck chairs: rename group actions to match intent for clarity 2019-03-07 12:54:21 +00:00
9efa6c8c85 same thing as screen_find() 2019-03-06 13:32:19 +00:00
0bda8f7606 Separate out the menu window from the client resize/move geom window; in each
case, create and destroy on-demand. Isolate more menu specific code.
2019-03-04 19:28:17 +00:00
9d5b0e5d22 fix a few misplaced (and misnamed) ewmh root window functions 2019-03-04 14:48:59 +00:00
fda68a40de _NET_WORKAREA needs ngroups, so screen_update_geometry() needs to come after
conf_group().
2019-03-04 14:36:02 +00:00
0c0551b8bf simplify xftcolor config 2019-03-04 13:33:39 +00:00
9d25218458 Tie group number and name together during config. 2019-03-01 14:32:01 +00:00
ae231f67d0 Move the group index (desktop number) check to the only 2 callers that require
checking due to ewmh.
2019-02-28 23:26:12 +00:00
880b5cda3f Ensure we don't action on the last group when the requested one is not found. 2019-02-28 23:20:52 +00:00
8cd6d1154c Selectively hide and show clients based on state; merge client_unhide() and
client_show().
2019-02-28 13:11:53 +00:00
cd4be1c17a Add a configtest flag (-n).
based on a diff from Sascha Paunovic.
2019-02-25 18:07:48 +00:00
a5ba9aa9da Add 'group-close-[n]' action to close all windows within specified group.
heavily based on a diff from Nam Nguyen.
2019-02-25 16:40:49 +00:00
43cd19378e simplify screen 'area' usage for initial client placement 2019-02-23 19:17:17 +00:00
953cf1ce89 restore order from before r1.248 (vtile/vtile containment changes). 2019-02-22 20:52:13 +00:00
535cf541c8 Rename internal functions to delinate between client remove, delete and xproto
delete; 'window-close' is now the proper action, but 'window-delete' as an
alias will remain until more interesting changes require breaking configs.
2019-02-22 19:40:32 +00:00
044ef5a8cd Limit vtile/htile actions to clients fully within the screen of master client.
from Charles A Daniels.
2019-02-22 14:39:18 +00:00
c307e37dcb fix missing includes 2019-02-13 15:43:24 +00:00
695eb1d8e5 Stop asking for events (NoEventMask) from menu window once done with
the menu (we don't destroy it, only unmap).
2018-11-14 19:22:51 +00:00
194589eb6b Allow 'transientfor' clients to inherit group and bwidth either during init or
via property notify events. Previously only the flags were set but nothing was
in the path to apply said flags and/or bwidth. Required slight of re-orgnaization
of client_init.
2018-11-13 17:37:13 +00:00
268deed916 merge from base, from sashan@:
> - odd condition/test in PF lexer
> (and other lexers too)
>
> This commit rectifies earlier change:
>
> in the lex... even inside quotes, a \ followed by space or tab should
> expand to space or tab, and a \ followed by newline should be ignored
> (as a line continuation).  compatible with the needs of hoststated
> (which has the most strict quoted string requirements), and ifstated
> (where one commonly does line continuations in strings).
>
> OK deraadt@, OK millert@
2018-11-09 16:00:54 +00:00
a63b87e315 Use the original client border width to adjust initial placement of clients
containing {P,US}Position requests where they are explicitly set to 'ignore' in
cwmrc(5); clients are unaware that their border will be altered (removed in
this case) when calcuating position and thus end up a factor of their original
border width off once mapped by cwm(1). cwm(1) will essentially shift the
client to the edge if the original request's position and border match.

Window offset noticed by at least Andre Stoebe via bugs@, and others since
(and likely before). Thanks!
2018-11-08 15:49:42 +00:00
9999c3e6e0 Remove unused prototype; from Ross L Richardson. 2018-07-16 14:19:23 +00:00
0551094182 Do not print any parse errors when ~/.cwmrc is missing. Regression introduced in
revision 1.109 of calmwm.c.

ok okan@
2018-02-19 19:29:42 +00:00
b1929b5ed6 Store the screen's visual type and colormap. 2018-02-13 15:43:15 +00:00
13763662c9 Consolidate region 'view' and 'area'. 2018-02-13 15:06:22 +00:00
e6bf7429b3 limit scope of screen_apply_gap() 2018-02-09 20:08:07 +00:00
1a5f80bd0b Clean up conf_file/homedir and conf_init() bits. 2018-02-09 19:54:54 +00:00
f3211427c1 Use screen's saved view instead of re-querying the server. 2018-02-06 15:05:20 +00:00
14c17b5f9b Slightly expand and expose verbose debugging. 2018-02-04 22:56:26 +00:00
8623c7add7 add debugging for x events 2018-02-02 13:50:22 +00:00
34e15dbd7a Add a simple debug logging mechanism. 2018-02-02 13:40:55 +00:00
9bf750b054 Simplification; use asprintf where appropriate now. 2018-02-02 13:27:25 +00:00
174537f29e Use func attributes where appropriate. 2018-02-01 15:17:51 +00:00
f34e659ca7 Fix wins comparison declaration since it's unsigned from XQueryTree(). 2018-01-23 16:18:59 +00:00
03a2e9cf05 Generate name_to_func[] in a clean and readable fashion. 2018-01-23 16:00:21 +00:00
5324f9a4e3 Shrink tier[] by one after removing matchname in r1.55. 2018-01-23 13:51:39 +00:00
8675b5e158 If the requested group number is invalid, bail but don't kill cwm. 2018-01-23 13:48:49 +00:00
e99f1d4683 Quick fix: exit after a failed execvp in u_spawn instead; previously we did in
u_exec, but the introduction of re-exec'ing the previous invocation of cwm if
'exec_wm' failed missed the 'exec' failing path. Will likely split out as a
proper fix.

Odd behaviour reported by Ve Telko.
2018-01-08 16:21:54 +00:00
50c0a4eef6 Only exec the fallback when in CWM_EXEC_WM state.
Broken quit noticed by Ve Telko.
2018-01-02 14:04:58 +00:00
5672d5d203 Typo, from Julien Steinhauser. 2017-12-30 22:25:09 +00:00
15ca9c03ba If the replacement window manager fails to start, restart the fallback (the
original invocation of cwm).
2017-12-29 20:09:19 +00:00
6e7dbf5bb7 Convert menu-exec-wm from an abritrary exec menu, into a config-based menu from
which one may configure (wm <name> <path_and_args>) (and choose) specific
window managers to replace the running one. 'wm cwm cwm' is included by
default.

No objections and seems sensible to sthen.
2017-12-29 20:03:46 +00:00
43db5b55ea As done for buttonrelease, work specific un-cycling and un-highlighting actions
into the keyrelease event, only performing what's actually needed for each;
should result in much fewer events against keyreleases. No intended behaviour
change.

Additionally, like we do for group membership, grab the keyboard only when
required for cycling.
2017-12-29 18:50:43 +00:00
ba75c13953 Merge group_toggle_membership_leave into the buttonrelease event and only do
border work for a group/ungroup action.
2017-12-29 16:55:50 +00:00
5ddaed415c add helper function client_show to bring together like actions for unhide/raise 2017-12-29 12:54:54 +00:00
156681f0a5 Add support for re-exec'ing with SIGHUP; equivalent to the already built-in
'restart' function.
2017-12-27 18:46:18 +00:00
3d7c82936e Use poll and XNextEvent to replace XNextEvent blocking inside the x11 event
handler.
2017-12-27 17:04:35 +00:00
03e5d86952 zap stray that snuck in 2017-12-22 21:30:01 +00:00
dfaf44c0ac Return the connection number for the display. 2017-12-22 21:27:45 +00:00
c5d03b0853 Fix a few comments and while here, wrap some long lines. 2017-12-22 21:21:44 +00:00
18a53717ae Use a variable to keep track of flags for menu_filter(). 2017-12-19 19:38:43 +00:00
bc5215f41a Add support for _NET_WM_STATE_SKIP_PAGER and _NET_WM_STATE_SKIP_TASKBAR; eerily
close to cwm's 'ignore'.

Roughly based on an initial diff from Walter Alejandro Iglesias, but with
support for both Atoms and without cwm-based bindings.
2017-12-19 14:30:53 +00:00
5e5d06f063 remove duplicate ExposureMask 2017-12-15 13:13:17 +00:00
64ff5f399a move variable declarations up, to match everything else 2017-12-13 15:10:17 +00:00
add109c006 clean up after previous (noprompt removal) 2017-12-12 15:37:16 +00:00
888f6c5319 Unconditionally show prompt on menus, regardless of invocation. 2017-12-11 20:58:18 +00:00
0fc9d47fb4 Original idea from Dimitris Papastamos to move windows to corners a while ago;
re-proposed by Julien Steinhauser with an updated diff. Apparently this was in
the original calmnwm.

However, expand the original idea and let clients 'snap' to edges instead,
neatly allowing key bindings that snap to adjacent edges (i.e. corners) as
well. No default bindings assigned.
2017-12-07 16:25:33 +00:00
f0524fe07a give command and group menus their own match callbacks 2017-12-07 16:03:10 +00:00
b06ddae624 stash dir into conf since it'll be of use 2017-12-07 15:47:14 +00:00
0d76265e23 organize this a bit better 2017-12-07 15:40:54 +00:00
592e8efaee spacing 2017-12-07 15:39:47 +00:00
d9d6b4f88f Revert r1.109 (Switch to XWindowEvent() pulling out events that match the mask
*and* window.) of mousefunc.c. When a client destroys itself while we are
moving or resizing it, XWindowEvent() blocks. Found the hard way by Anton
Lazarov, and Lea°hNeukirchen found the right bit to revert - thanks! Reverting
since the reason to switch from XMaskEvent was unclear.
2017-11-30 18:18:51 +00:00
7d7e256396 Case matters for menu matching on executables; from ben@lloyd.im. 2017-09-06 14:15:13 +00:00
8dee1182a2 Use the key names from keysymdef.h in the default key bindings list for
clarification.

from Michael Reed.
2017-07-21 15:55:37 +00:00
60ed85c50f remove extra parentheses 2017-07-14 18:01:46 +00:00
c039e7fb8c Pull over the remaining re-implemented window move/resize functions and create
a wrapper so that the key and mouse based move/resize callbacks can be unified.
This has already been done with other window operations and menus.
2017-07-14 17:23:38 +00:00
aefc0bf0fb rename one function, matching others, to help upcoming change 2017-07-12 16:56:26 +00:00
d179dfdeb9 Replace fgetln(3) with POSIX getline(3); inspired by brynet and Ingo.
feedback and ok brynet@
2017-07-10 13:36:58 +00:00
f94fde51fb fix a few WARNINGS (new sentence, new line and extraneous Pp macro) found with
mandoc -Tlint
2017-07-06 17:09:17 +00:00
eb79ce65c9 from src, by espie@:
no need to generate y.tab.h if nothing uses it, set YFLAGS to nothing
2017-07-06 17:01:10 +00:00
16a2ccc225 drop obsolete comment 2017-05-09 18:43:40 +00:00
113ffcf47e Alter callbacks to take a struct instead of a growing number of arguments;
greatly simplifies upcoming work.
2017-05-09 13:40:18 +00:00
189a735eaa Ensure clients stay within the viewable bounds on placement, even with empty
borders; based on a patch from Vadim Vygonets.
2017-05-05 14:14:19 +00:00
3d6ff6dabf Clean up, unify and accurately calculate edge distance with client move/resize
actions, so as to not lose windows off the edge.

inspired by diffs (and feedback) from Vadim Vygonets.
2017-05-01 12:54:55 +00:00
4d85e2e2a6 Switch bwidth type; unfortunately X11 is inconsistent. 2017-04-26 21:10:54 +00:00
15b9a8fe27 The r1.36 menuq_add() conversion did this one wrong; fix by reverting to the
original code which adds to resultentry list, as opposed to the wrong one in
menuq_add(). Fixes crash noticed by at least Rickard Gustafsson.
2017-04-25 13:40:33 +00:00
717e6c8167 Remove 'noresult' (and simplify) as it does nothing and makes the logic around
it needless. History doesn't show what this might have been used for in future
iterations.
2017-04-25 12:08:05 +00:00
ffcfff3dea search_match_path() isn't supposed to return anything. 2017-04-24 15:06:11 +00:00
56b44257a5 Move queue init to caller so it's only called once in a few cases. 2017-04-24 13:35:25 +00:00
15a6fcc851 sort 2017-04-24 13:31:19 +00:00
9b56325908 Raise the previously focused window, instead of the previous window in the
cycle list; seems to match behaviour of other wm's; from Walter Alejandro
Iglesias.
2017-04-24 12:27:32 +00:00
50dd70afc5 For {h,v}tile, instead of keeping the master client's {h,v} geometry, expand it
to %50 of the area, then fill in the remaining space with the other clients in
the same group; from Gerrit Meyerheim.

support from ajacoutot.
2017-04-24 12:18:04 +00:00
8d9d84d859 Fix group hidden state when a client wants to be on all desktops on start;
reported by Vadim Vygonets with diff, but another approach was taken.
2017-02-10 15:00:54 +00:00
172da14d77 Call client_resize instead of client_move after client_placecalc since the size
may also change.

from Vadim Vygonets
2017-02-06 18:10:28 +00:00
f908118a3a Typo on binding name; from Redouan Ait Mallouk. 2017-01-15 21:07:44 +00:00
96918a06e6 Ensure client stays inbound on key-based resize; based on logic existing in
key-based client move; from Vadim Vygonets.
2017-01-05 21:18:20 +00:00
613d11434a When a window has a user or program specified position, ensure the edge of the
final position is at least viewable and warp'able by the difference of bwidth;
prevents mapping windows completely off the virtual screen.
2016-12-19 14:17:26 +00:00
8b4666cb92 stray newlines 2016-12-06 21:59:33 +00:00
a7f2ab7497 Add search_print_text(), a default callback for mi->print in menu_filter(). While
here, normalize the remaining search_print_* argument paramters.
2016-12-06 21:54:10 +00:00
89e4e7fb14 Consistent use of menuq_add for ssh menu. 2016-12-06 21:09:22 +00:00
2ae4797297 Now that dim.{x,y} are available early, use them before requiring a
MotionNotify event.
2016-12-06 21:03:58 +00:00
74092f78aa Set dim.{x,y} during client_init and update on resize, instead of
(re)calculating only when applying hints.
2016-12-06 21:00:13 +00:00
cf4c1879e5 'window-search' is spelled 'menu-window'; the former snuck in during the
conversion('menu-window' already existed and was properlly documented); found
the hard way by sthen@ while trying to convert.
2016-12-06 15:03:13 +00:00
cfffa70364 Fold unbinding functions into one for each, key and mouse; plugs a leak when
unbinding a mouse button bound to a command.
2016-12-02 17:02:17 +00:00
5b7e66a13b use the correct type 2016-12-02 16:50:19 +00:00
94f681fc90 Tame the number of 'exec' and 'path' search_match wrappers. No functional
change now, though more can likely go later, losing the (paritally complete or
incomplete/broken) argument completion bits.
2016-12-01 20:28:19 +00:00
b94f0748d8 Switch ssh menu to search_match_text; like group/window/cmd menus, use only a
substring match. The previous matching is only intended for the exec menus.
2016-12-01 18:44:09 +00:00
92111e526d Change 'menu-window' to display all windows; then add 'menu-window-hidden' for
the previous behaviour of 'menu-window'.  'menu-window' becomes the default
binding; use 'bind-mouse "1" menu-window-hidden' to restore old behaviour for
those who prefer.

OK sthen@ (long long time ago on a different version)
2016-12-01 18:17:52 +00:00
d968a6c1bf Normalize bind function names, based on a few categories: window, group, menu
and pointer.

Replace 'bind' and 'mousebind' options with 'bind-key' and 'bind-mouse',
respectively, replace special 'unmap' keyword with 'unbind-key' and
'unbind-mouse', and additionally allow unbinding all with 'all' keyword.
2016-12-01 17:17:27 +00:00
ae9f900b91 Use an additional check with lstat(2) when d_type is unknown.
from James McDonald via portable.
2016-11-15 18:43:09 +00:00
db02592e5c revert previous; upcoming changes will hopefully deal with these more
naturally.
2016-11-15 00:22:02 +00:00
62dc5ae132 Add a wrapper based upon xevent handlers around client move/resize for key and
mouse bindings.
2016-11-15 00:07:03 +00:00
ed22d7a944 Define callbacks, then default bindings. 2016-11-14 21:25:59 +00:00
64e133b289 Reorganize for upcoming changes. 2016-11-14 19:56:05 +00:00
98c913cc3b Remove the (8) default bindings for pointer move since they conflict with
default bindings for emacs, which wins; the feature remains and can be bound to
whatever users wish with cwmrc(5).

from mpi@
2016-11-14 13:52:33 +00:00
db93599a0f Make it clear these are flags. 2016-10-24 20:44:08 +00:00
972e28d58c Remove duplicate check that strsubmatch() already does; while here, fix a
comment.
2016-10-24 18:57:12 +00:00
eb43101591 Sprinkle __func__ in appropriate error messages. 2016-10-24 17:39:38 +00:00
ffd60b3cab Get rid of 'matchname'; it's too surprising to have the menu change during
client search as different potential str matches are cycled through. If there's
interest, the only string that doesn't exist in the listing is the window's
class - that can be added of course, but it makes the line too long imho.
2016-10-24 17:16:23 +00:00
b1af1bedd0 clean up search_match_client(); no behaviour change 2016-10-22 19:16:43 +00:00
0bb1be86c6 Refactor callbacks to take a void * so as to not try and generalize into
client_ctx in keypress and buttonpress event handlers; pass appropriate *ctx's
based on context.

While here, limit some globals, replace defines with appropriate variables and
fix some naming.
2016-10-18 17:03:30 +00:00
38eac7d7e9 remove another unused proto 2016-10-12 16:11:15 +00:00
15bf703e1c Rename 2 kbfunc to match closer to what they do 2016-10-06 14:53:52 +00:00
987ee736b9 Add an argument to the callbacks to pass the xevent context, button or
key press. This allows to remove a few hacks to duplicate functions only
for behaviour changes; now differing behaviours are pushed down to the
callback. Also will allow for previously unavailable actions to be bind-able
down the road.
2016-10-06 14:41:19 +00:00
66f5360fd4 Check the ptr bounds in the new client during cycling, since not all
actions do ptrsave, such as restoring client geometry; adapted from a
diff by Vadim Vygonets.
2016-10-06 14:30:05 +00:00
e7dcb17e1e More accurate to say 'toggle', rather than 'select', for group[n]/nogroup. 2016-10-05 14:01:23 +00:00
c131620d7b Add CM-a for 'nogroup' (CM-0 stays for now); update manpage to reflect. 2016-10-05 13:35:17 +00:00
d40820d3f3 Stash wmname into conf. 2016-10-05 13:10:59 +00:00
a37606c63f When removing xrandr regions, ensure clients are within the bounds of
the screen; adapted from an ancient diff from Sviatoslav Chagaev. Things
in this area will likely change, but put this in so it works now and
serves as a reminder.
2016-10-04 20:15:55 +00:00
5c13775d31 Calculate client nameqlen in client_setname(), the only place it's
needed/used.
2016-10-04 15:52:32 +00:00
9306c1fbd3 Turn CALMWM_NGROUPS define into variable, ngroups. 2016-10-04 15:18:20 +00:00
8aa5033d12 Start simplifying menu code; and in turn, remove a cursor no longer
needed.
2016-10-03 18:43:49 +00:00
03f5dc219e Defaults are split between defines and conf_init(); normalize these, as
well as give 'sticky' groups its own variable.
2016-10-03 14:42:34 +00:00
792f85cde9 For both kb and mouse move, it is possible to grab a client and move it
completely off the screen/region; instead, if the pointer is outside of
the client bounds, warp the pointer to the closest edge before moving.
2016-10-03 13:52:17 +00:00
a8a111dffd client_ptrwarp should not deal with unhiding or raising clients (non ptr
requests); most callers do this already - deal with the few that do not.
client_ptrwarp becomes a simple wrapper (setpos) but it will be expanded.
2016-10-03 13:41:30 +00:00
1d3a6905f1 remove unused proto 2016-09-30 21:44:51 +00:00
1c54fc079d Set the initial ptr position during client init, instead of waiting
until (maybe) a ptrwarp call. Likewise, explicitly ensure an inbounds ptr
position (same as initial) when saving.
2016-09-30 20:55:54 +00:00
2d8f621b8d Use instinsic X11 functions for key/btn/ptr grab/ungrab/regrab requests;
the one line wrappers provided no value and limited altering calls where
needed; additionally, most of them had but one caller.
2016-09-30 18:28:06 +00:00
8b26a43bf1 Replace mousefunc_sweep_draw() with a generic menu_windraw() using va
lists; use it appropriately for both window dimension and position in
the respective mousefunc calls.

ok bryent@
2016-09-30 15:12:19 +00:00
f63b2e2341 Switch to XWindowEvent() pulling out events that match the mask *and*
window.
2016-09-30 15:05:02 +00:00
24d6348e52 no need to unmap menu window again 2016-09-29 00:30:40 +00:00
0e8c706633 Mechanical change: move screen menu bits to their own struct. 2016-09-29 00:21:55 +00:00
92b81d3df5 Inline Xft draw and extents wrappers; too much abstraction. 2016-09-28 17:06:33 +00:00
b32989d379 Do not call sweep_draw() too early: don't yet have w/h dimensions; plus
we will get a MotionNotify event right away anyway, setting required
parameters.
2016-09-28 15:54:54 +00:00
57b2a6cf79 Continue merging kb and mouse functions: fold
mousefunc_menu_{client,cmd,group} into the respective
kbfunc_menu_{client,cmd,group} functions; simply pass a flag down from
config denoting mouse action behaviour.
2016-09-22 14:36:03 +00:00
3947f1268a Allow ctrl-[ for abort (esc); from Benjamin Scher Purcell 2016-09-20 19:58:54 +00:00
08631748fd de-static client_inbound() 2016-09-20 19:11:19 +00:00
74e4a3c60b remove debug that accidentally snuck in 2016-09-20 18:23:12 +00:00
9cf3174696 Get rid of curcc, instead cycle through the queue; removes the need for
client_none().
2016-09-20 18:21:32 +00:00
6a53e3a859 During init, query screen for _NET_ACTIVE_WINDOW and set that client as
active; while we already look at what's under the pointer, use this
information first, then look under the pointer (saving that round-trip).
This restores the active state to a client after restart even if the
pointer is not above it (and of course the pointer is not above another
client).
2016-09-16 14:32:02 +00:00
2bbe111cc0 Some clients fail to setup hints at all, so initalize for them; fallout
from r1.218 switching to malloc - clearly missed this case.

found the hard way by brynet@
2016-09-14 21:00:24 +00:00
b8933ebcca Fix-up a few simple uses of client_current(): check CLIENT_ACTIVE flag
instead of relying on curcc.
2016-09-14 19:45:33 +00:00
9124a561e3 init label 2016-09-13 17:42:58 +00:00
a94254137c Limit mouse resize to hints within the client; matches kbd resize
behaviour.
2016-09-13 13:42:28 +00:00
e1234b75b8 Switch to just malloc since we need initialize most everything anyway. 2016-09-12 13:48:41 +00:00
b14a4b222d change 'sticky' to 'stick' to toggle client stickiness (seems the
default binding worked for everyone for a long time!); conflict with
group sticky found by Ali Farzanrad - thanks!
2016-09-12 13:47:00 +00:00
c82c3f0835 Simplify group_holds_only_hidden(); from Vadim Vygonets. 2016-09-02 16:07:11 +00:00
67a9eaa440 Simplify toggling flags; from Vadim Vygonets. 2016-09-02 15:08:44 +00:00
44f3fefe11 Do not draw borders on ignored clients when returning from fullscreen;
from Vadim Vygonets.
2016-09-01 18:38:52 +00:00
4cf9a34b65 Remove redundant minimum client size adjustment (minw and minh are
always positive since r1.214); from Vadim Vygonets.
2016-09-01 18:34:04 +00:00
8c1b05e534 Enable the use of numpad Enter key on menus; from Henrique N. Lengler.
ok beck phessler
2016-08-28 15:23:24 +00:00
5015c850bd add a column to previous commit for consitency. 2016-08-13 09:59:48 +00:00
375368a94c conf_screen: report the fontname that can't be opened in case of failure.
ok dcoppa@
2016-08-13 09:58:37 +00:00
ffc365bc5d If supplied format to menuq_add() is NULL, fill text with an empty
string; found by Christian Neukirchen.
2016-04-28 16:28:38 +00:00
4ac6daa27d Fix a typo from r1.201; fixes window_grouptoggle binding. 2015-11-17 15:19:19 +00:00
8aa2f317af If a client does not set increment values, use 'moveamount' as a way to
scale keyboard based resizes; extend kbfunc_amount().

Behaviour noted by, tested by, and ok sthen@
2015-11-17 14:32:38 +00:00
e8d77b6890 Inline the only use of mousefunc_sweep_calc. 2015-11-17 14:31:28 +00:00
323672ace7 more client vs screen context differences 2015-11-12 21:28:03 +00:00
4aca2b8764 If a client sets hints, honor them for kb resize requests, just like we
do for mouse based resize requests.

Based on a patch from Vadim Vygonets.
2015-11-12 18:33:30 +00:00
9a48836ceb Move kb pointer movement out of the kbfunc_client_moveresize since it's
got nothing to do with clients, thus doing flags work causes lots of
waste and almost useless jumpy pointer movements; while here, split out
move and resize since they share almost no code, just like mouse client
move/resize; factor out amount and factor. Still wonder why this is
here, but it works now.
2015-11-12 18:26:41 +00:00
a2c066e447 pledge "stdio rpath proc exec" cwm before main event loop, after
init/setup - mostly for menu building.

ok semarie@ (another cwm user)
2015-11-12 17:56:54 +00:00
00bdd48b1d Partial revert of replacing screen_area() with region_find(); until a
fix for a regression is found; this bug has been around for a long time
it seems, but this change exposed it. Likely need to track clients in to
and out of regions.
2015-11-11 14:22:01 +00:00
09565bc423 Use position on root to figure out region. 2015-11-10 22:06:57 +00:00
e20110f344 Start cleaning up name vs function differences; replace magic numbers. 2015-11-10 20:05:33 +00:00
31c74e9157 Clean up unused defines. 2015-11-09 20:15:23 +00:00
d7bd299819 Extend region to include both view and work areas; switch to
region_find() which no longer needs to recalculate gap each time
a client (or menu) is created or altered. If no RandR, fall back
to display dimensions while building regions instead of during
execution.
2015-11-09 20:03:29 +00:00
5fcf251672 Only when mapping clients from an initial wm start or restart, query the
pointer and if it matches the child window, activate it; new clients
will not need to make this roundtrip to the server.

Based on a patch from Preben Guldberg.
2015-09-23 14:09:40 +00:00
0fdcf3f3df On execwm, we should properly release resources before exec'ing into a
new window manager; so allow CWM_EXEC_WM to assign new wm to wm_argv and
pass through cwm_status (now EXECWM) so that x_teardown() gets called
before exec'ing the new window manager.  Removes the need for a separate
x_restart() now, using new wm_argv; and consolidates errno for execvp.
2015-09-16 17:58:25 +00:00
47a10cc055 Lost fix from r1.112; add comment.
Reported (again!) by Peter Kane.
2015-08-28 12:07:28 +00:00
28d4001eca Mechanical change: group->gc 2015-08-27 18:53:14 +00:00
f467838e7b Add consistent checks against NULL. 2015-08-27 18:42:56 +00:00
19826222f6 Move client cycle grab/ungrab into a more relevant place; while here,
update comments about why we need to grab/ungrab the keyboard.
2015-08-27 18:40:09 +00:00
5391659629 Re-add lost chunk in group_cycle from r1.113. 2015-08-27 17:43:44 +00:00
6d53091429 Further simplify _NET_WM_DESKTOP handling using new group_assign(). 2015-08-25 20:35:49 +00:00
871ed39ccf oops; remove left over debug print 2015-08-25 19:52:02 +00:00
cb60a4b917 Allowing sending a valid 'nogroup' (0) group_ctx to group_assign()
(since we init all groups), though assigning the client's group to NULL
for 'sticky'; use this simplification in a few places (others to
follow).
2015-08-25 19:49:19 +00:00
96262a6b0c Split out sticky mode checks and the restoring of a client's group and
_NET_WM_DESKTOP from the config-based auto-grouping; no (intentional)
behavior changes.  Needed for further work in cleaning up this area.
2015-08-25 18:29:10 +00:00
dcfbc9e809 Implement _NET_CLIENT_LIST_STACKING (from Thomas Admin), but
bottom-to-top order, as per spec (notified Thomas as well).
2015-08-24 15:42:57 +00:00
97db17d056 Don't allow freeze operations on fullscreen (consistent with what
fullscreen does).
2015-08-24 14:57:19 +00:00
4269ea0463 Sort _NET_WM_STATE Atoms like the spec. 2015-08-24 14:56:10 +00:00
b224945446 Move CLIENT_STICKY logic from client hide/unhide to group hide/unhide;
rationale being that clients should be able to hide/unhide independently
of group switching.
2015-08-23 17:31:20 +00:00
ae9306748b Add Xkb modifier to ignore mask; from Alexander Polakov. 2015-08-21 16:53:48 +00:00
cd3bbb1c9c Fix whitespace. 2015-08-21 16:52:37 +00:00
1d31f9000c Add client freeze extension to _NET_WM_STATE Atom, allowing flag to
persist. As usual with new Atoms, requires X restart.
2015-08-21 16:30:02 +00:00
05478f061e _NET_WM_STATE_STICKY implies only sticky at the group/desktop level, not
position and size; based on discussion with a few.
2015-08-21 16:14:39 +00:00
c96fd247dd Instead of special casing the 'term' and 'lock' commands, go back to
keeping them hidden; showing them has apparently caused confusion/angst.
2015-08-21 16:05:55 +00:00
a79253abdc Leave command list order from .cwmrc alone; remove sort. 2015-08-21 15:55:39 +00:00
871c9f24ba Bring group and client cycle closer together. 2015-08-21 15:52:49 +00:00
54bbd88e51 Alter big move and resize bindings to match what's in cwm(1);
functionally the same, but re-binding should be based on default
bindings. Matches other similiar bindings.

Discovered by a portable user.
2015-08-20 14:45:15 +00:00
0d13b7c220 introduce 'groupsearch' for group menu search; matches on either group
number/shortcut and/or name.
2015-07-12 14:31:47 +00:00
5c2decc8d0 simplify menu print text 2015-07-12 14:21:09 +00:00
02779e64b8 revert previous; seems search_match_text() needs mi->text pre-populated.
(only used in one place, application menu searching); re-visit later.

broken application menu searching reported by Peter Kane.
2015-07-03 17:11:16 +00:00
cb900def7f style 2015-07-01 14:36:42 +00:00
8efaf33cfb no longer need to pass down format strings after introducing search_print_cmd 2015-06-30 19:02:24 +00:00
5d8027b75d Introduce a callback for cmd menu printing, special-casing 'lock' and
'term'.
2015-06-30 18:54:12 +00:00
c87953eb64 keep cmdq sorted 2015-06-30 18:44:29 +00:00
6b8b856217 style and spacing nits 2015-06-30 18:42:50 +00:00
8515d717ae Re-implement XClientMessage handling so that we can feed screen_find and
client_find valid resources as needed, relieving the need for
screen_find to ungracefully handle invalid root windows. Removes a long
standing XXX.  Should theoretically allow XClientMessage handling on
more than one X screen.  Alter callers of screen_find to handle
failures.
2015-06-30 14:01:43 +00:00
9ea5f25347 Shuffle code in kbfunc_ssh so that a missing known_hosts file still
allows a (now blank) menu to appear, as opposed to nothing at all.

Behavior reported by Alex Greif.
2015-06-29 14:24:40 +00:00
e7b4045ece move client_find down 2015-06-28 19:54:37 +00:00
17720de4ab replace assert usage 2015-06-28 19:50:46 +00:00
18f63629fd region is a _ctx, so name it so 2015-06-26 18:54:25 +00:00
66bc416217 Mechanical change from xinerama to region backed areas. 2015-06-26 17:17:46 +00:00
90288e2fc3 collect 'gap' applications 2015-06-26 16:11:21 +00:00
8aa40078d1 Replace screen region info gathering with XRandR equivalent of Xinerama
queries (currently act on XRandR events anyway). Fall-back mode without
XRandR is still what X provides. This removes -lXinerama.
2015-06-26 15:21:58 +00:00
ee400b08a8 typo in comment; from jsteinha [at] iutbayonne.univ-pau.fr 2015-06-09 13:02:15 +00:00
654bae4f59 just populating the ctx is enough since the menu uses a callback and ignores anything else 2015-06-08 15:43:13 +00:00
e9750e2144 switch to search_print_client() as the print callback since it will now display labels as well 2015-06-08 15:41:27 +00:00
8888c44888 add client label 2015-06-08 15:34:03 +00:00
9180bb1a06 stash window dimensions 2015-06-08 15:11:29 +00:00
8653c88c90 clean up 2015-06-08 15:08:44 +00:00
bd5f724931 even if the menuq is empty, at least show an empty menu instead of just
bailing making it look like the binding isn't working.
2015-06-07 19:10:00 +00:00
cd5827491c use the same geometry struct in menus as everywhere else 2015-06-05 18:43:36 +00:00
a4cba7e113 add a flag to indicate a menu list instead of overloading 'prompt' 2015-06-05 15:01:51 +00:00
f22a3b1065 redundant check for 'list' 2015-06-05 14:54:04 +00:00
d9f38134be a start to cleaning:
- no reason for pointer movement and window movement and resizing
  sections that just describe default key bindings
- key bindings are for all search and exec dialogs, not just for windows
- adding missing bindings
- normalize and wordsmith
- re-order sections according to mdoc(7)

feedback and ok from jmc@
2015-05-31 23:07:36 +00:00
b1c2046efd merge kbd and mouse grouptoggle 2015-05-21 00:37:04 +00:00
31d4fe9f33 fill in mwm defines 2015-05-20 23:54:39 +00:00
b9db4486da Fix autogroup so name,class doesn't need to be quoted.
ok okan@ on an older version of this diff
2015-05-17 04:39:50 +00:00
d328f63c7d Make window name and window class separate parameters to conf_autogroup.
No functional change, but will be used shortly.

ok okan@
2015-05-17 04:34:01 +00:00
557cd382dc plug a leak 2015-03-29 00:21:05 +00:00
a4a414b68b Introduce a xreallocarray and convert a few xcalloc instances that do
not require zero'ing.
2015-03-28 23:12:47 +00:00
0bbe0ad98c Reshuffle and slightly simplify menu_complete_path(), removing an
allocation, for tab-completion; checked by Alexander Polakov as well.
2015-03-28 22:09:10 +00:00
5b64e1540c plug a leak 2015-03-28 21:55:48 +00:00
bad97699f9 Simplify key/mb binding moving argtype into flags and dropping another
variable; removes the need to zero out struct binding, leaving a simple
malloc.
2015-03-26 21:41:43 +00:00
ac42dff6c1 simplify error messages; discussed with doug@ 2015-02-14 18:24:12 +00:00
7e0c2e7728 calloc -> malloc 2015-01-24 18:16:59 +00:00
d8fa58bb62 use malloc over calloc here 2015-01-23 20:26:36 +00:00
5146f661bd First restore net_wm_state(ewmh), then wm_state(iccc); prevents clients
from re-hiding on restart due to flag toggling (note that this is ripe
for re-vamping). Behavior only observed on restarts.

Problem found by, and initial patch from, Henri Kemppainen (thanks!),
though ever so slightly different one applied.
2015-01-23 19:35:11 +00:00
7936b9b2a7 Switch to limits.h; replace MAXPATHLEN and MAXHOSTNAMELEN with PATH_MAX
and HOST_NAME_MAX+1, respectively.

ok doug@
2015-01-19 14:54:16 +00:00
c412f040df Catch up with src parse.y changes by jsg@:
Don't allow embedded nul characters in strings.
Fixes a pfctl crash with an anchor name containing
an embedded nul found with the afl fuzzer.

pfctl parse.y patch from and ok deraadt@
2015-01-17 02:05:03 +00:00
8d1eb202bf Add gcc format attributes for yyerror(); fix a few yyerror() calls.
Adapted from src parse.y changes by doug@. OK doug@
2015-01-16 18:28:08 +00:00
9cada703b9 no need for calloc(1,.. here, malloc is fine since we initialize 2014-10-08 15:31:01 +00:00
836c9f49d6 make group_init work like other *_init's 2014-10-08 12:48:51 +00:00
e9dbd150ea these have nothing to do with 'sticky', but rather group membership; rename. 2014-09-27 19:04:32 +00:00
319d90099d Pass just the group to group_setactive instead of the screen and an
index which then needed to be found in a queue.
2014-09-27 18:57:11 +00:00
845e82015c Update _NET_CURRENT_DESKTOP with the screen's group_active->num. 2014-09-23 14:25:08 +00:00
cb65869d7a Move stuff that doesn't belong in group_init; while here, explicitly
initialize hideall and cycling.
2014-09-23 13:45:48 +00:00
cbc7f76074 Move motion time check to the top of each MotionNotify block (and
eliminate from ButtonRelease); further limits the amount of work done
outside the threshold, notably mousefunc_sweep_calc,
screen_find_xinerama and client_snapcalc.
2014-09-18 13:56:58 +00:00
8fd0f43ec2 these client actions are just toggles; less confusing with better names 2014-09-17 18:41:44 +00:00
458dd31b93 ewmh states _NET_WM_STATE_STICKY should not alter position 2014-09-17 18:09:30 +00:00
736d973f46 Use a similarly named check as sticky for hidden check in a group. 2014-09-17 16:32:53 +00:00
7eef4eb63d don't toggle _WM_STATE_HIDDEN here yet 2014-09-17 16:30:21 +00:00
a61812d52d Implement EWMH _NET_WM_STATE_HIDDEN. 2014-09-17 16:00:44 +00:00
74f4a1bad9 Introduce a check to see if a group holds only 'sticky' clients and use
this check to decide if a group is virtually empty.  Rationale: if a
group contains *only* 'sticky' clients, it should be skipped while
cycling through groups.  Apply similar logic to the group menu.

Based on an idea from phessler@, who also tested another version.
2014-09-17 14:31:37 +00:00
4b6dc96398 use similiar style for client flags 2014-09-15 13:00:49 +00:00
26b95de019 Remove incorrect cast in kbfunc_exec. In kbfunc_ssh, reverse logic on
truncation check so it's obvious.
2014-09-11 16:06:26 +00:00
d27fc99784 fold in 'active' into 'flags' 2014-09-10 20:30:38 +00:00
20c1113fdd move the check for an empty queue up during cycle 2014-09-08 21:24:27 +00:00
aac16013d2 name the group client queue appropriately, like other queues 2014-09-08 21:15:14 +00:00
b64ce8558c more style nits and wrapping 2014-09-08 20:37:02 +00:00
bc70374264 since mruq has been folded in, rename mru-named functions 2014-09-08 20:32:40 +00:00
26ba152692 Remove duplicate client queue (mruq); instead, remove and take the
global Clientq and place it inside screen_ctx since every client belongs
to a screen, then use the same per screen clientq to track stacking
order (the sole reason for mruq).
2014-09-08 20:11:22 +00:00
a7f3f29ea9 Now that a group knows its screen, only pass down the group_ctx. 2014-09-08 13:51:29 +00:00
5b46f0f7d8 Add screen_ctx to group_ctx, and populate on init. 2014-09-07 20:57:26 +00:00
3d12b6d1d9 more style nits 2014-09-07 19:27:30 +00:00
be091b3523 screen_fromroot -> screen_find 2014-09-07 17:38:38 +00:00
78e0f21225 Get rid of a redundant array of groups per screen; we already have a
link to the group queue for each screen.
2014-09-07 17:27:20 +00:00
f7af0ebd72 Few style nits; extend 'path' to MAXPATHLEN. 2014-09-06 18:50:43 +00:00
977992626a generic sighandler 2014-09-06 16:24:32 +00:00
140f8b9eba style nit 2014-09-06 16:18:08 +00:00
5cd4cce3a0 Move termpath and lockpath into cmdq; side effect is that 'lock' and
'term' now show up in the application menu.
2014-09-06 16:14:35 +00:00
142f52a0aa Rework group names: stash the group name inside the group_ctx as opposed
to having to manage an array outside in screen_ctx for group names and
shortcuts.  Simplifies (and moves bits for) reading, and constructing
data for, EWMH's _NET_DESKTOP_NAMES.
2014-09-06 16:08:58 +00:00
87d604f119 bring menu bits closer together 2014-09-02 14:08:39 +00:00
231abb818a add explicit paran and drop some empty lines bringing like functions closer 2014-09-01 18:17:32 +00:00
becc7f260c Merge group_menu into mousefunc_menu_group. 2014-09-01 18:04:58 +00:00
3b99d53576 Since the flatting out of sc->group_names is only for setting
NET_DESKTOP_NAMES, merge the helper into xu_ewmh_net_desktop_names,
where we actually set the property.
2014-08-25 14:31:22 +00:00
7314a3aefd Implement _NET_WM_STATE_STICKY, bound to CM-s by default; allows any
client to 'stick' to all desktops (ewmh speak) or groups - this
currently has the same affect as setting a client's group to 'nogroup',
with the exception that the client can also be in a group, so when
un-sticking, the client will go back to its original group/desktop.
2014-08-25 12:49:19 +00:00
ed164794cb Continue effort to bring keyboard and mouse functions together; merge
name_to_kbfunc and name_to_mousefunc.
2014-08-24 15:49:58 +00:00
9f36d4af35 gc->hidden has never consistently kept track of a group's state;
group_show() and group_hide() are not the only ways a group can change
state - if all clients in a group are either hidden or unhidden, then
that group's state should change, as well as the various EWMH ways.
Instead of trying to keep track in a wide variety of places, simply
query the clients in a group before needing to take action based on the
group's state.  Solves long standing confusion of when a group is hidden
or not.
2014-08-24 15:37:45 +00:00
fe533fdc8e Fix nogroup regression, where nogroup became an actual group - the
symantics between cwm groups and ewmh got in the way.  Ensure a client
that wants to be in nogroup stays in nogroup (thus stays in view), even
when (re)reading NET_WM_DESKTOP.  Paritially reverts patchset 644
(2014-02-07 13:09 PST) which deals with a NULL cc->group.  All to be
revisited when NET_WM_STATE_STICKY hits cwm.

Reported by many; testing and ok phessler.
2014-08-22 19:04:00 +00:00
b31b09dfc2 Purely mechanical; unify 'num', 'no' and 'shortcut'. 2014-08-20 15:15:29 +00:00
30da2211dd Split off group window restacking. 2014-08-20 13:42:27 +00:00
7f45471538 whitespace 2014-08-20 12:35:39 +00:00
5d22b261a6 fix a misleading comment and function name 2014-08-20 12:33:12 +00:00
6c835fd585 Remove unnecessary memset since reload was replaced with restart;
from Kent Spillner.
2014-08-19 18:39:41 +00:00
01cca3c114 Pull highstack from group_ctx (and useless calculations of); in the one
place that we use highstack, replace that usage with a local variable
(for now until stacking is done properly).
2014-08-19 12:47:51 +00:00
1192007171 Get rid of nhidden in group_ctx; it actually never reported correctly
since nhidden wasn't incremented nor decremeted in all the right places,
thus confusing matters.  We don't need to carry a count around, so just
use a local variable in the one place we need one to supply
XRestackWindows().
2014-08-18 13:57:57 +00:00
e9cb5b743f plug memleak (currently unused func); from Tiago Cunha 2014-04-21 12:52:14 +00:00
d46b0f8848 Alignment fix; found the hard way on sparc64 by landry@ (and thanks too
for fast access to a box!)

ok deraadt@, matthieu@
2014-02-27 00:52:57 +00:00
6798e3dde3 Make sure we cycle through existing client's group membership and set
the hidden state on the group; important to know group hidden state
after a re-exec or restart of cwm (as easily seen in group menu).
2014-02-08 02:49:30 +00:00
1208225fbd Replace a few hand rolled loops with like tailq loops. 2014-02-08 02:40:43 +00:00
2a87320bbf all mapped clients now should have a group, so simplify some cases 2014-02-07 21:59:56 +00:00
3cb81ebeea If _NET_WM_DESKTOP is set to -1 during client creation, place the client into
group 0 (nogroup); solves problem initially discovered by oga@nicotinebsd with
tint2.  A clientmessage *after* client creation already handles this case.

Go further and assign every client to a group; in non-sticky mode, group 0
(nogroup) and sticky mode, the active group.  In both cases, autogroup will
override the group assignment.  Removing a group from a client always places
the client back into group 0 (nogroup).  Autogroup can also assign a client to
group 0 (nogroup) to keep a client always visible (unless of course one opts to
hide all clients).
2014-02-07 18:09:54 +00:00
98d8483d35 Some clients set the urgency flag even if they are the active client;
prevent annoying behavior by only setting the cwm urgency flag if the client
is not active; diff from Thomas Adam.
2014-02-06 20:58:46 +00:00
f793964c9e Introduce a region queue and replace screen's XineramaScreenInfo; we
still use Xinerama to populate the regions per screen, but will switch
at a more appropriate time.
2014-02-03 21:07:47 +00:00
8a6dd51fac make this XQueryTree like the other 2014-02-03 20:29:05 +00:00
ad96c16838 Move redundant bits from screen_init (while dealing with existing
clients) directly into client_init, performing the X roundtrip only
once. With the previous change in maprequest, this moves decision making
into one place for creating new clients.
2014-02-03 20:20:39 +00:00
ad76995af7 Move redundant window attr fetch from maprequest directly into
client_init and perform that X roundtrip only once.
2014-02-02 21:34:05 +00:00
ad1b78c6d1 No need to store screen colormap and visual; rather just use the X
macros in the one place they are needed.
2014-02-02 16:29:04 +00:00
5f9c7a21c7 Unlike free(3), XFree(3) can't be passed a NULL pointer. 2014-02-02 16:13:50 +00:00
0a71742af4 The menu already limits entries with MENU_MAXENTRY, so don't bother
holding a command name limit as well.
2014-02-02 15:46:05 +00:00
fd827fd757 Take menu's bwidth into account for position/size; reported by Thomas Adam. 2014-02-01 19:28:46 +00:00
8b63ac62c2 Let the config parser continue parsing even after encountering an error;
original idea (with now-outdated patch) from Thomas Adam.  Since we now
report where errors exist, this now makes more sense.  Expand a bit on
config file parsing in the cwm(1).

Discussed with a few, including sthen; ok sthen.
2014-02-01 00:25:04 +00:00
34477b8a35 re-add lost free from previous 2014-01-30 22:41:16 +00:00
cc1902f57c Switch ignoreq to winname struct since it's basically the same thing;
removes limit on name matching.
2014-01-30 22:17:22 +00:00
7928c1ad7c use the same autogroupwin variable as everywhere else 2014-01-30 15:43:53 +00:00
fdefcecfa0 Move cwm_status around to avoid header fu, and remove extraneous signal
header from xevents.c; noticed by Christian Neukirchen.
2014-01-30 15:41:11 +00:00
7b5b7cc9e9 Remove duplicate mouse functions and instead use the kbfunc ones. No
user visable changes at this point, but they'll merge at an appropriate
time.
2014-01-30 14:40:21 +00:00
2be890489b Minimize trivial differences between a few kb and mb functions. 2014-01-29 22:30:00 +00:00
59fe14bd2f keybinding -> key binding 2014-01-29 21:17:33 +00:00
db0b2fde5c Merge keybinding and mousebinding queues into using the same merged
struct, binding; they were essentially the same accept for what was
'pressed', keysym or button.
2014-01-29 21:13:52 +00:00
4438970b64 Much like we do for keyboard and mouse bindings, remove duplicates for
command name - last match.
2014-01-29 18:43:27 +00:00
1f8f19b4d5 Check command name/path for truncation and provide user feedback during
config parse (and use conf_cmd_add to populate defaults); based on a
discussion with Tiago Cunha.  While this looks ugly, there are likely
some other changes here to come.
2014-01-29 18:34:22 +00:00
c28467cda5 Check ignore windowname for truncation and provide user feedback during
config parse; based on a discussion with Tiago Cunha.
2014-01-28 20:22:21 +00:00
df15337a9f The EWMH spec states that if the cardinal returned is 0xFFFFFFFF (-1)
then the window should appear on all desktops, which in our case is
assigned to group 0.  Found to fix stalonetray due to the non-ewmh aware
range checking in group_movetogroup(); from Thomas Adam.
2014-01-28 13:40:40 +00:00
51b3fbee52 Move conf_init/clear into main - no behaviour change; from Tiago Cunha. 2014-01-28 00:42:20 +00:00
0608610cc7 move some init up and shed some blank lines 2014-01-27 15:13:09 +00:00
469db5f371 simplify parse_config using assignment; inspired by a very old diff from
Tiago Cunha.
2014-01-27 14:49:40 +00:00
6f10349843 more range checking 2014-01-24 22:38:02 +00:00
c7e2ee5dd5 correct arguments and drop the cast.
sanity check by oga@nicotinebsd
2014-01-24 15:08:06 +00:00
53e77acafc no need to quote within warning 2014-01-23 17:13:38 +00:00
79248a385b If no title is supplied, term uses only the basename for its title.
This is useless when searching for windows launched via the ssh command
menu; supply a more useful title: '[ssh] <hostname>'.

Idea from todd@, ok todd@
2014-01-23 16:51:28 +00:00
3d2eec293a zap whitespace 2014-01-22 22:41:09 +00:00
978a5767ec cwm_argv doesn't need to be global any longer 2014-01-22 22:26:05 +00:00
5121ea5e10 start properly releasing X resources during teardown 2014-01-22 22:14:02 +00:00
77aa5ac45b Somewhat streamline event loop/restart/quit handling; most notable
change allows a restart to trigger proper teardown first, even though
teardown is not (yet) complete.

After some discussion with oga@nicotinebsd.org regarding a more
complicated version/idea.
2014-01-22 21:48:27 +00:00
ac3162439a Sprinkle a few more const; from Tiago Cunha. 2014-01-21 15:42:44 +00:00
83f9ef884a Save the ptr position before lowering via kbd, so as to be able to cycle
back with the pointer in the right place; matches behaviour when
lowering via the mouse function.
2014-01-20 23:18:47 +00:00
c7adadaf9d merge KBFLAG_NEEDCLIENT and MOUSEBIND_CTX_*; brings kbfunc and mousefunc
bits even closer.
2014-01-20 23:03:51 +00:00
34f43e3f2d Use argument to pass down flags for mousefunc cyclegroup; removes
rcyclegroup wrapper need - now similar to kbfunc.
2014-01-20 22:31:53 +00:00
d91571c567 constify and rename some confusing variables around cmdq. 2014-01-20 21:34:32 +00:00
7263fb4c84 - remove redundant range check for buttons in conf_bind_mouse.
- make conf_bind_kbd return error on non-matches to match what
   conf_bind_mouse does.
 - rename some variables while here for clarity.
 - constify bind and cmd.

from Tiago Cunha.
2014-01-20 19:06:04 +00:00
720b5452aa Add a function that adds an entry to a menuq, normalizing a common code
path; from Tiago Cunha.
2014-01-20 18:58:03 +00:00
43ccf4eae0 use consistent types 2014-01-03 15:29:06 +00:00
08342471c8 state is long 2014-01-03 14:23:50 +00:00
2843ba1e28 calculate proper menu width/height on the first Expose event; 'jump' (while using gap) noticed by Christian Neukirchen 2014-01-02 22:49:10 +00:00
376e98c2c8 Accept _NET_CURRENT_DESKTOP ClientMessage; from Thomas Adam, though
instead of group toggle, group only.
2014-01-02 22:43:55 +00:00
5a5e7441e1 Accept _NET_WM_DESKTOP clientmessage; from Thomas Adam 2014-01-02 22:26:27 +00:00
10d4dcb127 bring mousefunc closer to kbfunc 2014-01-02 21:30:20 +00:00
c4f6134ebe gc keycode in keybinding since we only deal with keysym now 2014-01-02 21:17:23 +00:00
8420398068 rename for clarity 2014-01-02 21:15:39 +00:00
46b1d6ef1e When a client doesn't specify size hints, nothing prevents a resize to
0x0 - don't allow this situation during mouse resize (check already in
place for kbd resize).

Reported by brynet@
2014-01-02 20:58:20 +00:00
9b8dc1ba7f missing stdarg.h include 2013-12-17 16:12:18 +00:00
da2bea3ffa replace with memset 2013-12-17 16:10:43 +00:00
19fc7f666b Implement support for EWMH's _NET_WM_STATE_FULLSCREEN hint.
Since we already have a form of 'maximize', we need to differentiate
between 'maximize' and the new 'fullscreen' mode.  The 'maximize' mode
will continue to honor gap but now *retains* the border, matching the
'vert/horz maximize' behaviour.  The new 'fullscreen' mode supports and
follows the _NET_WM_STATE_FULLSCREEN hint, allowing the client perform
additional window modifications; in this mode, cwm(1) will *ignore* gap,
remove borders and freeze(move/resize) the client.  Additionally,
'fullscreen' mode will remember various combinations of previous states.

* default keybinding changes: CM-f 'fullscreen', CM-m 'maximize' (re-map
  as desired).

Positive feedback from a few, testing and ok sthen@
2013-12-16 19:02:17 +00:00
f98f4615c0 Teach screen_find_xinerama() to apply gap only when told to do so;
adjust callers.  Needed for an upcoming feature.
2013-12-13 22:39:13 +00:00
5732b65139 Instead of using work area, use the Xinerama area for snap calculations;
based on a patch from Thomas Adam with appropriate adjustments for gap.
2013-12-13 21:51:56 +00:00
91a29396e8 we need the save-set when re-exec'ing so as to not lose State on our hidden clients 2013-12-13 15:56:44 +00:00
40858be0ae stray space and sort while here 2013-12-13 14:45:47 +00:00
34ae428cec Add support for XUrgency and matching _NET_WM_STATE_DEMANDS_ATTENTION
ewmh hint; urgencyborder is configurable.  The urgency flag will stick,
even while on a client in a non-viewable group, until the client
receives focus (where the border is reset).  Initial diff from Thomas
Adam with some changes/enhancements from me.
2013-12-13 14:40:52 +00:00
fe177b7c61 Make sure we really take work area gap into account with snap calculations;
from Dominik Honnef via Christian Neukirchen.
2013-12-12 21:50:50 +00:00
b276a2ef00 ICCCM explicitly states that server time (CurrentTime) should *not* be
used for focus events, but rather the timestamp of the generated event.
Track the last event timestamp and send it down for a WM_TAKE_FOCUS
ClientMessage.  I suspect we should do this for clients that don't
announce this Atom as well, though the raciness gets us into a bind.

Solves focus order issue since WM_TAKE_FOCUS; fix verified by sthen@

ok sthen@
2013-12-12 20:15:07 +00:00
e767ac9c65 we don't need to manage the save-set since we're not reparenting; left-over from pwin 2013-12-11 22:14:23 +00:00
09e07ddaaf since we are drawing in unhide, no need to during client setup 2013-12-11 17:23:31 +00:00
68f365cddb apply mwm hints later 2013-12-11 15:46:47 +00:00
7e0749b0b1 Add client wrapper for XWMHints to support XA_WM_HINTS in PropertyNotify
events; based off a diff from Thomas Adam.
2013-12-11 15:41:11 +00:00
0d9b1becff Remove extra work and simplify client state handling. 2013-12-11 14:16:09 +00:00
23a1abdd8a Stash Class and WM Hints in client_ctx 2013-12-11 14:09:21 +00:00
1d68f0683a Redraw client border when unhiding; during a hide, we just unset
the active flag but never redraw since it'll be in IconicState.

Behaviour reported by sthen@
2013-12-10 21:27:37 +00:00
7fad5224d4 If not using sticky mode (the default), clients aren't automagically
assigned a group, thus cc->group will be NULL - fix the client group
shortcut in menu lists; crash reported by Christian Neukirchen.
2013-12-08 13:51:38 +00:00
5dc65d9242 When we receive a NotionNotify event, there's no need to (incorrectly
might I add) redraw the top menu selection.
2013-12-02 20:01:19 +00:00
161ed1801a Always highlight the first menu item (helpful to see selected items when
not using a mouse and therefore not generating Expose/MotionNotify
events); from Thomas Adam.
2013-12-02 19:49:26 +00:00
d1b232fe81 Prepend the group shortcut in the client search menu; from Thomas Adam.
Likewise, prepend shortcut in unhide menu.
2013-12-02 19:30:27 +00:00
6b72168d92 Since we use IconicState as our hidden state, check for the hidden flag
and unmanage the client if we're not hidden (basically if NormalState)
during an UnmapNotify event.

Resolves an issue with mplayer going fullscreen while not using NetWM
hints; behaviour regression reported by Ido Admon.
2013-12-02 14:30:12 +00:00
5e67a12262 like gap, make snapdist per screen 2013-11-27 18:34:34 +00:00
1b6ef8e9ed alter -r1.145 getsizehints to deal with clients that don't have
WM_NORMAL_HINTS.
2013-11-27 17:04:35 +00:00
abf52049b9 Remove the option to bind a key by keycode with brackets; it never
worked (and no one complained!).  While it's fairly easy to fix, users
should be using keysym names and not keycodes.

Discussed at length months ago with todd@, matthieu@ and Owain.
2013-11-27 16:24:17 +00:00
250f98bf15 simplify/unfold 2013-11-27 14:20:32 +00:00
fa25915a75 Rewrite active/inactive client handling in client_setactive();
client_leave() served no real purpose, likewise no reason to handle
LeaveNotify events since an EnterNotify will process the next active
client (and we don't have anything important to process anyway), so
xev_handle_leavenotify() goes as well.  Allows a simplification of
client_mtf() and client_cycle_leave() for clarity.  While here, unify a
few client_current() checks.

No intended behaviour change.
2013-11-27 00:01:23 +00:00
03b19f1487 Log message:
use u_char for buffers in yylex, for ctype calls, as done in all other
parse.y in the tree
found by millert@, ok okan@
2013-11-25 18:21:55 +00:00
2937b2066f Alter the r1.35 of event.c race fix. Remove the forward looking event
queue check (removing the need for a server grab/ungrab) - if the client
is going away, let it fall all the way through to a DestroyNotify event.
There's no longer a need for us to manually destroy a client ourselves
(removing yet another server grab/ungrab).  Instead, when the
UnmapNotify event is synthetic, simply set the state to Withdrawn (as
per ICCCM), else Iconic (in our case 'hidden').

Verified with test case from the 2009 race which was the original reason
for r1.35 of event.c.
2013-11-12 21:25:00 +00:00
bda68b0924 Put back the border draw call in client_resize; since we are adding and
removing the border on maximized clients we need to redraw.

Also noticed by Tim van der Molen
2013-11-11 12:51:15 +00:00
3bb928a1c2 stash WMProtocols in flags 2013-11-08 17:35:12 +00:00
c1bc6d37b3 quick keyboard focus fix for clients that neither populate wmhints nor wmprotocols, like rdesktop; focus needs to be re-visited 2013-11-05 00:55:42 +00:00
b5915eb989 The only reason we need to keep XSizeHints in our client_ctx is for
flags, so just add one to hints; consolidates sizehints and shrinks.
Additionally don't abuse PSize for XGetWMNormalHints() failures.
2013-11-02 19:13:56 +00:00
b8f53666bd x/y from XSizeHints are obsolete (and have been for a long time), so
instead use x/y from XWindowAttributes when USPosition|PPosition are
set.
2013-11-01 21:54:20 +00:00
06eb13dfd9 re-add support for WM_TAKE_FOCUS, and additionally this time only call
XSetInputFocus() for clients that have the InputHint; latter fix
discovered by Valery Masiutsin with a PoC patch - solves keyboard input
focus loss for java apps.
2013-11-01 14:07:19 +00:00
6e17b41f56 A client_delete should behave differently depending on whether the
triggering event was unmap (with pending destroy) log destroy; we only
need to grab/ungrab the server lock, set WithdrawnState and
XRemoveFromSaveSet clients coming from an unmap event - doing so for
clients coming from destroy are already gone, hence we generate errors.
2013-10-25 19:46:16 +00:00
6867821abe shuffle 2013-10-20 02:00:02 +00:00
5b733a152d wrap key ungrab like btn ungrab, for it'll be used again 2013-10-20 01:55:32 +00:00
9ff288baef revert 1.138 (WM_TAKE_FOCUS) for now 2013-10-20 01:35:47 +00:00
a2013ee9dd Using xu_btn_ungrab() buttons during client_leave doesn't work (error
BadValue) when the modifier is already AnyModifier .  Instead alter
xu_btn_ungrab() to ungrab AnyButton/AnyModifier and call it only when a
client is coming into focus in client_setactive(), instead of iterating
over ignore mods - matches how we handle key grabs.
2013-10-19 19:39:34 +00:00
083a023f2c I believe we redraw the border in too many cases; likely a leftover from
the cc->pwin days - don't redraw on every unhide, resize, and mouse
move/resize Expose event (note, all Expose events trigger a redraw
anyway).

Tested with some finicky X apps I could think of, though I'm sure others
will find more - if so, and they 'lose' the border, please report!
2013-10-19 18:59:22 +00:00
a70b2d81af For clients that support WM_TAKE_FOCUS in their WM_PROTOCOLS property, send
a ClientMessage event.
2013-10-19 00:24:54 +00:00
a88b8c1363 a few err->errx since we don't have error messages here; from Tiago Cunha 2013-10-17 13:59:10 +00:00
bfd3f5e5e1 trying parsing a XLFD string first, then by pattern 2013-10-07 13:40:26 +00:00
6ac51b8e41 unify type; no change 2013-10-03 13:51:57 +00:00
a439012b58 we no longer need to construct an array for _NET_SUPPORTED. 2013-07-16 14:30:48 +00:00
fbb9d32d0a don't need the size here 2013-07-16 14:22:25 +00:00
ca416b6b82 max -> nitems 2013-07-16 14:04:44 +00:00
ae4ab06559 shuffle down protoypes 2013-07-15 23:53:19 +00:00
4ef96a2772 collapse lines 2013-07-15 23:51:59 +00:00
4119b5c065 simplify atom handling; allows us to limit to one round-trip to server
for gathering Atoms.
2013-07-15 14:50:44 +00:00
bd7b8163bb bring buttonpress and keypress event handlers slightly closer together 2013-07-10 14:15:58 +00:00
9571038358 type fixes 2013-07-10 14:11:42 +00:00
dd10412804 since the root and event window are the same in the case of a button
event on the screen's root window, there's no need to pass down the
entire XButtonEvent event, at least to group_menu(), the only callback
which takes an argument at this point; instead use the already populated
screen.
2013-07-09 01:24:49 +00:00
9bf2498d7e add support for mouse based group {,r}cycle; from Rodrigo Mosconi. not
bound by default.
2013-07-08 18:39:20 +00:00
1f244fe29c move kbfunc and mousefunc closer together 2013-07-08 18:19:22 +00:00
a493734066 clarify kbd vs mouse functions 2013-07-08 16:32:51 +00:00
912ec90ea1 move duplicate kbd and mouse modifier parsing to a generic function;
from Tiago Cunha
2013-07-08 16:10:55 +00:00
fe439f2b96 replace a few (x)malloc with (x)calloc to prevent potential integer
overflows; from Tiago Cunha
2013-07-08 15:48:16 +00:00
7a7e5cd592 whitespace and style fixes; from Tiago Cunha and one from me. 2013-07-08 15:46:16 +00:00
fbcdce6be9 properly fix (and re-organize) selfont selection. 2013-06-23 17:57:50 +00:00
7004700ce0 when selfont is configured, make sure we continue and configure the rest
of the screen (quick fix); discovered the hard way by Rodrigo Mosconi.
2013-06-20 02:33:57 +00:00
234b8214df move Cursors into conf. 2013-06-17 17:11:10 +00:00
23d84adb5e now that we have conf_screen, which configures individual screens
*after* config parsing, we no longer need to split up display/screen
initialization, so collapse.
2013-06-17 14:08:51 +00:00
8b00f438be allow mouse button4 and button5; from Rodrigo Mosconi 2013-06-17 00:57:47 +00:00
6059073a5f move synthetic responses and have client_msg only work with WM_PROTOCOLS,
since that's all ClientMessageEvent is for anyway.
2013-06-10 21:37:30 +00:00
b365ceac0e Check for, and honour, CWStackMode and CWSibling change requests during a
ConfigureRequest event.  Additionally, honour a border width change;
detailed report and patch from Mike Small.
2013-06-10 20:11:43 +00:00
09f3275561 Unlike other parse.y variants, cwm's allowed 'command xx /path/to/xx' without
quotes. Reinstate this support lost in recent sync diff and add a comment to
show that it's intentional. ok okan@
2013-06-03 20:33:17 +00:00
692d341dfc fix type in a ClientMessage (xu_sendmsg). 2013-05-27 23:20:45 +00:00
be1a7a3f5c alter conf_grab(_kbd) to first ungrab AnyKey/AnyModifier, then proceed
to grab keys in keybindingq.  we don't need to ungrab/grab on every
addition to the queue, just once with a complete keybindingq; simplify
grabbing keys per screen (during init) and during a MappingNotify.

while here, change conf_grab_{kbd,mouse} to require only a Window.
2013-05-23 16:52:39 +00:00
7cc1c7344f since we don't have any screens yet, there's no reason to conf_{,un}grab
here; just build keybindingq.
2013-05-22 20:23:21 +00:00
d1eadee922 get rid of long standing XXX: now that we configure screens based on
config options, add the keybinding GrabKey calls here
2013-05-22 16:54:09 +00:00
532f132194 move validation of pointer Button into conf_mousebind so we check
validity during the parse phase and not bother adding it to the queue,
instead of each time a client needs to grab (when it's too late);
furthermore, make this a config error, stop parsing and load the
default config.
2013-05-22 16:32:15 +00:00
866f5af9c7 sync with src changes 2013-05-22 13:02:14 +00:00
421bf22ac7 handle _NET_WM_STATE ClientMessage; from Alexander Polakov. 2013-05-21 00:29:20 +00:00
c2042cd523 stray whitespace 2013-05-20 21:32:00 +00:00
ad8020e17d handle _NET_ACTIVE_WINDOW ClientMessage; from Alexander Polakov. 2013-05-20 21:19:15 +00:00
284af4ca0c add support for _NET_WM_STATE_MAXIMIZED_{HORZ,VERT}; from Alexander Polakov.
while I'm unsure of the final look of _NET_WM_STATE, there's no reason
to delay this support.
2013-05-20 21:13:58 +00:00
270df196ac - configure menuwin with the screen, then create the xft drawable using
the menu window since that's the only place on which we draw
- elminate the need to change the drawable on every font draw
2013-05-20 20:21:04 +00:00
e14123210a no reason to pass around *sc when it's already in menu_ctx. 2013-05-20 20:04:36 +00:00
5b4c55616a move the 2 small font helper functions to xutil.c 2013-05-19 23:38:20 +00:00
e41c84c752 move the rest of xft init into screen_conf, since most of it is based on
config parameters.
2013-05-19 23:16:29 +00:00
dac00a232f - switch border colors to Xft
- merge border/menu color structures/functions since they now both use Xft
- switch xu_xorcolor to operating on XftColor instead of just
  XRenderColor (basically adding pixel)
- if color name allocation fails, revert back to default (this, along
  with font validation should occur during config parse, but we don't
  have screens setup yet - likely to change at some point)
2013-05-19 23:09:59 +00:00
c84145661e add support for _NET_CLOSE_WINDOW 2013-05-19 17:05:52 +00:00
556a50d8f7 treat WM_CHANGE_STATE like other atoms 2013-05-19 17:03:55 +00:00
01bfdd7b42 use XGetWMProtocols and simplify WM_PROTOCOL handling 2013-05-19 17:02:04 +00:00
3253f5a4a1 simplify 2013-05-19 17:01:29 +00:00
be72620432 if -> ifdef 2013-05-14 13:39:53 +00:00
c637a54048 - let callers of font_draw figure out (and pass) the color instead of an
'active' flag.
- use strlen() inside of font_draw; the only instance where it wasn't
  used happened to be ignored on a subsequent draw.
2013-05-14 12:35:56 +00:00
112f616d1d swap x/y calculations in kbd move/resize to match those in the respective mouse functions 2013-05-11 22:03:17 +00:00
2b926784ba new -> init 2013-05-11 22:01:07 +00:00
3a38686137 replace conf_{gap,color,font} with conf_screen since really we are
configuring the screen *after* parsing, just as we do a conf_client on
client manage.
2013-05-11 21:46:27 +00:00
9b9e95d742 more type fixes for mask/button 2013-05-10 16:32:47 +00:00
d0fe80b1f4 spacing 2013-05-10 16:10:40 +00:00
e05c0a2c60 int type fixes 2013-05-10 16:05:34 +00:00
457938fbd7 fix KeySym type 2013-05-10 15:44:43 +00:00
5f06e5a8ca border width/color makes sense for some, so put it back 2013-05-07 01:35:41 +00:00
1a06f09fa0 negative values for borderwith, moveamount, snapdist and gap are
configuration errors, so warn and load defaults.
2013-05-06 19:09:19 +00:00
1db7cc2a18 remove group in client_delete directly. 2013-05-06 16:03:11 +00:00
27854d9061 border width/color makes no sense on menuwin 2013-05-06 16:00:34 +00:00
e91c716262 - no need to position and size the menu window before an Expose event
since we'll be calculating required size later anyway; allows us to
  consolidate all prompt/display/search string building goop into
  menu_draw.
- reset the pos/size of menuwin when leaving a menu.
- reverse the 'prompt' NULL check to be consistent with 'initial' one
  and fix a whitespace nit while here.
2013-05-02 20:18:35 +00:00
0d209028be zap leftover debug printf 2013-05-02 19:41:52 +00:00
9de81f3d2e get rid of cc->name in the resize box and make dimensions more readable. 2013-05-02 19:33:17 +00:00
bb56bf4c4b only redraw the name/size box when the client resizes, not every time
there's movement; should slightly help with resize syncs.
2013-05-02 19:30:10 +00:00
5acf6c147f no need for font_{ascent,descent,height} wrappers; limit font_width to
just requiring xftfont.
2013-05-02 17:25:15 +00:00
5ab3b373d3 group conf_* init functions 2013-04-30 21:12:20 +00:00
ff6f5301f0 missing proto 2013-04-30 21:11:07 +00:00
6e8f1f2955 type fix 2013-04-30 21:10:23 +00:00
94e341725b use an int in screen_init and avoid needing to cast for screen number (which). 2013-04-29 00:56:47 +00:00
006a29e617 mechanical xu_{get,set}state -> xu_{get,set}_wm_state change 2013-04-17 13:57:06 +00:00
302690624e slightly rework WM_STATE set/get to make it less ambigious; will be more clear
on what needs to change to make it right in the end.
2013-04-17 13:52:20 +00:00
1dbcc394ae zap extra space 2013-04-17 13:31:47 +00:00
a899d267fe add conf_ignore and move group_make_autogroup to conf_autogroup to match. 2013-04-17 13:30:38 +00:00
16ed8bf8e4 only a window is required to set WM_STATE. also un-confuse xu_ptr_getpos
by using 'win' instead of 'rootwin' so as not to imply only the root
window is queried, rather any window.
2013-04-14 16:13:17 +00:00
f3dfc4968c we handle WM_STATE here, so remove misleading comment. 2013-04-12 20:54:27 +00:00
ef1b78f464 we already set window state in client_hide or client_unhide right before, so
there's no need to do it again.
2013-04-12 20:45:57 +00:00
b5f6bd205c makes no sense to set an error handler which uses X_Dpy before XOpenDisplay. 2013-04-12 14:49:16 +00:00
6296efadaa push Screenq into screen_init 2013-04-12 14:46:30 +00:00
90f95416c6 _NET_WM_NAME is UTF8_STRING type 2013-04-10 19:08:09 +00:00
58c1d48d10 plug memleak; always need to menuq_clear even when a selection is made. 2013-04-08 15:43:04 +00:00
62a685d82a reverse logic to make it like the others 2013-04-08 13:05:27 +00:00
28b54db221 consistency 2013-04-08 13:02:31 +00:00
8c47a12a86 missing prototype 2013-04-08 00:56:21 +00:00
f18d2c94c2 add missing proto; replace magic number 2013-04-05 17:36:02 +00:00
670207f79b zap stray whitespace 2013-04-05 17:07:25 +00:00
c5a76f1d5b - no reason to breakout ClassHints work, so fold into client_{new,delete},
but keep _MOTIF_WM_HINTS separate.
- simplify fetching app/class hint.
- fix _MOTIF_WM_HINTS Atom type.
2013-04-03 20:22:55 +00:00
9cad4c73b3 honor PATH search order for exec; from Andres Perera. 2013-04-03 19:28:00 +00:00
ec4474a33a move XUngrabServer to the end of client_new() to avoid races where clients,
such as those using sdl, attempt to manage the clients themselves when the
clients aren't fully ready.  other wm's grab the xserver during the whole
client setup process, so match.

behavior found by jsg.
2013-04-03 19:20:50 +00:00
fbb0df4155 replace handrolled for loop with TAILQ_FOREACH; from andres.p@zoho.com 2013-03-09 21:55:56 +00:00
47aa485fa2 put back r1.68 which allows an empty group to be sticky; behavior
change noticed by Thomas Pfaff and diagnosis why we need to
group_setactive in this case by Alexander Polakov.  replace XXX with
a useful comment.
2013-01-13 13:55:12 +00:00
62acbee4b3 set the initial group to '1', missed by recent off-by-one group
numbering re-work; discovered the hard way by sthen@.

ok sthen@
2013-01-10 15:28:11 +00:00
3a7596968b add per-group vert/horiz tiling support; introduces 2 new bind commands,
'vtile' and 'htile'; from Alexander Polakov.
2013-01-08 15:16:04 +00:00
bf9d981597 teach screen_find_xinerama() about gap and adjust (simplify) callers;
menu becomes gap-aware for free.
2013-01-08 04:12:51 +00:00
e7b85cfb2f fix menu/client placement in panning setups; XineramaQueryScreens gives
us the width of the psuedo screen, but here we need the edge instead
(xmax/ymax); just re-use w/h here for now.
2013-01-07 21:53:23 +00:00
4ffe56b9a3 revert previous 2013-01-07 21:45:24 +00:00
7c4ed94757 unbreak xinerama support from r1.41 for panning setups 2013-01-07 20:32:19 +00:00
c426254da5 use cc->bwidth in client_vmax since we've yet to reset it (matches
client_hmax); from Jan Stary
2013-01-06 01:01:26 +00:00
6d123cd96d rename {h,v}max functions for consistency; from Jan Stary 2013-01-04 16:30:03 +00:00
579f981718 really these are just border colors, so adjust the define 2013-01-04 16:27:58 +00:00
96adffcd9d spacing 2013-01-04 16:23:51 +00:00
698530155d get rid of struct color 2013-01-04 16:23:04 +00:00
c139df129c pass the screen workarea, as opposed to viewarea, allowing client
snapping to honor gap.
2013-01-02 21:41:14 +00:00
2ac65bd288 re-work client_snapcalc() so it takes client and edge dimensions with
snapdist; allows for simplier snap calculations.

required for an upcoming diff for honoring gap.
2013-01-02 21:37:21 +00:00
6e5dda99a6 merge in Xinerama screen query; no functional change. 2013-01-02 18:11:23 +00:00
ce8ef02ed2 have screen_find_xinerama() return struct geom *reliably* instead of
XineramaScreenInfo; simplifies goop around the callers.
2013-01-02 16:26:34 +00:00
e492ed8e41 more variable consistency 2013-01-02 02:19:20 +00:00
2d28b71a1b info->xine, for consistent variable names 2013-01-02 02:02:08 +00:00
afb3648440 after we toggle a group hidden, it makes no sense to set it as active
(in sticky or non-stick mode), regardless of existing clients assigned
to that group; oga marked this bit XXX in -r1.34 for it didn't seem make
sense then either.

pulled from a diff from from Alexander Polakov.
2013-01-01 14:50:01 +00:00
ccbb1f1529 least intrusive way to plug a memleak when unbinding a duplicate key for
kbfunc_cmdexec; from Tiago Cunha
2013-01-01 14:33:52 +00:00
6cb334e503 replace emptystring with strdup here as well so we know we are free'ing
a malloc'd variable everytime; from Tiago Cunha
2013-01-01 14:26:29 +00:00
0957fbbee2 make num of groups no longer off-by-one; from Alexander Polakov
note that a re-exec of cwm will not rewrite the group number atom of
*existing* clients, so they will remain off-by-one until each client has
its atom updated, or of course a restart of X.
2013-01-01 14:19:56 +00:00
dc1e3a8843 gc unused cmd 'flags' variable 2012-12-19 15:21:34 +00:00
c565b790ed expand CHILDMASK 2012-12-18 18:39:55 +00:00
86eaf5e973 use MOUSEMASK since we already have it 2012-12-18 18:35:36 +00:00
31e9fe4dcd remove unused SEARCHMASK 2012-12-18 17:44:18 +00:00
e5d59c2d7b define LockMask|Mod2Mask; no functional change 2012-12-18 17:37:39 +00:00
b848a2b236 simplify config file setup; with Tiago Cunha 2012-12-18 00:14:41 +00:00
479e9f769c put a default known_hosts into conf 2012-12-17 23:54:57 +00:00
75f65f399e pull user home directory via getenv or getpwuid and stash it so we don't
need to do this everytime; with Tiago Cunha
2012-12-17 23:03:41 +00:00
fe44d1dfce cmap -> colormap in client_ctx 2012-12-17 18:35:26 +00:00
af13c08108 stash the default screen visual and colormap in screen_ctx 2012-12-17 18:34:06 +00:00
82e8ec4245 replace client highlight with a client flag 2012-12-17 17:48:57 +00:00
8e67d1389c make client_mtf static 2012-12-17 14:58:46 +00:00
3a3e0383b2 create and use menuq_clear() helper; from Tiago Cunha 2012-12-17 14:32:39 +00:00
d651c1cc3b current_client() returns _curcc, so use it where appropriate 2012-12-17 14:26:29 +00:00
980c6de1ff screen font -> xftfont 2012-12-17 14:20:52 +00:00
96cd288a2a knf 2012-12-17 02:53:29 +00:00
6900cd3612 non-trivial menu drawing rewrite, moving to Xft and solving various
font/color drawing issues; from Alexander Polakov
2012-12-17 02:28:45 +00:00
a3aaad2c18 zap extra lines 2012-11-29 16:50:03 +00:00
560acb43fc specific last match for autogroup; few iterations with Kent Spillner. 2012-11-29 04:25:49 +00:00
7edabe94f2 x_setupscreen -> screen_init; no functional change. 2012-11-29 03:54:46 +00:00
5947879dfb remove dead extern 2012-11-29 03:34:19 +00:00
3e151f8c76 add xasprintf() for upcoming changes. 2012-11-28 14:32:44 +00:00
2b9d921eda ever since the 9wm code bits were removed or replaced, this file has
been a no-op, for each source file has a complete license marker (ISC).

no objections from oga, who did the 9wm rewrite/remove work in 2008.
2012-11-28 14:25:05 +00:00
fad4798e5b replace hand rolled font_make() with XftFontOpenName() and merge into
font_init().
2012-11-28 14:14:44 +00:00
93f64ffc55 add some checks 2012-11-16 14:15:48 +00:00
7b00e3fe76 variable name consistency; from Thomas Pfaff 2012-11-14 21:31:53 +00:00
587d623e4a tab-complete buglet fix: once exec_path is completed, allow for
subsequent completion; from Alexander Polakov
2012-11-14 21:12:24 +00:00
28224ff830 sort 2012-11-09 03:52:02 +00:00
04d4ed7b7e fix some warnings; inspired by a diff from Thordur Bjornsson. 2012-11-08 20:18:19 +00:00
c9c0a5fdbb style nit; from Tiago Cunha. 2012-11-07 21:10:32 +00:00
55edbe460d add comment why we mouse unbind, just like kbd 2012-11-07 21:04:55 +00:00
7f1851b8f6 now that we have FOREACH_SAFE queue macros, use them where appropriate;
from Tiago Cunha.
2012-11-07 21:01:48 +00:00
bd25218333 plug a leak when using 'unmap' for kbd/mouse bindings; from Tiago Cunha. 2012-11-07 20:37:55 +00:00
76b0874b4c get rid of the xfree() wrapper around free(); from Tiago Cunha. 2012-11-07 20:34:39 +00:00
dfb6aed82a clarify windowname and windowclass values are pulled from the WM_CLASS
property; from Kent Spillner
2012-11-07 14:59:07 +00:00
94db8ca2ed zap trailing space 2012-11-07 14:58:26 +00:00
438c0332a1 missing headers; from Thordur Bjornsson. 2012-11-07 14:49:46 +00:00
c53c1af2db spacing 2012-11-07 14:40:51 +00:00
4b84287d19 tab completion support for menus; from Alexander Polakov.
ok sthen@ on an older incarnation
2012-11-07 14:39:44 +00:00
dabc05034f try to clarify xprop(1) output, with respect to WM_CLASS, without going
overboard; suggested idea by jmc
2012-11-01 01:10:47 +00:00
620af2e52d no longer a reason to carry conf_path in struct conf, so dice. 2012-10-31 22:06:24 +00:00
4fb420514d replace 'reload' with 'restart', which merely re-exec's cwm using the
existing argv; same idea with respect to argv saving as Alexander
Polakov.  reload support was half-complete and is getting in the way.

agreed to by many
2012-10-31 19:30:19 +00:00
c256052308 on reload, run each client through conf_client to pick up potential
ignore and bwidth changes; also add a hack for existing maximized
windows so they don't inherit a new bwidth.

based on a diff from, and discussion with, Tiago Cunha.
2012-10-29 19:46:03 +00:00
56358be755 clarify autogroup option; based on diffs from kspillner@acm.org with
feedback from jmc
2012-10-28 20:13:02 +00:00
742bcec522 comment what this whole bit does, not just part of it. 2012-10-23 16:13:59 +00:00
710347df1b add a height to struct menu and use it in the most obvious of places. 2012-10-23 16:08:59 +00:00
637c52abf8 treat menu width the same as the height is treated when deciding its
max size and location; partially from a diff from Alexander Polakov.
2012-10-23 15:50:15 +00:00
c21d56e5a1 Stop drawing when menu doesn't fit inside the screen; picked from a
larger diff from Alexander Polakov.
2012-10-23 15:32:38 +00:00
871fdf5671 revert previous for now until a way to test more than a few encodings is found 2012-09-12 15:09:33 +00:00
637edf38d5 be explicit in which key masks we allow during keypress and buttonpress
events; from Alexander Polakov - makes non-us layout reliable.
2012-09-10 13:28:04 +00:00
3a45879d76 replace with xu_getprop wrapper used everywhere else. 2012-09-09 20:52:57 +00:00
86524e21dd extend client_resize so that it can know when to reset max flags and
bwidth; this allows a client to be resized from a max state, which now
gets treated like a non-max'd client.  based on a diff that does part of
this in a different way from Alexander Polakov.
2012-09-09 19:47:47 +00:00
7071261bde support multibyte input to menu code; from Alexander Polakov with a tiny tweak. 2012-08-07 14:05:49 +00:00
013497c79c Further simplify Xinerama init and re-init on XRR events.
While testing for Xinerama during setup was done display-wide, each time
XineramaQueryScreens() is called either in start-up or due to an XRR
event, the library re-tests for the Xinerama extension anyway before
moving on; so the initial test is redundant and allows another global to
go away with one other change: always fill in sc->xinerama (and _no),
regardless of the success of malloc in XineramaQueryScreens(), and use
it to see if Xinerama dimensions exist when asked by client and/or menu
code.
2012-07-18 21:53:22 +00:00
3f956098d9 unify various max routines to match client placement and partially menu ones
when calculating screen dimensions.
2012-07-16 01:53:14 +00:00
57af364a21 check value 2012-07-16 01:42:00 +00:00
e42d1c7f01 move the HasXinerama check into screen_find_xinerama and simplify logic;
moves closer to logic in menu code.
2012-07-16 01:36:30 +00:00
0e8815dfb0 re-use geom struct in client_ctx (saved)geometry. 2012-07-13 17:01:04 +00:00
186a78ff1e convert xmax/ymax uses to view geometry. 2012-07-13 15:21:35 +00:00
cc08aef0df introduce screen "view" area and "work" area (gap applied) to simplify
various blocks that require understanding the screen geometry.
2012-07-13 14:18:04 +00:00
2450e309ea fix atom for setting WM_STATE. 2012-07-08 02:55:01 +00:00
6faef40c55 fix atom for retrieving WM_STATE between re-exec's. 2012-07-08 02:50:41 +00:00
c8a17ef536 remove a redundant assignment and another one up. 2012-07-08 01:00:24 +00:00
cb893d0aa9 querying for Xinerama should be done per display, not per screen, so
move chuck to display init; allows some shuffling to occur limiting
screen_init_xinerama()'s scope while keeping order intact.
2012-07-06 14:18:00 +00:00
315f25f7ab Add a couple examples of keybindings using keysyms, as discussed
with okan@ and sthen@.

OK okan@, sthen@
2012-07-06 08:41:29 +00:00
1124ee5cc1 the display's width and height are updated after an XRandR event so we
don't need to pass down the new values to screen_update_geometry(); so
just read the width/height values directly for both uses of
screen_update_geometry().  prep for further changes in this area.
2012-07-05 17:35:13 +00:00
287a5b2aad assign and use screen ctx where appropriate and consistently. 2012-07-04 23:42:03 +00:00
3681b26914 use the screen ctx since we already have it assigned. 2012-07-04 18:07:12 +00:00
8c7964468f fix missing atom (WM_PROTOCOLS) wrt new style handing; without this, the
window manager didn't know if a client supported CLIENT_PROTO_DELETE and
thus used a hammer, XKillClient.

behaviour reported by Tim van der Molen.
2012-07-04 18:00:13 +00:00
f98e123bfc re-implement atom handing; makes for a normalized and more consistent
separation between cwm and ewmh.  seen by a few.
2012-07-03 13:49:03 +00:00
956c47dbeb get rid of more stray lines/spaces 2012-05-16 21:57:21 +00:00
490ef6a7df instead of using the menu window for _NET_SUPPORTING_WM_CHECK, create a
dummy one to use instead; allows us to not have to wait for menu_init(),
so re-shuffle _NET_SUPPORTED slightly.

ok sthen@
2012-05-16 01:17:14 +00:00
b4d582c6ef fix comment 2012-05-16 01:10:11 +00:00
ac82403a51 cycle through other common cycling modifiers; based on a diff from
Alexander Polakov.

ok sthen@
2012-05-16 01:09:17 +00:00
dd5bfdb064 convert from deprecated XKeycodeToKeysym to XkbKeycodeToKeysym
ok sthen@
2012-05-16 01:04:36 +00:00
57766d8606 altpersist->cycling to be more clear that this is for cycling mod
persistence; based on a diff from Alexander Polakov, in preparation for
looping through other potential cycling modifiers.
2012-05-13 15:17:13 +00:00
fb4936d0f7 knf, some from a diff from Tiago Cunha. 2012-05-13 15:15:54 +00:00
63b59e44c1 wrap long lines; from Tiago Cunha. 2012-05-10 00:39:47 +00:00
1d8839e8ad fix section order: move AUTHORS below HISTORY; from Tiago Cunha
ok jmc@
2012-05-09 18:37:39 +00:00
26c391b3dd kill useless .Pp
ok jmc@
2012-05-07 21:25:29 +00:00
fd9b83a232 check if we're in the group already, else multiple calls to
group_movetogroup() on one client will still increment nhidden if the
group is hidden.

found the hard way by Thomas Jeunet and fix from Alexander Polakov -
thanks to both!

ok oga@
2011-12-29 20:48:38 +00:00
22c2bc618b put snapdist in the correct location; as an option, not a bind; Tiago Cunha.
ok oga@
2011-11-06 02:03:47 +00:00
fded46ba9f rename variable to reduce potential for name-space collision.
bikesheding and ok oga@.
2011-10-17 18:18:38 +00:00
f60f630b81 use xfree instead of free since strings is allocated with xmalloc; from
dhill

ok oga@
2011-10-12 15:43:50 +00:00
ba3dfcf7bd move client to group (movetogroup) and hide client only if group is
already hidden (suggested behavior from Alexander Polakov).

ok sthen oga
2011-09-19 07:23:03 +00:00
22f366830e fix spelling I keep getting wrong for some unknown reason; found by and
diff from Alexander Polakov.
2011-09-13 09:17:30 +00:00
796b32123d add WM_TRANSIENT_FOR event support: moves dialogs, toolbars and such to
the group of the main application window; based on a diff from Alexander
Polakov with CLIENT_IGNORE flag suggestion from oga@.

ok oga@
2011-09-13 08:41:57 +00:00
b96caa16e6 repair groupcycle (broke after cycle-in-group support added more flags);
found by and fix from Thomas Pfaff.

ok oga@
2011-09-13 08:37:49 +00:00
82d31aec1d allow configurable menu font color; from Alexander Polakov with a tweak
from me.

ok oga@
2011-09-08 12:35:33 +00:00
a262f8e80c allow menufg/menubg to be configurable; from Alexander Polakov.
ok oga@
2011-09-08 12:07:03 +00:00
840323558d reinit menu on reload; from Alexander Polakov. needed for catching
upcoming menu config changes.

ok oga@
2011-09-08 12:00:49 +00:00
d85b3adc0c restore a comment and add another for clarity. 2011-09-05 07:37:55 +00:00
oga
44d8b1d3ac Make flavours of maximisation additive.
i.e. horiz-max + vertmax = full maximisation.  full - horiz = vertmax.
etc.

Martynas wrote something like this once, so I did okan, this version
seems to finally deal with the corner cases.

ok okan@.
2011-09-04 16:59:31 +00:00
b852a73a60 split off window hints from geometry so we don't need to carry them all
around when dealing with {,h,v}max.  same idea from oga.
2011-09-03 09:42:33 +00:00
325129c6ba simplify color initialization.
ok oga@
2011-09-03 09:25:39 +00:00
142a36a0c0 Add {r,}cycleingroup to cycle through clients belonging to the same
group as the active client (as opposed to all unhidden clients); from
Alexander Polakov, with a tiny tweak requested by oga.

ok oga@
2011-09-03 09:20:58 +00:00
b51f8e6a99 "defaultfont" is unclear (and confusing while reading code) when it also
applies to the user supplied font, so rename.

ok oga@
2011-09-03 09:17:16 +00:00
a4683b55f8 zap unused macro. ok oga@ 2011-08-29 09:10:49 +00:00
0dcf7efb8e restore mouse move via the keyboard, noticed by todd@. while the check
for cc was wrong due to the fact that cc->sc is always filled in during
the event, we don't even need it - just operate on the focused screen's
root window regardless.

ok todd@ oga@
2011-08-29 09:09:45 +00:00
oga
be3b8a0748 A while ago I wrote some code to not warp to ignored windows on map (rev
1.52), not realising that the previous (less efficient) fix had already
been commited (rev 1.50).

Had this in my tree for ages to remove the previous code. Effectively
reverts rev 1.50.

ok okan@
2011-08-22 16:34:34 +00:00
2dc8df110c revert r1.11 of parse.y and create logic in conf_setup instead to deal
with the various scenarios of when to attempt a parse of the config,
load defaults, and when to warn and/or exit.  triggered by bogus warning
first noticed by sobrado@.

ok oga@
2011-08-22 16:18:05 +00:00
912dd46a7e Re-draw borders after reloading, not before; from Alexander Polakov.
ok oga@
2011-07-26 08:51:24 +00:00
30dbdf4178 use the menu border; from Alexander Polakov, but with the existing define.
ok oga@
2011-07-25 15:41:05 +00:00
f51f3cb9c2 We are inconsistent when it comes to function returns, so just go all
the way with the cwm specific parts.

ok oga@
2011-07-25 15:10:24 +00:00
69ac0624cc Clarify defines and make them not look like non-local ones; started by a
small diff from Thomas Pfaff.

ok oga@
2011-07-23 13:09:11 +00:00
c585dfbf32 correct spelling; from Alexander Polakov. 2011-07-14 11:39:53 +00:00
3db2d84fa8 UTF8-ify, from Alexander Polakov, but without setlocale(), after
feedback from stsp@ - thanks!

'go for it' oga@
2011-06-27 12:46:54 +00:00
bcf90f5f34 warn if we can't parse the config file on start, just like we do on reload.
part of a larger diff that was ok oga@
2011-06-25 13:37:05 +00:00
0573d184f7 Since cwm(1) uses the same parser as others in src, document how
comments and line extensions work.  Taken from sthen@'s recent
commit in src.

ok sthen@
2011-06-25 13:12:56 +00:00
d8747ae702 add 'normal' cursor and shuffle the others we use to make a bit more
sense and to be slightly less un-expected.  from Alexander Polakov.
re-use 'normal' cursor now instead XC_hand1 for menu selection.  i
really wish X had real docs and made sense.

ok on earlier diff with '?' removed (but it's back now) oga@
2011-06-24 06:52:23 +00:00
8f1c583361 New option to raise a client via the mouse (unbound by default);
opposing action, lower, already exists and bound.  Both keyboard
mappings already exist.

'no opinion either way' oga@
2011-06-24 06:09:26 +00:00
34ba6cdbcc introduce a new config option to snap to the screen edge. 'snapdist'
keyword taken from a diff from Sviatoslav Chagaev to do the same thing,
but implemented in a completely way (based on some very old code from
mk@).  default set to 0, so no behavior change.

ok oga@ (who would also like to take it further...)
2011-06-24 06:06:24 +00:00
b230e611be re-do various bits of {,h,v}max for simplicity and less flag handling.
as a bonus, flipping between various combinations of vmax+hmax provides
a more predictable behavior.

commitski oga@
2011-06-24 06:01:47 +00:00
c566b31bd0 replace the non-working check to see if another wm is running with a
method that actually works.  checking for icccm compliant wm's should
also be done first, but that's another diff (noted by oga).

ok oga@
2011-06-24 05:58:51 +00:00
d39f5b9183 more nitems usage.
ok oga@
2011-06-24 05:54:30 +00:00
c8ea76a965 re-order sweep draw so that we map into the client window after
re-parenting; from Sviatoslav Chagaev.

ok oga@
2011-06-24 05:51:25 +00:00
c2a8363dd9 struct XftFont already has height which we can use directly instead of
calculating ourselves, so do so.

ok oga@
2011-06-24 05:45:57 +00:00
f6fcd0eb5d alter a few function returns and prototypes; found by lint.
ok oga@
2011-06-24 05:40:09 +00:00
69cc58555d Correct extern declaration and while here, rename a variable to be
pedantic.

from Thomas Pfaff.

ok oga@
2011-06-24 05:33:41 +00:00
89d8a14b6d collapse client and group {r,}cycle defines since they are really
the same thing.

ok oga@
2011-06-24 05:30:42 +00:00
9a6a2d3cf3 switch to installing source manuals:
* cope with new bsd.man.mk
* update imake configuration

ports use of imake remains unchanged
2011-06-23 22:48:59 +00:00
64d8bb630a fix botched client and group cycle defines; noticed by Thomas Pfaff.
"no cookie! fix it" - oga@
2011-05-15 17:58:47 +00:00
fa64bc2f32 remove left over XSync; ok oga@ 2011-05-13 12:53:19 +00:00
c8cd94882d tag and comment cleanup; ok oga@ 2011-05-11 13:53:51 +00:00
43450c8fd7 introduce a new 'freeze' flag (CMS-f by default) which may be applied to
any window, after which all move/resize requests will be ignored,
essentially freezing the window in place.

there's a possibility to merge this with the 'ignore' concept, pending
on how ignore+freeze should behave (really more ewmh stuff), but punting
for now since ponies are on the line.

requested and tested by thib at k2k11 with ponies, unicorns and rainbows.

'save the unicorns' todd@, ok oga@
2011-05-07 17:15:37 +00:00
oga
760c6b5522 On map, don't warp to windows that are marked as ignored.
Requested by Christian Neukirchen last august. He provided a patch but the one I
wrote was significantly simpler (1 - 2 + in the whole diff).

makes sense to okan@.
2011-05-06 19:39:44 +00:00
604a5d07a4 bump window resize back to 60hz. instead, we should not need to sync
every time we move/resize a window, so remove XSync in both mouse move
and resize events.  tested by Brynet as well.

ok oga@
2011-05-05 19:52:52 +00:00
8ed968601e re-org. ok oga@ 2011-05-05 16:40:37 +00:00
c62c0ee9db make the menu window aware of xinerama info; this makes the menu stay
within the current screen, like other cwm window placements and
mutations (vmax/hmax/max) - from Sviatoslav Chagaev.

ok oga@
2011-05-05 15:32:24 +00:00
349b3295b8 revert the XSync timing change for client move only; first noticed by
brynet.

sure oga@
2011-03-23 07:27:32 +00:00
5972c7a507 warp the pointer back, iff we don't move the mouse, once we are done
with the menu; idea and initial from Sviatoslav Chagaev.

discussion with and ok oga@
2011-03-22 13:50:40 +00:00
e28a7f832e we should re-focus the client and ungrab the ptr even if we don't have a
mouse based match (i.e. in the kbd no match case).  update the comment
as well.

ok oga@
2011-03-22 11:09:52 +00:00
9c587d9725 fix nousance of always highlighting the first entry even when there is
no match (seen in the ctrl-a case)

ok oga@
2011-03-22 11:05:13 +00:00
765479fc86 move the default case to the end.
ok oga@
2011-03-22 11:03:05 +00:00
a50bfb613d reduce the number of times we sync during a window resize.
ok oga@
2011-03-22 10:59:08 +00:00
2c706e60c7 introduce nitems macro, with the appropriate ifndef.
ok oga@
2011-03-22 10:57:31 +00:00
8f88cd474a if virt/horz un-maximizing, restore only the un-maximized axis
coordinates; allows moving a client and not restoring the maximized axis
coordinates.

picked from a larger martynas diff from ages ago.

ok oga@
2011-03-22 10:56:08 +00:00
9b4985439e (0,0) is also inside in the screen; from Sviatoslav Chagaev.
ok oga@
2011-03-22 10:54:42 +00:00
3ff303658c while this piece deals with client argv's in a seemingly inefficient way
(noticed by Tim Peniket), since we don't ever do anything with cliarg,
remove the hunk and cliarg completely.

ok oga@
2011-03-22 10:52:37 +00:00
a12fb346a2 remove XXX and move a configure event out of the event handler functions.
reminded by a similiar diff from Thomas Pfaff.

ok oga@
2011-03-22 10:49:46 +00:00
00b502b1da move the single keycode function directly into the menu code.
ok oga@
2011-03-22 10:47:59 +00:00
e03323d22e xcb is no longer optional. 2011-03-08 20:48:59 +00:00
64e62989d0 if we are saving the pointer location for a specific client, make sure
that if it is not already inbounds, put it in the default location,
which happens to be inbounds.

behavior noticed by Thomas Pfaff while maximizing and un-maximizing a
window, leaving the pointer behind and causing client_cycle() to be a
bit lost.

ok oga@
2011-02-13 20:09:57 +00:00
0884d38e3b we lose track of highstack somewhere, so recompute it before we need it.
fixes a crash reported by christian neukirchen.  ok okan
2011-02-13 17:25:20 +00:00
cd23316a72 in MotionNotify geom.x, geom.y calculations take into account bwidth.
fixes the annoying bug where windows would go +bwidth pixels right,
+bwidth pixels down.  ok okan@
2010-12-14 11:08:47 +00:00
111a88129d Explicitely link libxcb when needed for static arches. 2010-11-27 14:25:47 +00:00
1f310d57e2 s/-offset -indent/-offset indent/ for correct indentation,
and properly encode \(:a
found by mandoc -Tlint
2010-09-25 21:58:18 +00:00
ff3df256a1 s/\.Pb/.Pp/ for correct vertical spacing; found by mandoc -Tlint 2010-09-25 21:48:08 +00:00
dee6ac5b7d do not warp to clients marked 'ignore'; from chneukirchen at gmail - thanks.
(with the manpage bit from me).

ok oga@
2010-09-25 20:04:55 +00:00
2d66003e4b picked a henning diff from src - original log:
fix linecount bug with comments spanning multiple lines
problem reported with the obvious fix for bgpd by Sebastian Benoit
<benoit-lists at fb12.de>, also PR 6432

ok oga@
2010-09-25 20:02:58 +00:00
917bce4b8d spacing nits 2010-09-25 20:01:27 +00:00
2440efad06 revert -r1.45 of group.c (log was: fix window name and class to match
cwmrc(5)).  instead, fix cwmrc(5) to match the old behavior which also
happens to match the example config, of which many have based their
configs; this also nicely matches the output of xprop(1).

clean-up of variable names as a separate commit.

suggested by sthen (and something we should have done initially).

discussed with and ok oga@
2010-07-30 12:28:19 +00:00
aaca5b7e45 fix backwards example (after r1.45 of group.c); noticed by phessler@
ok oga@ phessler@
2010-07-23 15:13:00 +00:00
2a5e1791d4 fix window name and class to match cwmrc(5); from Holger Mikolon - thanks!
ok oga@
2010-06-28 12:29:04 +00:00
85a53083cb initialize nitems
ok oga@
2010-05-22 22:32:08 +00:00
72e6d2d0a9 replace XFetchName() with something more intelligent which attempts to
use the appropriate netwm Atom first, as well as deal with utf8.

slightly different incarnation tested by sthen@ and ajacoutot@ - thanks!

ok oga@
2010-05-22 22:10:31 +00:00
oga
a292c96977 grab events on the root window *before* we look for existing windows.
This closes a race we were hitting often where stuff started right
before cwm may not get noticed and not have borders.

ok okan@. Prompted by something todd noticed.
2010-04-12 16:17:46 +00:00
b12e6fc5cd clean up a few xu_* functions to just accept what they need (Window).
ok oga@
2010-04-11 16:51:26 +00:00
46c9b5cbae Fix formatting errors breaking the xenocara mandoc(1) build:
* .Bl may only have .It children
* .SH requires an argument
* blank lines are illegal outside literal context

Now "cd /usr/xenocara && make man" succeeds,
but unfortunately, that covers a minority of X11 manuals only.

ok matthieu@
2010-03-20 20:13:27 +00:00
507480a695 preserve labels after an edit action is aborted; extending the menu
struct just for this is the least intrusive approach until the menu code
is reviewed.

inspired by Thomas Pfaff's report on tech@

ok oga@
2010-02-10 01:23:05 +00:00
c4a97053cd Honour program-specified window position in size hints when placing windows.
Makes XMMS windows appear as expected.

ok okan, oga
2010-02-02 19:28:46 +00:00
e88bda0df5 - allow per-screen gap; not (yet) user configurable.
- teach _NET_WORKAREA about gap.

ok oga@
2010-01-27 03:04:50 +00:00
ccb207a8a8 pull all non-X11 headers from calmwm.h and place them only where they
are required.

encourged to go all the way by oga@
2009-12-15 04:10:42 +00:00
09a2d7fb98 spacing 2009-12-15 03:38:11 +00:00
b27c3c22b5 pull these headers only into files that need them.
ok oga@
2009-12-15 03:34:34 +00:00
2ad2b5f31d rid ourselves of these functional macros; convert to real functions.
ok oga@
2009-12-15 03:26:22 +00:00
597cb25820 mostly irrelevant now, so remove.
ok oga@
2009-12-15 03:25:22 +00:00
b6b7d273d4 merge the 2 common header files; specific includes to be pulled out as
separate commits.

ok oga@
2009-12-15 03:24:36 +00:00
oga
49661d405b kill _CWM_GRP atom setting. The netwm stuff does us well enough now that
it's superfluous.

ok okan@
2009-12-14 16:39:01 +00:00
oga
3b87bdb047 add _NET_WORKAREA. for now we ignore the gap, this'll change soonish.
ok okan@
2009-12-11 18:09:16 +00:00
oga
28e94b2fbc another int/long fixup that was giving dodgy property values on amd64, shame on
me for not reading xlibs (appauling) documentation more closely.

ok okan@
2009-12-11 17:57:38 +00:00
oga
a0ec2515e9 implement support for _NET_WM_DESKTOP properties on windows.
it works kinda like _CWM_GRP, which we added to aid restarts a while
ago, but it's standardised and clients are specifically allowed to set
it to request a desktop.

for noe we leave _CWM_GRP support in, but its days are now numbered.

while i'm here fixup an int/long mixup with an earlier diff.

ok okan@
2009-12-11 17:55:42 +00:00
oga
b35cbf81d8 Implement _NET_DESKTOP_NAMES, this one was a bit tricky since thespec
says that a pager can change the property at any time (most need a
clientmessage). So deal with property updates.

Needed to shuffle some of the other code around since we can't just use
shortcut_to_name[] everywhere now.

ok okan@
2009-12-11 17:51:42 +00:00
oga
9b04930f24 Implement _NET_VIRTUAL_ROOTS (just clear it, we don't use that technique)
and _NET_SHOWING_DESKTOP (we're never doing so right now).

only three informational root-window hints to go.

ok okan@
2009-12-10 23:21:26 +00:00
oga
a7c3a7cac3 Implement _NET_CURRENT_DESKTOP, _NET_DESKTOP_VIEWPORT and
_NET_DESKTOP_GEOMETRY.

ok okan@
2009-12-10 23:14:58 +00:00
oga
134e777cf0 finish unfucking the screen_ctx handling.
remove screen_current() it was utterly bogus when nscreens > 1.

pass a fake client_ctx in the case where there's no client and the
kbfunc or mousefunc doesn't need a real one, it just contains the
current screen, modify these functions so that they pass down the screen
context to their callees.

make groups per screen, it's the only way it makes sense in this regard.

ok okan@.
2009-12-10 17:16:51 +00:00
ee7df6a95f start fixing screen_ctx usage, for it is utterly broken. bring font
into screen_ctx and start passing screen_ctx around to in order get rid
of Curscreen; fixup per-screen config colors the same way.

diff mostly from oga@, with a bit harsher reaction to the state of screen_ctx.

"please commit" oga@
2009-12-08 16:52:17 +00:00
oga
aa88d5848e Implement _NET_NUMBER_OF_DESKTOPS, currently this is statically 9 and
unchangable. the group code needs some cleaning up before this will be a
bit less hackish.

ok okan@
2009-12-07 23:19:51 +00:00
oga
728d2a40dd support _NET_CLIENT_LIST.
the x property api doesn't let you remove one entry from an X property
array, so client_remove is kinda expensive, but there's no real way
around that..

ok okan@
2009-12-07 22:46:15 +00:00
oga
3c60d854db Implement _NET_ACTIVE_WINDOW. for now just the informational hint is
supported, the client message to change this will be supported when all
informational hints are working.

ok okan@
2009-12-07 22:21:59 +00:00
3e309894c1 introduce the beginnings of netwm support, minimally and correctly;
allows java to be happy, but additionally stops others from whinning
about a non-netwm complaint wm.  more to come.

written a few times; this one includes a clever hack from oga@ to
populate _NET_SUPPORTED.

ok oga@
2009-12-07 21:20:52 +00:00
46630531f8 fix off-by-one where a mere click would select the first item inside a menu
from Thomas Pfaff

ok oga@
2009-12-07 19:48:08 +00:00
ab4d36531c we already have sc from the passed cc, so just used that instead.
ok oga@
2009-12-07 19:45:36 +00:00
892e1e1c0d be consistent
ok oga@
2009-12-07 19:44:31 +00:00
4e2014863b remove unused extern
ok oga@
2009-12-07 19:42:59 +00:00
42bf29fb20 style (whitespaces)
ok oga, okan
2009-11-28 17:52:12 +00:00
afaf69cefc Corrected grammar in comment.
ok (and better style suggestion by) oga, okan
2009-11-22 21:38:50 +00:00
oga
85d8697676 With Xinerama enabled, the borders of a maximized window will show up on
all adjacent screens. This patch hides the borders while the window is
maximized.

From Bertrand Janin; thanks!

ok okan@
2009-09-25 15:57:49 +00:00
4af6a60d84 re-introduce the intention of the change from rev 1.4 in menu.c here
instead, by moving the check for '\0' to only the places that it
matters.  hint and 50% of the diff from oga@, prodded by todd@

ok oga@
2009-09-05 16:06:15 +00:00
38ad2e1d9c style
ok oga
2009-09-05 14:10:11 +00:00
7295c51155 unroll the CCTOSC macro; from Thomas Pfaff
ok oga@
2009-08-27 01:38:08 +00:00
b9f8367089 static; ok oga@ 2009-08-25 12:05:11 +00:00
0a44f2e5c4 we are not doing access control here, so replace the "check if file is
executable" goo with access(2).

originally from jacekm@ long time ago.

"i can live with that" oga@
2009-08-25 02:02:59 +00:00
oga
1968561fcc Reduce duplciation of code for checking modifiers in key/mouse bindings.
shaves a bunch of bytes.

ok okan@
2009-08-25 01:44:39 +00:00
oga
95f65b8be6 Instead of calling conf_bind*() 50 gazillion times in a row, store an
array with all the parameters in and just loop over that to setup the
default keybindings - it's so much easier to read.

okan@ "love love love"ed this
2009-08-25 01:42:05 +00:00
oga
8fd4ff1c7c Instead of messing around everytime we do a resize, just clamp the
resize increments to a minimum of one, and use it unconditionally.

"you've convinced me, do it!" okan@
2009-08-25 01:32:40 +00:00
fcb2684db1 unroll macro; ok oga@ 2009-08-25 01:26:09 +00:00
oga
e2b1cb98c1 Add a keybinding to allow horizontal maximisation of a window (CMS-enter).
based on a diff by Thomas Pfaff; thanks!

ok okan@
2009-08-24 23:54:41 +00:00
028a1778db bring together gathering, calculating and applying of size hints;
additionally, respect aspect ratio hints.

ok oga@
2009-08-24 23:49:04 +00:00
oga
09d88f4a18 Instead of having a function that just calls TAILQ_INIT on a global, use
TAILQ_HEAD_INITIALIZER() and drop the function.

ok okan@
2009-08-24 21:22:48 +00:00
oga
e7f0d63413 instead of checking for flags in the client context, then removing them.
e.g.:

if (flags & flags_we_care_about)
	flags &= ~(flags_we_care_about);

just whack the flags unconditionally, it's simpler.

okan@ agrees.
2009-08-24 17:04:39 +00:00
82911249e2 remove unnecessary Ar macros
ok jmc@
2009-08-08 17:27:51 +00:00
e095e955a8 remove unnecessary Dq macro; based on a diff from Martin Toft
feedback and ok jmc@, martynas@
2009-08-08 00:25:52 +00:00
oga
590eb4f37b use fnmatch to glob the entries in the exec menu.
allows shell globbing constructs such as *ctl, etc in the exec menu (m-?
by default).

Adapted from a diff from Thomas Pfaff, okan@ got almost the same diff as
me when reworking it, and oked this one.
2009-06-26 12:45:12 +00:00
f44862be9c static local functions and data; almost identical diff from Thomas Pfaff
ok oga@
2009-06-26 12:21:58 +00:00
b13d592c57 tidy up startup/init routines
ok oga@
2009-06-23 21:52:38 +00:00
bcc0f73bb6 compact a bit by condensing a few if-else's; from Thomas Pfaff
"go on then" oga@
2009-06-20 00:55:41 +00:00
58d12134b1 unroll XCALLOC/XMALLOC macros; since we use xcalloc/xmalloc all over the
place anyway, this makes things a bit more consistent; from Thomas Pfaff

ok oga@
2009-06-20 00:22:39 +00:00
18c7d89c98 spacing 2009-06-20 00:19:56 +00:00
ee59e4a5a1 `exec'' and `ssh'' are lowercase.
ok martynas@
2009-06-19 10:43:49 +00:00
055b244bb4 items on the first list should have full stops too.
ok martynas@
2009-06-18 20:44:40 +00:00
71ad069846 the on-line manual should use the same notation for key bindings
as the configuration file, this way writing configuration files is easier;
add a few missing interactive command (.Ic) macros to key bindings;
slightly improve spacing in the lists; other tweaks.

ok martynas@
2009-06-18 20:24:54 +00:00
11b4b7fec6 remove unnecessary casts; from Thomas Pfaff
ok oga@
2009-06-17 13:08:37 +00:00
61f841ea58 re-factor parts of mouse move/resize bit to shrink and make more
readable; no behavior change

ok oga@
2009-06-17 12:45:01 +00:00
d7589ca80b move like defines to a central, logical location; no binary change.
aok oga@
2009-06-17 12:30:17 +00:00
3eec3b3802 'no' is the answer to the comment question: cc->name can't be NULL at
this point due to client_setname()'s work; remove this check.

ok oga@
2009-05-30 00:30:27 +00:00
d1b84c5415 re-order a bit for readability.
"if it makes you happy" oga@
2009-05-30 00:30:17 +00:00
6e9fa7548b revert the 1.4 change - causes a double free noticed by grange@ a while
ago while using kazehakase (or clients that don't set a name).

ok oga@
2009-05-30 00:29:08 +00:00
8bbc376fd9 In movetogroup, check the window's current group and skip client_hide()
if it's the same as the active group. Was in my original movetogroup diff,
but it got simplified a little too far.  ok oga@
2009-05-19 12:49:37 +00:00
2c29a1de65 nuke the leading underscore notation for local static functions - there
are far better ways to know.

"go for it" oga@
2009-05-18 00:23:35 +00:00
oga
d2cfeb40b4 oops, we appear to have grown an extra prototype for group_only(), get
the secateurs out.
2009-05-18 00:17:46 +00:00
oga
382662d003 Rip out the event layer and just use a static array of callbacks like
every other window manager since twm.

The event layer is very nice, very shiny, very flexible, and very much
underutilised. We don't need any of those shiny features so it's
probably better to earn ourselves 1k smaller text size instead.

ok todd@, okan@
2009-05-18 00:14:19 +00:00
9be7726606 redraw all borders at once on reload
"sure" oga@
2009-05-17 23:54:17 +00:00
4d5dc5d9ea a long time coming - re-work the way we deal with colors: since we're
using Xft(3), use it to select the font color as well instead of trying
to build one; properly allocate and free colors at-will, e.g. we now
have configurable colors.

feedback and ok's todd@ and oga@
2009-05-17 23:40:57 +00:00
5d51c8e0e5 minor bit of knf, just to be consistent; oga@ doesn't mind that much 2009-05-17 23:37:52 +00:00
4c10afe2cc unbreak 2009-05-17 22:48:47 +00:00
eb7803269e add a "movetogroup" function, which hides the current window from
display and moves it to another group. useful with the recently added
"grouponly" function, giving the ability to use groups as simple
virtual desktops (similar to e.g. xmonad, dwm and scrotwm).

this doesn't have default keyboard bindings; cwmrc(5) now shows how
you could use these functions (use M-1...9 for grouponly1...9 and
MS-1...9 for movetogroup1...9 to emulate the default dwm bindings).

ok oga@
2009-05-17 17:04:59 +00:00
6df7cba24e redraw the border when unhiding a client window. fixes the situation where
you change to a different group and the mouse isn't over a window; previously
the border of the previously active window was highlighted but it didn't
actually have focus.

reads ok to oga@.
2009-05-17 16:51:43 +00:00
oga
29cdc29c6e add missing prototype. 2009-05-14 16:29:58 +00:00
oga
3de90d44fc Add a new command (currently no default keybindings for it), grouponly[1-9].
This works like the group select binding, but hides all other groups.

So, the people who've been complaining that they don't get "virtual
desktops" in cwm may want to try this out in cwmrc (from memory, untested):

---

#cwmrc

# add new windows to the current group
set sticky

# automatically sticky windows. xclock for now.
# to make more windows sticky use group_toggle to unset their group
autogroup 0 xclock

# make the group selection keys hide other groups, emulate virtual desktops
bind CM-1 grouponly1
bind CM-2 grouponly2
bind CM-3 grouponly3
bind CM-4 grouponly4
bind CM-5 grouponly5
bind CM-6 grouponly6
bind CM-7 grouponly7
bind CM-8 grouponly8
bind CM-9 grouponly9

---

mostly by sthen, tweaks from me.

ok todd@, "if it works i'm ok with it" okan@, ok sthen@
2009-05-14 16:24:04 +00:00
fbb1edf2b3 right and middle mouse buttons swapped; from rgouveia@cosmico.net 2009-05-04 22:01:35 +00:00
64f0038db7 no need to use the global here.
ok todd@ oga@
2009-05-04 19:13:33 +00:00
4f34392258 properly document menu_unhide; tweak a patch from rgouveia@cosmico.net - thanks.
ok oga@
2009-05-04 18:05:21 +00:00
655c33c489 fix the other 50% of xrandr cases; reported by sthen@
"commit that" oga@, ok sthen@
2009-05-01 17:50:20 +00:00
cc68490fe1 don't sync more than 60 times per sec on resize and move; idea from scrotwm.
ok oga@ sometime ago
2009-04-15 14:10:07 +00:00
ea96e92ac8 properly teardown X connection upon quit; static a few while here,
requested by oga@

ok oga@ sometime ago
2009-04-15 14:01:45 +00:00
8a490fc270 we include sys/param.h, so remove sys/types.h; sort while here.
ok oga@
2009-04-12 23:51:10 +00:00
8346de997f - avoid shadowed Mask declaration in menu_filter
- make _xev_reincorporate static
evmask naming oga@, input okan@.  ok okan@, oga@
2009-03-28 16:38:54 +00:00
17ae65adc5 add 'moveamount' to cwmrc; it sets keyboard movement amount, making
it more useful on large screens
manpage tweak & ok jmc@
ok okan@, oga@
2009-02-07 21:07:00 +00:00
507b65a27f remove leftover from mdoc.samples; ok jmc@ 2009-02-07 16:59:11 +00:00
4fe12f528c fix off-by-one in geom.[xy], after pwin changes. keyboard movement
to the rightmost or bottommost corners would confuse cwm:
- there's no way to get the window back
- tab cycling breaks
ok okan@, oga@
2009-02-03 22:20:31 +00:00
6ad198022b remove Nscreens and x_screenname() - we really don't need them.
ok oga@
2009-01-27 02:16:20 +00:00
oga
c750462d13 One of the most annoying things to do was restart cwm and lose all of
your group state. Fix this up by using an X Atom (_CWM_GRP) to store the
name of the group that we're using (the name, not the number is because
at one point we may make the group numbers dynamic). I've been talking
about this since c2k8. so CM-w means you keep all of your windows grouped
properly.

ok okan@, todd@
2009-01-27 00:42:53 +00:00
9203c7e8ca passing a null pointer to free() is valid; sprinkle a few free->xfree.
ok oga@
2009-01-23 20:47:45 +00:00
oga
b23cef2e4a Whitespace nit.
pointed out by okan.
2009-01-23 20:07:20 +00:00
oga
01af04a342 Switch to using XInternAtoms for caching the atom numbers. Saves a pile
of function calls and server roundtrips.

ok okan@
2009-01-23 20:04:30 +00:00
7660bf0db0 move conf_clear() and add proto.
ok todd@ oga@
2009-01-23 19:00:59 +00:00
oga
779177a53d Move the keybinding argument to a union to prevent warnings where
sizeof(int) != sizeof(void *). This has been annoying me for ages.

ok okan@, todd@
2009-01-23 18:58:40 +00:00
87964e5c7e now that pwin is gone gone gone, we no longer have to do the bwidth
dance; xevents now able to deal with a border being set (which fixes
those annoying movie-watching apps).

ok todd@, oga@
2009-01-22 19:01:56 +00:00
oga
e239976078 The default font name is strduped, so don't test for default font name
(therefore leaking it) when cleaning up a conf struct.

ok okan@
2009-01-22 18:16:38 +00:00
oga
712f3f62c7 Oops, missed an atom.
ok okan@.
2009-01-22 18:06:16 +00:00
oga
e2f3810fe8 Cache all of the X atoms we use at startup.
Do this instead of querying for them every time we use them. This
removes an XXX that has been in there since time began. This will become
more important as we move towards supporting netwm.

ok todd@, okan@.
2009-01-22 15:26:33 +00:00
1b269199c1 borderwidth as a cwmrc(5) keyword, really helps debugging
from okan@
ok oga@
2009-01-21 15:04:38 +00:00
0548673f2f library dependency ordering matters for static archs, -lXext last in this case
from matthieu@, verified on vax
2009-01-19 20:23:19 +00:00
bd4c4d7734 remove unused
ok oga@
2009-01-17 20:39:24 +00:00
oga
fa87ef4a9e Finally fix the really annoying race where if you rapidly switch groups several
times you'd end up losing clients (thinking they had gone away).

From the ICCCM (which should not be read without a stiff drink in hand,
I made this mistake so you don't have to): to request a window to be
withdrawn one should send a synthetic UnmapRequest event when iconified.
To request iconification one should just unmap the window. The ICCM
further recommends that the synthetic event should just be taken as a
cue to withdraw, to deal with legacy clients. Taking a hint from this,
rework xev_handle_unmaprequest to correctly detect these situations.  A
Withdrawn window may come back anywhere, even as a subwindow of
something else, so the correct way to handle this state is to forget it
ever existed.

While i'm here, kill a dumb attempt to notice this in client_delete, and
nuke the very unnecessary arguments.

Todd confirmed this fixes the `race'.

ok todd@, ok ok okan@
2009-01-17 18:41:50 +00:00
399253a4ff revert just the 'race fix'; more works needs to be ironed out with
events and state.

agreed by oga
2009-01-16 16:49:17 +00:00
ec8e6052ba remove pwin, bringing us to one client, one window. we no longer have
to push attributes around, so things get a lot simplier, while fixing a
few issues in the meantime; original suggestion by Edd Barrett many many
moons ago.

annoying window placement and race, found in c2k8 by todd, fix by oga!

lots of feedback from todd and oga - thanks!

"commit that bad boy" oga@
2009-01-16 15:24:14 +00:00
oga
5c757cc7f4 On startup, don't leak memory when we enumerate existing windows.
The behaviour until now was to ask X for the windows name (which is
malloced) then drop that on the floor and do nothing with it. Skip this
foolery and just skip the window. I don't believe I never noticed this before!

"you can has ok" okan@
2009-01-15 17:23:12 +00:00
49e218cf53 - add missing prototypes.
- properly name, place and static private functions.
- move function which finds the xinerama screen for a coordinate to
a more appropriate place while altering its semantics to match others.
- tiny bit of style.

ok oga@
2009-01-15 00:32:35 +00:00
7e110f379b better cast; noticed by ray@
ok ray@ oga@
2009-01-13 15:25:43 +00:00
oga
c07123ec78 Add -Wall to CFLAGS, it's helped find a few dodgy constructs.
ok okan@.
2009-01-11 21:48:27 +00:00
oga
d1050afb60 shortcut_to_name should not be defined as static in a header file. Put
it in group.c where it it used most, and add an extern definition for
the other users of it.

Found by gcc -Wall. ok okan@
2009-01-11 21:46:48 +00:00
dcfae161a2 add missing prototypes
ok oga@
2009-01-11 21:34:22 +00:00
0aca400461 better comparison idiom; found with -Wall
ok oga@
2009-01-11 21:33:45 +00:00
590169ce24 - merge grab_sweep() into mousefunc_window_resize().
- merge grab_drag() into mousefunc_window_move().
- properly name, proto and static private functions.
- since we already do XMoveResizeWindow() and XMoveWindow() in (now)
mousefunc_window_resize() and mousefunc_window_move() respectively,
client_resize() and client_move() calls are unnecessary.

ok oga@
2009-01-11 18:34:46 +00:00
99afa5091f FcNameParse() manpage lies, cast here.
found with pcc.

ok oga@
2009-01-11 18:32:08 +00:00
b47283ab41 remove unused variables
ok oga@
2009-01-11 18:25:49 +00:00
oga
b523788c0e If the mousebutton is unknown when we go to grab, don't just print a
warning, but also skip the XGrabButton call. Noticed by code inspection
by okan@, but we agreed my fix was cleaner.

ok okan.
2009-01-08 21:35:19 +00:00
ee0ec9a453 remove "search should ignore the current window" from list, for the
current behavior is better...

ok oga@
2009-01-06 00:41:09 +00:00
d2a54bc115 HasXinerama is an int
ok oga@
2009-01-06 00:19:55 +00:00
841c646a2b remove unused code
ok oga@
2009-01-06 00:18:07 +00:00
oga
25af744559 Kill obviously dead variable. 2008-12-04 23:55:04 +00:00
oga
be5dfb4ea4 Don't ignore sigpipe. Everytime cwm forks it execs anyway (so it
shouldn't get that signal), and this causes problems for our children
since they inherit the ignore.

Pointed out by Jacek Masiulani in pr 6010; thanks!
2008-12-03 23:55:46 +00:00
oga
a0739c6cd4 Xinerama and XRandR dual head support for cwm(1). Now we detect the xrandr
reconfiguration events and change our sizes depending on that. We also detect
the xinerama screens for maximize, vertmaximize and initial window placement.

This could be improved by automatically resizing maximized windows when
the screen resolution changes and by moving windows that would be hidden
into visible space. Said changes will come shortly.

Tested by many. matthieu@ didn't oppose.
2008-09-29 23:16:46 +00:00
oga
e2610449d1 .Bl needs a matching .El. From Martin Toft a while ago, thanks! 2008-09-22 14:37:12 +00:00
oga
2bd5e53c2e Improve wording of the ``ignore'' directive. From Martin Toft a while
ago, ok okan@ from similar amount of time ago.
2008-09-22 14:35:16 +00:00
oga
60a88f54cc *sigh* Revert the diff that wasn't meant to go in yet.
note to self: When you mean to type cvs commit search.c, don't forget
the filename.
2008-09-22 14:28:04 +00:00
oga
61601991b5 Display the current window title not a previous one in the case of
``show all'' in the window search dialogue. Noticed and diff from Tim
van der Molen, thanks!
2008-09-22 14:15:03 +00:00
a0082c58a4 Keep the exec menu entries sorted.
Go for it okan@
2008-09-03 04:39:12 +00:00
oga
04441482d4 fix the froggy problem.
Implement a handler for the MappingEvent, meaning that the keymap has changed.
When this happens, ungrab all bindings, update the map, and regrab.

Fixes the problem where some keybindings wouldn't work under non us or
uk keymaps (especially the .fr map, it seems). Issue noticed by
ajacoutot@, ratchov@, and a few people on misc. Based on an initial diff
from ratchov@.

ok okan.
2008-07-22 21:01:54 +00:00
oga
0df9e0673c We've been handling grabbing wrong all this time (noticed at c2k8).
add conf_grab() and conf_ungrab, and use them in the keybinding manipulation
functions to {,un}grab the binding for all screens we have defined.

the lovely little ordering problem comes in here, since when we parse
the config initially Screenq is empty, so regrab after we fill the
queue, hopefully later reordering will remove this little need and there
will be much rejoicing.

ok okan.
2008-07-22 20:51:54 +00:00
oga
436a9e5c54 split x_setup() into two. dpy_init() for setting up the display and
checking the X config, and x_setup to set up the screens.

There's an ordering problem that means that some of this init needs to
come after the config is parsed, the rest should ideally happen before
though. This is a rough split, it will be refined later. Again, needed
for an upcoming change.

ok okan.
2008-07-22 20:42:24 +00:00
oga
20052e0248 Add xu_key_ungrab() and a mirror to xu_key_ungrab(). a couple of changes
that are coming up depend on it.

ok okan.
2008-07-22 20:26:12 +00:00
oga
13b640ea29 Kill screen_init(). it's been stubbed out for a while now. I don't envision it
coming back in it's current form.

ok okan@.
2008-07-22 19:54:57 +00:00
oga
2f8639d37b kill another leftover prototype.
ok okan@
2008-07-22 19:52:54 +00:00
oga
556f7a0871 Put back the initialisation of gc in group_cycle. No cookie for okan.
Reported by Dan Harnett, thanks!
2008-07-18 15:40:52 +00:00
2798cdc9a7 move client_vertmaximize to a more sensible location, purely for readability.
"don't mind at all" oga@
2008-07-15 22:12:09 +00:00
8afabd6c55 save an X call and use what we already have stored.
ok oga@
2008-07-15 22:06:48 +00:00
96f03c8cbc don't compensate for bwidth twice.
ok oga@
2008-07-15 13:52:02 +00:00
6d268bfa4a Nm makes more sense than Xr, from Pierre Riteau - thanks! 2008-07-11 22:43:44 +00:00
oga
b6dab5ccf3 Change "a window" to "current window" in documentation. it's more correct.
While i'm here: Capital letter and full stop in descriptions in cwmrc.5

"looks good - do it" okan@.
2008-07-11 15:42:29 +00:00
a556d3fa1f add Xr for cwm(1) 2008-07-11 15:20:04 +00:00
6ea4b1bd3b no more hidden (and mysterious) config reloads and allow binding a key
to a config reload; CMS-r by default.

ok oga@
2008-07-11 15:18:29 +00:00
8be175b175 replace snprintf with strlcpy
ok oga@
2008-07-11 14:24:34 +00:00
85e6c61360 we already have ymax, so use it instead of asking X for it again.
ok oga@
2008-07-11 14:23:30 +00:00
b23fad3987 spacing, declaration lineup to be consistent throughout cwm,
readability, and a bit of knf.

ok oga@
2008-07-11 14:21:28 +00:00
734f45ab4b only cycle through visible *and* non-ignored windows.
ok oga@
2008-06-30 17:52:37 +00:00
oga
993fd4311f Allow a mouse binding to hide a window, and add a default keybinding for CMS-M3,
so it's hard to press by accident, but there if you need it.

requested (in a way) and tested by johan and todd.
2008-06-25 22:44:42 +00:00
oga
a6ec6cd9e9 Support mod4 (windows key) in mouse bindings too. 2008-06-25 22:40:27 +00:00
oga
05b17bf803 Support shift in mouse bindings. There's really no reason not to.
tested by johan@ and todd@.
2008-06-25 22:38:36 +00:00
oga
2dfd021f8b Actually grab the correct mouse buttons for a window, instead of doing the
old hardcoded ones (which now can be wrong).

tested by todd@ and johan@.
2008-06-25 22:37:29 +00:00
oga
77058c59e2 Sort flags.
From Pierre Riteau, thanks!

ok okan@.
2008-06-25 01:09:09 +00:00
oga
187e7dfad2 Stop keyboard move moving the window utterly off the screen. If that
happens there's no way to get it back.  Also, stop resize making a
windows size negative or zero. X does not like that one bit.

Diff from Martynas. Ok okan@.
2008-06-25 00:52:47 +00:00
oga
6f1ed5bfe3 Don't link "-lX11 -lXau -lXdmcp" twice.
From Martin Toft, thanks!
2008-06-19 02:21:30 +00:00
oga
e21e7680e4 No need to map/unmap the window on hide/show since we already do the
same to its parent.

"makes sense" okan@.
2008-06-18 20:42:29 +00:00
oga
2bddbe12f4 Revert previous "fix" it introduces new issues of its own.
The problem that's causing us to lose windows is that rapid hiding and
unhiding causes a backlog of X events, so we lose track of client state,
and delete cc->pwin when we should not. A proper fix will arrive when it's been
worked out.
2008-06-18 19:09:12 +00:00
0ba60f0b94 missed one mouse function
noticed by oga
2008-06-17 23:46:49 +00:00
oga
4f2d4724c9 Ignore caps lock and numlock for keyboard bindings. The way Xlib makes
you do this is ugly. Also remove mod2 (numlock) and mod3 (odd) from the
list of keybinding modifiers. They don't make much sense here.

based on a heavily modified diff from Martynas.

ok okan.
2008-06-17 23:40:33 +00:00
oga
19ba704ee3 Just rework the mouse binding calculation on event to look like the
kbfunc one.  Makes the code a lot easier to read.

Fixes a bug i introduced in the last commit here.

ok okan.
2008-06-17 20:55:48 +00:00
oga
9657664c7b The mousebinding code missing a break once it had found the correct
binding, this expose another issue that's still being debugged.
Issue pointed out by Dan Harnett, thanks!

While i'm here KNF and rework the logic to not be ass-backwards.

ok okan.
2008-06-17 20:21:17 +00:00
mk
867652c484 Make this not crash when compiled with -g.
Found by myself, analysis by kurt@, fix by me with input from otto.

``Just get some fix in...'' deraadt
2008-06-16 19:09:48 +00:00
oga
07cd0b1ac5 Rip out and burn the HASH_* stuff. We don't need a SPLAY tree for one font.
makes the code a lot simpler. While here rearrange the font handling functions
to be less shit.

ok and help okan@.
2008-06-15 02:47:46 +00:00
96d7310b4a (mostly) proper xshape event support
ok oga@
2008-06-14 22:04:11 +00:00
160228210b unbreak 2008-06-14 21:59:09 +00:00
9d9c61b8f6 slightly alter the semantics of config files:
- if no config file, continue silently and apply defaults
 - if config file, parse and move on
 - if config file specified but not found, error out

ok oga@
2008-06-14 21:51:00 +00:00
bdcbbe7f53 confable menu and window mouse bindings from rivo nurges (thanks!) with
some minor fixups, man page bits and knf.

ok oga@
2008-06-14 21:48:54 +00:00
b4ae492b7b finally document functions that can be bound, removing the need to have
name_to_kbfunc[] around.

feedback jmc@, ok oga@
2008-06-13 21:22:34 +00:00
oga
01eecac5d4 Don't client_delete() on an Unmap event, only do that on a client delete event.
found by (among others) todd@ when you have a lot of clients and do something
that maps and umaps a lot of windows fast.

Debugged with aid of gdb, todd, okan and NULL pointers in a pizza place in
edmonton while waiting an inordinately long time for food.

ok okan@, todd@
2008-06-13 03:41:58 +00:00
077173527b kill another long gone proto 2008-06-12 19:10:56 +00:00
ff9e573e1d remove old (moved) code
ok oga@
2008-06-12 18:55:35 +00:00
198bb381a9 instead of forcing the ptr in the middle everytime, be more 'calm'; keep
the ptr still unless it moves out-of-bounds, then just follow the edge.

brought up by todd@

ok oga@
2008-06-12 18:32:06 +00:00
6f1f3592d4 place the pointer in the middle of the window after resizing with grab,
just like keyboard resize.

from Edd Barrett

ok oga@
2008-06-12 05:10:24 +00:00
78c8bf08cb ignore if non-zero expose events, for we could be covered by multiple
windows; merely an optimization.

ok oga@
2008-06-12 05:01:13 +00:00
4377b5ac3f re-work client_placecalc()
- make sure new clients sit inside the current screen
- respect 'gap' placement on new clients

ok oga@
2008-06-12 04:59:51 +00:00
9037043088 Enter -> Return, to be consistant and correct.
found the hard way by johan and discovered by oga.

"do it" oga@
2008-06-05 14:29:01 +00:00
610e8e83ac prevent trying to exec a null char; could potentially happen with a
canceled or empty searchstr.

ok oga@
2008-06-05 04:01:37 +00:00
efbfc5fa42 actually honor termpath and lockpath if specified in cwmrc.
"now" oga@
2008-06-05 00:07:05 +00:00
b86d3cfae9 "Meta is a perfectly well defined concept in X (The keys bound to the
Meta_L or Meta_R keysysm).  no need to redefine it roughly there" - matthieu@
2008-06-03 21:27:47 +00:00
72bc2a295b make sure to take bwdith into account when placing a new window.
ok oga@
2008-05-23 18:57:35 +00:00
oga
48528d9ba1 Grab the keyboard when we initialise the menu. This stops the keyboard
shortcut code stealing our events in some cases.

"put 'er in" okan@.
2008-05-23 18:48:57 +00:00
oga
779cf04f05 Make menu_filter handle mouse movement too. This enables the keyboard
search dialogues to be manipulated with the mouse, too. It also allows
me to shrink the codebase further by killing grab_menu().

One known issue with highlighting the first entry in a search dialogue,
that'll be fixed soonish.

ok okan@, tested by Edd Barrett and todd@.
2008-05-21 14:11:19 +00:00
oga
1e46ba72f7 Pull out the behaviour in grab_label and search_start into one utility
function menu_filter(). The plan is to eventually merge in grab_menu too.
Shrinks the code a fair bit.

Also, change XMaskEvent for XWindowEvent to prevent getting exposes for other
windows. This is particuarly noticable on slow machines with a LOT of xterms
(todd, you're an odd man).

ok okan@, todd@.
2008-05-20 14:50:51 +00:00
oga
3bb0b451f7 General cleanup.
ok okan@.
2008-05-19 18:53:09 +00:00
53116c4ec3 stop normalizing search input; searching and matching are still
case-insensitive.  since this was the only use of normalizing input,
simplify as well.

allows one to exec with mixed case unmatched commands.

"works for me" oga@
2008-05-19 18:07:53 +00:00
oga
981c2480db Function prototypes should not have parameter names in them. These must
have been missed last time i knfed this.

ok okan.
2008-05-19 17:32:22 +00:00
6733ac217f client_cyclenext() -> client_cycle() since we now pass an arg.
removes a stray proto as well.

discussed with and ok oga@
2008-05-19 17:24:19 +00:00
oga
71f99ab78f allow an autogroup value of 0 to mean no group. This means you can set
automatically "sticky" (in the traditional sense of the word) windows in
autogroup mode.

Based on an initial diff from Andrew Fresh, thanks!

ok okan@.
2008-05-19 17:13:55 +00:00
d347aa3d9a as done with cycle/rcycle, make prev/next group switching one kbfuncs
and use a flag; adjusted to match and rename to {r,}cycle.

"ok, since i came up with the same thing" oga@
2008-05-19 17:11:19 +00:00
oga
43d6e147c2 Use the XGrabKeyboard hack in for alt-tabbing as well. This stops the
mru getting the order messed up when gvim/xpdf et all steal key events.

While i'm here, change the logic in client_cyclenext() to use break instead
of goto, it's nicer that way.

Thirdly, instead of two different kbfuncs, just use the one and a flag.

"put your cycle diff in so I can pkg_delete gvim" okan@
2008-05-19 15:17:50 +00:00
7957a470fd finally implement keyboard binding for group toggling
idea for the
    "slightly-less-abhorrent-hack-but-a-hack-nonetheless-TM" from oga@

grab and ungrab the keyboard to get around some silly X apps that like
stealing events

ok oga@
2008-05-19 12:56:58 +00:00
a94f4bbb7a send the correct x/y coordinates to XConfigureWindow()
fixes some windows that seem as if they don't fit; noticed by Edd Barrett.

ok oga@
2008-05-18 20:06:36 +00:00
5a0128bdc7 remove extra calls to client_draw_border()
ok oga@
2008-05-18 20:00:16 +00:00
5fee379cb5 fix backwards logic in example; found by oga@ 2008-05-18 19:57:43 +00:00
oga
b700be764a Fix two problems with conf_unbind():
1) it used TAILQ_FOREACH() when it's removing entrys from the list, this
   is bad.
2) We didn't free key, so there was a small memleak too.

also rework conf_bindname's logic slightly to be more simple.

ok okan@
2008-05-18 19:47:19 +00:00
oga
27b023ebcb Kill conf_get_int(), it was a silly function anyway.
Since it's only used once just put the (simplified) logic into
conf_client() instead. This  means we can kill an enum and
CONF_IGNORECASE, too.

ok okan@
2008-05-18 19:43:50 +00:00
oga
5c402536fa group_ctx->name is only used in this one function, and for now it
corresponds directly to the static list of group names. Just use the
static list and stop strdup()ing a new version for the context struct.
Since that never got freed this also fixes a small memleak.

Kill some unused variables while i'm here.

ok okan@
2008-05-18 19:38:18 +00:00
oga
a21a064a9b When we're cleaning out the lists in parse_config and conf_clear it's a
lot simpler just to do while (entry = TAILQ_FIRST(head)) than to do a
for () over the whole lot. Simpler, shorter and probably faster.

ok okan@
2008-05-18 19:34:09 +00:00
0f50af616e - re-order and mostly re-write cwmrc(5)
- merge example config file into cwmrc(5) and remove (little good in here)

feedback from jmc@ - thanks!

ok simon@
2008-05-18 19:33:36 +00:00
9a58e74401 fix cwm's current XShape support from Edd Barrett -thanks.
XShape events should be handled at some point.

ok oga@
2008-05-17 03:59:54 +00:00
oga
5034a77849 KNF, no binary change.
From Pierre Riteau. Thanks!
2008-05-15 22:18:00 +00:00
ec77265b87 tiny bit of knf
ok oga@
2008-05-15 21:56:21 +00:00
458f96936d Signal handler of SIGCHLD calls waitpid() which sets errno on error. To
avoid clubbering of errno in normal context, save_errno got introduced.

ok oga
2008-05-06 15:12:04 +00:00
oga
cd0ce46817 Rework the alt-tabbing code to be a lot simpler.
Diff mostly from Edd Barrett, with some minor changes from me.
Unfortunately the issue where apps like gvim and xpdf are stealing
keyrelease events causing the ordering to be messed up, but this is a
lot better. A fix for the aforementioned issue shall be forthcoming,
once a good one's been found.

ok okan@, also tested by todd@
2008-05-01 18:01:13 +00:00
79569a4d59 Allow slashes in unquoted strings.
From Pierre Riteau
Makes sense to oga@
2008-04-29 20:17:28 +00:00
e3971fc758 nits from Pierre Riteau - thanks!
ok oga@
2008-04-28 01:27:46 +00:00
oga
898bfff36a merge kbfunc_{ptrmove,client_{move,resize}} into one function that takes a flag,
this code was almost identical...

ok okan.
2008-04-16 13:47:29 +00:00
oga
cd5c340e01 remove infowin. It slipped out of the last commit, for some reason. 2008-04-16 13:40:34 +00:00
oga
f473dc3d12 Replace a few leftover calls to strdup and calloc with xstrdup and xcalloc
respectively.

ok okan.
2008-04-16 13:38:09 +00:00
oga
f67772be65 Remove screen_infomsg(), nothing uses it.
ok okan.
2008-04-16 13:35:37 +00:00
oga
642afbdf8c kill an unused struct member.
ok okan
2008-04-16 13:33:26 +00:00
oga
d5794a6b02 make the argument parser for commands accept quoted strings, while i'm
there make u_spawn use exec_wm (renamed to u_exec) for it's execution to
remove duplicated code.

This means constructs like this work in .cwmrc:

bind CM-t "ssh -Y 192.168.1.2 \"xterm -e top\""

or alternatively:

bind CM-t "ssh -Y 192.168.1.2 'xterm -e top'"

"in it goes" okan@.
2008-04-15 21:20:56 +00:00
oga
887a5aa65f Kill dirent_isdir() and dirent_islink() nothing used them since the new
parser went in.

ok okan.
2008-04-15 20:26:50 +00:00
oga
75182c6d9c hit it with the knf stick. 2008-04-15 20:24:41 +00:00
oga
3a94c57afc Add "gap" support to .cwmrc. The options put in here make gaps on the edge
of the screen where an application won't be {,vert}maximized over. used for
placing a statusbar or something like xclock.

Patch from Edd Barrett, with input from myself and okan. Thanks!

ok okan@.
2008-04-15 18:46:58 +00:00
4bbb472a25 - add vi keybindings to search
- allow for ctrl-h as well

discussion with and ok oga@
2008-04-15 18:33:13 +00:00
fe80d40063 malloc -> calloc
suggested by and ok oga@
2008-04-15 18:22:08 +00:00
343ec1bb4f remove alt-tab menu
discussed with a few

ok oga@
2008-04-09 18:10:47 +00:00
oga
eb77aabea1 No cookie for okan.
fix use-after-free that broke exec's path getting stuff.

``paths'' isn't used anymore, but pointers to within that array are still
used in the next loop. delay freeing it until after then.
2008-04-08 17:38:27 +00:00
9702d4cfd7 better 'quit' keybinding default (CMS-q)
feedback from oga@ and simon@

ok oga@ simon@
2008-04-08 14:12:28 +00:00
539b5c6534 Make _xev_quit "volatile sig_atomic_t" for proper correctness.
Noticed by oga@, thanks!
2008-04-08 00:09:50 +00:00
0f18223042 Add quit function, bind it per default to CM-q and change exec_wm
binding to CM-w.

Inital diff from Gleydson Soares
Feedback from oga@ and okan@

ok oga@
2008-04-07 23:47:09 +00:00
cb2cc70c3f - use $PATH before _PATH_DEFPATH, from Tim van der Molen
- plug leak, noticed by oga

feedback and ok oga@
2008-04-05 21:09:19 +00:00
ef0859de20 Sync usage() with reality and manpage.
"ok, but no cookie" oga@
2008-04-03 13:58:57 +00:00
oga
34c0a0635f Fix a couple of issues with the maximization code.
If a window is vertically maximized, then resized, before the MAXIMIZED
flag wasn't removed, now it is. so doing a resize then does the right
thing.

Also, separate flags are needed for vertical and normal maximziation,
else when you do vertical-maximize, followed by maximize, the window
returns to it's original size.

ok simon@, okan@
2008-03-26 15:45:42 +00:00
e704b57d33 Introduce bsd.xconf.mk to set default config variables used
at several places in the Xenocara build in a central place instead
of duplicating the checks all over the place. ok oga@.
2008-03-25 23:41:50 +00:00
c3aa344e78 Replace the symlink configuration scheme with a simple yacc parser as
found in other places of the tree.  Remove sticky and font commandline
options and add another one for alternative config locations.
Split off cwmrc(5) from cwm(1), nuke #ifdef __OpenBSD__ while there.

tested by various kind people, feedback from oga@ and okan@ - thanks!
ok oga@, jasper@, okan@
2008-03-23 15:09:21 +00:00
38ff7a904e allow autogrouping and sticky mode to work together
ok oga@
2008-03-22 21:34:07 +00:00
oga
36c1aac90f Rip out, burn, and dance around the grave of group-edit mode.
I've yet to speak to anyone who uses it, so just kill it.

You can still add/remove from groups using the mouse binding.  Groups
may get a re-work sometime soon if i have a stroke of genius.

knocks about 4k off the i386 binary for me.

ok okan@, todd@.
2008-03-22 15:09:45 +00:00
oga
cd46788d85 Remove a bunch of unused variables and incorrect comments.
"ok with me" okan@.
2008-03-22 14:09:02 +00:00
oga
fead0d511f As mentioned in my last commit, there was an issue where the switching
code would always assume that the number of windows to switch to was
three if there were more windows hidden. Check for CLIENT_HIDDEN when we
count. Now it counts correctly.

ok simon@.
2008-03-19 00:18:28 +00:00
oga
f85ba10437 client_{,r}cycle() doens't need a client. so get rid of KBFUNC_NEEDSCLIENT.
this prevents the issue where you close or hide a window, and end up
with no client selected (you're on the root window). When that happened
alt-tab failed.  This, however, exposed to me a few more issues in the
alt-tabbing code:

-the code to detect how many lines we need looks bogus (you always get
three)

-alt-tabbing when everything is hidden always reawakes the most recent
window.

Fixes for these will be forthcoming.

ok simon@.
2008-03-18 00:48:56 +00:00
a466ddaa2d typo fix. ok oga 2008-03-14 14:38:10 +00:00
d816834954 Change the default for XSRCDIR to /usr/xenocara. ok deraadt@ 2008-03-03 07:01:44 +00:00
oga
de36e6ec2f add exec_wm to calmwm.h, it was missing (bad ian@!)
Also, exec_wm() currenty err()s out if something failed with the exec,
killing the currently running wm. This is bad. Replace the err() with
warn() instead.


from Gleydson Soares, thanks!
2008-02-20 13:00:18 +00:00
oga
7ef6f63557 Typo: s/supression/suppression
from Pierre Riteau, thanks!
2008-02-20 12:56:10 +00:00
oga
3f63e529bf usage never returns, and thus should be __dead.
ok jasper@.
2008-02-13 21:48:03 +00:00
oga
9cb4f8884e add usage() for when an unknown option is given.
from Gleydson Soares <gsoares@gmail.com>, thanks!

ok jasper@
2008-02-13 21:04:19 +00:00
oga
09dbddac87 Make cwm print the XDisplayName() if it fails to open the display,
instead of an error message that'll be gibberish to most people.

from Gleydson Soares. Thanks!

ok simon@.
2008-02-13 12:09:47 +00:00
ian
a936ffc470 Trivial typo in recent "exec windowmanager" addition 2008-01-22 17:35:23 +00:00
oga
de72f62924 All of the 9wm code in cwm has been removed or re-written. Edit LICENSE
and the manpage to reflect this. While i'm here remove the note in todo
about cleaning up the menu code; it's been done.

ok ian@, okan@ (he also provided most of the manpage rework)
2008-01-16 16:14:55 +00:00
oga
7fb2664f92 huge amount of cleanup and dead code removal.
full description of changes:
-remove fontlist, and all associated structures/calls, it's not needed.
 this also removes any doubt about leftover 9wm code (the list was
 borrowed from it). Since cwm now uses Xft for everything, the legacy
 font handling is just not needed.
-add /* FALLTHROUGH */ comments into grab_{label,menu}. I actually
 didn't intend grab_menu to be a fallthrough, but it actually works quite
 well there, so remove the extra rectangle drawing. I love it when that
 happens.
-remove a couple of unused prototypes that were obviously missed
 before.
-remove a bunch of commented out or if 0ed out code. It doesn't look to
 be coming back anytime soon.
-several functions returned an int, but this was never checked. most of
 them only failed if they failed to grab the pointer (thus the internal
 state didn't change), so just make them void and return early if this is
 the case.
-remove several unused functions and some useless variables.

knocks something like 200bytes off the stripped binary size for me.

ok marc@, tested by several others.
2008-01-16 11:39:20 +00:00
oga
1eed217b1c Rewrite most of grab_menu in grab.c (it was partly 9wm code).
This should work functionally the same, with a few simplifications.

Changes:
- we don't care if you're holding another button when you release the
  menu key if you don't want to select anything, move off the menu.
- remove the hysteresis from the menu selection (before you had to move
  more than three pixels onto a new menu entry before it selected it)
- simplify a lot of the selection code
- kill dead code.
- do what the XXX comment said and cache the screensize (i may tweak
  this later).

As far as I can tell, the only code remaining from 9wm is the list of
fonts in calmwm.c. Others appear to concur.

ok marc@, looked over and tested by a few others. Reminders from okan@.
2008-01-14 15:21:10 +00:00
oga
e5cabb0f43 - Remove the "all rights reserved" tag at the top of most of the source
files, and replace them with the actual ISC license.

- add license to the manpage (it was lacking before)

- correct license statement in the README

Permission given by Marius (copyright holder):
"1. please replace with the standard ISC license
2. you may add the ISC license to the man page
3. feel free to replace the information in the README as well"

and Dros (copyright holder for group.c):
"Please switch group.c to the ISC License."

ok ian@
2008-01-11 16:06:44 +00:00
oga
3de5c68888 Kill some more dead code, cursor.c goes away.
ok marc@
2008-01-08 20:21:43 +00:00
160d6aa910 Adjust initial window placement with any geometry that would place
the window at or over the right or bottom edge.
OK oda@
2008-01-03 20:20:20 +00:00
oga
847191cff3 Kill draw.c, nothing uses the code in it.
More dead code removals to come.

ok marc@
2008-01-03 01:58:16 +00:00
oga
f82afee4e2 Kill some warnings intoduced with the execwm feature.
ok marc@
2008-01-03 01:56:25 +00:00
381ba77e03 remove declaration of removed function
Reminded by matthieu@  (thanks!)
2008-01-02 20:54:32 +00:00
01a3f493d6 remove unused code
OK oga@
2008-01-02 20:47:11 +00:00
219f297493 Only use the x,y values from the XSizeHints structure when they are greater
than zero.   The fields are obsolete and not always used.
OK jasper@
2008-01-01 22:28:59 +00:00
2e72df662d allow the search feature to work in the root window, like other similar ones.
ok todd@
2007-12-31 02:49:45 +00:00
ian
8b3cd2243a Add a "restart wm" function. ok oga@ 2007-11-28 16:35:52 +00:00
oga
f14a3eeebf Another messed up keybinding.
I blame todd...

ok okan@
2007-11-28 16:02:37 +00:00
19ae2f65de re-add a lost group keybinding
ok oga@ todd@
2007-11-27 17:17:08 +00:00
oga
3341229c74 Make cwm default keybindings always exist. Additional keybindings now
overlap with the new ones, overriding them. Also a new "unmap" keyword
in binding definitions now unmaps a binding without adding a new one.

This seriously shrinks the ~/.calmwm/.keys directory of anyone who defines
their own bindings whilst wanting some of the defaults.

Looked over, liked and ok todd@
2007-11-19 22:18:16 +00:00
jmc
ebebed71bd fix a pasto: documentation/5639 from viq
while i'm at it:
- fix an .El botch up
- kill trailing whitespace
- new sentence, new line
2007-11-16 23:04:56 +00:00
4b85adbe60 introduce conf_bindname() to drastically simplify conf.c
really liked by oga@
2007-11-13 23:26:04 +00:00
576d299095 enable pointer movement in cwm via C-<arrowkeys>
looked over by oga@
2007-11-13 23:08:49 +00:00
oga
dc39e11ff9 Small manpage nit.
From Okan Demirmen, thanks!
2007-11-08 13:03:22 +00:00
oga
6b00b86622 Change MOVE_AMOUNT in kbfunc.c to 1 from 10. This allows more fine tuning when
moving and resizing windows using the keyboard.

Future diffs might make this value configurable.

ok jasper@, todd@.
2007-11-07 22:02:04 +00:00
oga
e64e1709ba Document cwm's keybinding support. It was already there, but not in the manpage.
While I'm here add support for extra modifier keys.

"commit commit!" jasper@, ok todd@.
2007-11-07 22:00:26 +00:00
oga
699b048959 Add support to cwm for resizing the windows using Control-Meta-[hjkl].
Please note that this remaps Control-Meta-L (label) to Control-Meta-N (name).

ok jasper@, todd@.
2007-11-07 21:58:03 +00:00
ian
af71fc930a wording 2007-10-07 16:56:21 +00:00
56994282f0 When cycling, only the end of the window names will be printed if the
name is too long. so show the beginning instead.

from Pierre Riteau <pierre.riteau at free.fr>

"looks correct" matthieu@
2007-10-02 18:01:45 +00:00
0584867396 fix buffer overflow, as sizeof(paths) won't fit inside the array.
from Stefan Kempf

"looks right to me" matthieu@
2007-09-06 06:01:14 +00:00
5fa1a97034 Initial import of cwm-3.
tested by sturm@, ok matthieu@
2007-04-27 17:58:48 +00:00
28 changed files with 6756 additions and 5319 deletions

32
LICENSE
View File

@ -1,32 +0,0 @@
Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
Copyright (c) 2004 Andy Adamson <dros@monkey.org>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Parts derived from 9wm:
9wm is free software, and is Copyright (c) 1994 by David Hogan.
Permission is granted to all sentient beings to use this software,
to make copies of it, and to distribute those copies, provided
that:
(1) the copyright and licence notices are left intact
(2) the recipients are aware that it is free software
(3) any unapproved changes in functionality are either
(i) only distributed as patches
or (ii) distributed as a new program which is not called 9wm
and whose documentation gives credit where it is due
(4) the author is not held responsible for any defects
or shortcomings in the software, or damages caused by it.
There is no warranty for this software. Have a nice day.

View File

@ -1,23 +1,22 @@
# $OpenBSD$
.include <bsd.own.mk>
X11BASE?= /usr/X11R6
.include <bsd.xconf.mk>
PROG= cwm
SRCS= calmwm.c draw.c screen.c xmalloc.c client.c grab.c search.c \
util.c xutil.c conf.c input.c xevents.c group.c geographic.c \
kbfunc.c cursor.c font.c
SRCS= calmwm.c screen.c xmalloc.c client.c menu.c \
search.c util.c xutil.c conf.c xevents.c group.c \
kbfunc.c parse.y
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2
CPPFLAGS+= -I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR}
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lXau -lXdmcp \
-lfontconfig -lexpat -lfreetype -lz -lX11 -lXau -lXdmcp -lXext
CFLAGS+= -Wall
YFLAGS=
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lxcb -lXau -lXdmcp \
-lfontconfig -lexpat -lfreetype -lz -lXrandr -lXext
MANDIR= ${X11BASE}/man/cat
CLEANFILES= cwm.cat1
MANDIR= ${X11BASE}/man/man
MAN= cwm.1 cwmrc.5
obj: _xenocara_obj

59
README
View File

@ -1,59 +0,0 @@
--------------------------------------------------------------------------------
cwm release three
--------------------------------------------------------------------------------
by Marius Aamodt Eriksen <marius@monkey.org>
contributions by Andy Adamson <dros@monkey.org>,
Niels Provos <provos@monkey.org>,
Martin Murray <mmurray@monkey.org>,
Dimitris Economou <dimeco@stanford.edu> &
Antti Nyk<79>nen <aon@iki.fi>.
http://monkey.org/~marius/cwm
DESCRIPTION
cwm is a window manager initially inspired by evilwm[1]. It
developed out of modifications to evilwm, but eventually the code
base of evilwm did not accomodate well for the new features added.
So calmwm was written from scratch.
Its main goal is to be as efficient as possible, while providing
a very clean, simple & attractive aesthetic.
cwm has several novel features, including the ability to search
for windows.
HIGHLIGHTS IN RELEASE TWO
* Improved alt-tabbing, including the ability to reverse cycle.
* Display of a context menu when alt-tabbing, showing the previous,
current and next window in the cycle order.
* Much improved ranking in search.
* In search-menus, the ability to list every item.
HIGHLIGHTS IN RELEASE THREE
* More search ranking improvements
* Many contributions by Antti Nyk<79>nen: keyboard binding "i18n",
show window labels in minimized window menu, automatic window
grouping, MWM hints support & some bug fixes.
* Xft support & the addition of the -f flag (see manpage).
INSTALL
./configure
make
su
make install
DOCUMENTATION
See the manpage cwm(1).
LICENSE
cwm is distributed under a BSD like license. Feel free to use,
modify and distribute in any form. See the LICENSE file for more
information.
[1] http://evilwm.sourceforge.net/

30
TODO
View File

@ -1,30 +0,0 @@
- clean up menu code from 9wm
- window initial position
- don't map windows if it's within [some time increment] of active typing,
this is part of the "calm" goal. also, it helps if you're mindlessly
typing in a password and the keyboard input ends up in some other window,
bad...
- integrate everything into /ONE/ event loop.
register handlers, with the ability to select, for example,
a window, or an event, etc. (no, maybe not...)
- ignoreq, always lower them. perhaps implement by lowering the entire
queue on each XLower...
- search window should try to stay inside of the screen boundaries.
- geographical keyboard navigation (window switching)
- search should ignore the current window. (not add to match list).
- make kbd shortcuts/events more general. the ability to associate an
event with a mode (i.e. prioritize). gets rid of hacky-ness in
groups, etc.
- figure out what's up when alt-tab goes back to the current window
once before moving on.
- cache all the atoms somewhere.

489
calmwm.c
View File

@ -2,351 +2,236 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <locale.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "calmwm.h"
Display *X_Dpy;
XFontStruct *X_Font;
Display *X_Dpy;
Time Last_Event_Time = CurrentTime;
Atom cwmh[CWMH_NITEMS];
Atom ewmh[EWMH_NITEMS];
struct screen_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
struct conf Conf;
volatile sig_atomic_t cwm_status;
Cursor Cursor_move;
Cursor Cursor_resize;
Cursor Cursor_select;
Cursor Cursor_default;
Cursor Cursor_question;
struct screen_ctx_q Screenq;
struct screen_ctx *Curscreen;
u_int Nscreens;
struct client_ctx_q Clientq;
int Doshape, Shape_ev;
int Starting;
struct conf Conf;
struct fontdesc *DefaultFont;
char *DefaultFontName;
/* From TWM */
#define gray_width 2
#define gray_height 2
static char gray_bits[] = {0x02, 0x01};
/* List borrowed from 9wm/rio */
char *tryfonts[] = {
"9x15bold",
"blit",
"*-lucidatypewriter-bold-*-14-*-75-*",
"*-lucidatypewriter-medium-*-12-*-75-*",
"fixed",
"*",
NULL,
};
static void _sigchld_cb(int);
__dead void usage(void);
static void sighdlr(int);
static int x_errorhandler(Display *, XErrorEvent *);
static int x_init(const char *);
static void x_teardown(void);
static int x_wmerrorhandler(Display *, XErrorEvent *);
int
main(int argc, char **argv)
{
int ch;
int conf_flags = 0;
char *display_name = NULL;
char *fallback;
int ch, xfd, nflag = 0;
struct pollfd pfd[1];
char *display_name = NULL;
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
warnx("no locale support");
mbtowc(NULL, NULL, MB_CUR_MAX);
DefaultFontName = "sans-serif:pixelsize=14:bold";
conf_init(&Conf);
while ((ch = getopt(argc, argv, "d:sf:")) != -1) {
fallback = u_argv(argv);
Conf.wm_argv = u_argv(argv);
while ((ch = getopt(argc, argv, "c:d:nv")) != -1) {
switch (ch) {
case 'c':
free(Conf.conf_file);
Conf.conf_file = xstrdup(optarg);
break;
case 'd':
display_name = optarg;
break;
case 's':
conf_flags |= CONF_STICKY_GROUPS;
case 'n':
nflag = 1;
break;
case 'f':
DefaultFontName = xstrdup(optarg);
case 'v':
Conf.debug++;
break;
default:
errx(1, "Unknown option '%c'", ch);
usage();
}
}
argc -= optind;
argv += optind;
/* Ignore a few signals. */
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
err(1, "signal");
if (signal(SIGCHLD, sighdlr) == SIG_ERR ||
signal(SIGHUP, sighdlr) == SIG_ERR ||
signal(SIGINT, sighdlr) == SIG_ERR ||
signal(SIGTERM, sighdlr) == SIG_ERR)
err(1, "signal");
if (signal(SIGCHLD, _sigchld_cb) == SIG_ERR)
err(1, "signal");
if (parse_config(Conf.conf_file, &Conf) == -1) {
warnx("error parsing config file");
if (nflag)
return 1;
}
if (nflag)
return 0;
group_init();
xfd = x_init(display_name);
cwm_status = CWM_RUNNING;
Starting = 1;
conf_setup(&Conf);
Conf.flags |= conf_flags;
client_setup();
x_setup(display_name);
Starting = 0;
if (pledge("stdio rpath proc exec", NULL) == -1)
err(1, "pledge");
xev_init();
XEV_QUICK(NULL, NULL, MapRequest, xev_handle_maprequest, NULL);
XEV_QUICK(NULL, NULL, UnmapNotify, xev_handle_unmapnotify, NULL);
XEV_QUICK(NULL, NULL, ConfigureRequest,
xev_handle_configurerequest, NULL);
XEV_QUICK(NULL, NULL, PropertyNotify, xev_handle_propertynotify, NULL);
XEV_QUICK(NULL, NULL, EnterNotify, xev_handle_enternotify, NULL);
XEV_QUICK(NULL, NULL, LeaveNotify, xev_handle_leavenotify, NULL);
XEV_QUICK(NULL, NULL, ButtonPress, xev_handle_buttonpress, NULL);
XEV_QUICK(NULL, NULL, ButtonRelease, xev_handle_buttonrelease, NULL);
XEV_QUICK(NULL, NULL, KeyPress, xev_handle_keypress, NULL);
XEV_QUICK(NULL, NULL, KeyRelease, xev_handle_keyrelease, NULL);
XEV_QUICK(NULL, NULL, Expose, xev_handle_expose, NULL);
XEV_QUICK(NULL, NULL, DestroyNotify, xev_handle_destroynotify, NULL);
XEV_QUICK(NULL, NULL, ClientMessage, xev_handle_clientmessage, NULL);
memset(&pfd, 0, sizeof(pfd));
pfd[0].fd = xfd;
pfd[0].events = POLLIN;
while (cwm_status == CWM_RUNNING) {
xev_process();
if (poll(pfd, 1, INFTIM) == -1) {
if (errno != EINTR)
warn("poll");
}
}
x_teardown();
if (cwm_status == CWM_EXEC_WM) {
u_exec(Conf.wm_argv);
warnx("'%s' failed to start, starting fallback", Conf.wm_argv);
u_exec(fallback);
}
xev_loop();
return (0);
return 0;
}
void
x_setup(char *display_name)
static int
x_init(const char *dpyname)
{
int i;
struct screen_ctx *sc;
char *fontname;
int i;
TAILQ_INIT(&Screenq);
if ((X_Dpy = XOpenDisplay(display_name)) == NULL)
errx(1, "%s:%d XOpenDisplay()", __FILE__, __LINE__);
if ((X_Dpy = XOpenDisplay(dpyname)) == NULL)
errx(1, "unable to open display \"%s\"", XDisplayName(dpyname));
XSetErrorHandler(x_wmerrorhandler);
XSelectInput(X_Dpy, DefaultRootWindow(X_Dpy), SubstructureRedirectMask);
XSync(X_Dpy, False);
XSetErrorHandler(x_errorhandler);
Doshape = XShapeQueryExtension(X_Dpy, &Shape_ev, &i);
Conf.xrandr = XRRQueryExtension(X_Dpy, &Conf.xrandr_event_base, &i);
i = 0;
while ((fontname = tryfonts[i++]) != NULL) {
if ((X_Font = XLoadQueryFont(X_Dpy, fontname)) != NULL)
break;
}
xu_atom_init();
conf_cursor(&Conf);
if (fontname == NULL)
errx(1, "Couldn't load any fonts.");
for (i = 0; i < ScreenCount(X_Dpy); i++)
screen_init(i);
Nscreens = ScreenCount(X_Dpy);
for (i = 0; i < (int)Nscreens; i++) {
XMALLOC(sc, struct screen_ctx);
x_setupscreen(sc, i);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
}
Cursor_move = XCreateFontCursor(X_Dpy, XC_fleur);
Cursor_resize = XCreateFontCursor(X_Dpy, XC_bottom_right_corner);
/* (used to be) XCreateFontCursor(X_Dpy, XC_hand1); */
Cursor_select = XCreateFontCursor(X_Dpy, XC_hand1);
/* Cursor_select = cursor_bigarrow(Curscreen); */
Cursor_default = XCreateFontCursor(X_Dpy, XC_X_cursor);
/* Cursor_default = cursor_bigarrow(Curscreen); */
Cursor_question = XCreateFontCursor(X_Dpy, XC_question_arrow);
}
int
x_setupscreen(struct screen_ctx *sc, u_int which)
{
XColor tmp;
XGCValues gv, gv1/* , gv2 */;
Window *wins, w0, w1;
u_int nwins, i = 0;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
struct keybinding *kb;
sc->display = x_screenname(which);
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, which);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"black", &sc->fgcolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"#00cc00", &sc->bgcolor, &tmp);
XAllocNamedColor(X_Dpy,DefaultColormap(X_Dpy, which),
"blue", &sc->fccolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"red", &sc->redcolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"#00ccc8", &sc->cyancolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"white", &sc->whitecolor, &tmp);
XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
"black", &sc->blackcolor, &tmp);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry)
xu_key_grab(sc->rootwin, kb->modmask, kb->keysym);
/* Special -- for alt state. */
/* xu_key_grab(sc->rootwin, 0, XK_Alt_L); */
/* xu_key_grab(sc->rootwin, 0, XK_Alt_R); */
sc->blackpixl = BlackPixel(X_Dpy, sc->which);
sc->whitepixl = WhitePixel(X_Dpy, sc->which);
sc->bluepixl = sc->fccolor.pixel;
sc->redpixl = sc->redcolor.pixel;
sc->cyanpixl = sc->cyancolor.pixel;
sc->gray = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->blackpixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
sc->blue = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->bluepixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
sc->red = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin,
gray_bits, gray_width, gray_height,
sc->redpixl, sc->whitepixl, DefaultDepth(X_Dpy, sc->which));
gv.foreground = sc->blackpixl^sc->whitepixl;
gv.background = sc->whitepixl;
gv.function = GXxor;
gv.line_width = 1;
gv.subwindow_mode = IncludeInferiors;
gv.font = X_Font->fid;
sc->gc = XCreateGC(X_Dpy, sc->rootwin,
GCForeground|GCBackground|GCFunction|
GCLineWidth|GCSubwindowMode|GCFont, &gv);
#ifdef notyet
gv2.foreground = sc->blackpixl^sc->cyanpixl;
gv2.background = sc->cyanpixl;
gv2.function = GXxor;
gv2.line_width = 1;
gv2.subwindow_mode = IncludeInferiors;
gv2.font = X_Font->fid;
#endif
sc->hlgc = XCreateGC(X_Dpy, sc->rootwin,
GCForeground|GCBackground|GCFunction|
GCLineWidth|GCSubwindowMode|GCFont, &gv);
gv1.function = GXinvert;
gv1.subwindow_mode = IncludeInferiors;
gv1.line_width = 1;
gv1.font = X_Font->fid;
sc->invgc = XCreateGC(X_Dpy, sc->rootwin,
GCFunction|GCSubwindowMode|GCLineWidth|GCFont, &gv1);
font_init(sc);
DefaultFont = font_getx(sc, DefaultFontName);
/*
* XXX - this should *really* be in screen_init(). ordering
* problem.
*/
TAILQ_INIT(&sc->mruq);
/* Initialize menu window. */
grab_menuinit(sc);
search_init(sc);
/* Deal with existing clients. */
XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
for (i = 0; i < nwins; i++) {
XGetWindowAttributes(X_Dpy, wins[i], &winattr);
if (winattr.override_redirect ||
winattr.map_state != IsViewable) {
char *name;
XFetchName(X_Dpy, wins[i], &name);
continue;
}
client_new(wins[i], sc, winattr.map_state != IsUnmapped);
}
XFree(wins);
Curscreen = sc; /* XXX */
screen_init();
screen_updatestackingorder();
rootattr.event_mask = ChildMask|PropertyChangeMask|EnterWindowMask|
LeaveWindowMask|ColormapChangeMask|ButtonMask;
/* Set the root cursor to a nice obnoxious arrow :-) */
/* rootattr.cursor = cursor_bigarrow(sc); */
XChangeWindowAttributes(X_Dpy, sc->rootwin,
/* CWCursor| */CWEventMask, &rootattr);
XSync(X_Dpy, False);
return (0);
}
char *
x_screenname(int which)
{
char *cp, *dstr, *sn;
size_t snlen;
if (which > 9)
errx(1, "Can't handle more than 9 screens. If you need it, "
"tell <marius@monkey.org>. It's a trivial fix.");
dstr = xstrdup(DisplayString(X_Dpy));
if ((cp = rindex(dstr, ':')) == NULL)
return (NULL);
if ((cp = index(cp, '.')) != NULL)
*cp = '\0';
snlen = strlen(dstr) + 3; /* string, dot, number, null */
sn = (char *)xmalloc(snlen);
snprintf(sn, snlen, "%s.%d", dstr, which);
free(dstr);
return (sn);
}
int
x_errorhandler(Display *dpy, XErrorEvent *e)
{
#ifdef DEBUG
{
char msg[80], number[80], req[80];
XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(X_Dpy, "XRequest", number,
"<unknown>", req, sizeof(req));
warnx("%s(0x%x): %s", req, (u_int)e->resourceid, msg);
}
#endif
if (Starting &&
e->error_code == BadAccess &&
e->request_code == X_GrabKey)
errx(1, "root window unavailable - perhaps another "
"wm is running?");
return (0);
return ConnectionNumber(X_Dpy);
}
static void
_sigchld_cb(int which)
x_teardown(void)
{
pid_t pid;
int status;
struct screen_ctx *sc;
unsigned int i;
/* Collect dead children. */
while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
(pid < 0 && errno == EINTR))
;
conf_clear(&Conf);
TAILQ_FOREACH(sc, &Screenq, entry) {
for (i = 0; i < CWM_COLOR_NITEMS; i++)
XftColorFree(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which),
&sc->xftcolor[i]);
XftFontClose(X_Dpy, sc->xftfont);
XUngrabKey(X_Dpy, AnyKey, AnyModifier, sc->rootwin);
}
XUngrabPointer(X_Dpy, CurrentTime);
XUngrabKeyboard(X_Dpy, CurrentTime);
for (i = 0; i < CF_NITEMS; i++)
XFreeCursor(X_Dpy, Conf.cursor[i]);
XSync(X_Dpy, False);
XSetInputFocus(X_Dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
XCloseDisplay(X_Dpy);
}
static int
x_wmerrorhandler(Display *dpy, XErrorEvent *e)
{
errx(1, "root window unavailable - perhaps another wm is running?");
return 0;
}
static int
x_errorhandler(Display *dpy, XErrorEvent *e)
{
#ifdef DEBUG
char msg[80], number[80], req[80];
XGetErrorText(X_Dpy, e->error_code, msg, sizeof(msg));
(void)snprintf(number, sizeof(number), "%d", e->request_code);
XGetErrorDatabaseText(X_Dpy, "XRequest", number,
"<unknown>", req, sizeof(req));
warnx("%s(0x%x): %s", req, (unsigned int)e->resourceid, msg);
#endif
return 0;
}
static void
sighdlr(int sig)
{
pid_t pid;
int save_errno = errno, status;
switch (sig) {
case SIGCHLD:
/* Collect dead children. */
while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0 ||
(pid < 0 && errno == EINTR))
;
break;
case SIGHUP:
cwm_status = CWM_EXEC_WM;
break;
case SIGINT:
case SIGTERM:
cwm_status = CWM_QUIT;
break;
}
errno = save_errno;
}
__dead void
usage(void)
{
extern char *__progname;
(void)fprintf(stderr, "usage: %s [-nv] [-c file] [-d display]\n",
__progname);
exit(1);
}

989
calmwm.h

File diff suppressed because it is too large Load Diff

1628
client.c

File diff suppressed because it is too large Load Diff

1143
conf.c

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +0,0 @@
/*
* cursor.c
*
* Copyright (c) 2005 Marius Eriksen <marius@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "headers.h"
#include "calmwm.h"
/* Pretty much straight out of 9wm... */
struct cursor_data {
int width;
int hot[2];
u_char mask[64];
u_char fore[64];
};
static struct cursor_data Bigarrow = {
16,
{0, 0},
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F,
0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x1F, 0xFF, 0x3F,
0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F,
0xCF, 0x1F, 0x8F, 0x0F, 0x07, 0x07, 0x03, 0x02,
},
{ 0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x3F, 0xFE, 0x0F,
0xFE, 0x07, 0xFE, 0x07, 0xFE, 0x0F, 0xFE, 0x1F,
0xFE, 0x3F, 0xFE, 0x7F, 0xFE, 0x3F, 0xCE, 0x1F,
0x86, 0x0F, 0x06, 0x07, 0x02, 0x02, 0x00, 0x00,
},
};
static Cursor
_mkcursor(struct cursor_data *c, struct screen_ctx *sc)
{
Pixmap f, m;
f = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin, (char *)c->fore,
c->width, c->width, 1, 0, 1);
m = XCreatePixmapFromBitmapData(X_Dpy, sc->rootwin, (char *)c->mask,
c->width, c->width, 1, 0, 1);
return (XCreatePixmapCursor(X_Dpy, f, m,
&sc->blackcolor, &sc->whitecolor, c->hot[0], c->hot[1]));
}
Cursor
cursor_bigarrow(struct screen_ctx *sc)
{
return _mkcursor(&Bigarrow, sc);
}

380
cwm.1
View File

@ -1,7 +1,20 @@
.\" $OpenBSD$
.\"
.\" The following requests are required for all man pages.
.Dd June 29, 2007
.\" Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate$
.Dt CWM 1
.Os
.Sh NAME
@ -10,136 +23,184 @@
.Sh SYNOPSIS
.\" For a program: program [-abc] file ...
.Nm cwm
.Op Fl s
.Op Fl nv
.Op Fl c Ar file
.Op Fl d Ar display
.Op Fl f Ar fontname
.Sh DESCRIPTION
.Nm
is a window manager for X11.
It was originally inspired by evilwm, but was rewritten from scratch
due to limitations in the evilwm codebase.
The from-scratch rewrite borrowed some code from 9wm.
.Nm
contains many new features which all concentrate on the efficiency and
transparency of window management.
.Nm
also aims to maintain the most simplest and pleasant aesthetic.
is a window manager for X11 which contains many features that
concentrate on the efficiency and transparency of window management,
while maintaining the simplest and most pleasant aesthetic.
.Pp
The following notation is used throughout this page:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It Ic C
Control
.It Ic M
Meta (Alt on PCs)
.It Ic S
Shift
.It Ic M1
Left mouse button
.It Ic M2
Middle mouse button
.It Ic M3
Right mouse button
The options are as follows:
.Bl -tag -width Ds
.It Fl c Ar file
Specify an alternative configuration file.
By default,
.Nm
loads
.Pa ~/.cwmrc ,
if present.
Any error messages from lines in the configuration file will be sent to
.Em stderr ;
however,
.Nm
will continue to process the rest of the configuration file.
.It Fl d Ar display
Specify the display to use.
.It Fl n
Configtest mode.
Only check the configuration file for validity.
.It Fl v
Verbose mode.
Multiple
.Fl v
options increase the verbosity.
.El
.Pp
.Nm
is very simple in its use.
Most of the actions are initiated via keybindings.
The current keybindings are described below;
their functionality is described in more detail later.
actions are initiated either via key or mouse bindings.
The following notations are used throughout this page:
.Pp
.Bl -tag -width "C-M-EscapeXXX" -offset indent -compact
.It Ic C-M-Enter
.Bl -tag -width Ds -offset indent -compact
.It Ic C
Control key.
.It Ic M
Meta key.
.It Ic S
Shift key.
.It Ic 4
Mod4 (windows) key.
.It Ic M1
Left mouse button.
.It Ic M2
Middle mouse button.
.It Ic M3
Right mouse button.
.El
.Pp
The default key bindings are:
.Pp
.Bl -tag -width "CM-EscapeXXXXX" -offset indent -compact
.It Ic CM-Return
Spawn a new terminal.
.It Ic C-M-Delete
.It Ic CM-Delete
Lock the screen.
.It Ic M-Enter
.It Ic M-Return
Hide current window.
.It Ic M-Down
Lower current window.
.It Ic M-Up
Raise current window.
.It Ic M-/
.It Ic M-slash
Search for windows.
.It Ic C-/
.It Ic C-slash
Search for applications.
.It Ic C-M-l
.It Ic CM-n
Label current window.
.It Ic M-Tab
Cycle through currently visible windows.
.It Ic M-S-Tab
.It Ic MS-Tab
Reverse cycle through currently visible windows.
.It Ic C-M-x
Delete current window.
.It Ic C-M-Escape
Enter group edit mode.
.It Ic C-M-[n]
Select group n, where n is 1-9.
.It Ic C-M-0
Select all groups.
.It Ic CM-x
Close current window.
.It Ic CM-[n]
Toggle visibility of group n, where n is 1-9.
.It Ic CM-a
Toggle visibility of all groups.
.It Ic CM-g
Toggle group membership of current window.
.It Ic M-Right
Switch to next group.
Cycle through active groups.
.It Ic M-Left
Switch to previous group.
.It Ic C-M-f
Toggle full-screen size of window.
.It Ic C-M-=
Toggle vertical maximization of window.
.It Ic M-?
Reverse cycle through active groups.
.It Ic CMS-f
Toggle freezing geometry of current window.
.It Ic CM-s
Toggle stickiness of current window.
.It Ic CM-f
Toggle full-screen mode of current window.
.It Ic CM-m
Toggle maximization of current window.
.It Ic CM-equal
Toggle vertical maximization of current window.
.It Ic CMS-equal
Toggle horizontal maximization of current window.
.It Ic M-[hjkl]
Move window by a small amount.
.It Ic MS-[hjkl]
Move window by a large amount; see
.Xr cwmrc 5 .
.It Ic CM-[hjkl]
Resize window by a small amount.
.It Ic CMS-[hjkl]
Resize window by a large amount; see
.Xr cwmrc 5 .
.It Ic M-question
Spawn
.Dq Exec program
.Dq exec program
dialog.
.It Ic M-.
.It Ic M-period
Spawn
.Dq Ssh to
.Dq ssh to
dialog.
This parses
.Pa $HOME/.ssh/known_hosts
to provide host auto-completion.
.Xr ssh 1
will be executed via the configured terminal emulator.
.It Ic CM-w
Spawn
.Dq exec WindowManager
menu, allowing a switch to another window manager.
.It Ic CMS-r
Restart.
.It Ic CMS-q
Quit.
.El
.Pp
The mouse bindings are also important, they are:
The default mouse bindings are:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It M-M1
Move a window.
.It C-M-M1
Toggle a window's membership in the current group.
A blue highlight indicates the window has been added to the group;
a red highlight indicates it has been removed.
.It M-M2
Resize a window/select a window.
.It M-M3
Lower a window.
.Bl -tag -width "CM-EscapeXXXXX" -offset indent -compact
.It Ic M-M1
Move current window.
.It Ic CM-M1
Toggle group membership of current window.
.It Ic M-M2
Resize current window
.It Ic M-M3
Lower current window.
.It Ic CMS-M3
Hide current window.
.El
.Pp
The following key bindings may be used to navigate
search and exec dialogs:
.Pp
.Bl -tag -width "[Down] or C-s or M-j" -offset indent -compact
.It Ic [Return]
Select item.
.It Ic [Down], C-s No or Ic M-j
Next item.
.It Ic [Up], C-r No or Ic M-k
Previous item.
.It Ic [Backspace] No or Ic C-h
Backspace.
.It Ic C-u
Clear input.
.It Ic C-a
List all available items.
.It Ic [Esc]
Cancel.
.El
.Pp
The options for
.Nm
are as follows:
.Bl -tag -width Ds
.It Fl d Ar display
Specify the display to use.
.It Fl f Ar fontname
Makes the
.Xr Xft 3
font string
.Ar fontname
the default font.
.It Fl s
Set sticky group mode on.
The default behavior for new windows is to not assign any group.
This changes the default behavior to assigning the currrently selected
group to any newly created windows.
.El
.Sh WINDOW MOVEMENT
.Nm
windows can be moved with the use of the keyboard through Vi-like bindings.
M-[hjkl] moves the current window a small amount, while M-shift-[hjkl] moves
the current window a larger amount.
For example, to move the current window to the left a small amount, press M-h.
To move the current window down by a larger amount, press M-shift-j.
rereads its configuration file when it receives a hangup signal,
.Dv SIGHUP ,
by executing itself with the name and arguments with which it was started.
This is equivalent to the
.Ar restart
function.
.Sh SEARCH
.Nm
features the ability to search for windows by their current title,
@ -152,61 +213,45 @@ keeps a history of the 5 previous titles of a window.
When searching, the leftmost character of the result list may show a
flag:
.Pp
.Bl -tag -width 10n -offset -indent -compact
.Bl -tag -width Ds -offset indent -compact
.It !
The window is the currently focused window.
Window is currently focused.
.It &
The window is hidden.
.El
.Pp
The following keybindings may be used to navigate the result list:
.Pp
.Bl -tag -width "[Down] or C-sXXX" -offset indent -compact
.It Ic [Down] No or Ic C-s
Select the next window in the list.
.It Ic [Up] No or Ic C-r
Select the previous window in the list.
.It Ic C-u
Clear the input.
.It Ic [Enter]
Focus the selected window.
.It Ic [Esc]
Quit.
.It Ic C-a
Whenever there are no matching windows, list every window.
Window is hidden.
.El
.Sh APPLICATIONS
.Nm
manages a list of applications defined with the
.Cm command
configuration option.
.Sh GROUPS
.Nm
has the ability to group windows together, and use the groups to
perform operations on the entire group instead of just one window.
Currently, the only operation that is supported is to hide and unhide
the grouped windows.
Together with the
.Fl s
.Pa sticky
option, this can be used to emulate virtual desktops.
.Pp
To edit groups, enter the group edit mode, and select/unselect the
groups with the group selection mouse click.
A blue border will be shown on the currently selected windows.
The group selection keyboard shortcuts can also be used to change
which group to edit.
To edit groups, use the group selection commands to toggle membership
of a group.
A blue border will be shown briefly on windows added to the current group,
and a red border will be shown on those just removed.
.Sh MENUS
Menus are recalled by clicking the mouse on the root window:
.Pp
.Bl -tag -width 10n -offset -indent -compact
.It M1
Show list of currently hidden windows.
Clicking on an item will unhide that window.
.It M2
.Bl -tag -width Ds -offset indent -compact
.It Ic M1
Show list of currently defined windows.
Selecting an item will warp to that window, unhiding it if necessary.
.It Ic M2
Show list of currently defined groups.
Clicking on an item will hide/unhide that group.
.It M3
Show list of applications as defined in
.Pa ~/.calmwm .
Clicking on an item will spawn that application.
Selecting an item will hide/unhide that group.
.It Ic M3
Show list of applications as defined in the configuration file.
Selecting an item will spawn that application.
.El
.Sh ENVIRONMENT
.Bl -tag -width "DISPLAYXXX"
.Bl -tag -width "DISPLAYXXX" -compact
.It DISPLAY
.Nm
starts on this display unless the
@ -214,63 +259,32 @@ starts on this display unless the
option is given.
.El
.Sh FILES
.Bl -tag -width Ds
.It Pa ~/.calmwm
Any directory entries here are shown in the application menu.
When it is selected, the image is executed with
.Xr execve 2 .
One use of this is to create symbolic links for your favorite
applications in this directory using
.Xr ln 1 .
.Pp
The entries
.Nm term
and
.Nm lock
have a special meaning.
When they exist they point to the terminal program and screen locking
programs used by the keybindings specified above.
The defaults for these are
.Xr xterm 1
and
.Xr xlock 1 ,
respectively.
.It Pa ~/.calmwm/.autogroup
Symlinks in this directory are read upon startup and control the
automatic grouping feature, which is based on the window name and class
properties.
To obtain the name and class of a window, use
.Ql xprop WM_CLASS ,
then click on the window.
The first quoted string is the window name; the second one is the
window class.
.Pp
The name of a link can be the window class, or the window class and name
separated by a comma.
The link target is a group name (one, two, \&..., nine).
For example, to make all windows in the
.Xr xterm 1
class go to the third group:
.Bd -literal -offset indent
$ ln -s three ~/.calmwm/.autogroup/XTerm
.Ed
.Bl -tag -width "~/.cwmrcXX" -compact
.It Pa ~/.cwmrc
Default
.Nm
configuration file.
.El
.Sh SEE ALSO
.Xr cwmrc 5
.Sh HISTORY
.Nm
was originally inspired by evilwm, but was rewritten from scratch
due to limitations in the evilwm codebase.
The from-scratch rewrite borrowed some code from 9wm, however that code
has since been removed or rewritten.
.Pp
.Nm
first appeared in
.Ox 4.2 .
.Sh AUTHORS
.An -nosplit
.Pp
.Nm
contains some code from 9wm.
.Pp
The
.Nm
software has been developed by
was developed by
.An Marius Aamodt Eriksen Aq marius@monkey.org
with contributions from
.An Andy Adamson Aq dros@monkey.org ,
.An Niels Provos Aq provos@monkey.org ,
and
.An Antti Nyk<EFBFBD>nen Aq aon@iki.fi .
.An Antti Nyk\(:anen Aq aon@iki.fi .
Ideas, discussion with many others.
.\" .Sh HISTORY
.\".Aq marius@monkey.org .
.\" .Sh CAVEATS

504
cwmrc.5 Normal file
View File

@ -0,0 +1,504 @@
.\" $OpenBSD$
.\"
.\" Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate$
.Dt CWMRC 5
.Os
.Sh NAME
.Nm cwmrc
.Nd calm window manager configuration file
.Sh DESCRIPTION
This manual page describes the
.Xr cwm 1
configuration file.
.Pp
The current line can be extended over multiple lines using a backslash
.Pq Sq \e .
Comments can be put anywhere in the file using a hash mark
.Pq Sq # ,
and extend to the end of the current line.
Care should be taken when commenting out multi-line text:
the comment is effective until the end of the entire block.
.Pp
Arguments containing whitespace should be surrounded by double quotes
.Pq \&" .
.Pp
The following options are accepted:
.Bl -tag -width Ds
.It Ic autogroup Ar group Oo Ar windowname , Oc Ns Ar windowclass
Automatically add new windows to
.Ar group
if their class property matches
.Ar windowclass ,
or if their name and class properties match
.Ar windowname
and
.Ar windowclass ,
respectively.
The more specific last match wins.
.Ar group
is a number between 0 and 9.
If
.Ar group
is 0, matching windows will not be added to any group; this may be
used to override
.Dq sticky group mode .
.Pp
The name and class values, respectively, for existing windows
are both set in the WM_CLASS property and may be obtained using
.Xr xprop 1 .
.It Ic bind-key Ar key function
Bind or rebind key
.Ar key
to
.Ar function .
The modifier keys come first, followed by a
.Sq - ,
then a keysym name, taken from
.Pa /usr/X11R6/include/X11/keysymdef.h .
.Pp
The following modifiers are recognised:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It Ic C
Control key.
.It Ic M
Meta key.
.It Ic S
Shift key.
.It Ic 4
Mod4 (windows) key.
.It Ic 5
Mod5 (AltGr) key.
.El
.Pp
The
.Ar function
may either be one from the
.Sx BIND FUNCTION LIST
(see below) or the command line that is to be executed.
.It Ic bind-mouse Ar button function
Bind or rebind button
.Ar button
to
.Ar function .
The modifier keys come first, followed by a
.Sq - ,
then the button number.
.Pp
The same modifiers are recognised as for
.Ar key
in
.Nm bind-key .
.Pp
The following buttons are recognised:
.Pp
.Bl -tag -width Ds -offset indent -compact
.It Ic 1
Left mouse button.
.It Ic 2
Middle mouse button.
.It Ic 3
Right mouse button.
.It Ic 4
Scroll up mouse button.
.It Ic 5
Scroll down mouse button.
.El
.Pp
The
.Ar function
may be taken from the
.Sx BIND FUNCTION LIST
(see below) or the command line that is to be executed.
.It Ic borderwidth Ar pixels
Set the window border width to
.Ar pixels .
.It Ic color activeborder Ar color
Set the color of the active border.
.It Ic color font Ar color
Set menu font color.
.It Ic color selfont Ar color
Set font color for selected menu item.
.It Ic color groupborder Ar color
Set the color of the border while grouping a window.
.It Ic color inactiveborder Ar color
Set the color of the inactive border.
.It Ic color menubg Ar color
Set menu background color.
.It Ic color menufg Ar color
Set menu foreground color.
.It Ic color urgencyborder Ar color
Set the color of the border of a window indicating urgency.
.It Ic color ungroupborder Ar color
Set the color of the border while ungrouping a window.
.It Ic command Ar name path
Every
.Ar name
entry is shown in the application menu.
When selected, the defined
.Ar path
is executed with
.Xr execvp 3 .
.Pp
The
.Ar name
entries
.Nm term
and
.Nm lock
have a special meaning.
They point to the terminal and screen locking programs specified by
key bindings.
The defaults are
.Xr xterm 1
and
.Xr xlock 1 ,
respectively.
.It Ic fontname Ar font
Change the default
.Ar font
for
.Xr Xft 3 .
.It Ic gap Ar top bottom left right
Define a
.Dq gap
in pixels at the edge of the screen, so that when a
window is maximized it will not overlap this area.
This
.Dq gap
can be used for applications such as
.Xr xclock 1 ,
where the user may wish to remain visible.
.It Ic htile Ar percent
Set the percentage of screen the master window should occupy
after calling
.Ic window-htile .
If set to 0, the horizontal size of the master window will
remain unchanged.
The default is 50.
.It Ic ignore Ar windowname
Ignore, and do not warp to, windows with the name
.Ar windowname
when drawing borders and cycling through windows.
.It Ic moveamount Ar pixels
Set a default size for the keyboard movement bindings,
in pixels.
The default is 1.
.It Ic snapdist Ar pixels
Minimum distance to snap-to adjacent edge, in pixels.
The default is 0.
.It Ic sticky Ic yes Ns \&| Ns Ic no
Toggle sticky group mode.
The default behavior for new windows is to not assign any group.
By enabling sticky group mode,
.Xr cwm 1
will assign new windows to the currently selected group.
.It Ic unbind-key Ar key
Unbind function bound to
.Ar key .
A special
.Ar key
keyword
.Dq all
can be used to unbind all keys.
.It Ic unbind-mouse Ar button
Unbind function bound to
.Ar button .
A special
.Ar button
keyword
.Dq all
can be used to unbind all buttons.
.It Ic vtile Ar percent
Set the percentage of screen the master window should occupy
after calling
.Ic window-vtile .
If set to 0, the vertical size of the master window will
remain unchanged.
The default is 50.
.It Ic wm Ar name path
Every
.Ar name
entry is shown in the wm menu.
When selected, the window manager is replaced by
.Ar path .
.El
.Sh BIND FUNCTION LIST
.Bl -tag -width 23n -compact
.It restart
Restart the running
.Xr cwm 1 .
.It quit
Quit
.Xr cwm 1 .
.It terminal
Spawn a new terminal.
.It lock
Lock the screen.
.It menu-window
Launch window search menu.
.It menu-window-hidden
Launch hidden window search menu.
.It menu-cmd
Launch application search menu.
.It menu-group
Launch group search menu.
.It menu-exec
Launch
.Dq exec program
menu.
.It menu-exec-wm
Launch
.Dq exec WindowManager
menu.
.It menu-ssh
Launch
.Dq ssh
menu.
.It group-toggle-[n]
Toggle visibility of group n, where n is 1-9.
.It group-only-[n]
Show only group n, where n is 1-9, hiding other groups.
.It group-last
Show only the previously active group.
.It group-close-[n]
Close all windows in group n, where n is 1-9.
.It group-toggle-all
Toggle visibility of all groups.
.It window-group
Toggle group membership of current window.
.It window-movetogroup-[n]
Hide current window from display and move to group n, where n is 1-9.
.It group-cycle
Forward cycle through groups.
.It group-rcycle
Reverse cycle through groups.
.It window-cycle
Forward cycle through windows.
.It window-rcycle
Reverse cycle through windows.
.It window-cycle-ingroup
Forward cycle through windows in current group.
.It window-rcycle-ingroup
Reverse cycle through windows in current group.
.It window-close
Close current window.
.It window-hide
Hide current window.
.It window-lower
Lower current window.
.It window-raise
Raise current window.
.It window-menu-label
Label current window.
.It window-freeze
Freeze current window geometry.
.It window-stick
Stick current window to all groups (same as assigning to nogroup).
.It window-fullscreen
Full-screen current window (gap + border removed).
.It window-maximize
Maximize current window (gap + border honored).
.It window-vmaximize
Vertically maximize current window (gap + border honored).
.It window-hmaximize
Horizontally maximize current window (gap + border honored).
.It window-htile
Current window is placed at the top of the screen, maximized
horizontally and resized to
.Ar htile
(default half) of the vertical screen space.
Other windows in its group share remaining screen space.
.It window-vtile
Current window is placed on the left of the screen, maximized vertically
and resized to
.Ar vtile
(default half) of the horizontal screen space.
Other windows in its group share remaining screen space.
.It window-move
Move current window.
.It window-resize
Resize current window.
.It window-move-up
Move window
.Ar moveamount
pixels up.
.It window-move-down
Move window
.Ar moveamount
pixels down.
.It window-move-right
Move window
.Ar moveamount
pixels right.
.It window-move-left
Move window
.Ar moveamount
pixels left.
.It window-move-up-big
Move window 10 times
.Ar moveamount
pixels up.
.It window-move-down-big
Move window 10 times
.Ar moveamount
pixels down.
.It window-move-right-big
Move window 10 times
.Ar moveamount
pixels right.
.It window-move-left-big
Move window 10 times
.Ar moveamount
pixels left.
.It window-resize-up
Resize window
.Ar moveamount
pixels up.
.It window-resize-down
Resize window
.Ar moveamount
pixels down.
.It window-resize-right
Resize window
.Ar moveamount
pixels right.
.It window-resize-left
Resize window
.Ar moveamount
pixels left.
.It window-resize-up-big
Resize window 10 times
.Ar moveamount
pixels up.
.It window-resize-down-big
Resize window 10 times
.Ar moveamount
pixels down.
.It window-resize-right-big
Resize window 10 times
.Ar moveamount
pixels right.
.It window-resize-left-big
Resize window 10 times
.Ar moveamount
pixels left.
.It window-snap-up
Snap window to top edge.
.It window-snap-down
Snap window to bottom edge.
.It window-snap-right
Snap window to right edge.
.It window-snap-left
Snap window to left edge.
.It window-snap-up-right
Snap window to top-right corner.
.It window-snap-up-left
Snap window to top-left corner.
.It window-snap-down-right
Snap window to bottom-right corner.
.It window-snap-down-left
Snap window to bottom-left corner.
.It pointer-move-up
Move pointer
.Ar moveamount
pixels up.
.It pointer-move-down
Move pointer
.Ar moveamount
pixels down.
.It pointer-move-right
Move pointer
.Ar moveamount
pixels right.
.It pointer-move-left
Move pointer
.Ar moveamount
pixels left.
.It pointer-move-up-big
Move pointer 10 times
.Ar moveamount
pixels up.
.It pointer-move-down-big
Move pointer 10 times
.Ar moveamount
pixels down.
.It pointer-move-right-big
Move pointer 10 times
.Ar moveamount
pixels right.
.It pointer-move-left-big
Move pointer 10 times
.Ar moveamount
pixels left.
.El
.Sh FILES
.Bl -tag -width "~/.cwmrcXXX" -compact
.It Pa ~/.cwmrc
Default
.Xr cwm 1
configuration file.
.El
.Sh EXAMPLES
.Bd -literal
# Set default Xft(3) font
fontname "sans-serif:pixelsize=14:bold"
# Turn on sticky-group mode
sticky yes
# Any entry here is shown in the application menu
command firefox firefox
command xmms xmms
command top "xterm -e top"
# Autogroup definitions
autogroup 3 "aterm,XTerm"
autogroup 3 "xterm,XTerm"
# Ignore programs by that name by not drawing borders around them.
ignore XMMS
ignore xwi
ignore xapm
ignore xclock
# Key bindings
bind-key CM-r window-menu-label
bind-key CS-Return "xterm -e top"
bind-key C4-equal window-vmaximize
bind-key C4S-equal window-hmaximize
bind-key M-1 group-only-1
bind-key M-2 group-only-2
bind-key M-3 group-only-3
bind-key MS-1 window-movetogroup-1
bind-key MS-2 window-movetogroup-2
bind-key MS-3 window-movetogroup-3
unbind-key 4-o
unbind-key CM-equal
unbind-key CMS-equal
# Mouse bindings
bind-mouse M-2 window-lower
bind-mouse M-3 window-resize
.Ed
.Sh SEE ALSO
.Xr cwm 1
.Sh HISTORY
The
.Nm
file format first appeared in
.Ox 4.4 .

21
draw.c
View File

@ -1,21 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
void
draw_outline(struct client_ctx *cc)
{
struct screen_ctx *sc = CCTOSC(cc);
XDrawRectangle(X_Dpy, sc->rootwin, sc->invgc,
cc->geom.x - cc->bwidth, cc->geom.y - cc->bwidth,
cc->geom.width + cc->bwidth, cc->geom.height + cc->bwidth);
}

159
font.c
View File

@ -1,159 +0,0 @@
/*
* font.c - cwm font abstraction
*
* Copyright (c) 2005 Marius Eriksen <marius@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "hash.h"
#include "headers.h"
#include "calmwm.h"
static XftFont *_make_font(struct screen_ctx *sc, struct fontdesc *fdp);
HASH_GENERATE(fonthash, fontdesc, node, fontdesc_cmp);
int
fontdesc_cmp(struct fontdesc *a, struct fontdesc *b)
{
return strcmp(a->name, b->name);
}
/*
* Fowler/Noll/Vo hash
* http://www.isthe.com/chongo/tech/comp/fnv/
*/
#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
unsigned int
fontdesc_hash(struct fontdesc *fdp)
{
const unsigned char *p, *end, *start;
unsigned int hash = FNV_1_32;
start = fdp->name;
end = (const unsigned char *)fdp->name + strlen(fdp->name);
for (p = start; p < end; p++) {
hash *= FNV_P_32;
hash ^= (unsigned int)*p;
}
return (hash);
}
void
font_init(struct screen_ctx *sc)
{
XColor xcolor, tmp;
HASH_INIT(&sc->fonthash, fontdesc_hash);
sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
if (sc->xftdraw == NULL)
errx(1, "XftDrawCreate");
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
"black", &xcolor, &tmp))
errx(1, "XAllocNamedColor");
sc->xftcolor.color.red = xcolor.red;
sc->xftcolor.color.green = xcolor.green;
sc->xftcolor.color.blue = xcolor.blue;
sc->xftcolor.color.alpha = 0x00ff00;
sc->xftcolor.pixel = xcolor.pixel;
}
struct fontdesc *
font_getx(struct screen_ctx *sc, const char *name)
{
struct fontdesc *fdp;
if ((fdp = font_get(sc, name)) == NULL)
errx(1, "font_get()");
return (fdp);
}
struct fontdesc *
font_get(struct screen_ctx *sc, const char *name)
{
struct fontdesc fd, *fdp;
XftFont *fn;
fd.name = name;
if ((fdp = HASH_FIND(fonthash, &sc->fonthash, &fd)) == NULL
&& (fn = _make_font(sc, &fd)) != NULL) {
fdp = xmalloc(sizeof(*fdp));
fdp->name = xstrdup(fd.name);
fdp->fn = fn;
fdp->sc = sc;
HASH_INSERT(fonthash, &sc->fonthash, fdp);
}
return (fdp);
}
int
font_width(struct fontdesc *fdp, const char *text, int len)
{
XGlyphInfo extents;
XftTextExtents8(X_Dpy, fdp->fn, (const XftChar8*)text, len, &extents);
return (extents.xOff);
}
void
font_draw(struct fontdesc *fdp, const char *text, int len,
Drawable d, int x, int y)
{
XftDrawChange(fdp->sc->xftdraw, d);
/* Really needs to be UTF8'd. */
XftDrawString8(fdp->sc->xftdraw, &fdp->sc->xftcolor, fdp->fn, x, y,
(const FcChar8*)text, len);
}
int
font_ascent(struct fontdesc *fdp)
{
return fdp->fn->ascent;
}
int
font_descent(struct fontdesc *fdp)
{
return fdp->fn->descent;
}
static XftFont *
_make_font(struct screen_ctx *sc, struct fontdesc *fdp)
{
XftFont *fn = NULL;
FcPattern *pat, *patx;
XftResult res;
if ((pat = FcNameParse(fdp->name)) == NULL)
return (NULL);
if ((patx = XftFontMatch(X_Dpy, sc->which, pat, &res)) != NULL)
fn = XftFontOpenPattern(X_Dpy, patx);
FcPatternDestroy(pat);
return (fn);
}

View File

@ -1,53 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
struct client_ctx *
geographic_west(struct client_ctx *from_cc)
{
/* Window *wins, w0, w1; */
/* struct screen_ctx *sc = screen_current(); */
/* u_int nwins, i; */
/* struct client_ctx *cc; */
screen_updatestackingorder();
return (NULL);
}
#if 0
int
_visible(struct client_ctx *this_cc)
{
int stacking = cc->stackingorder;
struct client_ctx *cc;
if (cc->flags & CLIENT_HIDDEN)
return (0);
TAILQ_FOREACH(cc, &Clientq, entry) {
if (cc->flags & CLIENT_HIDDEN)
continue;
if (cc->stackingorder > stacking &&
cc->geom.x <= this_cc->geom.x &&
cc->geom.y <= this_cc->geom.y &&
cc->geom.width > (this_cc->geom.width +
(this_cc->geom.x - cc->geom.x) &&
cc->geom.height > (this_cc->geom.height - cc->geom.height))
return (0);
}
return (1);
}
#endif

560
grab.c
View File

@ -1,560 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
int _sweepcalc(struct client_ctx *, int, int, int, int);
int _nobuttons(XButtonEvent *);
#define ADJUST_HEIGHT(cc, dy) ((cc->geom.height - cc->geom.min_dy)/ dy)
#define ADJUST_WIDTH(cc, dx) ((cc->geom.width - cc->geom.min_dx)/ dx)
void
grab_sweep_draw(struct client_ctx *cc, int dx, int dy)
{
struct screen_ctx *sc = CCTOSC(cc);
int x0 = cc->geom.x, y0 = cc->geom.y;
char asize[10]; /* fits "nnnnxnnnn\0" */
int wide, height, wide_size, wide_name;
struct fontdesc *font = DefaultFont;
snprintf(asize, sizeof(asize), "%dx%d",
ADJUST_WIDTH(cc, dx), ADJUST_HEIGHT(cc, dy));
wide_size = font_width(font, asize, strlen(asize)) + 4;
wide_name = font_width(font, cc->name, strlen(cc->name)) + 4;
wide = MAX(wide_size, wide_name);
height = font_ascent(font) + font_descent(font) + 1;
XMoveResizeWindow(X_Dpy, sc->menuwin, x0, y0, wide, height * 2);
XMapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, cc->win, 0, 0);
XClearWindow(X_Dpy, sc->menuwin);
font_draw(font, cc->name, strlen(cc->name), sc->menuwin,
2, font_ascent(font) + 1);
font_draw(font, asize, strlen(asize), sc->menuwin,
wide/2 - wide_size/2, height + font_ascent(font) + 1);
}
int
grab_sweep(struct client_ctx *cc)
{
XEvent ev;
struct screen_ctx *sc = CCTOSC(cc);
int x0 = cc->geom.x, y0 = cc->geom.y;
int dx, dy;
dx = MAX(1, cc->size->width_inc);
dy = MAX(1, cc->size->height_inc);
client_raise(cc);
client_ptrsave(cc);
if (xu_ptr_grab(sc->rootwin, MouseMask, Cursor_resize) < 0)
return (-1);
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
grab_sweep_draw(cc, dx, dy);
for (;;) {
/* Look for changes in ptr position. */
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
switch (ev.type) {
case Expose:
client_draw_border(cc);
break;
case MotionNotify:
if (_sweepcalc(cc, x0, y0, ev.xmotion.x, ev.xmotion.y))
/* Recompute window output */
grab_sweep_draw(cc, dx, dy);
XMoveResizeWindow(X_Dpy, cc->pwin,
cc->geom.x - cc->bwidth,
cc->geom.y - cc->bwidth,
cc->geom.width + cc->bwidth*2,
cc->geom.height + cc->bwidth*2);
XMoveResizeWindow(X_Dpy, cc->win,
cc->bwidth, cc->bwidth,
cc->geom.width, cc->geom.height);
break;
case ButtonRelease:
XUnmapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0);
xu_ptr_ungrab();
client_ptrwarp(cc);
return (0);
}
}
/* NOTREACHED */
}
int
grab_drag(struct client_ctx *cc)
{
int x0 = cc->geom.x, y0 = cc->geom.y, xm, ym;
struct screen_ctx *sc = CCTOSC(cc);
XEvent ev;
client_raise(cc);
if (xu_ptr_grab(sc->rootwin, MouseMask, Cursor_move) < 0)
return (-1);
xu_ptr_getpos(sc->rootwin, &xm, &ym);
for (;;) {
XMaskEvent(X_Dpy, MouseMask|ExposureMask, &ev);
switch (ev.type) {
case Expose:
client_draw_border(cc);
break;
case MotionNotify:
cc->geom.x = x0 + (ev.xmotion.x - xm);
cc->geom.y = y0 + (ev.xmotion.y - ym);
XMoveWindow(X_Dpy, cc->pwin,
cc->geom.x - cc->bwidth, cc->geom.y - cc->bwidth);
break;
case ButtonRelease:
xu_ptr_ungrab();
return (0);
}
}
/* NOTREACHED */
}
/*
* Adapted from 9wm.
*/
/* XXX - this REALLY needs to be cleaned up. */
#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask)
#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask)
#define AllButtonMask (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
#ifdef notyet
struct client_ctx *
grab_menu_getcc(struct menu_q *menuq, int off)
{
int where = 0;
struct menu *mi;
TAILQ_FOREACH(mi, menuq, entry)
if (off == where++)
return mi->ctx;
return (NULL);
}
#endif
void *
grab_menu(XButtonEvent *e, struct menu_q *menuq)
{
struct screen_ctx *sc;
struct menu *mi;
XEvent ev;
int i, n, cur = 0, old, wide, high, status, drawn, warp;
int x, y, dx, dy, xmax, ymax;
int tx, ty;
struct fontdesc *font = DefaultFont;
if ((sc = screen_fromroot(e->root)) == NULL || e->window == sc->menuwin)
return (NULL);
dx = 0;
i = 0;
TAILQ_FOREACH(mi, menuq, entry) {
wide = font_width(font, mi->text, strlen(mi->text)) + 4;
if (wide > dx)
dx = wide;
if (mi->lasthit)
cur = i;
i++;
}
n = i;
wide = dx;
high = font_ascent(font) + font_descent(font) + 1;
dy = n*high;
x = e->x - wide/2;
y = e->y - cur*high - high/2;
warp = 0;
/* XXX - cache these in sc. */
xmax = DisplayWidth(X_Dpy, sc->which);
ymax = DisplayHeight(X_Dpy, sc->which);
if (x < 0) {
e->x -= x;
x = 0;
warp++;
}
if (x+wide >= xmax) {
e->x -= x+wide-xmax;
x = xmax-wide;
warp++;
}
if (y < 0) {
e->y -= y;
y = 0;
warp++;
}
if (y+dy >= ymax) {
e->y -= y+dy-ymax;
y = ymax-dy;
warp++;
}
if (warp)
xu_ptr_setpos(e->root, e->x, e->y);
XMoveResizeWindow(X_Dpy, sc->menuwin, x, y, dx, dy);
XSelectInput(X_Dpy, sc->menuwin, MenuMask);
XMapRaised(X_Dpy, sc->menuwin);
status = xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_select);
if (status < 0) {
XUnmapWindow(X_Dpy, sc->menuwin);
return (NULL);
}
drawn = 0;
#ifdef notyet
if (e->button == Button1) {
struct client_ctx *cc;
cc = grab_menu_getcc(menuq, cur);
if (cc != NULL) {
client_unhide(cc);
XRaiseWindow(X_Dpy, sc->menuwin);
}
}
#endif
for (;;) {
XMaskEvent(X_Dpy, MenuMask, &ev);
switch (ev.type) {
default:
warnx("menuhit: unknown ev.type %d\n", ev.type);
break;
case ButtonPress:
break;
case ButtonRelease:
if (ev.xbutton.button != e->button)
break;
x = ev.xbutton.x;
y = ev.xbutton.y;
i = y/high;
if (cur >= 0 && y >= cur*high-3 && y < (cur+1)*high+3)
i = cur;
if (x < 0 || x > wide || y < -3)
i = -1;
else if (i < 0 || i >= n)
i = -1;
/* else */
/* m->lasthit = i; */
if (!_nobuttons(&ev.xbutton))
i = -1;
/* XXX */
/* ungrab(&ev.xbutton); */
xu_ptr_ungrab();
XUnmapWindow(X_Dpy, sc->menuwin);
n = 0;
TAILQ_FOREACH(mi, menuq, entry)
if (i == n++)
break;
return (mi);
case MotionNotify:
if (!drawn)
break;
x = ev.xbutton.x;
y = ev.xbutton.y;
old = cur;
cur = y/high;
if (old >= 0 && y >= old*high-3 && y < (old+1)*high+3)
cur = old;
if (x < 0 || x > wide || y < -3)
cur = -1;
else if (cur < 0 || cur >= n)
cur = -1;
if (cur == old)
break;
if (old >= 0 && old < n) {
#ifdef notyet
if (e->button == Button1) {
struct client_ctx *cc;
cc = grab_menu_getcc(menuq, old);
if (cc != NULL)
client_hide(cc);
}
#endif
XFillRectangle(X_Dpy, sc->menuwin,
sc->hlgc, 0, old*high, wide, high);
}
if (cur >= 0 && cur < n) {
#ifdef notyet
if (e->button == Button1) {
struct client_ctx *cc;
cc = grab_menu_getcc(menuq, cur);
if (cc != NULL) {
client_unhide(cc);
XRaiseWindow(X_Dpy,
sc->menuwin);
}
}
#endif
xu_ptr_regrab(MenuGrabMask, Cursor_select);
XFillRectangle(X_Dpy, sc->menuwin,
sc->hlgc, 0, cur*high, wide, high);
} else
xu_ptr_regrab(MenuGrabMask, Cursor_default);
break;
case Expose:
XClearWindow(X_Dpy, sc->menuwin);
i = 0;
TAILQ_FOREACH(mi, menuq, entry) {
tx = (wide - font_width(font, mi->text,
strlen(mi->text)))/2;
ty = i*high + font_ascent(font) + 1;
font_draw(font, mi->text, strlen(mi->text),
sc->menuwin, tx, ty);
i++;
}
if (cur >= 0 && cur < n)
XFillRectangle(X_Dpy, sc->menuwin,
sc->hlgc, 0, cur*high, wide, high);
drawn = 1;
}
}
}
void
grab_menuinit(struct screen_ctx *sc)
{
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
}
#define LABEL_MAXLEN 256
#define LabelMask (KeyPressMask|ExposureMask)
void
grab_label(struct client_ctx *cc)
{
struct screen_ctx *sc = screen_current();
int x, y, dx, dy, fontheight, focusrevert;
XEvent e;
char labelstr[LABEL_MAXLEN];
char dispstr[LABEL_MAXLEN + sizeof("label>") - 1];
Window focuswin;
char chr;
enum ctltype ctl;
size_t len;
struct fontdesc *font = DefaultFont;
if (cc->label != NULL)
strlcpy(labelstr, cc->label, sizeof(labelstr));
else
labelstr[0] = '\0';
xu_ptr_getpos(sc->rootwin, &x, &y);
dy = fontheight = font_ascent(font) + font_descent(font) + 1;
dx = font_width(font, "label>", 6);
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
XSelectInput(X_Dpy, sc->searchwin, LabelMask);
XMapRaised(X_Dpy, sc->searchwin);
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, sc->searchwin,
RevertToPointerRoot, CurrentTime);
for (;;) {
XMaskEvent(X_Dpy, LabelMask, &e);
switch (e.type) {
case KeyPress:
if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
&ctl, &chr, 0) < 0)
continue;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(labelstr)) > 0)
labelstr[len - 1] = '\0';
break;
case CTL_RETURN:
/* Done */
if (strlen(labelstr) == 0)
goto out;
if (cc->label != NULL)
xfree(cc->label);
cc->label = xstrdup(labelstr);
case CTL_ABORT:
goto out;
default:
break;
}
if (chr != '\0') {
char str[2];
str[0] = chr;
str[1] = '\0';
strlcat(labelstr, str, sizeof(labelstr));
}
case Expose:
snprintf(dispstr, sizeof(dispstr), "label>%s", labelstr);
dx = font_width(font, dispstr, strlen(dispstr));
dy = fontheight;
XClearWindow(X_Dpy, sc->searchwin);
XResizeWindow(X_Dpy, sc->searchwin, dx, dy);
font_draw(font, dispstr, strlen(dispstr),
sc->searchwin, 0, font_ascent(font) + 1);
break;
}
}
out:
XSetInputFocus(X_Dpy, focuswin,
focusrevert, CurrentTime);
XUnmapWindow(X_Dpy, sc->searchwin);
}
#define ExecMask (KeyPressMask|ExposureMask)
void
grab_exec(void)
{
int x, y, dx, dy, fontheight, focusrevert, len;
char cmdstr[MAXPATHLEN];
char dispstr[MAXPATHLEN + sizeof("exec>") - 1];
char chr, str[2];
enum ctltype ctl;
struct fontdesc *font = DefaultFont;
struct screen_ctx *sc = screen_current();
XEvent e;
Window focuswin;
cmdstr[0] = '\0';
xu_ptr_getpos(sc->rootwin, &x, &y);
dy = fontheight = font_ascent(font) + font_descent(font) + 1;
dx = font_width(font, "exec>", 5);
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
XSelectInput(X_Dpy, sc->searchwin, ExecMask);
XMapRaised(X_Dpy, sc->searchwin);
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, sc->searchwin,
RevertToPointerRoot, CurrentTime);
for (;;) {
XMaskEvent(X_Dpy, ExecMask, &e);
switch (e.type) {
case KeyPress:
if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
&ctl, &chr, 0) < 0)
continue;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(cmdstr)) > 0)
cmdstr[len - 1] = '\0';
break;
case CTL_RETURN:
if (strlen(cmdstr) > 0)
u_spawn(cmdstr);
goto out;
break;
case CTL_ABORT:
goto out;
default:
break;
}
if (chr != '\0') {
str[0] = chr;
str[1] = '\0';
strlcat(cmdstr, str, sizeof(cmdstr));
}
case Expose:
snprintf(dispstr, sizeof(dispstr), "exec>%s", cmdstr);
dx = font_width(font, dispstr, strlen(dispstr));
dy = fontheight;
XClearWindow(X_Dpy, sc->searchwin);
XResizeWindow(X_Dpy, sc->searchwin, dx, dy);
font_draw(font, dispstr, strlen(dispstr),
sc->searchwin, 0, font_ascent(font) + 1);
break;
}
}
out:
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
XUnmapWindow(X_Dpy, sc->searchwin);
}
int
_sweepcalc(struct client_ctx *cc, int x0, int y0, int motionx, int motiony)
{
int width, height;
width = cc->geom.width;
height = cc->geom.height;
cc->geom.width = abs(x0 - motionx);
cc->geom.height = abs(y0 - motiony);
if (cc->size->flags & PResizeInc) {
cc->geom.width -=
(cc->geom.width - cc->geom.min_dx) % cc->size->width_inc;
cc->geom.height -=
(cc->geom.height - cc->geom.min_dy) % cc->size->height_inc;
}
if (cc->size->flags & PMinSize) {
cc->geom.width = MAX(cc->geom.width, cc->size->min_width);
cc->geom.height = MAX(cc->geom.height, cc->size->min_height);
}
if (cc->size->flags & PMaxSize) {
cc->geom.width = MIN(cc->geom.width, cc->size->max_width);
cc->geom.height = MIN(cc->geom.height, cc->size->max_height);
}
cc->geom.x = x0 <= motionx ? x0 : x0 - cc->geom.width;
cc->geom.y = y0 <= motiony ? y0 : y0 - cc->geom.height;
return (width != cc->geom.width || height != cc->geom.height);
}
/* XXX */
int
_nobuttons(XButtonEvent *e) /* Einstuerzende */
{
int state;
state = (e->state & AllButtonMask);
return (e->type == ButtonRelease) && (state & (state - 1)) == 0;
}

776
group.c
View File

@ -3,131 +3,112 @@
*
* Copyright (c) 2004 Andy Adamson <dros@monkey.org>
* Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/types.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "calmwm.h"
#define CALMWM_NGROUPS 9
static struct group_ctx *group_next(struct group_ctx *);
static struct group_ctx *group_prev(struct group_ctx *);
static void group_restack(struct group_ctx *);
static void group_set_active(struct group_ctx *);
int Groupmode = 0;
int Groupnamemode = 0;
struct group_ctx *Group_active = NULL;
struct group_ctx *Group_current = NULL;
struct group_ctx Groups[CALMWM_NGROUPS];
char Group_name[256];
int Groupfocusset = 0;
Window Groupfocuswin;
int Groupfocusrevert;
int Grouphideall = 0;
struct group_ctx_q Groupq;
#define GroupMask (KeyPressMask|ExposureMask)
static char *shortcut_to_name[] = {
"XXX", "one", "two", "three",
"four", "five", "six", "seven",
"eight", "nine",
};
static void
_group_add(struct group_ctx *gc, struct client_ctx *cc)
void
group_assign(struct group_ctx *gc, struct client_ctx *cc)
{
if (cc == NULL || gc == NULL)
errx(1, "_group_add: a ctx is NULL");
if ((gc != NULL) && (gc->num == 0))
gc = NULL;
if (cc->group == gc)
return;
cc->gc = gc;
if (cc->group != NULL)
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
cc->group = gc;
cc->groupcommit = 0;
xu_ewmh_set_net_wm_desktop(cc);
}
static void
_group_remove(struct client_ctx *cc)
void
group_hide(struct group_ctx *gc)
{
if (cc == NULL || cc->group == NULL)
errx(1, "_group_remove: a ctx is NULL");
struct screen_ctx *sc = gc->sc;
struct client_ctx *cc;
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL;
cc->groupcommit = 0;
cc->highlight = 0;
client_draw_border(cc);
}
screen_updatestackingorder(gc->sc);
static void
_group_commit(struct group_ctx *gc)
{
struct client_ctx *cc;
if (gc == NULL)
errx(1, "_group_commit: ctx is null");
TAILQ_FOREACH(cc, &gc->clients, group_entry)
cc->groupcommit = 1;
}
static void
_group_purge(struct group_ctx *gc)
{
struct client_ctx *cc;
if (gc == NULL)
errx(1, "_group_commit: ctx is null");
TAILQ_FOREACH(cc, &gc->clients, group_entry)
if (cc->groupcommit == 0)
_group_remove(cc);
}
static void
_group_hide(struct group_ctx *gc)
{
struct client_ctx *cc;
screen_updatestackingorder();
gc->nhidden = 0;
gc->highstack = 0;
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
client_hide(cc);
gc->nhidden++;
if (cc->stackingorder > gc->highstack)
gc->highstack = cc->stackingorder;
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (!(cc->flags & CLIENT_STICKY) &&
!(cc->flags & CLIENT_HIDDEN))
client_hide(cc);
}
gc->hidden = 1; /* XXX: equivalent to gc->nhidden > 0 */
}
void
group_show(struct group_ctx *gc)
{
struct screen_ctx *sc = gc->sc;
struct client_ctx *cc;
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (!(cc->flags & CLIENT_STICKY) &&
(cc->flags & CLIENT_HIDDEN))
client_show(cc);
}
group_restack(gc);
group_set_active(gc);
}
static void
_group_show(struct group_ctx *gc)
group_restack(struct group_ctx *gc)
{
struct client_ctx *cc;
Window *winlist;
u_int i;
int lastempty = -1;
struct screen_ctx *sc = gc->sc;
struct client_ctx *cc;
Window *winlist;
int i, lastempty = -1;
int nwins = 0, highstack = 0;
winlist = (Window *) xcalloc(sizeof(*winlist) * (gc->highstack + 1));
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (cc->stackingorder > highstack)
highstack = cc->stackingorder;
}
winlist = xreallocarray(NULL, (highstack + 1), sizeof(*winlist));
/*
* Invert the stacking order as XRestackWindows() expects them
* top-to-bottom.
*/
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
winlist[gc->highstack - cc->stackingorder] = cc->pwin;
client_unhide(cc);
/* Invert the stacking order for XRestackWindows(). */
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
winlist[highstack - cc->stackingorder] = cc->win;
nwins++;
}
/* Un-sparseify */
for (i = 0; i <= gc->highstack; i++) {
for (i = 0; i <= highstack; i++) {
if (!winlist[i] && lastempty == -1)
lastempty = i;
else if (winlist[i] && lastempty != -1) {
@ -137,498 +118,261 @@ _group_show(struct group_ctx *gc)
}
}
XRestackWindows(X_Dpy, winlist, gc->nhidden);
xfree(winlist);
gc->hidden = 0;
Group_active = gc;
}
static void
_group_destroy(struct group_ctx *gc)
{
struct client_ctx *cc;
if (gc->name != NULL) {
xfree(gc->name);
gc->name = NULL;
}
while ((cc = TAILQ_FIRST(&gc->clients)) != NULL) {
TAILQ_REMOVE(&gc->clients, cc, group_entry);
cc->group = NULL;
cc->groupcommit = 0;
cc->highlight = 0;
client_draw_border(cc);
}
XRestackWindows(X_Dpy, winlist, nwins);
free(winlist);
}
void
group_init(void)
group_init(struct screen_ctx *sc, int num, const char *name)
{
int i;
struct group_ctx *gc;
TAILQ_INIT(&Groupq);
gc = xmalloc(sizeof(*gc));
gc->sc = sc;
gc->name = xstrdup(name);
gc->num = num;
TAILQ_INSERT_TAIL(&sc->groupq, gc, entry);
for (i = 0; i < CALMWM_NGROUPS; i++) {
TAILQ_INIT(&Groups[i].clients);
Groups[i].hidden = 0;
Groups[i].shortcut = i + 1;
TAILQ_INSERT_TAIL(&Groupq, &Groups[i], entry);
}
Group_current = Group_active = &Groups[0];
if (num == 1)
group_set_active(gc);
}
/*
* manipulate the 'current group'
*/
#if 0
/* set current group to the first empty group
* returns 0 on success, -1 if there are no empty groups
*/
int
group_new(void)
void
group_set_active(struct group_ctx *gc)
{
int i;
struct screen_ctx *sc = gc->sc;
for (i=0; i < CALMWM_NGROUPS; i++) {
if (TAILQ_EMPTY(&Groups[i].clients)) {
Group_current = &Groups[i];
sc->group_active = gc;
return (0);
xu_ewmh_net_current_desktop(sc);
}
void
group_movetogroup(struct client_ctx *cc, int idx)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == idx) {
if (cc->gc == gc)
return;
if (gc->num != 0 && group_holds_only_hidden(gc))
client_hide(cc);
group_assign(gc, cc);
}
}
return (-1);
}
#endif
/* change the current group */
void
group_toggle_membership(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc = sc->group_active;
if (cc->gc == gc) {
group_assign(NULL, cc);
cc->flags |= CLIENT_UNGROUP;
} else {
group_assign(gc, cc);
cc->flags |= CLIENT_GROUP;
}
client_draw_border(cc);
}
int
group_select(int idx)
group_holds_only_sticky(struct group_ctx *gc)
{
struct group_ctx *gc = Group_current;
struct client_ctx *cc;
struct screen_ctx *sc = gc->sc;
struct client_ctx *cc;
if (idx < 0 || idx >= CALMWM_NGROUPS)
return (-1);
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
cc->highlight = 0;
client_draw_border(cc);
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (!(cc->flags & CLIENT_STICKY))
return 0;
}
_group_commit(gc);
Group_current = &Groups[idx];
group_display_draw(screen_current());
return (0);
return 1;
}
/* enter group mode */
void
group_enter(void)
int
group_holds_only_hidden(struct group_ctx *gc)
{
if (Groupmode != 0)
errx(1, "group_enter called twice");
struct screen_ctx *sc = gc->sc;
struct client_ctx *cc;
if (Group_current == NULL)
Group_current = &Groups[0];
/* setup input buffer */
Group_name[0] = '\0';
Groupmode = 1;
group_display_init(screen_current());
group_display_draw(screen_current());
}
/* exit group mode */
void
group_exit(int commit)
{
struct group_ctx *gc = Group_current;
struct client_ctx *cc;
if (Groupmode != 1)
errx(1, "group_exit called twice");
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
cc->highlight = 0;
client_draw_border(cc);
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (!(cc->flags & (CLIENT_HIDDEN | CLIENT_STICKY)))
return 0;
}
return 1;
}
if (commit) {
_group_commit(gc);
} else {
/* abort */
_group_purge(gc);
if (!TAILQ_EMPTY(&gc->clients))
_group_destroy(gc);
void
group_only(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
if (sc->group_last != sc->group_active)
sc->group_last = sc->group_active;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == idx)
group_show(gc);
else
group_hide(gc);
}
}
XUnmapWindow(X_Dpy, screen_current()->groupwin);
void
group_toggle(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
if (Groupnamemode) {
XSetInputFocus(X_Dpy, Groupfocuswin, Groupfocusrevert,
CurrentTime);
Groupfocusset = 0;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == idx) {
if (group_holds_only_hidden(gc))
group_show(gc);
else
group_hide(gc);
}
}
Groupmode = Groupnamemode = 0;
}
void
group_click(struct client_ctx *cc)
group_toggle_all(struct screen_ctx *sc)
{
struct group_ctx *gc = Group_current;
struct group_ctx *gc;
if (gc == cc->group)
_group_remove(cc);
else
_group_add(gc, cc);
group_display_draw(screen_current());
}
/* Used to add a newly mapped window to the active group */
void
group_sticky(struct client_ctx *cc)
{
_group_add(Group_active, cc);
}
void
group_sticky_toggle_enter(struct client_ctx *cc)
{
struct group_ctx *gc = Group_active;
if (gc == cc->group) {
_group_remove(cc);
cc->highlight = CLIENT_HIGHLIGHT_RED;
} else {
_group_add(gc, cc);
cc->highlight = CLIENT_HIGHLIGHT_BLUE;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (sc->hideall)
group_show(gc);
else
group_hide(gc);
}
client_draw_border(cc);
sc->hideall = !sc->hideall;
}
void
group_sticky_toggle_exit(struct client_ctx *cc)
group_close(struct screen_ctx *sc, int idx)
{
cc->highlight = 0;
client_draw_border(cc);
}
struct group_ctx *gc;
struct client_ctx *cc;
/*
* selection list display
*/
void
group_display_init(struct screen_ctx *sc)
{
sc->groupwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
}
void
group_display_draw(struct screen_ctx *sc)
{
struct group_ctx *gc = Group_current;
int x, y, dx, dy, fontheight, titlelen;
struct client_ctx *cc;
char titlebuf[1024];
struct fontdesc *font = DefaultFont;
snprintf(titlebuf, sizeof(titlebuf), "Editing group %d", gc->shortcut);
x = y = 0;
fontheight = font_ascent(font) + font_descent(font) + 1;
dx = titlelen = font_width(font, titlebuf, strlen(titlebuf));
dy = fontheight;
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
cc->highlight = CLIENT_HIGHLIGHT_BLUE;
client_draw_border(cc);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == idx) {
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
client_close(cc);
}
}
}
XMoveResizeWindow(X_Dpy, sc->groupwin, x, y, dx, dy);
/* XXX */
XSelectInput(X_Dpy, sc->groupwin, GroupMask);
XMapRaised(X_Dpy, sc->groupwin);
XClearWindow(X_Dpy, sc->groupwin);
font_draw(font, titlebuf, strlen(titlebuf), sc->groupwin,
0, font_ascent(font) + 1);
}
void
group_display_keypress(KeyCode k)
{
struct group_ctx * gc = Group_current;
char chr;
enum ctltype ctl;
int len;
if (!Groupnamemode)
return;
if (input_keycodetrans(k, 0, &ctl, &chr, 1) < 0)
goto out;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(Group_name)) > 0)
Group_name[len - 1] = '\0';
break;
case CTL_RETURN:
if (gc->name != NULL)
xfree(gc->name);
gc->name = xstrdup(Group_name);
group_exit(1);
return;
default:
break;
}
if (chr != '\0')
snprintf(Group_name, sizeof(Group_name), "%s%c",
Group_name, chr);
out:
group_display_draw(screen_current());
}
/* if group_hidetoggle would produce no effect, toggle the group's hidden state
*/
void
_group_fix_hidden_state(struct group_ctx *gc)
{
struct client_ctx *cc;
int same = 0;
TAILQ_FOREACH(cc, &gc->clients, group_entry) {
if (gc->hidden == ((cc->flags & CLIENT_HIDDEN) ? 1 : 0))
same++;
}
if (same == 0)
gc->hidden = !gc->hidden;
}
void
group_hidetoggle(int idx)
group_cycle(struct screen_ctx *sc, int flags)
{
struct group_ctx *gc;
#ifdef notyet
char buf[128];
#endif
struct group_ctx *newgc, *oldgc, *showgroup = NULL;
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_hidetoggle: index out of range (%d)", idx);
oldgc = sc->group_active;
gc = &Groups[idx];
_group_fix_hidden_state(gc);
if (gc->hidden)
_group_show(gc);
else {
_group_hide(gc);
if (TAILQ_EMPTY(&gc->clients))
Group_active = gc;
}
#ifdef notyet
snprintf(buf, sizeof(buf), "Group %d", idx + 1);
screen_infomsg(buf);
#endif
}
#define GROUP_NEXT(gc, fwd) (fwd) ? \
TAILQ_NEXT(gc, entry) : TAILQ_PREV(gc, group_ctx_q, entry)
/*
* Jump to the next/previous active group. If none exist, then just
* stay put.
*/
void
group_slide(int fwd)
{
struct group_ctx *gc, *showgroup = NULL;
assert(Group_active != NULL);
gc = Group_active;
newgc = oldgc;
for (;;) {
gc = GROUP_NEXT(gc, fwd);
if (gc == NULL)
gc = fwd ? TAILQ_FIRST(&Groupq) :
TAILQ_LAST(&Groupq, group_ctx_q);
if (gc == Group_active)
newgc = (flags & CWM_CYCLE_REVERSE) ? group_prev(newgc) :
group_next(newgc);
if (newgc == oldgc)
break;
if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
showgroup = gc;
else if (!gc->hidden)
_group_hide(gc);
if (!group_holds_only_sticky(newgc) && showgroup == NULL)
showgroup = newgc;
else if (!group_holds_only_hidden(newgc))
group_hide(newgc);
}
if (showgroup == NULL)
return;
_group_hide(Group_active);
group_hide(oldgc);
if (showgroup->hidden)
_group_show(showgroup);
if (group_holds_only_hidden(showgroup))
group_show(showgroup);
else
Group_active = showgroup;
group_set_active(showgroup);
}
/* called when a client is deleted */
void
group_client_delete(struct client_ctx *cc)
static struct group_ctx *
group_next(struct group_ctx *gc)
{
if (cc->group == NULL)
return;
struct screen_ctx *sc = gc->sc;
struct group_ctx *newgc;
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL; /* he he */
cc->groupcommit = 0;
return(((newgc = TAILQ_NEXT(gc, entry)) != NULL) ?
newgc : TAILQ_FIRST(&sc->groupq));
}
void
group_menu(XButtonEvent *e)
static struct group_ctx *
group_prev(struct group_ctx *gc)
{
struct menu_q menuq;
struct menu *mi;
int i;
struct group_ctx *gc;
struct screen_ctx *sc = gc->sc;
struct group_ctx *newgc;
TAILQ_INIT(&menuq);
return(((newgc = TAILQ_PREV(gc, group_q, entry)) != NULL) ?
newgc : TAILQ_LAST(&sc->groupq, group_q));
}
for (i = 0; i < CALMWM_NGROUPS; i++) {
gc = &Groups[i];
int
group_restore(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
int num;
long grpnum;
if (TAILQ_EMPTY(&gc->clients))
continue;
if (!xu_ewmh_get_net_wm_desktop(cc, &grpnum))
return 0;
if (gc->name == NULL)
gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
num = (grpnum == -1) ? 0 : grpnum;
num = MIN(num, (Conf.ngroups - 1));
XCALLOC(mi, struct menu);
if (gc->hidden)
snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
gc->shortcut, gc->name);
else
snprintf(mi->text, sizeof(mi->text), "%d: %s",
gc->shortcut, gc->name);
mi->ctx = gc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
if (TAILQ_EMPTY(&menuq))
return;
mi = (struct menu *)grab_menu(e, &menuq);
if (mi == NULL || mi->ctx == NULL)
goto cleanup;
gc = (struct group_ctx *)mi->ctx;
if (gc->hidden)
_group_show(gc);
else
_group_hide(gc);
cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == num) {
group_assign(gc, cc);
return 1;
}
}
return 0;
}
void
group_namemode(void)
{
Groupnamemode = 1;
group_display_draw(screen_current());
}
void
group_alltoggle(void)
{
int i;
for (i=0; i < CALMWM_NGROUPS; i++) {
if (Grouphideall)
_group_show(&Groups[i]);
else
_group_hide(&Groups[i]);
}
if (Grouphideall)
Grouphideall = 0;
else
Grouphideall = 1;
}
void
group_deletecurrent(void)
{
_group_destroy(Group_current);
XUnmapWindow(X_Dpy, screen_current()->groupwin);
Groupmode = Groupnamemode = 0;
}
void
group_done(void)
{
struct group_ctx *gc = Group_current;
if (gc->name != NULL)
xfree(gc->name);
gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
group_exit(1);
}
void
int
group_autogroup(struct client_ctx *cc)
{
struct autogroupwin *aw;
struct group_ctx *gc;
char group[CALMWM_MAXNAMELEN];
struct screen_ctx *sc = cc->sc;
struct autogroup *ag;
struct group_ctx *gc;
int num = -1, both_match = 0;
if (cc->app_class == NULL || cc->app_name == NULL)
return;
if (cc->res_class == NULL || cc->res_name == NULL)
return 0;
TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
if (strcmp(aw->class, cc->app_class) == 0 &&
(aw->name == NULL || strcmp(aw->name, cc->app_name) == 0)) {
strlcpy(group, aw->group, sizeof(group));
break;
TAILQ_FOREACH(ag, &Conf.autogroupq, entry) {
if (strcmp(ag->class, cc->res_class) == 0) {
if ((ag->name != NULL) &&
(strcmp(ag->name, cc->res_name) == 0)) {
num = ag->num;
both_match = 1;
} else if (ag->name == NULL && !both_match)
num = ag->num;
}
}
TAILQ_FOREACH(gc, &Groupq, entry) {
if (strcmp(shortcut_to_name[gc->shortcut], group) == 0)
_group_add(gc, cc);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == num) {
group_assign(gc, cc);
return 1;
}
}
return 0;
}

68
hash.h
View File

@ -1,68 +0,0 @@
/*
* hash.h - generic hash template, akin to queue.h & tree.h
*
* Copyright (c) 2005 Marius Eriksen <marius@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _HASH_H_ /* Possibly this is too generic. */
#define _HASH_H_
#include <sys/tree.h>
#define HASH_ENTRY SPLAY_ENTRY
#define HASH_HEAD(name, type, nbuckets) \
SPLAY_HEAD(name##_HASH_TREE, type); \
struct name { \
struct name##_HASH_TREE buckets[nbuckets]; \
unsigned int (*hashfn)(struct type *elm); \
};
#define HASH_NBUCKETS(head) \
(sizeof((head)->buckets)/sizeof((head)->buckets[0]))
#define HASH_INIT(head, fn) do { \
int i; \
for (i = 0; i < HASH_NBUCKETS(head); i++) { \
SPLAY_INIT(&(head)->buckets[i]); \
} \
(head)->hashfn = fn; \
} while (0)
#define HASH_PROTOTYPE(name, type, field, cmp) \
SPLAY_PROTOTYPE(name##_HASH_TREE, type, field, cmp) \
struct type *name##_HASH_TREE_FIND(struct name *head, struct type *find); \
void name##_HASH_TREE_INSERT(struct name *head, struct type *insert);
#define HASH_GENERATE(name, type, field, cmp) \
SPLAY_GENERATE(name##_HASH_TREE, type, field, cmp) \
struct type *name##_HASH_TREE_FIND(struct name *head, struct type *find) \
{ \
struct name##_HASH_TREE *bucket = \
&head->buckets[(*head->hashfn)(find) % HASH_NBUCKETS(head)]; \
return SPLAY_FIND(name##_HASH_TREE, bucket, find); \
} \
void name##_HASH_TREE_INSERT(struct name *head, struct type *insert) \
{ \
struct name##_HASH_TREE *bucket = \
&head->buckets[(*head->hashfn)(insert) % HASH_NBUCKETS(head)]; \
\
SPLAY_INSERT(name##_HASH_TREE, bucket, insert); \
}
#define HASH_FIND(name, head, find) name##_HASH_TREE_FIND((head), (find))
#define HASH_INSERT(name, head, insert) name##_HASH_TREE_INSERT((head), (insert))
#endif /* _HASH_H_ */

View File

@ -1,44 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#ifndef _CALMWM_HEADERS_H_
#define _CALMWM_HEADERS_H_
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <dirent.h>
#include <getopt.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <X11/cursorfont.h>
#include <X11/extensions/shape.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <X11/Intrinsic.h>
#include <X11/Xos.h>
#include <X11/Xft/Xft.h>
#include <err.h>
#endif /* _CALMWM_HEADERS_H_ */

84
input.c
View File

@ -1,84 +0,0 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
*/
#include "headers.h"
#include "calmwm.h"
int
input_keycodetrans(KeyCode kc, u_int state,
enum ctltype *ctl, char *chr, int normalize)
{
int ks;
*ctl = CTL_NONE;
*chr = '\0';
if (state & ShiftMask)
ks = XKeycodeToKeysym(X_Dpy, kc, 1);
else
ks = XKeycodeToKeysym(X_Dpy, kc, 0);
/* Look for control characters. */
switch (ks) {
case XK_BackSpace:
*ctl = CTL_ERASEONE;
break;
case XK_Return:
*ctl = CTL_RETURN;
break;
case XK_Up:
*ctl = CTL_UP;
break;
case XK_Down:
*ctl = CTL_DOWN;
break;
case XK_Escape:
*ctl = CTL_ABORT;
break;
}
if (*ctl == CTL_NONE && (state & ControlMask)) {
switch (ks) {
case XK_s:
case XK_S:
/* Emacs "next" */
*ctl = CTL_DOWN;
break;
case XK_r:
case XK_R:
/* Emacs "previous" */
*ctl = CTL_UP;
break;
case XK_u:
case XK_U:
*ctl = CTL_WIPE;
break;
case XK_a:
case XK_A:
*ctl = CTL_ALL;
break;
}
}
if (*ctl != CTL_NONE)
return (0);
/*
* For regular characters, only (part of, actually) Latin 1
* for now.
*/
if (ks < 0x20 || ks > 0x07e)
return (-1);
*chr = (char)ks;
if (normalize)
*chr = tolower(*chr);
return (0);
}

1018
kbfunc.c

File diff suppressed because it is too large Load Diff

619
menu.c Normal file
View File

@ -0,0 +1,619 @@
/*
* calmwm - the calm window manager
*
* Copyright (c) 2008 Owain G. Ainsworth <oga@openbsd.org>
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include <sys/types.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "calmwm.h"
#define PROMPT_SCHAR "\xc2\xbb"
#define PROMPT_ECHAR "\xc2\xab"
#define MENUMASK (MOUSEMASK | ButtonMotionMask | KeyPressMask | \
ExposureMask)
#define MENUGRABMASK (MOUSEMASK | ButtonMotionMask | StructureNotifyMask)
enum ctltype {
CTL_NONE = -1,
CTL_ERASEONE = 0, CTL_WIPE, CTL_UP, CTL_DOWN, CTL_RETURN,
CTL_TAB, CTL_ABORT, CTL_ALL
};
struct menu_ctx {
struct screen_ctx *sc;
Window win;
XftDraw *xftdraw;
struct geom geom;
char searchstr[MENU_MAXENTRY + 1];
char dispstr[MENU_MAXENTRY*2 + 1];
char promptstr[MENU_MAXENTRY + 1];
int list;
int listing;
int changed;
int prev;
int entry;
int num;
int flags;
void (*match)(struct menu_q *, struct menu_q *, char *);
void (*print)(struct menu *, int);
};
static struct menu *menu_handle_key(XEvent *, struct menu_ctx *,
struct menu_q *, struct menu_q *);
static void menu_handle_move(struct menu_ctx *,
struct menu_q *, int, int);
static struct menu *menu_handle_release(struct menu_ctx *,
struct menu_q *, int, int);
static void menu_draw(struct menu_ctx *, struct menu_q *,
struct menu_q *);
static void menu_draw_entry(struct menu_ctx *, struct menu_q *,
int, int);
static int menu_calc_entry(struct menu_ctx *, int, int);
static struct menu *menu_complete_path(struct menu_ctx *);
static int menu_keycode(XKeyEvent *, enum ctltype *, char *);
struct menu *
menu_filter(struct screen_ctx *sc, struct menu_q *menuq, const char *prompt,
const char *initial, int flags,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*print)(struct menu *, int))
{
struct menu_ctx mc;
struct menu_q resultq;
struct menu *mi = NULL;
XEvent e;
Window focuswin;
int focusrevert, xsave, ysave, xcur, ycur;
TAILQ_INIT(&resultq);
xu_ptr_get(sc->rootwin, &xsave, &ysave);
(void)memset(&mc, 0, sizeof(mc));
mc.sc = sc;
mc.flags = flags;
mc.match = match;
mc.print = print;
mc.entry = mc.prev = -1;
mc.geom.x = xsave;
mc.geom.y = ysave;
if (mc.flags & CWM_MENU_LIST)
mc.list = 1;
(void)strlcpy(mc.promptstr, prompt, sizeof(mc.promptstr));
if (initial != NULL)
(void)strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
else
mc.searchstr[0] = '\0';
mc.win = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1,
Conf.bwidth,
sc->xftcolor[CWM_COLOR_MENU_FG].pixel,
sc->xftcolor[CWM_COLOR_MENU_BG].pixel);
mc.xftdraw = XftDrawCreate(X_Dpy, mc.win,
sc->visual, sc->colormap);
XSelectInput(X_Dpy, mc.win, MENUMASK);
XMapRaised(X_Dpy, mc.win);
if (XGrabPointer(X_Dpy, mc.win, False, MENUGRABMASK,
GrabModeAsync, GrabModeAsync, None, Conf.cursor[CF_QUESTION],
CurrentTime) != GrabSuccess) {
XftDrawDestroy(mc.xftdraw);
XDestroyWindow(X_Dpy, mc.win);
return NULL;
}
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, mc.win, RevertToPointerRoot, CurrentTime);
/* make sure keybindings don't remove keys from the menu stream */
XGrabKeyboard(X_Dpy, mc.win, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
for (;;) {
mc.changed = 0;
XWindowEvent(X_Dpy, mc.win, MENUMASK, &e);
switch (e.type) {
case KeyPress:
if ((mi = menu_handle_key(&e, &mc, menuq, &resultq))
!= NULL)
goto out;
/* FALLTHROUGH */
case Expose:
menu_draw(&mc, menuq, &resultq);
break;
case MotionNotify:
menu_handle_move(&mc, &resultq,
e.xbutton.x, e.xbutton.y);
break;
case ButtonRelease:
if ((mi = menu_handle_release(&mc, &resultq,
e.xbutton.x, e.xbutton.y)) != NULL)
goto out;
break;
default:
break;
}
}
out:
if ((mc.flags & CWM_MENU_DUMMY) == 0 && mi->dummy) {
/* no mouse based match */
free(mi);
mi = NULL;
}
XftDrawDestroy(mc.xftdraw);
XDestroyWindow(X_Dpy, mc.win);
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
/* restore if user didn't move */
xu_ptr_get(sc->rootwin, &xcur, &ycur);
if (xcur == mc.geom.x && ycur == mc.geom.y)
xu_ptr_set(sc->rootwin, xsave, ysave);
XUngrabPointer(X_Dpy, CurrentTime);
XUngrabKeyboard(X_Dpy, CurrentTime);
return mi;
}
static struct menu *
menu_complete_path(struct menu_ctx *mc)
{
struct screen_ctx *sc = mc->sc;
struct menu *mi, *mr;
struct menu_q menuq;
int mflags = (CWM_MENU_DUMMY);
mr = xcalloc(1, sizeof(*mr));
TAILQ_INIT(&menuq);
if ((mi = menu_filter(sc, &menuq, mc->searchstr, NULL, mflags,
search_match_path, search_print_text)) != NULL) {
mr->abort = mi->abort;
mr->dummy = mi->dummy;
if (mi->text[0] != '\0')
snprintf(mr->text, sizeof(mr->text), "%s \"%s\"",
mc->searchstr, mi->text);
else if (!mr->abort)
strlcpy(mr->text, mc->searchstr, sizeof(mr->text));
}
menuq_clear(&menuq);
return mr;
}
static struct menu *
menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
struct menu_q *resultq)
{
struct menu *mi;
enum ctltype ctl;
char chr[32];
size_t len;
int clen, i;
wchar_t wc;
if (menu_keycode(&e->xkey, &ctl, chr) < 0)
return NULL;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(mc->searchstr)) > 0) {
clen = 1;
while (mbtowc(&wc, &mc->searchstr[len-clen], MB_CUR_MAX) == -1)
clen++;
for (i = 1; i <= clen; i++)
mc->searchstr[len - i] = '\0';
mc->changed = 1;
}
break;
case CTL_UP:
mi = TAILQ_LAST(resultq, menu_q);
if (mi == NULL)
break;
TAILQ_REMOVE(resultq, mi, resultentry);
TAILQ_INSERT_HEAD(resultq, mi, resultentry);
break;
case CTL_DOWN:
mi = TAILQ_FIRST(resultq);
if (mi == NULL)
break;
TAILQ_REMOVE(resultq, mi, resultentry);
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
break;
case CTL_RETURN:
/*
* Return whatever the cursor is currently on. Else
* even if dummy is zero, we need to return something.
*/
if ((mi = TAILQ_FIRST(resultq)) == NULL) {
mi = xmalloc(sizeof(*mi));
(void)strlcpy(mi->text,
mc->searchstr, sizeof(mi->text));
mi->dummy = 1;
}
mi->abort = 0;
return mi;
case CTL_WIPE:
mc->searchstr[0] = '\0';
mc->changed = 1;
break;
case CTL_TAB:
if ((mi = TAILQ_FIRST(resultq)) != NULL) {
/*
* - We are in exec_path menu mode
* - It is equal to the input
* We got a command, launch the file menu
*/
if ((mc->flags & CWM_MENU_FILE) &&
(strncmp(mc->searchstr, mi->text,
strlen(mi->text))) == 0)
return menu_complete_path(mc);
/*
* Put common prefix of the results into searchstr
*/
(void)strlcpy(mc->searchstr,
mi->text, sizeof(mc->searchstr));
while ((mi = TAILQ_NEXT(mi, resultentry)) != NULL) {
i = 0;
while (tolower(mc->searchstr[i]) ==
tolower(mi->text[i]))
i++;
mc->searchstr[i] = '\0';
}
mc->changed = 1;
}
break;
case CTL_ALL:
mc->list = !mc->list;
break;
case CTL_ABORT:
mi = xmalloc(sizeof(*mi));
mi->text[0] = '\0';
mi->dummy = 1;
mi->abort = 1;
return mi;
default:
break;
}
if (chr[0] != '\0') {
mc->changed = 1;
(void)strlcat(mc->searchstr, chr, sizeof(mc->searchstr));
}
if (mc->changed) {
if (mc->searchstr[0] != '\0')
(*mc->match)(menuq, resultq, mc->searchstr);
} else if (!mc->list && mc->listing) {
TAILQ_INIT(resultq);
mc->listing = 0;
}
return NULL;
}
static void
menu_draw(struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq)
{
struct screen_ctx *sc = mc->sc;
struct menu *mi;
struct geom area;
int n, xsave, ysave;
XGlyphInfo extents;
if (mc->list) {
if (TAILQ_EMPTY(resultq)) {
/* Copy them all over. */
TAILQ_FOREACH(mi, menuq, entry)
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
mc->listing = 1;
} else if (mc->changed)
mc->listing = 0;
}
(void)snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%s%s",
mc->promptstr, PROMPT_SCHAR, mc->searchstr, PROMPT_ECHAR);
XftTextExtentsUtf8(X_Dpy, sc->xftfont,
(const FcChar8*)mc->dispstr, strlen(mc->dispstr), &extents);
mc->geom.w = extents.xOff;
mc->geom.h = sc->xftfont->ascent + sc->xftfont->descent;
mc->num = 1;
TAILQ_FOREACH(mi, resultq, resultentry) {
(*mc->print)(mi, mc->listing);
XftTextExtentsUtf8(X_Dpy, sc->xftfont,
(const FcChar8*)mi->print,
MIN(strlen(mi->print), MENU_MAXENTRY), &extents);
mc->geom.w = MAX(mc->geom.w, extents.xOff);
mc->geom.h += sc->xftfont->ascent + sc->xftfont->descent;
mc->num++;
}
area = screen_area(sc, mc->geom.x, mc->geom.y, 1);
area.w += area.x - Conf.bwidth * 2;
area.h += area.y - Conf.bwidth * 2;
xsave = mc->geom.x;
ysave = mc->geom.y;
/* Never hide the top, or left side, of the menu. */
if (mc->geom.x + mc->geom.w >= area.w)
mc->geom.x = area.w - mc->geom.w;
if (mc->geom.x < area.x) {
mc->geom.x = area.x;
mc->geom.w = MIN(mc->geom.w, (area.w - area.x));
}
if (mc->geom.y + mc->geom.h >= area.h)
mc->geom.y = area.h - mc->geom.h;
if (mc->geom.y < area.y) {
mc->geom.y = area.y;
mc->geom.h = MIN(mc->geom.h, (area.h - area.y));
}
if (mc->geom.x != xsave || mc->geom.y != ysave)
xu_ptr_set(sc->rootwin, mc->geom.x, mc->geom.y);
XClearWindow(X_Dpy, mc->win);
XMoveResizeWindow(X_Dpy, mc->win, mc->geom.x, mc->geom.y,
mc->geom.w, mc->geom.h);
n = 1;
XftDrawStringUtf8(mc->xftdraw,
&sc->xftcolor[CWM_COLOR_MENU_FONT], sc->xftfont,
0, sc->xftfont->ascent,
(const FcChar8*)mc->dispstr, strlen(mc->dispstr));
TAILQ_FOREACH(mi, resultq, resultentry) {
int y = n * (sc->xftfont->ascent + sc->xftfont->descent);
/* Stop drawing when menu doesn't fit inside the screen. */
if (mc->geom.y + y >= area.h)
break;
XftDrawStringUtf8(mc->xftdraw,
&sc->xftcolor[CWM_COLOR_MENU_FONT], sc->xftfont,
0, y + sc->xftfont->ascent,
(const FcChar8*)mi->print, strlen(mi->print));
n++;
}
if (n > 1)
menu_draw_entry(mc, resultq, 1, 1);
}
static void
menu_draw_entry(struct menu_ctx *mc, struct menu_q *resultq,
int entry, int active)
{
struct screen_ctx *sc = mc->sc;
struct menu *mi;
int color, i = 1, y;
TAILQ_FOREACH(mi, resultq, resultentry)
if (entry == i++)
break;
if (mi == NULL)
return;
y = entry * (sc->xftfont->ascent + sc->xftfont->descent);
color = (active) ? CWM_COLOR_MENU_FG : CWM_COLOR_MENU_BG;
XftDrawRect(mc->xftdraw, &sc->xftcolor[color], 0, y,
mc->geom.w, sc->xftfont->ascent + sc->xftfont->descent);
color = (active) ? CWM_COLOR_MENU_FONT_SEL : CWM_COLOR_MENU_FONT;
XftDrawStringUtf8(mc->xftdraw,
&sc->xftcolor[color], sc->xftfont, 0, y + sc->xftfont->ascent,
(const FcChar8*)mi->print, strlen(mi->print));
}
static void
menu_handle_move(struct menu_ctx *mc, struct menu_q *resultq, int x, int y)
{
mc->prev = mc->entry;
mc->entry = menu_calc_entry(mc, x, y);
if (mc->prev == mc->entry)
return;
if (mc->prev != -1)
menu_draw_entry(mc, resultq, mc->prev, 0);
if (mc->entry != -1) {
XChangeActivePointerGrab(X_Dpy, MENUGRABMASK,
Conf.cursor[CF_NORMAL], CurrentTime);
menu_draw_entry(mc, resultq, mc->entry, 1);
}
}
static struct menu *
menu_handle_release(struct menu_ctx *mc, struct menu_q *resultq, int x, int y)
{
struct menu *mi;
int entry, i = 1;
entry = menu_calc_entry(mc, x, y);
TAILQ_FOREACH(mi, resultq, resultentry)
if (entry == i++)
break;
if (mi == NULL) {
mi = xmalloc(sizeof(*mi));
mi->text[0] = '\0';
mi->dummy = 1;
}
return mi;
}
static int
menu_calc_entry(struct menu_ctx *mc, int x, int y)
{
struct screen_ctx *sc = mc->sc;
int entry;
entry = y / (sc->xftfont->ascent + sc->xftfont->descent);
/* in bounds? */
if (x < 0 || x > mc->geom.w || y < 0 ||
y > (sc->xftfont->ascent + sc->xftfont->descent) * mc->num ||
entry < 0 || entry >= mc->num)
entry = -1;
if (entry == 0)
entry = -1;
return entry;
}
static int
menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr)
{
KeySym ks;
*ctl = CTL_NONE;
chr[0] = '\0';
ks = XkbKeycodeToKeysym(X_Dpy, ev->keycode, 0,
(ev->state & ShiftMask) ? 1 : 0);
/* Look for control characters. */
switch (ks) {
case XK_BackSpace:
*ctl = CTL_ERASEONE;
break;
case XK_KP_Enter:
case XK_Return:
*ctl = CTL_RETURN;
break;
case XK_Tab:
*ctl = CTL_TAB;
break;
case XK_Up:
*ctl = CTL_UP;
break;
case XK_Down:
*ctl = CTL_DOWN;
break;
case XK_Escape:
*ctl = CTL_ABORT;
break;
}
if (*ctl == CTL_NONE && (ev->state & ControlMask)) {
switch (ks) {
case XK_s:
case XK_S:
/* Emacs "next" */
*ctl = CTL_DOWN;
break;
case XK_r:
case XK_R:
/* Emacs "previous" */
*ctl = CTL_UP;
break;
case XK_u:
case XK_U:
*ctl = CTL_WIPE;
break;
case XK_h:
case XK_H:
*ctl = CTL_ERASEONE;
break;
case XK_a:
case XK_A:
*ctl = CTL_ALL;
break;
case XK_bracketleft:
*ctl = CTL_ABORT;
break;
}
}
if (*ctl == CTL_NONE && (ev->state & Mod1Mask)) {
switch (ks) {
case XK_j:
case XK_J:
/* Vi "down" */
*ctl = CTL_DOWN;
break;
case XK_k:
case XK_K:
/* Vi "up" */
*ctl = CTL_UP;
break;
}
}
if (*ctl != CTL_NONE)
return 0;
if (XLookupString(ev, chr, 32, &ks, NULL) < 0)
return -1;
return 0;
}
void
menuq_add(struct menu_q *mq, void *ctx, const char *fmt, ...)
{
va_list ap;
struct menu *mi;
mi = xcalloc(1, sizeof(*mi));
mi->ctx = ctx;
va_start(ap, fmt);
if (fmt != NULL)
(void)vsnprintf(mi->text, sizeof(mi->text), fmt, ap);
else
mi->text[0] = '\0';
va_end(ap);
TAILQ_INSERT_TAIL(mq, mi, entry);
}
void
menuq_clear(struct menu_q *mq)
{
struct menu *mi;
while ((mi = TAILQ_FIRST(mq)) != NULL) {
TAILQ_REMOVE(mq, mi, entry);
free(mi);
}
}

639
parse.y Normal file
View File

@ -0,0 +1,639 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
* Copyright (c) 2001 Theo de Raadt. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
%{
#include <sys/types.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "calmwm.h"
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
static struct file {
TAILQ_ENTRY(file) entry;
FILE *stream;
char *name;
int lineno;
int errors;
} *file, *topfile;
struct file *pushfile(const char *, FILE *);
int popfile(void);
int yyparse(void);
int yylex(void);
int yyerror(const char *, ...)
__attribute__((__format__ (printf, 1, 2)))
__attribute__((__nonnull__ (1)));
int kw_cmp(const void *, const void *);
int lookup(char *);
int lgetc(int);
int lungetc(int);
int findeol(void);
static struct conf *conf;
typedef struct {
union {
int64_t number;
char *string;
} v;
int lineno;
} YYSTYPE;
%}
%token BINDKEY UNBINDKEY BINDMOUSE UNBINDMOUSE
%token FONTNAME STICKY GAP
%token AUTOGROUP COMMAND IGNORE WM
%token YES NO BORDERWIDTH MOVEAMOUNT HTILE VTILE
%token COLOR SNAPDIST
%token ACTIVEBORDER INACTIVEBORDER URGENCYBORDER
%token GROUPBORDER UNGROUPBORDER
%token MENUBG MENUFG
%token FONTCOLOR FONTSELCOLOR
%token ERROR
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.number> yesno
%type <v.string> string numberstring
%%
grammar : /* empty */
| grammar '\n'
| grammar main '\n'
| grammar color '\n'
| grammar error '\n' { file->errors++; }
;
string : string STRING {
if (asprintf(&$$, "%s %s", $1, $2) == -1) {
free($1);
free($2);
yyerror("string: asprintf");
YYERROR;
}
free($1);
free($2);
}
| STRING
;
numberstring : NUMBER {
char *s;
if (asprintf(&s, "%lld", $1) == -1) {
yyerror("string: asprintf");
YYERROR;
}
$$ = s;
}
| STRING
;
yesno : YES { $$ = 1; }
| NO { $$ = 0; }
;
main : FONTNAME STRING {
free(conf->font);
conf->font = $2;
}
| STICKY yesno {
conf->stickygroups = $2;
}
| BORDERWIDTH NUMBER {
if ($2 < 0 || $2 > INT_MAX) {
yyerror("invalid borderwidth");
YYERROR;
}
conf->bwidth = $2;
}
| HTILE NUMBER {
if ($2 < 0 || $2 > 99) {
yyerror("invalid htile percent");
YYERROR;
}
conf->htile = $2;
}
| VTILE NUMBER {
if ($2 < 0 || $2 > 99) {
yyerror("invalid vtile percent");
YYERROR;
}
conf->vtile = $2;
}
| MOVEAMOUNT NUMBER {
if ($2 < 0 || $2 > INT_MAX) {
yyerror("invalid movemount");
YYERROR;
}
conf->mamount = $2;
}
| SNAPDIST NUMBER {
if ($2 < 0 || $2 > INT_MAX) {
yyerror("invalid snapdist");
YYERROR;
}
conf->snapdist = $2;
}
| COMMAND STRING string {
if (strlen($3) >= PATH_MAX) {
yyerror("%s command path too long", $2);
free($2);
free($3);
YYERROR;
}
conf_cmd_add(conf, $2, $3);
free($2);
free($3);
}
| WM STRING string {
if (strlen($3) >= PATH_MAX) {
yyerror("%s wm path too long", $2);
free($2);
free($3);
YYERROR;
}
conf_wm_add(conf, $2, $3);
free($2);
free($3);
}
| AUTOGROUP NUMBER STRING {
if ($2 < 0 || $2 > 9) {
yyerror("invalid autogroup");
free($3);
YYERROR;
}
conf_autogroup(conf, $2, NULL, $3);
free($3);
}
| AUTOGROUP NUMBER STRING ',' STRING {
if ($2 < 0 || $2 > 9) {
yyerror("invalid autogroup");
free($3);
free($5);
YYERROR;
}
conf_autogroup(conf, $2, $3, $5);
free($3);
free($5);
}
| IGNORE STRING {
conf_ignore(conf, $2);
free($2);
}
| GAP NUMBER NUMBER NUMBER NUMBER {
if ($2 < 0 || $2 > INT_MAX ||
$3 < 0 || $3 > INT_MAX ||
$4 < 0 || $4 > INT_MAX ||
$5 < 0 || $5 > INT_MAX) {
yyerror("invalid gap");
YYERROR;
}
conf->gap.top = $2;
conf->gap.bottom = $3;
conf->gap.left = $4;
conf->gap.right = $5;
}
| BINDKEY numberstring string {
if (!conf_bind_key(conf, $2, $3)) {
yyerror("invalid bind-key: %s %s", $2, $3);
free($2);
free($3);
YYERROR;
}
free($2);
free($3);
}
| UNBINDKEY numberstring {
if (!conf_bind_key(conf, $2, NULL)) {
yyerror("invalid unbind-key: %s", $2);
free($2);
YYERROR;
}
free($2);
}
| BINDMOUSE numberstring string {
if (!conf_bind_mouse(conf, $2, $3)) {
yyerror("invalid bind-mouse: %s %s", $2, $3);
free($2);
free($3);
YYERROR;
}
free($2);
free($3);
}
| UNBINDMOUSE numberstring {
if (!conf_bind_mouse(conf, $2, NULL)) {
yyerror("invalid unbind-mouse: %s", $2);
free($2);
YYERROR;
}
free($2);
}
;
color : COLOR colors
;
colors : ACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_ACTIVE]);
conf->color[CWM_COLOR_BORDER_ACTIVE] = $2;
}
| INACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_INACTIVE]);
conf->color[CWM_COLOR_BORDER_INACTIVE] = $2;
}
| URGENCYBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_URGENCY]);
conf->color[CWM_COLOR_BORDER_URGENCY] = $2;
}
| GROUPBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_GROUP]);
conf->color[CWM_COLOR_BORDER_GROUP] = $2;
}
| UNGROUPBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_UNGROUP]);
conf->color[CWM_COLOR_BORDER_UNGROUP] = $2;
}
| MENUBG STRING {
free(conf->color[CWM_COLOR_MENU_BG]);
conf->color[CWM_COLOR_MENU_BG] = $2;
}
| MENUFG STRING {
free(conf->color[CWM_COLOR_MENU_FG]);
conf->color[CWM_COLOR_MENU_FG] = $2;
}
| FONTCOLOR STRING {
free(conf->color[CWM_COLOR_MENU_FONT]);
conf->color[CWM_COLOR_MENU_FONT] = $2;
}
| FONTSELCOLOR STRING {
free(conf->color[CWM_COLOR_MENU_FONT_SEL]);
conf->color[CWM_COLOR_MENU_FONT_SEL] = $2;
}
;
%%
struct keywords {
const char *k_name;
int k_val;
};
int
yyerror(const char *fmt, ...)
{
va_list ap;
file->errors++;
va_start(ap, fmt);
fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
return (0);
}
int
kw_cmp(const void *k, const void *e)
{
return (strcmp(k, ((const struct keywords *)e)->k_name));
}
int
lookup(char *s)
{
/* this has to be sorted always */
static const struct keywords keywords[] = {
{ "activeborder", ACTIVEBORDER},
{ "autogroup", AUTOGROUP},
{ "bind-key", BINDKEY},
{ "bind-mouse", BINDMOUSE},
{ "borderwidth", BORDERWIDTH},
{ "color", COLOR},
{ "command", COMMAND},
{ "font", FONTCOLOR},
{ "fontname", FONTNAME},
{ "gap", GAP},
{ "groupborder", GROUPBORDER},
{ "htile", HTILE},
{ "ignore", IGNORE},
{ "inactiveborder", INACTIVEBORDER},
{ "menubg", MENUBG},
{ "menufg", MENUFG},
{ "moveamount", MOVEAMOUNT},
{ "no", NO},
{ "selfont", FONTSELCOLOR},
{ "snapdist", SNAPDIST},
{ "sticky", STICKY},
{ "unbind-key", UNBINDKEY},
{ "unbind-mouse", UNBINDMOUSE},
{ "ungroupborder", UNGROUPBORDER},
{ "urgencyborder", URGENCYBORDER},
{ "vtile", VTILE},
{ "wm", WM},
{ "yes", YES}
};
const struct keywords *p;
p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
sizeof(keywords[0]), kw_cmp);
if (p)
return (p->k_val);
else
return (STRING);
}
#define MAXPUSHBACK 128
char *parsebuf;
int parseindex;
char pushback_buffer[MAXPUSHBACK];
int pushback_index = 0;
int
lgetc(int quotec)
{
int c, next;
if (parsebuf) {
/* Read character from the parsebuffer instead of input. */
if (parseindex >= 0) {
c = (unsigned char)parsebuf[parseindex++];
if (c != '\0')
return (c);
parsebuf = NULL;
} else
parseindex++;
}
if (pushback_index)
return ((unsigned char)pushback_buffer[--pushback_index]);
if (quotec) {
if ((c = getc(file->stream)) == EOF) {
yyerror("reached end of file while parsing "
"quoted string");
if (file == topfile || popfile() == EOF)
return (EOF);
return (quotec);
}
return (c);
}
while ((c = getc(file->stream)) == '\\') {
next = getc(file->stream);
if (next != '\n') {
c = next;
break;
}
yylval.lineno = file->lineno;
file->lineno++;
}
while (c == EOF) {
if (file == topfile || popfile() == EOF)
return (EOF);
c = getc(file->stream);
}
return (c);
}
int
lungetc(int c)
{
if (c == EOF)
return (EOF);
if (parsebuf) {
parseindex--;
if (parseindex >= 0)
return (c);
}
if (pushback_index + 1 >= MAXPUSHBACK)
return (EOF);
pushback_buffer[pushback_index++] = c;
return (c);
}
int
findeol(void)
{
int c;
parsebuf = NULL;
/* skip to either EOF or the first real EOL */
while (1) {
if (pushback_index)
c = (unsigned char)pushback_buffer[--pushback_index];
else
c = lgetc(0);
if (c == '\n') {
file->lineno++;
break;
}
if (c == EOF)
break;
}
return (ERROR);
}
int
yylex(void)
{
char buf[8096];
char *p;
int quotec, next, c;
int token;
p = buf;
while ((c = lgetc(0)) == ' ' || c == '\t')
; /* nothing */
yylval.lineno = file->lineno;
if (c == '#')
while ((c = lgetc(0)) != '\n' && c != EOF)
; /* nothing */
switch (c) {
case '\'':
case '"':
quotec = c;
while (1) {
if ((c = lgetc(quotec)) == EOF)
return (0);
if (c == '\n') {
file->lineno++;
continue;
} else if (c == '\\') {
if ((next = lgetc(quotec)) == EOF)
return (0);
if (next == quotec || next == ' ' ||
next == '\t')
c = next;
else if (next == '\n') {
file->lineno++;
continue;
} else
lungetc(next);
} else if (c == quotec) {
*p = '\0';
break;
} else if (c == '\0') {
yyerror("syntax error");
return (findeol());
}
if (p + 1 >= buf + sizeof(buf) - 1) {
yyerror("string too long");
return (findeol());
}
*p++ = c;
}
yylval.v.string = xstrdup(buf);
return (STRING);
}
#define allowed_to_end_number(x) \
(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
if (c == '-' || isdigit(c)) {
do {
*p++ = c;
if ((size_t)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
} while ((c = lgetc(0)) != EOF && isdigit(c));
lungetc(c);
if (p == buf + 1 && buf[0] == '-')
goto nodigits;
if (c == EOF || allowed_to_end_number(c)) {
const char *errstr = NULL;
*p = '\0';
yylval.v.number = strtonum(buf, LLONG_MIN,
LLONG_MAX, &errstr);
if (errstr) {
yyerror("\"%s\" invalid number: %s",
buf, errstr);
return (findeol());
}
return (NUMBER);
} else {
nodigits:
while (p > buf + 1)
lungetc((unsigned char)*--p);
c = (unsigned char)*--p;
if (c == '-')
return (c);
}
}
/* Similar to other parse.y copies, but also allows '/' in strings */
#define allowed_in_string(x) \
(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
x != '{' && x != '}' && x != '<' && x != '>' && \
x != '!' && x != '=' && x != '#' && x != ','))
if (isalnum(c) || c == ':' || c == '_' || c == '*' || c == '/') {
do {
*p++ = c;
if ((size_t)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
lungetc(c);
*p = '\0';
if ((token = lookup(buf)) == STRING)
yylval.v.string = xstrdup(buf);
return (token);
}
if (c == '\n') {
yylval.lineno = file->lineno;
file->lineno++;
}
if (c == EOF)
return (0);
return (c);
}
struct file *
pushfile(const char *name, FILE *stream)
{
struct file *nfile;
nfile = xcalloc(1, sizeof(struct file));
nfile->name = xstrdup(name);
nfile->stream = stream;
nfile->lineno = 1;
TAILQ_INSERT_TAIL(&files, nfile, entry);
return (nfile);
}
int
popfile(void)
{
struct file *prev;
if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
prev->errors += file->errors;
TAILQ_REMOVE(&files, file, entry);
fclose(file->stream);
free(file->name);
free(file);
file = prev;
return (file ? 0 : EOF);
}
int
parse_config(const char *filename, struct conf *xconf)
{
FILE *stream;
int errors = 0;
conf = xconf;
stream = fopen(filename, "r");
if (stream == NULL) {
if (errno == ENOENT)
return (0);
warn("%s", filename);
return (-1);
}
file = pushfile(filename, stream);
topfile = file;
yyparse();
errors = file->errors;
popfile();
return (errors ? -1 : 0);
}

338
screen.c
View File

@ -2,102 +2,306 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/types.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "calmwm.h"
extern struct screen_ctx_q Screenq;
extern struct screen_ctx *Curscreen;
static struct geom screen_apply_gap(struct screen_ctx *, struct geom);
static void screen_scan(struct screen_ctx *);
void
screen_init(int which)
{
struct screen_ctx *sc;
XSetWindowAttributes attr;
sc = xmalloc(sizeof(*sc));
TAILQ_INIT(&sc->clientq);
TAILQ_INIT(&sc->regionq);
TAILQ_INIT(&sc->groupq);
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, sc->which);
sc->colormap = DefaultColormap(X_Dpy, sc->which);
sc->visual = DefaultVisual(X_Dpy, sc->which);
sc->cycling = 0;
sc->hideall = 0;
conf_screen(sc);
xu_ewmh_net_supported(sc);
xu_ewmh_net_supported_wm_check(sc);
conf_group(sc);
sc->group_last = sc->group_active;
screen_update_geometry(sc);
xu_ewmh_net_desktop_names(sc);
xu_ewmh_net_number_of_desktops(sc);
xu_ewmh_net_showing_desktop(sc);
xu_ewmh_net_virtual_roots(sc);
attr.cursor = Conf.cursor[CF_NORMAL];
attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask |
EnterWindowMask | PropertyChangeMask | ButtonPressMask;
XChangeWindowAttributes(X_Dpy, sc->rootwin, (CWEventMask | CWCursor), &attr);
if (Conf.xrandr)
XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask);
screen_scan(sc);
screen_updatestackingorder(sc);
TAILQ_INSERT_TAIL(&Screenq, sc, entry);
XSync(X_Dpy, False);
}
static void
_clearwindow_cb(int sig)
screen_scan(struct screen_ctx *sc)
{
struct screen_ctx *sc = screen_current();
XUnmapWindow(X_Dpy, sc->infowin);
struct client_ctx *cc, *active = NULL;
Window *wins, w0, w1, rwin, cwin;
unsigned int nwins, i, mask;
int rx, ry, wx, wy;
XQueryPointer(X_Dpy, sc->rootwin, &rwin, &cwin,
&rx, &ry, &wx, &wy, &mask);
if (XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) {
for (i = 0; i < nwins; i++) {
if ((cc = client_init(wins[i], sc)) != NULL)
if (cc->win == cwin)
active = cc;
}
XFree(wins);
}
if (active)
client_set_active(active);
}
struct screen_ctx *
screen_fromroot(Window rootwin)
screen_find(Window win)
{
struct screen_ctx *sc;
struct screen_ctx *sc;
TAILQ_FOREACH(sc, &Screenq, entry)
if (sc->rootwin == rootwin)
return (sc);
/* XXX FAIL HERE */
return (TAILQ_FIRST(&Screenq));
}
struct screen_ctx *
screen_current(void)
{
return (Curscreen);
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->rootwin == win)
return sc;
}
warnx("%s: failure win 0x%lx", __func__, win);
return NULL;
}
void
screen_updatestackingorder(void)
screen_updatestackingorder(struct screen_ctx *sc)
{
Window *wins, w0, w1;
struct screen_ctx *sc = screen_current();
u_int nwins, i, s;
struct client_ctx *cc;
Window *wins, w0, w1;
struct client_ctx *cc;
unsigned int nwins, i, s;
if (!XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins))
return;
if (XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) {
for (s = 0, i = 0; i < nwins; i++) {
/* Skip hidden windows */
if ((cc = client_find(wins[i])) == NULL ||
cc->flags & CLIENT_HIDDEN)
continue;
for (s = 0, i = 0; i < nwins; i++) {
/* Skip hidden windows */
if ((cc = client_find(wins[i])) == NULL ||
cc->flags & CLIENT_HIDDEN)
continue;
cc->stackingorder = s++;
}
XFree(wins);
}
}
cc->stackingorder = s++;
struct region_ctx *
region_find(struct screen_ctx *sc, int x, int y)
{
struct region_ctx *rc;
TAILQ_FOREACH(rc, &sc->regionq, entry) {
if ((x >= rc->view.x) && (x < (rc->view.x + rc->view.w)) &&
(y >= rc->view.y) && (y < (rc->view.y + rc->view.h))) {
break;
}
}
return rc;
}
struct geom
screen_area(struct screen_ctx *sc, int x, int y, int apply_gap)
{
struct region_ctx *rc;
struct geom area = sc->view;
TAILQ_FOREACH(rc, &sc->regionq, entry) {
if ((x >= rc->view.x) && (x < (rc->view.x + rc->view.w)) &&
(y >= rc->view.y) && (y < (rc->view.y + rc->view.h))) {
area = rc->view;
break;
}
}
if (apply_gap)
area = screen_apply_gap(sc, area);
return area;
}
void
screen_update_geometry(struct screen_ctx *sc)
{
struct region_ctx *rc;
sc->view.x = 0;
sc->view.y = 0;
sc->view.w = DisplayWidth(X_Dpy, sc->which);
sc->view.h = DisplayHeight(X_Dpy, sc->which);
sc->work = screen_apply_gap(sc, sc->view);
while ((rc = TAILQ_FIRST(&sc->regionq)) != NULL) {
TAILQ_REMOVE(&sc->regionq, rc, entry);
free(rc);
}
XFree(wins);
if (Conf.xrandr) {
XRRScreenResources *sr;
XRRCrtcInfo *ci;
int i;
sr = XRRGetScreenResources(X_Dpy, sc->rootwin);
for (i = 0, ci = NULL; i < sr->ncrtc; i++) {
ci = XRRGetCrtcInfo(X_Dpy, sr, sr->crtcs[i]);
if (ci == NULL)
continue;
if (ci->noutput == 0) {
XRRFreeCrtcInfo(ci);
continue;
}
rc = xmalloc(sizeof(*rc));
rc->num = i;
rc->view.x = ci->x;
rc->view.y = ci->y;
rc->view.w = ci->width;
rc->view.h = ci->height;
rc->work = screen_apply_gap(sc, rc->view);
TAILQ_INSERT_TAIL(&sc->regionq, rc, entry);
XRRFreeCrtcInfo(ci);
}
XRRFreeScreenResources(sr);
} else {
rc = xmalloc(sizeof(*rc));
rc->num = 0;
rc->view.x = 0;
rc->view.y = 0;
rc->view.w = DisplayWidth(X_Dpy, sc->which);
rc->view.h = DisplayHeight(X_Dpy, sc->which);
rc->work = screen_apply_gap(sc, rc->view);
TAILQ_INSERT_TAIL(&sc->regionq, rc, entry);
}
xu_ewmh_net_desktop_geometry(sc);
xu_ewmh_net_desktop_viewport(sc);
xu_ewmh_net_workarea(sc);
}
static struct geom
screen_apply_gap(struct screen_ctx *sc, struct geom geom)
{
geom.x += sc->gap.left;
geom.y += sc->gap.top;
geom.w -= (sc->gap.left + sc->gap.right);
geom.h -= (sc->gap.top + sc->gap.bottom);
return geom;
}
/* Bring back clients which are beyond the screen. */
void
screen_assert_clients_within(struct screen_ctx *sc)
{
struct client_ctx *cc;
int top, left, right, bottom;
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->sc != sc)
continue;
top = cc->geom.y;
left = cc->geom.x;
right = cc->geom.x + cc->geom.w + (cc->bwidth * 2) - 1;
bottom = cc->geom.y + cc->geom.h + (cc->bwidth * 2) - 1;
if ((top > sc->view.h || left > sc->view.w) ||
(bottom < 0 || right < 0)) {
cc->geom.x = sc->gap.left;
cc->geom.y = sc->gap.top;
client_move(cc);
}
}
}
void
screen_init(void)
screen_prop_win_create(struct screen_ctx *sc, Window win)
{
sc->prop.win = XCreateSimpleWindow(X_Dpy, win, 0, 0, 1, 1, 0,
sc->xftcolor[CWM_COLOR_MENU_BG].pixel,
sc->xftcolor[CWM_COLOR_MENU_BG].pixel);
sc->prop.xftdraw = XftDrawCreate(X_Dpy, sc->prop.win,
sc->visual, sc->colormap);
struct screen_ctx *sc = screen_current();
sc->cycle_client = NULL;
sc->infowin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
/* XXX - marius. */
if (signal(SIGALRM, _clearwindow_cb) == SIG_ERR)
err(1, "signal");
XMapWindow(X_Dpy, sc->prop.win);
}
void
screen_infomsg(char *msg)
screen_prop_win_destroy(struct screen_ctx *sc)
{
struct screen_ctx *sc = screen_current();
char buf[1024];
int dy, dx;
struct fontdesc *font = DefaultFont;
XUnmapWindow(X_Dpy, sc->infowin);
alarm(0);
snprintf(buf, sizeof(buf), ">%s", msg);
dy = font_ascent(font) + font_descent(font) + 1;
dx = font_width(font, buf, strlen(buf));
XMoveResizeWindow(X_Dpy, sc->infowin, 0, 0, dx, dy);
XMapRaised(X_Dpy, sc->infowin);
font_draw(font, buf, strlen(buf), sc->infowin,
0, font_ascent(font) + 1);
alarm(1);
XftDrawDestroy(sc->prop.xftdraw);
XDestroyWindow(X_Dpy, sc->prop.win);
}
void
screen_prop_win_draw(struct screen_ctx *sc, const char *fmt, ...)
{
va_list ap;
char *text;
XGlyphInfo extents;
va_start(ap, fmt);
xvasprintf(&text, fmt, ap);
va_end(ap);
XftTextExtentsUtf8(X_Dpy, sc->xftfont, (const FcChar8*)text,
strlen(text), &extents);
XResizeWindow(X_Dpy, sc->prop.win, extents.xOff, sc->xftfont->height);
XClearWindow(X_Dpy, sc->prop.win);
XftDrawStringUtf8(sc->prop.xftdraw, &sc->xftcolor[CWM_COLOR_MENU_FONT],
sc->xftfont, 0, sc->xftfont->ascent + 1,
(const FcChar8*)text, strlen(text));
free(text);
}

600
search.c
View File

@ -2,364 +2,112 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/types.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <fnmatch.h>
#include <glob.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "calmwm.h"
#define SearchMask (KeyPressMask|ExposureMask)
#define PATH_ANY 0x0001
#define PATH_EXEC 0x0002
static int _strsubmatch(char *, char *, int);
static void match_path_type(struct menu_q *, char *, int);
static int match_substr(char *, char *, int);
void
search_init(struct screen_ctx *sc)
static int
match_substr(char *sub, char *str, int zeroidx)
{
sc->searchwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
1, 1, 1, sc->blackpixl, sc->whitepixl);
size_t len, sublen;
unsigned int n, flen;
if (sub == NULL || str == NULL)
return 0;
len = strlen(str);
sublen = strlen(sub);
if (sublen > len)
return 0;
if (zeroidx)
flen = 0;
else
flen = len - sublen;
for (n = 0; n <= flen; n++)
if (strncasecmp(sub, str + n, sublen) == 0)
return 1;
return 0;
}
/*
* ranking. each rank type is assigned a weight. multiply this by
* the rank given. add them up. simple linear combination.
*/
/*
* Input: list of items,
* Output: choose one
* so, exactly like menus
*/
struct menu *
search_start(struct menu_q *menuq,
void (*match)(struct menu_q *, struct menu_q *, char *),
void (*rank)(struct menu_q *resultq, char *search),
void (*print)(struct menu *mi, int print),
char *prompt, int dummy)
{
struct screen_ctx *sc = screen_current();
int x, y, dx, dy, fontheight,
focusrevert, mutated, xmax, ymax, warp, added, beobnoxious = 0;
XEvent e;
char searchstr[MENU_MAXENTRY + 1];
char dispstr[MENU_MAXENTRY*2 + 1];
char promptstr[MENU_MAXENTRY + 1];
Window focuswin;
struct menu *mi = NULL, *dummy_mi = NULL;
struct menu_q resultq;
char chr;
enum ctltype ctl;
size_t len;
u_int n;
static int list = 0;
int listing = 0;
char endchar = '<EFBFBD>';
struct fontdesc *font = DefaultFont;
if (prompt == NULL)
prompt = "search";
TAILQ_INIT(&resultq);
xmax = DisplayWidth(X_Dpy, sc->which);
ymax = DisplayHeight(X_Dpy, sc->which);
xu_ptr_getpos(sc->rootwin, &x, &y);
searchstr[0] = '\0';
snprintf(promptstr, sizeof(promptstr), "%s <20>", prompt);
dy = fontheight = font_ascent(font) + font_descent(font) + 1;
snprintf(dispstr, sizeof(dispstr), "%s%c", promptstr, endchar);
dx = font_width(font, dispstr, strlen(dispstr));
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
XSelectInput(X_Dpy, sc->searchwin, SearchMask);
XMapRaised(X_Dpy, sc->searchwin);
/*
* TODO: eventually, the mouse should be able to select
* results as well. Right now we grab it only to set a fancy
* cursor.
*/
if (xu_ptr_grab(sc->searchwin, 0, Cursor_question) < 0) {
XUnmapWindow(X_Dpy, sc->searchwin);
return (NULL);
}
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, sc->searchwin, RevertToPointerRoot, CurrentTime);
for (;;) {
added = mutated = 0;
XMaskEvent(X_Dpy, SearchMask, &e);
switch (e.type) {
case KeyPress:
/*
* XXX - C-s & C-r for next and prev.
*/
if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
&ctl, &chr, 1) < 0)
continue;
switch (ctl) {
case CTL_ERASEONE:
if ((len = strlen(searchstr)) > 0) {
searchstr[len - 1] = '\0';
mutated = 1;
}
break;
case CTL_UP:
mi = TAILQ_LAST(&resultq, menu_q);
if (mi == NULL)
break;
TAILQ_REMOVE(&resultq, mi, resultentry);
TAILQ_INSERT_HEAD(&resultq, mi, resultentry);
break;
case CTL_DOWN:
mi = TAILQ_FIRST(&resultq);
if (mi == NULL)
break;
TAILQ_REMOVE(&resultq, mi, resultentry);
TAILQ_INSERT_TAIL(&resultq, mi, resultentry);
break;
case CTL_RETURN:
/* This is just picking the match the
* cursor is over. */
if ((mi = TAILQ_FIRST(&resultq)) != NULL) {
goto found;
} else if (dummy) {
dummy_mi = xmalloc(sizeof *dummy_mi);
(void) strlcpy(dummy_mi->text,
searchstr, sizeof(dummy_mi->text));
dummy_mi->dummy = 1;
goto found;
}
goto out;
case CTL_WIPE:
searchstr[0] = '\0';
mutated = 1;
break;
case CTL_ALL:
list = !list;
break;
case CTL_ABORT:
goto out;
default:
break;
}
if (chr != '\0') {
char str[2];
str[0] = chr;
str[1] = '\0';
mutated = 1;
added =
strlcat(searchstr, str, sizeof(searchstr));
}
beobnoxious = 0;
if (mutated && strlen(searchstr) > 0) {
(*match)(menuq, &resultq, searchstr);
beobnoxious = TAILQ_EMPTY(&resultq);
if (!beobnoxious && rank != NULL)
(*rank)(&resultq, searchstr);
} else if (mutated)
TAILQ_INIT(&resultq);
if (!list && listing && !mutated) {
TAILQ_INIT(&resultq);
listing = 0;
}
case Expose:
if (list) {
if (TAILQ_EMPTY(&resultq) && list) {
/* Copy them over and rank them. */
TAILQ_FOREACH(mi, menuq, entry)
TAILQ_INSERT_TAIL(&resultq, mi,
resultentry);
if (rank != NULL)
(*rank)(&resultq, searchstr);
listing = 1;
} else if (mutated)
listing = 0;
}
snprintf(dispstr, sizeof(dispstr), "%s%s%c",
promptstr, searchstr, endchar);
dx = font_width(font, dispstr, strlen(dispstr));
dy = fontheight;
TAILQ_FOREACH(mi, &resultq, resultentry) {
char *text;
if (print != NULL) {
(*print)(mi, listing);
text = mi->print;
} else {
mi->print[0] = '\0';
text = mi->text;
}
dx = MAX(dx, font_width(font, text,
MIN(strlen(text), MENU_MAXENTRY)));
dy += fontheight;
}
/*
* Calculate new geometry.
*
* XXX - put this into a util function -- it's
* used elsewhere, too.
*/
warp = 0;
if (x < 0) {
x = 0;
warp = 1;
}
if (x + dx >= xmax) {
x = xmax - dx;
warp = 1;
}
if (y < 0) {
y = 0;
warp = 1;
}
if (y + dy >= ymax) {
y = ymax - dy;
warp = 1;
}
if (warp)
xu_ptr_setpos(sc->rootwin, x, y);
XClearWindow(X_Dpy, sc->searchwin);
XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
font_draw(font, dispstr, strlen(dispstr), sc->searchwin,
0, font_ascent(font) + 1);
n = 1;
TAILQ_FOREACH(mi, &resultq, resultentry) {
char *text = mi->print[0] != '\0' ?
mi->print : mi->text;
font_draw(font, text,
MIN(strlen(text), MENU_MAXENTRY),
sc->searchwin,
0, n*fontheight + font_ascent(font) + 1);
n++;
}
if (n > 1)
XFillRectangle(X_Dpy, sc->searchwin, sc->gc,
0, fontheight, dx, fontheight);
if (beobnoxious)
XFillRectangle(X_Dpy, sc->searchwin, sc->gc,
0, 0, dx, fontheight);
break;
}
}
out:
/* (if no match) */
xu_ptr_ungrab();
XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
found:
XUnmapWindow(X_Dpy, sc->searchwin);
if (dummy && dummy_mi != NULL)
return (dummy_mi);
return (mi);
}
/*
* Match: label, title, class.
*/
void
search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL;
int ntiers = sizeof(tierp)/sizeof(tierp[0]);
struct menu *mi, *tierp[3], *before = NULL;
struct client_ctx *cc;
struct winname *wn;
(void)memset(tierp, 0, sizeof(tierp));
TAILQ_INIT(resultq);
memset(tierp, 0, sizeof(tierp));
/*
* In order of rank:
*
* 1. Look through labels.
* 2. Look at title history, from present to past.
* 3. Look at window class name.
*/
TAILQ_FOREACH(mi, menuq, entry) {
int tier = -1, t;
struct client_ctx *cc = mi->ctx;
cc = (struct client_ctx *)mi->ctx;
/* First, try to match on labels. */
if (cc->label != NULL && _strsubmatch(search, cc->label, 0)) {
cc->matchname = cc->label;
/* Match on label. */
if (match_substr(search, cc->label, 0))
tier = 0;
}
/* Then, on window names. */
/* Match on window name history, from present to past. */
if (tier < 0) {
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, winname_q, entry)
if (_strsubmatch(search, wn->name, 0)) {
cc->matchname = wn->name;
tier = 2;
break;
}
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, name_q, entry)
if (match_substr(search, wn->name, 0)) {
tier = 1;
break;
}
}
/*
* See if there is a match on the window class
* name.
*/
if (tier < 0 && _strsubmatch(search, cc->app_class, 0)) {
cc->matchname = cc->app_class;
tier = 3;
}
/* Match on window resource class. */
if ((tier < 0) && match_substr(search, cc->res_class, 0))
tier = 2;
if (tier < 0)
continue;
/*
* De-rank a client one tier if it's the current
* window. Furthermore, this is denoted by a "!" when
* printing the window name in the search menu.
*/
if (cc == client_current() && tier < ntiers - 1)
/* Current window is ranked down. */
if ((tier < nitems(tierp) - 1) && (cc->flags & CLIENT_ACTIVE))
tier++;
/*
* Clients that are hidden get ranked one up.
*/
if (cc->flags & CLIENT_HIDDEN && tier > 0)
/* Hidden window is ranked up. */
if ((tier > 0) && (cc->flags & CLIENT_HIDDEN))
tier--;
assert(tier < ntiers);
/*
* If you have a tierp, insert after it, and make it
* the new tierp. If you don't have a tierp, find the
@ -367,7 +115,6 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
* Always make your current tierp the newly inserted
* entry.
*/
for (t = tier; t >= 0 && ((before = tierp[t]) == NULL); t--)
;
@ -381,95 +128,162 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
}
void
search_print_client(struct menu *mi, int list)
search_match_cmd(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct client_ctx *cc = mi->ctx;
char flag = ' ';
struct menu *mi;
struct cmd_ctx *cmd;
if (cc == client_current())
flag = '!';
else if (cc->flags & CLIENT_HIDDEN)
flag = '&';
if (list)
cc->matchname = TAILQ_FIRST(&cc->nameq)->name;
snprintf(mi->print, sizeof(mi->print), "%c%s", flag, cc->matchname);
if (!list && cc->matchname != cc->name &&
strlen(mi->print) < sizeof(mi->print) - 1) {
int diff = sizeof(mi->print) - 1 - strlen(mi->print);
const char *marker = "";
char buf[MENU_MAXENTRY + 1];
/* One for the ':' */
diff -= 1;
if (strlen(cc->name) > diff) {
marker = "..";
diff -= 2;
} else {
diff = strlen(cc->name);
}
strlcpy(buf, mi->print, sizeof(buf));
snprintf(mi->print, sizeof(mi->print),
"%s:%.*s%s", buf, diff, cc->name, marker);
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry) {
cmd = (struct cmd_ctx *)mi->ctx;
if (match_substr(search, cmd->name, 0))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
}
void
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
search_match_group(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi;
struct menu *mi;
struct group_ctx *gc;
char *s;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
if (_strsubmatch(search, mi->text, 0))
TAILQ_FOREACH(mi, menuq, entry) {
gc = (struct group_ctx *)mi->ctx;
xasprintf(&s, "%d %s", gc->num, gc->name);
if (match_substr(search, s, 0))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
free(s);
}
}
static void
match_path_type(struct menu_q *resultq, char *search, int flag)
{
struct menu *mi;
char *pattern;
glob_t g;
int i;
xasprintf(&pattern, "%s*", search);
if (glob(pattern, GLOB_MARK, NULL, &g) != 0)
return;
for (i = 0; i < g.gl_pathc; i++) {
if ((flag & PATH_EXEC) && access(g.gl_pathv[i], X_OK))
continue;
mi = xcalloc(1, sizeof(*mi));
(void)strlcpy(mi->text, g.gl_pathv[i], sizeof(mi->text));
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
globfree(&g);
free(pattern);
}
void
search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi;
struct menu *mi, *mj;
int r;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
if (_strsubmatch(search, mi->text, 1))
TAILQ_FOREACH(mi, menuq, entry) {
if (match_substr(search, mi->text, 1) == 0 &&
fnmatch(search, mi->text, 0) == FNM_NOMATCH)
continue;
TAILQ_FOREACH(mj, resultq, resultentry) {
r = strcmp(mi->text, mj->text);
if (r < 0)
TAILQ_INSERT_BEFORE(mj, mi, resultentry);
if (r <= 0)
break;
}
if (mj == NULL)
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
if (TAILQ_EMPTY(resultq))
match_path_type(resultq, search, PATH_EXEC);
}
void
search_rank_text(struct menu_q *resultq, char *search)
search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
return;
TAILQ_INIT(resultq);
match_path_type(resultq, search, PATH_ANY);
}
static int
_strsubmatch(char *sub, char *str, int zeroidx)
void
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
size_t len, sublen;
u_int n, flen;
struct menu *mi;
if (sub == NULL || str == NULL)
return (0);
len = strlen(str);
sublen = strlen(sub);
if (sublen > len)
return (0);
if (!zeroidx)
flen = len - sublen;
else
flen = 0;
for (n = 0; n <= flen; n++)
if (strncasecmp(sub, str + n, sublen) == 0)
return (1);
return (0);
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry) {
if (match_substr(search, mi->text, 0))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
}
void
search_match_wm(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi;
struct cmd_ctx *wm;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry) {
wm = (struct cmd_ctx *)mi->ctx;
if ((match_substr(search, wm->name, 0)) ||
(match_substr(search, wm->path, 0)))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
}
void
search_print_client(struct menu *mi, int listing)
{
struct client_ctx *cc = (struct client_ctx *)mi->ctx;
char flag = ' ';
if (cc->flags & CLIENT_ACTIVE)
flag = '!';
else if (cc->flags & CLIENT_HIDDEN)
flag = '&';
(void)snprintf(mi->print, sizeof(mi->print), "(%d) %c[%s] %s",
(cc->gc) ? cc->gc->num : 0, flag,
(cc->label) ? cc->label : "", cc->name);
}
void
search_print_cmd(struct menu *mi, int listing)
{
struct cmd_ctx *cmd = (struct cmd_ctx *)mi->ctx;
(void)snprintf(mi->print, sizeof(mi->print), "%s", cmd->name);
}
void
search_print_group(struct menu *mi, int listing)
{
struct group_ctx *gc = (struct group_ctx *)mi->ctx;
(void)snprintf(mi->print, sizeof(mi->print),
(group_holds_only_hidden(gc)) ? "%d: [%s]" : "%d: %s",
gc->num, gc->name);
}
void
search_print_text(struct menu *mi, int listing)
{
(void)snprintf(mi->print, sizeof(mi->print), "%s", mi->text);
}
void
search_print_wm(struct menu *mi, int listing)
{
struct cmd_ctx *wm = (struct cmd_ctx *)mi->ctx;
(void)snprintf(mi->print, sizeof(mi->print), "%s [%s]",
wm->name, wm->path);
}

148
util.c
View File

@ -2,71 +2,139 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/types.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "calmwm.h"
#define MAXARGLEN 20
static void log_msg(const char *, va_list);
int
void
u_spawn(char *argstr)
{
char *args[MAXARGLEN], **ap;
char **end = &args[MAXARGLEN - 1];
switch (fork()) {
case 0:
ap = args;
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL)
ap++;
*ap = NULL;
setsid();
execvp(args[0], args);
err(1, args[0]);
break;
u_exec(argstr);
exit(1);
case -1:
warn("fork");
return (-1);
default:
break;
}
return (0);
}
int dirent_exists(char *filename) {
struct stat buffer;
void
u_exec(char *argstr)
{
#define MAXARGLEN 20
char *args[MAXARGLEN], **ap = args;
char **end = &args[MAXARGLEN - 2], *tmp;
char *s = argstr;
return stat(filename, &buffer);
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL) {
if (**ap == '\0')
continue;
ap++;
if (argstr != NULL) {
/* deal with quoted strings */
switch(argstr[0]) {
case '"':
case '\'':
if ((tmp = strchr(argstr + 1, argstr[0]))
!= NULL) {
*(tmp++) = '\0';
*(ap++) = ++argstr;
argstr = tmp;
}
break;
default:
break;
}
}
}
*ap = NULL;
(void)setsid();
(void)execvp(args[0], args);
warn("%s", s);
}
int dirent_isdir(char *filename) {
struct stat buffer;
int return_value;
char *
u_argv(char * const *argv)
{
size_t siz = 0;
int i;
char *p;
return_value = stat(filename, &buffer);
if (argv == 0)
return NULL;
if(return_value == -1)
return 0;
else
return S_ISDIR(buffer.st_mode);
for (i = 0; argv[i]; i++)
siz += strlen(argv[i]) + 1;
if (siz == 0)
return NULL;
p = xmalloc(siz);
strlcpy(p, argv[0], siz);
for (i = 1; argv[i]; i++) {
strlcat(p, " ", siz);
strlcat(p, argv[i], siz);
}
return p;
}
int dirent_islink(char *filename) {
struct stat buffer;
int return_value;
static void
log_msg(const char *msg, va_list ap)
{
char *fmt;
return_value = lstat(filename, &buffer);
if(return_value == -1)
return 0;
else
return S_ISLNK(buffer.st_mode);
if (asprintf(&fmt, "%s\n", msg) == -1) {
vfprintf(stderr, msg, ap);
fprintf(stderr, "\n");
} else {
vfprintf(stderr, fmt, ap);
free(fmt);
}
fflush(stderr);
}
void
log_debug(int level, const char *func, const char *msg, ...)
{
char *fmt;
va_list ap;
if (Conf.debug < level)
return;
va_start(ap, msg);
xasprintf(&fmt, "debug%d: %s: %s", level, func, msg);
log_msg(fmt, ap);
free(fmt);
va_end(ap);
}

866
xevents.c
View File

@ -2,9 +2,20 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
/*
@ -13,365 +24,294 @@
* management of the xevent's.
*/
#include "headers.h"
#include <sys/types.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "calmwm.h"
void _sendxmsg(Window, Atom, long);
static void xev_handle_maprequest(XEvent *);
static void xev_handle_unmapnotify(XEvent *);
static void xev_handle_destroynotify(XEvent *);
static void xev_handle_configurerequest(XEvent *);
static void xev_handle_propertynotify(XEvent *);
static void xev_handle_enternotify(XEvent *);
static void xev_handle_buttonpress(XEvent *);
static void xev_handle_buttonrelease(XEvent *);
static void xev_handle_keypress(XEvent *);
static void xev_handle_keyrelease(XEvent *);
static void xev_handle_clientmessage(XEvent *);
static void xev_handle_randr(XEvent *);
static void xev_handle_mappingnotify(XEvent *);
static void xev_handle_expose(XEvent *);
/*
* NOTE: in reality, many of these should move to client.c now that
* we've got this nice event layer.
*/
void (*xev_handlers[LASTEvent])(XEvent *) = {
[MapRequest] = xev_handle_maprequest,
[UnmapNotify] = xev_handle_unmapnotify,
[DestroyNotify] = xev_handle_destroynotify,
[ConfigureRequest] = xev_handle_configurerequest,
[PropertyNotify] = xev_handle_propertynotify,
[EnterNotify] = xev_handle_enternotify,
[ButtonPress] = xev_handle_buttonpress,
[ButtonRelease] = xev_handle_buttonrelease,
[KeyPress] = xev_handle_keypress,
[KeyRelease] = xev_handle_keyrelease,
[ClientMessage] = xev_handle_clientmessage,
[MappingNotify] = xev_handle_mappingnotify,
[Expose] = xev_handle_expose,
};
void
xev_handle_maprequest(struct xevent *xev, XEvent *ee)
static KeySym modkeys[] = { XK_Alt_L, XK_Alt_R, XK_Super_L, XK_Super_R,
XK_Control_L, XK_Control_R, XK_ISO_Level3_Shift };
static void
xev_handle_maprequest(XEvent *ee)
{
XMapRequestEvent *e = &ee->xmaprequest;
struct client_ctx *cc = NULL, *old_cc = client_current();
XWindowAttributes xattr;
struct screen_ctx *sc;
#ifdef notyet
int state;
#endif
XMapRequestEvent *e = &ee->xmaprequest;
struct screen_ctx *sc;
struct client_ctx *cc, *old_cc;
if (old_cc != NULL)
client_ptrsave(old_cc);
LOG_DEBUG3("parent: 0x%lx window: 0x%lx", e->parent, e->window);
if ((cc = client_find(e->window)) == NULL) {
XGetWindowAttributes(X_Dpy, e->window, &xattr);
cc = client_new(e->window, screen_fromroot(xattr.root), 1);
sc = CCTOSC(cc);
} else {
cc->beepbeep = 1;
}
if ((sc = screen_find(e->parent)) == NULL)
return;
#ifdef notyet /* XXX - possibly, we shouldn't map if
* the window is withdrawn. */
if (xu_getstate(cc, &state) == 0 && state == WithdrawnState)
warnx("WITHDRAWNSTATE for %s", cc->name);
#endif
if ((old_cc = client_current(sc)) != NULL)
client_ptr_save(old_cc);
client_ptrwarp(cc);
xev_register(xev);
if ((cc = client_find(e->window)) == NULL)
cc = client_init(e->window, NULL);
if ((cc != NULL) && (!(cc->flags & CLIENT_IGNORE)))
client_ptr_warp(cc);
}
void
xev_handle_unmapnotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_unmapnotify(XEvent *ee)
{
XUnmapEvent *e = &ee->xunmap;
struct client_ctx *cc;
struct screen_ctx *sc;
int wascurrent;
XUnmapEvent *e = &ee->xunmap;
struct client_ctx *cc;
LOG_DEBUG3("window: 0x%lx", e->window);
if ((cc = client_find(e->window)) != NULL) {
sc = CCTOSC(cc);
wascurrent = cc == client_current();
client_delete(cc, e->send_event, 0);
#ifdef notyet
/* XXX disable the ptrwarp until we handle it
* better. */
if (!client_delete(cc, e->send_event, 0) && wascurrent)
;/* client_ptrwarp(new_cc); */
#endif
if (e->send_event) {
xu_set_wm_state(cc->win, WithdrawnState);
} else {
if (!(cc->flags & CLIENT_HIDDEN))
client_remove(cc);
}
}
xev_register(xev);
}
void
xev_handle_destroynotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_destroynotify(XEvent *ee)
{
XDestroyWindowEvent *e = &ee->xdestroywindow;
struct client_ctx *cc;
XDestroyWindowEvent *e = &ee->xdestroywindow;
struct client_ctx *cc;
LOG_DEBUG3("window: 0x%lx", e->window);
if ((cc = client_find(e->window)) != NULL)
client_delete(cc, 1, 1);
xev_register(xev);
client_remove(cc);
}
void
xev_handle_configurerequest(struct xevent *xev, XEvent *ee)
static void
xev_handle_configurerequest(XEvent *ee)
{
XConfigureRequestEvent *e = &ee->xconfigurerequest;
struct client_ctx *cc;
struct screen_ctx *sc;
XWindowChanges wc;
XConfigureRequestEvent *e = &ee->xconfigurerequest;
struct client_ctx *cc;
struct screen_ctx *sc;
XWindowChanges wc;
LOG_DEBUG3("window: 0x%lx", e->window);
if ((cc = client_find(e->window)) != NULL) {
sc = CCTOSC(cc);
sc = cc->sc;
client_gravitate(cc, 0);
if (e->value_mask & CWWidth)
cc->geom.width = e->width;
cc->geom.w = e->width;
if (e->value_mask & CWHeight)
cc->geom.height = e->height;
cc->geom.h = e->height;
if (e->value_mask & CWX)
cc->geom.x = e->x;
if (e->value_mask & CWY)
cc->geom.y = e->y;
if (e->value_mask & CWBorderWidth)
cc->bwidth = e->border_width;
if (e->value_mask & CWSibling)
wc.sibling = e->above;
if (e->value_mask & CWStackMode)
wc.stack_mode = e->detail;
if (cc->geom.x == 0 &&
cc->geom.width >= DisplayWidth(X_Dpy, sc->which))
if (cc->geom.x == 0 && cc->geom.w >= sc->view.w)
cc->geom.x -= cc->bwidth;
if (cc->geom.y == 0 &&
cc->geom.height >= DisplayHeight(X_Dpy, sc->which))
cc->geom.y -= cc->bwidth;
if (cc->geom.y == 0 && cc->geom.h >= sc->view.h)
cc->geom.y -= cc->bwidth;
client_gravitate(cc, 1);
wc.x = cc->geom.x;
wc.y = cc->geom.y;
wc.width = cc->geom.w;
wc.height = cc->geom.h;
wc.border_width = cc->bwidth;
wc.x = cc->geom.x - cc->bwidth;
wc.y = cc->geom.y - cc->bwidth;
wc.width = cc->geom.width + cc->bwidth*2;
wc.height = cc->geom.height + cc->bwidth*2;
wc.border_width = 0;
XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);
client_config(cc);
} else {
/* let it do what it wants, it'll be ours when we map it. */
wc.x = e->x;
wc.y = e->y;
wc.width = e->width;
wc.height = e->height;
wc.border_width = e->border_width;
wc.stack_mode = Above;
e->value_mask &= ~CWStackMode;
/* We need to move the parent window, too. */
XConfigureWindow(X_Dpy, cc->pwin, e->value_mask, &wc);
xev_reconfig(cc);
XConfigureWindow(X_Dpy, e->window, e->value_mask, &wc);
}
wc.x = cc != NULL ? 0 : e->x;
wc.y = cc != NULL ? 0 : e->y;
wc.width = e->width;
wc.height = e->height;
wc.stack_mode = Above;
wc.border_width = 0;
e->value_mask &= ~CWStackMode;
e->value_mask |= CWBorderWidth;
XConfigureWindow(X_Dpy, e->window, e->value_mask, &wc);
xev_register(xev);
}
void
xev_handle_propertynotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_propertynotify(XEvent *ee)
{
XPropertyEvent *e = &ee->xproperty;
struct client_ctx *cc;
long tmp;
XPropertyEvent *e = &ee->xproperty;
struct screen_ctx *sc;
struct client_ctx *cc;
LOG_DEBUG3("window: 0x%lx", e->window);
if ((cc = client_find(e->window)) != NULL) {
switch(e->atom) {
switch (e->atom) {
case XA_WM_NORMAL_HINTS:
XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp);
client_get_sizehints(cc);
break;
case XA_WM_NAME:
client_setname(cc);
client_set_name(cc);
break;
case XA_WM_HINTS:
client_wm_hints(cc);
client_draw_border(cc);
break;
case XA_WM_TRANSIENT_FOR:
client_transient(cc);
client_draw_border(cc);
if (cc->gc)
group_movetogroup(cc, cc->gc->num);
break;
default:
/* do nothing */
if (e->atom == ewmh[_NET_WM_NAME])
client_set_name(cc);
break;
}
} else {
if (e->atom == ewmh[_NET_DESKTOP_NAMES]) {
if ((sc = screen_find(e->window)) != NULL)
xu_ewmh_net_desktop_names(sc);
}
}
xev_register(xev);
}
void
xev_reconfig(struct client_ctx *cc)
static void
xev_handle_enternotify(XEvent *ee)
{
XConfigureEvent ce;
XCrossingEvent *e = &ee->xcrossing;
struct client_ctx *cc;
ce.type = ConfigureNotify;
ce.event = cc->win;
ce.window = cc->win;
ce.x = cc->geom.x;
ce.y = cc->geom.y;
ce.width = cc->geom.width;
ce.height = cc->geom.height;
ce.border_width = 0;
ce.above = None;
ce.override_redirect = 0;
LOG_DEBUG3("window: 0x%lx", e->window);
XSendEvent(X_Dpy, cc->win, False, StructureNotifyMask, (XEvent *)&ce);
Last_Event_Time = e->time;
if ((cc = client_find(e->window)) != NULL)
client_set_active(cc);
}
void
xev_handle_enternotify(struct xevent *xev, XEvent *ee)
static void
xev_handle_buttonpress(XEvent *ee)
{
XCrossingEvent *e = &ee->xcrossing;
struct client_ctx *cc;
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc;
struct screen_ctx *sc;
struct bind_ctx *mb;
if ((cc = client_find(e->window)) == NULL) {
/*
* XXX - later. messes up unclutter. but may be
* needed when we introduce menu windows and such into
* the main event loop.
*/
#ifdef notyet
if (e->window != e->root)
client_nocurrent();
#endif
} else
client_setactive(cc, 1);
LOG_DEBUG3("root: 0x%lx window: 0x%lx subwindow: 0x%lx",
e->root, e->window, e->subwindow);
xev_register(xev);
}
if ((sc = screen_find(e->root)) == NULL)
return;
void
xev_handle_leavenotify(struct xevent *xev, XEvent *ee)
{
client_leave(NULL);
e->state &= ~IGNOREMODMASK;
xev_register(xev);
}
/* We can split this into two event handlers. */
void
xev_handle_buttonpress(struct xevent *xev, XEvent *ee)
{
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc, *old_cc = client_current();
struct screen_ctx *sc = screen_fromroot(e->root);
char *wname;
int altcontrol = e->state == (ControlMask|Mod1Mask);
cc = client_find(e->window);
if (sc->rootwin == e->window && !altcontrol) {
struct menu_q menuq;
struct menu *mi;
/* XXXSIGH!!!! */
if (e->button == Button2) {
group_menu(e);
goto out;
}
TAILQ_INIT(&menuq);
switch (e->button) {
case Button1:
TAILQ_FOREACH(cc, &Clientq, entry) {
if (cc->flags & CLIENT_HIDDEN) {
if (cc->label != NULL)
wname = cc->label;
else
wname = cc->name;
if (wname == NULL)
continue;
XCALLOC(mi, struct menu);
strlcpy(mi->text,
wname, sizeof(mi->text));
mi->ctx = cc;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
}
TAILQ_FOREACH(mb, &Conf.mousebindq, entry) {
if (e->button == mb->press.button && e->state == mb->modmask)
break;
case Button3: {
struct cmd *cmd;
if (conf_cmd_changed(Conf.menu_path)) {
conf_cmd_clear(&Conf);
conf_cmd_populate(&Conf, Conf.menu_path);
}
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
XCALLOC(mi, struct menu);
strlcpy(mi->text, cmd->label, sizeof(mi->text));
mi->ctx = cmd;
TAILQ_INSERT_TAIL(&menuq, mi, entry);
}
break;
}
default:
break;
}
if (TAILQ_EMPTY(&menuq))
goto out;
mi = (struct menu *)grab_menu(e, &menuq);
if (mi == NULL)
goto cleanup;
switch (e->button) {
case Button1:
cc = (struct client_ctx *)mi->ctx;
client_unhide(cc);
if (old_cc != NULL)
client_ptrsave(old_cc);
client_ptrwarp(cc);
break;
case Button3:
u_spawn(((struct cmd *)mi->ctx)->image);
break;
default:
break;
}
cleanup:
while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
TAILQ_REMOVE(&menuq, mi, entry);
xfree(mi);
}
goto out;
}
if (cc == NULL || e->state == 0)
goto out;
sc = CCTOSC(cc);
switch (e->button) {
case Button1:
if (altcontrol && !Groupmode)
group_sticky_toggle_enter(cc);
else {
grab_drag(cc);
client_move(cc);
}
if (mb == NULL)
return;
mb->cargs->xev = CWM_XEV_BTN;
switch (mb->context) {
case CWM_CONTEXT_CC:
if (((cc = client_find(e->window)) == NULL) &&
((cc = client_current(sc)) == NULL))
return;
(*mb->callback)(cc, mb->cargs);
break;
case Button2:
/* XXXSIGH!!! */
if (Groupmode)
group_click(cc);
else {
grab_sweep(cc);
client_resize(cc);
}
case CWM_CONTEXT_SC:
(*mb->callback)(sc, mb->cargs);
break;
case Button3:
client_ptrsave(cc);
client_lower(cc);
case CWM_CONTEXT_NONE:
(*mb->callback)(NULL, mb->cargs);
break;
}
out:
xev_register(xev);
}
void
xev_handle_buttonrelease(struct xevent *xev, XEvent *ee)
static void
xev_handle_buttonrelease(XEvent *ee)
{
struct client_ctx *cc = client_current();
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc;
if (cc != NULL && !Groupmode)
group_sticky_toggle_exit(cc);
xev_register(xev);
LOG_DEBUG3("root: 0x%lx window: 0x%lx subwindow: 0x%lx",
e->root, e->window, e->subwindow);
if ((cc = client_find(e->window)) != NULL) {
if (cc->flags & (CLIENT_ACTIVE | CLIENT_HIGHLIGHT)) {
cc->flags &= ~CLIENT_HIGHLIGHT;
client_draw_border(cc);
}
}
}
void
xev_handle_keypress(struct xevent *xev, XEvent *ee)
static void
xev_handle_keypress(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct client_ctx *cc = NULL; /* Make gcc happy. */
struct keybinding *kb;
KeySym keysym, skeysym;
int modshift;
XKeyEvent *e = &ee->xkey;
struct client_ctx *cc;
struct screen_ctx *sc;
struct bind_ctx *kb;
KeySym keysym, skeysym;
unsigned int modshift;
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
skeysym = XKeycodeToKeysym(X_Dpy, e->keycode, 1);
TAILQ_FOREACH(kb, &Conf.keybindingq, entry) {
if (keysym != kb->keysym && skeysym == kb->keysym)
LOG_DEBUG3("root: 0x%lx window: 0x%lx subwindow: 0x%lx",
e->root, e->window, e->subwindow);
if ((sc = screen_find(e->root)) == NULL)
return;
keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);
skeysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 1);
e->state &= ~IGNOREMODMASK;
TAILQ_FOREACH(kb, &Conf.keybindq, entry) {
if (keysym != kb->press.keysym && skeysym == kb->press.keysym)
modshift = ShiftMask;
else
modshift = 0;
@ -379,225 +319,175 @@ xev_handle_keypress(struct xevent *xev, XEvent *ee)
if ((kb->modmask | modshift) != e->state)
continue;
if ((kb->keycode != 0 && kb->keysym == NoSymbol &&
kb->keycode == e->keycode) || kb->keysym ==
(modshift == 0 ? keysym : skeysym))
if (kb->press.keysym == ((modshift == 0) ? keysym : skeysym))
break;
}
if (kb == NULL && e->window == screen_current()->groupwin)
group_display_keypress(e->keycode);
}
if (kb == NULL)
goto out;
if ((kb->flags & (KBFLAG_NEEDCLIENT|KBFLAG_FINDCLIENT)) &&
(cc = client_find(e->window)) == NULL &&
(cc = client_current()) == NULL)
if (kb->flags & KBFLAG_NEEDCLIENT)
goto out;
(*kb->callback)(cc, kb->argument);
out:
xev_register(xev);
}
/*
* This is only used for the alt supression detection.
*/
void
xev_handle_keyrelease(struct xevent *xev, XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc = screen_fromroot(e->root);
int keysym;
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
if (keysym != XK_Alt_L && keysym != XK_Alt_R)
goto out;
sc->altpersist = 0;
/*
* XXX - better interface... xevents should not know about
* how/when to mtf.
*/
client_mtf(NULL);
client_altrelease();
out:
xev_register(xev);
}
void
xev_handle_clientmessage(struct xevent *xev, XEvent *ee)
{
XClientMessageEvent *e = &ee->xclient;
struct client_ctx *cc = client_find(e->window);
Atom xa_wm_change_state = XInternAtom(X_Dpy, "WM_CHANGE_STATE", False);
if (cc == NULL)
goto out;
if (e->message_type == xa_wm_change_state && e->format == 32 &&
e->data.l[0] == IconicState)
client_hide(cc);
out:
xev_register(xev);
}
/*
* X Event handling
*/
static struct xevent_q _xevq, _xevq_putaway;
static short _xev_q_lock = 0;
void
xev_init(void)
{
TAILQ_INIT(&_xevq);
TAILQ_INIT(&_xevq_putaway);
}
struct xevent *
xev_new(Window *win, Window *root,
int type, void (*cb)(struct xevent *, XEvent *), void *arg)
{
struct xevent *xev;
XMALLOC(xev, struct xevent);
xev->xev_win = win;
xev->xev_root = root;
xev->xev_type = type;
xev->xev_cb = cb;
xev->xev_arg = arg;
return (xev);
}
void
xev_register(struct xevent *xev)
{
struct xevent_q *xq;
xq = _xev_q_lock ? &_xevq_putaway : &_xevq;
TAILQ_INSERT_TAIL(xq, xev, entry);
}
void
_xev_reincorporate(void)
{
struct xevent *xev;
while ((xev = TAILQ_FIRST(&_xevq_putaway)) != NULL) {
TAILQ_REMOVE(&_xevq_putaway, xev, entry);
TAILQ_INSERT_TAIL(&_xevq, xev, entry);
return;
kb->cargs->xev = CWM_XEV_KEY;
switch (kb->context) {
case CWM_CONTEXT_CC:
if (((cc = client_find(e->subwindow)) == NULL) &&
((cc = client_current(sc)) == NULL))
return;
(*kb->callback)(cc, kb->cargs);
break;
case CWM_CONTEXT_SC:
(*kb->callback)(sc, kb->cargs);
break;
case CWM_CONTEXT_NONE:
(*kb->callback)(NULL, kb->cargs);
break;
}
}
void
xev_handle_expose(struct xevent *xev, XEvent *ee)
/*
* This is only used for the modifier suppression detection.
*/
static void
xev_handle_keyrelease(XEvent *ee)
{
XExposeEvent *e = &ee->xexpose;
struct screen_ctx *sc = screen_current();
struct client_ctx *cc;
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc;
struct client_ctx *cc;
KeySym keysym;
unsigned int i;
if ((cc = client_find(e->window)) != NULL)
LOG_DEBUG3("root: 0x%lx window: 0x%lx subwindow: 0x%lx",
e->root, e->window, e->subwindow);
if ((sc = screen_find(e->root)) == NULL)
return;
keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);
for (i = 0; i < nitems(modkeys); i++) {
if (keysym == modkeys[i]) {
if ((cc = client_current(sc)) != NULL) {
if (sc->cycling) {
sc->cycling = 0;
client_mtf(cc);
}
if (cc->flags & CLIENT_HIGHLIGHT) {
cc->flags &= ~CLIENT_HIGHLIGHT;
client_draw_border(cc);
}
}
XUngrabKeyboard(X_Dpy, CurrentTime);
break;
}
}
}
static void
xev_handle_clientmessage(XEvent *ee)
{
XClientMessageEvent *e = &ee->xclient;
struct client_ctx *cc, *old_cc;
struct screen_ctx *sc;
LOG_DEBUG3("window: 0x%lx", e->window);
if (e->message_type == cwmh[WM_CHANGE_STATE]) {
if ((cc = client_find(e->window)) != NULL) {
if (e->data.l[0] == IconicState)
client_hide(cc);
}
} else if (e->message_type == ewmh[_NET_CLOSE_WINDOW]) {
if ((cc = client_find(e->window)) != NULL) {
client_close(cc);
}
} else if (e->message_type == ewmh[_NET_ACTIVE_WINDOW]) {
if ((cc = client_find(e->window)) != NULL) {
if ((old_cc = client_current(NULL)) != NULL)
client_ptr_save(old_cc);
client_show(cc);
client_ptr_warp(cc);
}
} else if (e->message_type == ewmh[_NET_WM_DESKTOP]) {
if ((cc = client_find(e->window)) != NULL) {
/*
* The EWMH spec states that if the cardinal returned
* is 0xFFFFFFFF (-1) then the window should appear
* on all desktops, in our case, group 0.
*/
if (e->data.l[0] == (unsigned long)-1)
group_movetogroup(cc, 0);
else
if (e->data.l[0] >= 0 &&
e->data.l[0] < Conf.ngroups)
group_movetogroup(cc, e->data.l[0]);
}
} else if (e->message_type == ewmh[_NET_WM_STATE]) {
if ((cc = client_find(e->window)) != NULL) {
xu_ewmh_handle_net_wm_state_msg(cc,
e->data.l[0], e->data.l[1], e->data.l[2]);
}
} else if (e->message_type == ewmh[_NET_CURRENT_DESKTOP]) {
if ((sc = screen_find(e->window)) != NULL) {
if (e->data.l[0] >= 0 &&
e->data.l[0] < Conf.ngroups)
group_only(sc, e->data.l[0]);
}
}
}
static void
xev_handle_randr(XEvent *ee)
{
XRRScreenChangeNotifyEvent *e = (XRRScreenChangeNotifyEvent *)ee;
struct screen_ctx *sc;
LOG_DEBUG3("size: %d/%d", e->width, e->height);
if ((sc = screen_find(e->root)) == NULL)
return;
XRRUpdateConfiguration(ee);
screen_update_geometry(sc);
screen_assert_clients_within(sc);
}
/*
* Called when the keymap has changed.
* Ungrab all keys, reload keymap and then regrab
*/
static void
xev_handle_mappingnotify(XEvent *ee)
{
XMappingEvent *e = &ee->xmapping;
struct screen_ctx *sc;
LOG_DEBUG3("window: 0x%lx", e->window);
XRefreshKeyboardMapping(e);
if (e->request == MappingKeyboard) {
TAILQ_FOREACH(sc, &Screenq, entry)
conf_grab_kbd(sc->rootwin);
}
}
static void
xev_handle_expose(XEvent *ee)
{
XExposeEvent *e = &ee->xexpose;
struct client_ctx *cc;
LOG_DEBUG3("window: 0x%lx", e->window);
if ((cc = client_find(e->window)) != NULL && e->count == 0)
client_draw_border(cc);
if (sc->groupwin == e->window)
group_display_draw(sc);
xev_register(xev);
}
#define ASSIGN(xtype) do { \
root = e. xtype .root; \
win = e. xtype .window; \
} while (0)
#define ASSIGN1(xtype) do { \
win = e. xtype .window; \
} while (0)
void
xev_loop(void)
xev_process(void)
{
Window win, root;
int type;
XEvent e;
struct xevent *xev, *nextxev;
for (;;) {
#ifdef DIAGNOSTIC
if (TAILQ_EMPTY(&_xevq))
errx(1, "X event queue empty");
#endif
XEvent e;
while (XPending(X_Dpy)) {
XNextEvent(X_Dpy, &e);
type = e.type;
win = root = 0;
switch (type) {
case MapRequest:
ASSIGN1(xmaprequest);
break;
case UnmapNotify:
ASSIGN1(xunmap);
break;
case ConfigureRequest:
ASSIGN1(xconfigurerequest);
break;
case PropertyNotify:
ASSIGN1(xproperty);
break;
case EnterNotify:
case LeaveNotify:
ASSIGN(xcrossing);
break;
case ButtonPress:
ASSIGN(xbutton);
break;
case ButtonRelease:
ASSIGN(xbutton);
break;
case KeyPress:
case KeyRelease:
ASSIGN(xkey);
break;
case DestroyNotify:
ASSIGN1(xdestroywindow);
break;
case ClientMessage:
ASSIGN1(xclient);
break;
default: /* XXX - still need shape event support. */
break;
}
/*
* Now, search for matches, and call each of them.
*/
_xev_q_lock = 1;
for (xev = TAILQ_FIRST(&_xevq); xev != NULL; xev = nextxev) {
nextxev = TAILQ_NEXT(xev, entry);
if ((type != xev->xev_type && xev->xev_type != 0) ||
(xev->xev_win != NULL && win != *xev->xev_win) ||
(xev->xev_root != NULL && root != *xev->xev_root))
continue;
TAILQ_REMOVE(&_xevq, xev, entry);
(*xev->xev_cb)(xev, &e);
}
_xev_q_lock = 0;
_xev_reincorporate();
if ((e.type - Conf.xrandr_event_base) == RRScreenChangeNotify)
xev_handle_randr(&e);
else if ((e.type < LASTEvent) && (xev_handlers[e.type] != NULL))
(*xev_handlers[e.type])(&e);
}
}
#undef ASSIGN
#undef ASSIGN1

View File

@ -2,49 +2,109 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/types.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "calmwm.h"
void *
xmalloc(size_t siz)
{
void *p;
void *p;
if (siz == 0)
errx(1, "xmalloc: zero size");
if ((p = malloc(siz)) == NULL)
err(1, "malloc");
return (p);
return p;
}
void *
xcalloc(size_t siz)
xcalloc(size_t no, size_t siz)
{
void *p;
void *p;
if ((p = calloc(1, siz)) == NULL)
if (siz == 0 || no == 0)
errx(1, "xcalloc: zero size");
if (SIZE_MAX / no < siz)
errx(1, "xcalloc: no * siz > SIZE_MAX");
if ((p = calloc(no, siz)) == NULL)
err(1, "calloc");
return (p);
return p;
}
void
xfree(void *p)
void *
xreallocarray(void *ptr, size_t nmemb, size_t size)
{
free(p);
void *p;
p = reallocarray(ptr, nmemb, size);
if (p == NULL)
errx(1, "xreallocarray: out of memory (new_size %zu bytes)",
nmemb * size);
return p;
}
char *
xstrdup(const char *str)
{
char *p;
char *p;
if ((p = strdup(str)) == NULL)
err(1, "strdup");
return (p);
return p;
}
int
xasprintf(char **ret, const char *fmt, ...)
{
va_list ap;
int i;
va_start(ap, fmt);
i = xvasprintf(ret, fmt, ap);
va_end(ap);
return i;
}
int
xvasprintf(char **ret, const char *fmt, va_list ap)
{
int i;
i = vasprintf(ret, fmt, ap);
if (i == -1)
err(1, "vasprintf");
return i;
}

652
xutil.c
View File

@ -2,161 +2,567 @@
* calmwm - the calm window manager
*
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
* All rights reserved.
*
* $Id$
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $OpenBSD$
*/
#include "headers.h"
#include <sys/types.h>
#include <sys/queue.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "calmwm.h"
int
xu_ptr_grab(Window win, int mask, Cursor curs)
void
xu_ptr_get(Window win, int *x, int *y)
{
return (XGrabPointer(X_Dpy, win, False, mask,
GrabModeAsync, GrabModeAsync,
None, curs, CurrentTime) == GrabSuccess ? 0 : -1);
}
Window w0, w1;
int tmp0, tmp1;
unsigned int tmp2;
int
xu_ptr_regrab(int mask, Cursor curs)
{
return (XChangeActivePointerGrab(X_Dpy, mask,
curs, CurrentTime) == GrabSuccess ? 0 : -1);
XQueryPointer(X_Dpy, win, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
}
void
xu_ptr_ungrab(void)
{
XUngrabPointer(X_Dpy, CurrentTime);
}
int
xu_btn_grab(Window win, int mask, u_int btn)
{
return (XGrabButton(X_Dpy, btn, mask, win,
False, ButtonMask, GrabModeAsync,
GrabModeSync, None, None) == GrabSuccess ? 0 : -1);
}
void
xu_btn_ungrab(Window win, int mask, u_int btn)
{
XUngrabButton(X_Dpy, btn, mask, win);
}
void
xu_ptr_getpos(Window rootwin, int *x, int *y)
{
int tmp0, tmp1;
u_int tmp2;
Window w0, w1;
XQueryPointer(X_Dpy, rootwin, &w0, &w1, &tmp0, &tmp1, x, y, &tmp2);
}
void
xu_ptr_setpos(Window win, int x, int y)
xu_ptr_set(Window win, int x, int y)
{
XWarpPointer(X_Dpy, None, win, 0, 0, 0, 0, x, y);
}
void
xu_key_grab(Window win, int mask, int keysym)
{
KeyCode code;
code = XKeysymToKeycode(X_Dpy, keysym);
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
mask |= ShiftMask;
XGrabKey(X_Dpy, XKeysymToKeycode(X_Dpy, keysym), mask, win, True,
GrabModeAsync, GrabModeAsync);
#if 0
XGrabKey(X_Dpy, XKeysymToKeycode(X_Dpy, keysym), LockMask|mask,
win, True, GrabModeAsync, GrabModeAsync);
#endif
}
void
xu_key_grab_keycode(Window win, int mask, int keycode)
{
XGrabKey(X_Dpy, keycode, mask, win, True, GrabModeAsync, GrabModeAsync);
}
void
xu_sendmsg(struct client_ctx *cc, Atom atm, long val)
{
XEvent e;
memset(&e, 0, sizeof(e));
e.xclient.type = ClientMessage;
e.xclient.window = cc->win;
e.xclient.message_type = atm;
e.xclient.format = 32;
e.xclient.data.l[0] = val;
e.xclient.data.l[1] = CurrentTime;
XSendEvent(X_Dpy, cc->win, False, 0, &e);
}
int
xu_getprop(struct client_ctx *cc, Atom atm, Atom type, long len, u_char **p)
xu_get_prop(Window win, Atom atm, Atom type, long len, unsigned char **p)
{
Atom realtype;
u_long n, extra;
int format;
Atom realtype;
unsigned long n, extra;
int format;
if (XGetWindowProperty(X_Dpy, cc->win, atm, 0L, len, False, type,
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
return (-1);
if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
return -1;
if (n == 0)
XFree(*p);
return (n);
return n;
}
int
xu_getstate(struct client_ctx *cc, int *state)
{
Atom wm_state = XInternAtom(X_Dpy, "WM_STATE", False);
long *p = NULL;
xu_get_strprop(Window win, Atom atm, char **text) {
XTextProperty prop;
char **list;
int nitems = 0;
if (xu_getprop(cc, wm_state, wm_state, 2L, (u_char **)&p) <= 0)
return (-1);
*text = NULL;
*state = (int)*p;
XFree((char *)p);
XGetTextProperty(X_Dpy, win, &prop, atm);
if (!prop.nitems) {
XFree(prop.value);
return 0;
}
return (0);
}
if (Xutf8TextPropertyToTextList(X_Dpy, &prop, &list,
&nitems) == Success && nitems > 0 && *list) {
if (nitems > 1) {
XTextProperty prop2;
if (Xutf8TextListToTextProperty(X_Dpy, list, nitems,
XUTF8StringStyle, &prop2) == Success) {
*text = xstrdup((const char *)prop2.value);
XFree(prop2.value);
}
} else {
*text = xstrdup(*list);
}
XFreeStringList(list);
}
XFree(prop.value);
char *
xu_getstrprop(struct client_ctx *cc, Atom atm)
{
u_char *cp;
if (xu_getprop(cc, atm, XA_STRING, 100L, &cp) <= 0)
return (NULL);
return ((char *)cp);
return nitems;
}
void
xu_setstate(struct client_ctx *cc, int state)
xu_send_clientmsg(Window win, Atom proto, Time ts)
{
long dat[2];
Atom wm_state;
XClientMessageEvent cm;
/* XXX cache */
wm_state = XInternAtom(X_Dpy, "WM_STATE", False);
(void)memset(&cm, 0, sizeof(cm));
cm.type = ClientMessage;
cm.window = win;
cm.message_type = cwmh[WM_PROTOCOLS];
cm.format = 32;
cm.data.l[0] = proto;
cm.data.l[1] = ts;
dat[0] = (long)state;
dat[1] = (long)None;
cc->state = state;
XChangeProperty(X_Dpy, cc->win, wm_state, wm_state, 32,
PropModeReplace, (unsigned char *)dat, 2);
XSendEvent(X_Dpy, win, False, NoEventMask, (XEvent *)&cm);
}
void
xu_get_wm_state(Window win, long *state)
{
long *p;
*state = -1;
if (xu_get_prop(win, cwmh[WM_STATE], cwmh[WM_STATE], 2L,
(unsigned char **)&p) > 0) {
*state = *p;
XFree(p);
}
}
void
xu_set_wm_state(Window win, long state)
{
long data[] = { state, None };
XChangeProperty(X_Dpy, win, cwmh[WM_STATE], cwmh[WM_STATE], 32,
PropModeReplace, (unsigned char *)data, 2);
}
void
xu_xorcolor(XftColor a, XftColor b, XftColor *r)
{
r->pixel = a.pixel ^ b.pixel;
r->color.red = a.color.red ^ b.color.red;
r->color.green = a.color.green ^ b.color.green;
r->color.blue = a.color.blue ^ b.color.blue;
r->color.alpha = 0xffff;
}
void
xu_atom_init(void)
{
char *cwmhints[] = {
"WM_STATE",
"WM_DELETE_WINDOW",
"WM_TAKE_FOCUS",
"WM_PROTOCOLS",
"_MOTIF_WM_HINTS",
"UTF8_STRING",
"WM_CHANGE_STATE",
};
char *ewmhints[] = {
"_NET_SUPPORTED",
"_NET_SUPPORTING_WM_CHECK",
"_NET_ACTIVE_WINDOW",
"_NET_CLIENT_LIST",
"_NET_CLIENT_LIST_STACKING",
"_NET_NUMBER_OF_DESKTOPS",
"_NET_CURRENT_DESKTOP",
"_NET_DESKTOP_VIEWPORT",
"_NET_DESKTOP_GEOMETRY",
"_NET_VIRTUAL_ROOTS",
"_NET_SHOWING_DESKTOP",
"_NET_DESKTOP_NAMES",
"_NET_WORKAREA",
"_NET_WM_NAME",
"_NET_WM_DESKTOP",
"_NET_CLOSE_WINDOW",
"_NET_WM_STATE",
"_NET_WM_STATE_STICKY",
"_NET_WM_STATE_MAXIMIZED_VERT",
"_NET_WM_STATE_MAXIMIZED_HORZ",
"_NET_WM_STATE_HIDDEN",
"_NET_WM_STATE_FULLSCREEN",
"_NET_WM_STATE_DEMANDS_ATTENTION",
"_NET_WM_STATE_SKIP_PAGER",
"_NET_WM_STATE_SKIP_TASKBAR",
"_CWM_WM_STATE_FREEZE",
};
XInternAtoms(X_Dpy, cwmhints, nitems(cwmhints), False, cwmh);
XInternAtoms(X_Dpy, ewmhints, nitems(ewmhints), False, ewmh);
}
/* Root Window Properties */
void
xu_ewmh_net_supported(struct screen_ctx *sc)
{
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTED],
XA_ATOM, 32, PropModeReplace, (unsigned char *)ewmh, EWMH_NITEMS);
}
void
xu_ewmh_net_supported_wm_check(struct screen_ctx *sc)
{
Window w;
w = XCreateSimpleWindow(X_Dpy, sc->rootwin, -1, -1, 1, 1, 0, 0, 0);
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTING_WM_CHECK],
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
XChangeProperty(X_Dpy, w, ewmh[_NET_SUPPORTING_WM_CHECK],
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
XChangeProperty(X_Dpy, w, ewmh[_NET_WM_NAME],
cwmh[UTF8_STRING], 8, PropModeReplace,
(unsigned char *)Conf.wmname, strlen(Conf.wmname));
}
void
xu_ewmh_net_desktop_geometry(struct screen_ctx *sc)
{
long geom[2] = { sc->view.w, sc->view.h };
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_GEOMETRY],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);
}
void
xu_ewmh_net_desktop_viewport(struct screen_ctx *sc)
{
long viewports[2] = {0, 0};
/* We don't support large desktops, so this is (0, 0). */
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_VIEWPORT],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)viewports, 2);
}
void
xu_ewmh_net_workarea(struct screen_ctx *sc)
{
unsigned long *workarea;
int i, ngroups = Conf.ngroups;
workarea = xreallocarray(NULL, ngroups * 4, sizeof(unsigned long));
for (i = 0; i < ngroups; i++) {
workarea[4 * i + 0] = sc->work.x;
workarea[4 * i + 1] = sc->work.y;
workarea[4 * i + 2] = sc->work.w;
workarea[4 * i + 3] = sc->work.h;
}
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_WORKAREA],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)workarea,
ngroups * 4);
free(workarea);
}
void
xu_ewmh_net_client_list(struct screen_ctx *sc)
{
struct client_ctx *cc;
Window *winlist;
int i = 0, j = 0;
TAILQ_FOREACH(cc, &sc->clientq, entry)
i++;
if (i == 0)
return;
winlist = xreallocarray(NULL, i, sizeof(*winlist));
TAILQ_FOREACH(cc, &sc->clientq, entry)
winlist[j++] = cc->win;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST],
XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);
free(winlist);
}
void
xu_ewmh_net_client_list_stacking(struct screen_ctx *sc)
{
struct client_ctx *cc;
Window *winlist;
int i = 0, j;
TAILQ_FOREACH(cc, &sc->clientq, entry)
i++;
if (i == 0)
return;
j = i;
winlist = xreallocarray(NULL, i, sizeof(*winlist));
TAILQ_FOREACH(cc, &sc->clientq, entry)
winlist[--j] = cc->win;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST_STACKING],
XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);
free(winlist);
}
void
xu_ewmh_net_active_window(struct screen_ctx *sc, Window w)
{
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_ACTIVE_WINDOW],
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
}
void
xu_ewmh_net_number_of_desktops(struct screen_ctx *sc)
{
long ndesks = Conf.ngroups;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_NUMBER_OF_DESKTOPS],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&ndesks, 1);
}
void
xu_ewmh_net_showing_desktop(struct screen_ctx *sc)
{
long zero = 0;
/* We don't support `showing desktop' mode, so this is zero.
* Note that when we hide all groups, or when all groups are
* hidden we could technically set this later on.
*/
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SHOWING_DESKTOP],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&zero, 1);
}
void
xu_ewmh_net_virtual_roots(struct screen_ctx *sc)
{
/* We don't support virtual roots, so delete if set by previous wm. */
XDeleteProperty(X_Dpy, sc->rootwin, ewmh[_NET_VIRTUAL_ROOTS]);
}
void
xu_ewmh_net_current_desktop(struct screen_ctx *sc)
{
long num = sc->group_active->num;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CURRENT_DESKTOP],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&num, 1);
}
void
xu_ewmh_net_desktop_names(struct screen_ctx *sc)
{
struct group_ctx *gc;
char *p, *q;
unsigned char *prop_ret;
int i = 0, j = 0, nstrings = 0, n = 0;
size_t len = 0, tlen, slen;
/* Let group names be overwritten if _NET_DESKTOP_NAMES is set. */
if ((j = xu_get_prop(sc->rootwin, ewmh[_NET_DESKTOP_NAMES],
cwmh[UTF8_STRING], 0xffffff, (unsigned char **)&prop_ret)) > 0) {
prop_ret[j - 1] = '\0'; /* paranoia */
while (i < j) {
if (prop_ret[i++] == '\0')
nstrings++;
}
}
p = (char *)prop_ret;
while (n < nstrings) {
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == n) {
free(gc->name);
gc->name = xstrdup(p);
p += strlen(p) + 1;
break;
}
}
n++;
}
if (prop_ret != NULL)
XFree(prop_ret);
TAILQ_FOREACH(gc, &sc->groupq, entry)
len += strlen(gc->name) + 1;
q = p = xreallocarray(NULL, len, sizeof(*p));
tlen = len;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
slen = strlen(gc->name) + 1;
(void)strlcpy(q, gc->name, tlen);
tlen -= slen;
q += slen;
}
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_NAMES],
cwmh[UTF8_STRING], 8, PropModeReplace, (unsigned char *)p, len);
free(p);
}
/* Application Window Properties */
int
xu_ewmh_get_net_wm_desktop(struct client_ctx *cc, long *n)
{
long *p;
if (xu_get_prop(cc->win, ewmh[_NET_WM_DESKTOP], XA_CARDINAL, 1L,
(unsigned char **)&p) <= 0)
return 0;
*n = *p;
XFree(p);
return 1;
}
void
xu_ewmh_set_net_wm_desktop(struct client_ctx *cc)
{
long num = 0xffffffff;
if (cc->gc)
num = cc->gc->num;
XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_DESKTOP],
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&num, 1);
}
Atom *
xu_ewmh_get_net_wm_state(struct client_ctx *cc, int *n)
{
Atom *state, *p = NULL;
if ((*n = xu_get_prop(cc->win, ewmh[_NET_WM_STATE], XA_ATOM, 64L,
(unsigned char **)&p)) <= 0)
return NULL;
state = xreallocarray(NULL, *n, sizeof(Atom));
(void)memcpy(state, p, *n * sizeof(Atom));
XFree((char *)p);
return state;
}
void
xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action,
Atom first, Atom second)
{
unsigned int i;
struct handlers {
Atom atom;
int flag;
void (*toggle)(struct client_ctx *);
} handlers[] = {
{ _NET_WM_STATE_STICKY,
CLIENT_STICKY,
client_toggle_sticky },
{ _NET_WM_STATE_MAXIMIZED_VERT,
CLIENT_VMAXIMIZED,
client_toggle_vmaximize },
{ _NET_WM_STATE_MAXIMIZED_HORZ,
CLIENT_HMAXIMIZED,
client_toggle_hmaximize },
{ _NET_WM_STATE_HIDDEN,
CLIENT_HIDDEN,
client_toggle_hidden },
{ _NET_WM_STATE_FULLSCREEN,
CLIENT_FULLSCREEN,
client_toggle_fullscreen },
{ _NET_WM_STATE_DEMANDS_ATTENTION,
CLIENT_URGENCY,
client_urgency },
{ _NET_WM_STATE_SKIP_PAGER,
CLIENT_SKIP_PAGER,
client_toggle_skip_pager},
{ _NET_WM_STATE_SKIP_TASKBAR,
CLIENT_SKIP_TASKBAR,
client_toggle_skip_taskbar},
{ _CWM_WM_STATE_FREEZE,
CLIENT_FREEZE,
client_toggle_freeze },
};
for (i = 0; i < nitems(handlers); i++) {
if (first != ewmh[handlers[i].atom] &&
second != ewmh[handlers[i].atom])
continue;
switch (action) {
case _NET_WM_STATE_ADD:
if (!(cc->flags & handlers[i].flag))
handlers[i].toggle(cc);
break;
case _NET_WM_STATE_REMOVE:
if (cc->flags & handlers[i].flag)
handlers[i].toggle(cc);
break;
case _NET_WM_STATE_TOGGLE:
handlers[i].toggle(cc);
}
}
}
void
xu_ewmh_restore_net_wm_state(struct client_ctx *cc)
{
Atom *atoms;
int i, n;
atoms = xu_ewmh_get_net_wm_state(cc, &n);
for (i = 0; i < n; i++) {
if (atoms[i] == ewmh[_NET_WM_STATE_STICKY])
client_toggle_sticky(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_VERT])
client_toggle_vmaximize(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_HORZ])
client_toggle_hmaximize(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_HIDDEN])
client_toggle_hidden(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_FULLSCREEN])
client_toggle_fullscreen(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_DEMANDS_ATTENTION])
client_urgency(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_SKIP_PAGER])
client_toggle_skip_pager(cc);
if (atoms[i] == ewmh[_NET_WM_STATE_SKIP_TASKBAR])
client_toggle_skip_taskbar(cc);
if (atoms[i] == ewmh[_CWM_WM_STATE_FREEZE])
client_toggle_freeze(cc);
}
free(atoms);
}
void
xu_ewmh_set_net_wm_state(struct client_ctx *cc)
{
Atom *atoms, *oatoms;
int n, i, j;
oatoms = xu_ewmh_get_net_wm_state(cc, &n);
atoms = xreallocarray(NULL, (n + _NET_WM_STATES_NITEMS), sizeof(Atom));
for (i = j = 0; i < n; i++) {
if (oatoms[i] != ewmh[_NET_WM_STATE_STICKY] &&
oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_VERT] &&
oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_HORZ] &&
oatoms[i] != ewmh[_NET_WM_STATE_HIDDEN] &&
oatoms[i] != ewmh[_NET_WM_STATE_FULLSCREEN] &&
oatoms[i] != ewmh[_NET_WM_STATE_DEMANDS_ATTENTION] &&
oatoms[i] != ewmh[_NET_WM_STATE_SKIP_PAGER] &&
oatoms[i] != ewmh[_NET_WM_STATE_SKIP_TASKBAR] &&
oatoms[i] != ewmh[_CWM_WM_STATE_FREEZE])
atoms[j++] = oatoms[i];
}
free(oatoms);
if (cc->flags & CLIENT_STICKY)
atoms[j++] = ewmh[_NET_WM_STATE_STICKY];
if (cc->flags & CLIENT_HIDDEN)
atoms[j++] = ewmh[_NET_WM_STATE_HIDDEN];
if (cc->flags & CLIENT_FULLSCREEN)
atoms[j++] = ewmh[_NET_WM_STATE_FULLSCREEN];
else {
if (cc->flags & CLIENT_VMAXIMIZED)
atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_VERT];
if (cc->flags & CLIENT_HMAXIMIZED)
atoms[j++] = ewmh[_NET_WM_STATE_MAXIMIZED_HORZ];
}
if (cc->flags & CLIENT_URGENCY)
atoms[j++] = ewmh[_NET_WM_STATE_DEMANDS_ATTENTION];
if (cc->flags & CLIENT_SKIP_PAGER)
atoms[j++] = ewmh[_NET_WM_STATE_SKIP_PAGER];
if (cc->flags & CLIENT_SKIP_TASKBAR)
atoms[j++] = ewmh[_NET_WM_STATE_SKIP_TASKBAR];
if (cc->flags & CLIENT_FREEZE)
atoms[j++] = ewmh[_CWM_WM_STATE_FREEZE];
if (j > 0)
XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE],
XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, j);
else
XDeleteProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE]);
free(atoms);
}