138 Commits
master ... v6.2

Author SHA1 Message Date
c36c5063e8 README: update 2017-10-17 19:01:20 +02:00
087b803b45 cvsimport
* refs/heads/master:
  Case matters for menu matching on executables; from ben@lloyd.im.
2017-09-06 14:15:13 +00:00
5a46349ec7 cvsimport
* refs/heads/master:
  Use the key names from keysymdef.h in the default key bindings list for clarification.
  remove extra parentheses
  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.
  rename one function, matching others, to help upcoming change
2017-07-27 15:07:12 +02:00
8908e5ec42 drop fgetln.c 2017-07-11 13:17:45 +02:00
1ceb2dd795 cvsimport
* refs/heads/master:
  Replace fgetln(3) with POSIX getline(3); inspired by brynet and Ingo.
  fix a few WARNINGS (new sentence, new line and extraneous Pp macro) found with mandoc -Tlint
  from src, by espie@: no need to generate y.tab.h if nothing uses it, set YFLAGS to nothing
2017-07-11 13:15:08 +02:00
4040f112e1 cvsimport
* refs/heads/master:
  drop obsolete comment
  Alter callbacks to take a struct instead of a growing number of arguments; greatly simplifies upcoming work.
  Ensure clients stay within the viewable bounds on placement, even with empty borders; based on a patch from Vadim Vygonets.
  Clean up, unify and accurately calculate edge distance with client move/resize actions, so as to not lose windows off the edge.
  Switch bwidth type; unfortunately X11 is inconsistent.
2017-05-09 18:43:40 +00:00
a8527b5661 calmwm: sighdlr: use -1 instead of WAIT_ANY 2017-04-25 22:26:57 +02:00
2d9185129b cvsimport
* refs/heads/master:
  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.
  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.
  search_match_path() isn't supposed to return anything.
  Move queue init to caller so it's only called once in a few cases.
  sort
  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.
  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.
2017-04-25 13:40:33 +00:00
ab8da61802 cvsimport
* refs/heads/master:
  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.
  Call client_resize instead of client_move after client_placecalc since the size may also change.
2017-02-10 15:00:54 +00:00
48b465bcff cvsimport
* refs/heads/master:
  Typo on binding name; from Redouan Ait Mallouk.
2017-01-15 21:07:44 +00:00
7ce071fdaa Leahize 2017-01-23 21:21:58 +01:00
b6a5b876e7 cvsimport
* refs/heads/master:
  Ensure client stays inbound on key-based resize; based on logic existing in key-based client move; from Vadim Vygonets.
  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.
2017-01-05 21:18:20 +00:00
44216b65c9 add config migration script 2016-12-16 14:31:33 +01:00
840dc39292 fix build 2016-12-16 14:29:50 +01:00
775ba78311 cvsimport
* refs/heads/master:
  stray newlines
  Add search_print_text(), a default callback for mi->print in menu_filter(). While here, normalize the remaining search_print_* argument paramters.
  Consistent use of menuq_add for ssh menu.
  Now that dim.{x,y} are available early, use them before requiring a MotionNotify event.
  Set dim.{x,y} during client_init and update on resize, instead of (re)calculating only when applying hints.
  '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.
  Fold unbinding functions into one for each, key and mouse; plugs a leak when unbinding a mouse button bound to a command.
  use the correct type
  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.
  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.
  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.
  Normalize bind function names, based on a few categories: window, group, menu and pointer.
  Use an additional check with lstat(2) when d_type is unknown.
  revert previous; upcoming changes will hopefully deal with these more naturally.
  Add a wrapper based upon xevent handlers around client move/resize for key and mouse bindings.
  Define callbacks, then default bindings.
  Reorganize for upcoming changes.
  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).
2016-12-16 13:48:38 +01:00
dcb741d2b1 cvsimport
* refs/heads/master: (34 commits)
  Make it clear these are flags.
  Remove duplicate check that strsubmatch() already does; while here, fix a comment.
  Sprinkle __func__ in appropriate error messages.
  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.
  clean up search_match_client(); no behaviour change
  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.
  remove another unused proto
  Rename 2 kbfunc to match closer to what they do
  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.
  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.
  More accurate to say 'toggle', rather than 'select', for group[n]/nogroup.
  Add CM-a for 'nogroup' (CM-0 stays for now); update manpage to reflect.
  Stash wmname into conf.
  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.
  Calculate client nameqlen in client_setname(), the only place it's needed/used.
  Turn CALMWM_NGROUPS define into variable, ngroups.
  Start simplifying menu code; and in turn, remove a cursor no longer needed.
  Defaults are split between defines and conf_init(); normalize these, as well as give 'sticky' groups its own variable.
  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.
  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-24 20:44:08 +00:00
fa06851b0e cvsimport
* refs/heads/master:
  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
8d44e4b3e8 cvsimport
* refs/heads/master:
  Some clients fail to setup hints at all, so initalize for them; fallout from r1.218 switching to malloc - clearly missed this case.
  Fix-up a few simple uses of client_current(): check CLIENT_ACTIVE flag instead of relying on curcc.
  init label
  Limit mouse resize to hints within the client; matches kbd resize behaviour.
  Switch to just malloc since we need initialize most everything anyway.
  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!
  Simplify group_holds_only_hidden(); from Vadim Vygonets.
  Simplify toggling flags; from Vadim Vygonets.
  Do not draw borders on ignored clients when returning from fullscreen; from Vadim Vygonets.
  Remove redundant minimum client size adjustment (minw and minh are always positive since r1.214); from Vadim Vygonets.
2016-09-14 21:00:24 +00:00
d2616ce397 cvsimport
* refs/heads/master:
  Enable the use of numpad Enter key on menus; from Henrique N. Lengler.
2016-08-28 15:23:24 +00:00
319b388b42 cvsimport
* refs/heads/master:
  add a column to previous commit for consitency.
  conf_screen: report the fontname that can't be opened in case of failure. ok dcoppa@
2016-08-13 09:59:48 +00:00
bbbaacf177 cvsimport
* refs/heads/master:
  If supplied format to menuq_add() is NULL, fill text with an empty string; found by Christian Neukirchen.
2016-06-08 13:18:37 +02:00
a889f32af6 menu: menuq_add: avoid passing null pointers to vsnprintf. 2016-04-02 17:21:04 +02:00
f9e9f76856 cvsimport
* refs/heads/master:
  Fix a typo from r1.201; fixes window_grouptoggle binding.
  If a client does not set increment values, use 'moveamount' as a way to scale keyboard based resizes; extend kbfunc_amount().
  Inline the only use of mousefunc_sweep_calc.
2015-11-17 15:19:19 +00:00
669631e5fa Run pledge only on OpenBSD. 2015-11-16 14:47:21 +01:00
4e51ce57a7 cvsimport
* refs/heads/master:
  more client vs screen context differences
  If a client sets hints, honor them for kb resize requests, just like we do for mouse based resize requests.
  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.
  pledge "stdio rpath proc exec" cwm before main event loop, after init/setup - mostly for menu building.
  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.
  Use position on root to figure out region.
  Start cleaning up name vs function differences; replace magic numbers.
  Clean up unused defines.
  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-12 21:28:03 +00:00
cd21e16675 cvsimport
* refs/heads/master:
  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.
  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-23 14:09:40 +00:00
3f0b6cf4ea cvsimport
* refs/heads/master: (21 commits)
  Lost fix from r1.112; add comment.
  Mechanical change: group->gc
  Add consistent checks against NULL.
  Move client cycle grab/ungrab into a more relevant place; while here, update comments about why we need to grab/ungrab the keyboard.
  Re-add lost chunk in group_cycle from r1.113.
  Further simplify _NET_WM_DESKTOP handling using new group_assign().
  oops; remove left over debug print
  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).
  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.
  Implement _NET_CLIENT_LIST_STACKING (from Thomas Admin), but bottom-to-top order, as per spec (notified Thomas as well).
  Don't allow freeze operations on fullscreen (consistent with what fullscreen does).
  Sort _NET_WM_STATE Atoms like the spec.
  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.
  Add Xkb modifier to ignore mask; from Alexander Polakov.
  Fix whitespace.
  Add client freeze extension to _NET_WM_STATE Atom, allowing flag to persist. As usual with new Atoms, requires X restart.
  _NET_WM_STATE_STICKY implies only sticky at the group/desktop level, not position and size; based on discussion with a few.
  Instead of special casing the 'term' and 'lock' commands, go back to keeping them hidden; showing them has apparently caused confusion/angst.
  Leave command list order from .cwmrc alone; remove sort.
  Bring group and client cycle closer together.
  ...
2015-08-28 12:07:28 +00:00
c0f2d0cc75 cvsimport 2015-07-12 14:31:47 +00:00
6716719593 cvsimport 2015-07-01 16:40:15 +02:00
4454948f21 cvsimport 2015-06-09 13:02:15 +00:00
7c4a8f3b51 Fix stat patch to use lstat(2) and fix logic 2015-04-23 21:42:34 +02:00
4cb6e0b17b Add an additional stat() check if a d_type check fails for kbfunc_exec lookups
Some filesystems (eg XFS) don't populate the d_type field of struct
dirent, used by kbfunc_exec to filter paths. This patch does an
additional stat() check for any file that fails the d_type check which
will work correctly on these filesystems.
2015-04-12 19:08:34 +02:00
da1021c60c queue.h: update. 2015-04-06 19:47:04 +02:00
ffbfc32999 add reallocarray.c 2015-03-29 18:12:47 +02:00
bc21e4aa37 cvsimport 2015-03-29 00:21:05 +00:00
668da8493a cvsimport 2015-02-11 14:20:35 +00:00
81c05b3a51 Merge pull request #8 from afh/pull/macosx
Use _POSIX_HOST_NAME_MAX
2015-02-11 15:19:03 +01:00
9cfb9225ed Use _POSIX_HOST_NAME_MAX
to be able to compile under Mac OS X.
2015-02-11 15:11:43 +01:00
976d77c76d update imported str*.c 2015-01-24 19:04:46 +01:00
b7a8c11750 update README 2015-01-24 18:31:20 +01:00
e4ccad30ce cvsimport 2015-01-24 17:03:58 +00:00
742732a1c8 cvsimport 2015-01-22 11:06:01 +01:00
089ec389dd also sign releases with signify 2014-12-15 16:00:31 +01:00
56fad8271d Fix reference to OpenBSD's CVS repo web interface 2014-12-15 15:51:15 +01:00
501aa2bcf3 cvsimport 2014-10-08 15:31:01 +00:00
c700f7e19a cvsimport 2014-09-27 19:04:32 +00:00
2540b3f4fe cvsimport 2014-09-18 13:56:58 +00:00
9735927809 update.sh: fix mirror 2014-09-07 17:49:00 +02:00
9e560bd745 cvsimport 2014-09-07 15:47:44 +00:00
870418ff68 README: mention OS X
Thanks to Alexis Hildebrandt for testing.
2014-06-23 16:40:30 +02:00
c7f481e6fa Don't use included strlcpy/strlcat when already defined as macros
OS X 10.9 with Fortify has conflicting prototypes:

In file included from calmwm.c:36:
./calmwm.h:28:8: error: conflicting types for '__builtin___strlcat_chk' /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/secure/_string.h:111:3:
note:
      expanded from macro 'strlcat'
  __builtin___strlcat_chk (dest, src, len, __darwin_obsz (dest))
2014-06-22 22:50:03 +02:00
a483e23e94 cvsimport 2014-04-21 12:52:14 +00:00
1101877305 Make PREFIX, MANPATH and CFLAGS optional variables
This change will make it possible to override PREFIX, MANPATH and
CFLAGS using environment variables. This makes the Makefile a little
more flexible, benefiting both endusers and those porting to package
systems like FreeBSD Ports and pkgsrc.

By braakvaak@aol.com.
2014-03-21 18:47:05 +01:00
4935bb73c0 builds on FreeBSD too 2014-03-14 16:43:40 +01:00
625be76fb9 Makefile: add sign action 2014-03-13 19:24:15 +01:00
2174a1960d Version 5.5 2014-03-13 19:19:19 +01:00
7c9565ec41 cvsimport 2014-02-27 00:52:57 +00:00
96af45583a remove TAILQ_END and __dead hacks 2014-02-23 15:49:58 +01:00
8ddc90665e cvsimport 2014-02-08 02:49:30 +00:00
8653141b4b cvsimport 2014-02-03 21:07:47 +00:00
b923524a8e cvsimport 2014-02-02 21:34:05 +00:00
c7d4add2f2 cvsimport 2014-02-01 00:25:04 +00:00
24f9bfb3ec cvsimport 2014-01-30 22:41:16 +00:00
1fd3fc4997 cvsimport 2014-01-29 22:30:00 +00:00
2b233f0548 cvsimport 2014-01-28 20:22:21 +00:00
5fd119daea cvsimport 2014-01-24 22:38:02 +00:00
371902b3c9 cvsimport 2014-01-21 15:42:44 +00:00
86b149ad25 cvsimport 2014-01-03 15:29:06 +00:00
f4c289b9e6 cvsimport 2014-01-03 14:23:50 +00:00
b387351df1 cvsimport 2013-12-17 16:12:18 +00:00
291e0dc088 add update.sh which I use for importing from CVS 2013-12-17 18:34:04 +01:00
44e2a2505b cvsimport 2013-12-16 19:02:17 +00:00
75b69c0b04 cvsimport 2013-12-13 22:39:13 +00:00
ddb67559f6 cvsimport 2013-12-13 15:56:44 +00:00
0cad4ef6e0 cvsimport 2013-12-13 12:57:57 +00:00
140028e905 cvsimport 2013-12-11 22:14:23 +00:00
2951979832 cvsimport 2013-12-08 13:51:38 +00:00
27513daee2 Revert "use u_char for buffers in yylex"
This reverts commit 03b19f1487.

This merely generates pointer signedness warnings for strtonum() and
lookup() and problems with the const char * prototype of xstrdup().
2013-12-06 23:16:54 +01:00
873763f4c6 cvsimport 2013-12-02 20:01:19 +00:00
3c78191e2e cvsimport 2013-11-12 21:25:00 +00:00
2037332bb7 cvsimport 2013-11-02 19:13:56 +00:00
caf8b315ab cvsimport 2013-11-01 14:07:19 +00:00
0c99788f66 cvsimport 2013-10-25 19:46:16 +00:00
0d6e8a9146 Makefile: rm -f is enough 2013-10-16 23:05:51 +02:00
f3477539bb cvsimport 2013-10-07 13:40:26 +00:00
0dec9e849d cvsimport 2013-07-16 14:30:48 +00:00
93bfc4a5c1 cvsimport 2013-07-10 14:15:58 +00:00
ba9baaf671 cvsimport 2013-06-23 17:57:50 +00:00
9a12ca3520 cvsimport 2013-06-20 02:33:57 +00:00
c30653b1c3 cvsimport 2013-06-03 20:33:17 +00:00
5515a365ba cvsimport 2013-05-29 22:41:51 +02:00
843f18aaee cvsimport 2013-04-30 21:12:20 +00:00
6f185bb03c cvsimport 2013-04-14 16:13:17 +00:00
a957ed7c7d cvsimport 2013-04-05 17:36:02 +00:00
cfc19dba7e cvsimport 2013-03-09 21:55:56 +00:00
9c6226faa8 cvsimport 2013-01-13 13:55:12 +00:00
104c7d5de3 cvsimport 2013-01-06 01:01:26 +00:00
f77166194f cvsimport 2012-12-19 15:21:34 +00:00
878eb6bf05 cvsimport 2012-11-28 14:32:44 +00:00
b4315a3fda Use vendored queue.h everywhere 2012-11-26 16:27:22 +01:00
9088b86b14 Vendor OpenBSD queue.h,v 1.36 2012-11-26 16:26:41 +01:00
319d4e179e cvsimport 2012-11-26 16:17:45 +01:00
e27f649ae7 cvsimport 2012-11-01 01:10:47 +00:00
c42043ede7 cvsimport 2012-10-29 19:46:03 +00:00
a2d0cbcf97 cvsimport 2012-09-12 15:09:33 +00:00
b18e365cb3 cvsimport 2012-08-07 14:05:49 +00:00
1545eb0837 cvsimport 2012-07-18 21:53:22 +00:00
8f587e6c80 cvsimport 2012-05-20 15:27:16 +02:00
0bb88fa567 define YYSTYPE_IS_DECLARED to work with bison 2.3 2012-05-04 17:46:42 +02:00
3bf492d2e9 compile with -D_GNU_SOURCE to get all relevant prototypes 2012-05-04 17:44:27 +02:00
601779351c Version 5.1 2012-05-02 14:26:57 +02:00
5f79bace21 Add release target to Makefile 2012-05-02 14:26:36 +02:00
de5efc6a54 Define compatibility macros only if they are needed 2012-05-02 14:26:14 +02:00
1603d18560 cvsimport 2011-12-29 20:48:38 +00:00
96ebac8b04 fix pkg-config packages 2011-12-12 16:17:39 +01:00
cbe46b651f cvsimport 2011-11-06 02:03:47 +00:00
901a75d3c6 cvsimport 2011-10-17 18:18:38 +00:00
58077c157b cvsimport 2011-10-12 15:43:50 +00:00
ce34d0066e Add README 2011-10-05 17:48:47 +02:00
7c7a5bdcdc rewrite Makefile 2011-10-05 17:48:33 +02:00
54c1b90725 cvsimport 2011-09-19 07:23:03 +00:00
3c67ec8ccc cvsimport 2011-09-13 09:17:30 +00:00
b1d81b7eb6 cvsimport 2011-09-08 12:35:33 +00:00
513c35dca9 cvsimport 2011-08-04 20:53:37 +02:00
f067809af4 cvsimport 2011-05-15 17:58:47 +00:00
a90a0b5705 cvsimport 2011-05-07 17:15:37 +00:00
2bac9a6be9 cvsimport 2011-05-03 19:28:18 +02:00
9eaece0541 cvsimport 2011-02-18 11:50:01 +00:00
5bc15cdb58 cvsimport 2010-12-24 23:42:39 +01:00
10622cf40d Add protoypes, fixes segfaults on x86 2010-09-26 14:51:23 +02:00
a64855f9cc Improve CFLAGS 2010-09-26 14:51:02 +02:00
e6d9effa8d Use yacc instead of byacc 2010-09-26 01:46:05 +02:00
b11c12e99b Merge branch 'origin' into linux 2010-09-26 01:43:12 +02:00
c9a14a8f40 cvsimport 2010-07-30 12:28:19 +00:00
e0c9657773 cvsimport 2010-05-22 22:32:08 +00:00
oga
f769df540d cvsimport 2010-04-12 16:17:46 +00:00
d90ab51111 Add missing functions 2010-02-21 19:18:12 +01:00
50aff37f50 Import linux.patch
Patch largely based on cwmbuild.sh from http://tamentis.com/hacks/cwm/
written by Bertrand Janin, updated by Christian Neukirchen.
2010-02-21 19:15:27 +01:00
26 changed files with 2525 additions and 1813 deletions

View File

@ -1,24 +1,53 @@
# $OpenBSD$
.include <bsd.xconf.mk>
# cwm makefile for BSD make and GNU make
# uses pkg-config, DESTDIR and PREFIX
PROG= cwm
PREFIX?= /usr/local
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 -I${.CURDIR}
OBJS= calmwm.o screen.o xmalloc.o client.o menu.o \
search.o util.o xutil.o conf.o xevents.o group.o \
kbfunc.o strlcpy.o strlcat.o y.tab.o \
strtonum.o reallocarray.o
CFLAGS+= -Wall
YFLAGS=
LDADD+= -L${X11BASE}/lib -lXft -lXrender -lX11 -lxcb -lXau -lXdmcp \
-lfontconfig -lexpat -lfreetype -lz -lXrandr -lXext
CPPFLAGS+= `pkg-config --cflags fontconfig x11 xft xrandr`
MANDIR= ${X11BASE}/man/man
MAN= cwm.1 cwmrc.5
CFLAGS?= -Wall -O2 -g -D_GNU_SOURCE
obj: _xenocara_obj
LDFLAGS+= `pkg-config --libs fontconfig x11 xft xrandr`
.include <bsd.prog.mk>
.include <bsd.xorg.mk>
MANPREFIX?= ${PREFIX}/share/man
all: ${PROG}
clean:
rm -f ${OBJS} ${PROG} y.tab.c
y.tab.c: parse.y
yacc parse.y
${PROG}: ${OBJS} y.tab.o
${CC} ${OBJS} ${LDFLAGS} -o ${PROG}
.c.o:
${CC} -c ${CFLAGS} ${CPPFLAGS} $<
install: ${PROG}
install -d ${DESTDIR}${PREFIX}/bin ${DESTDIR}${MANPREFIX}/man1 ${DESTDIR}${MANPREFIX}/man5
install -m 755 cwm ${DESTDIR}${PREFIX}/bin
install -m 644 cwm.1 ${DESTDIR}${MANPREFIX}/man1
install -m 644 cwmrc.5 ${DESTDIR}${MANPREFIX}/man5
release:
VERSION=$$(git describe --tags | sed 's/^v//;s/-[^.]*$$//') && \
git archive --prefix=cwm-$$VERSION/ -o cwm-$$VERSION.tar.gz HEAD
sign:
VERSION=$$(git describe --tags | sed 's/^v//;s/-[^.]*$$//') && \
gpg --armor --detach-sign cwm-$$VERSION.tar.gz && \
signify -S -s ~/.signify/cwm.sec -m cwm-$$VERSION.tar.gz && \
sed -i '1cuntrusted comment: verify with cwm.pub' cwm-$$VERSION.tar.gz.sig

112
README Normal file
View File

@ -0,0 +1,112 @@
This is a port of OpenBSD's excellent cwm[0] to Linux and other
Unices.
cwm is a window manager for X11 which contains many features that
concentrate on the efficiency and transparency of window
management. cwm also aims to maintain the simplest and most
pleasant aesthetic.
This port requires pkg-config, Xft, Xinerama and Xrandr. The included Makefile
should work with both GNU make and BSD make. It has been built successfully on
OpenBSD, FreeBSD, NetBSD, OS X 10.9 and Linux.
This version actively tracks changes in the OpenBSD CVS repository.
Releases are roughly coordinated.
The revision controlled version is at https://github.com/chneukirchen/cwm
Releases can be found at http://chneukirchen.org/releases
You are welcome to join the IRC channel ##cwm on Freenode to talk about cwm.
ChangeLog:
2012-05-02: First public release 5.1 of portable cwm.
2014-04-13: Second public release 5.5 of portable cwm.
User visible changes (for a full list including smaller bug fixes, see
http://www.openbsd.org/plus.html ff.)
Changes made between OpenBSD 5.1 and 5.2
* Fixed cwm(1) atom (WM_PROTOCOLS) style handing; closing a window will no
longer close entire application if the client supports CLIENT_PROTO_DELETE.
* Re-implement atom handing for more consistent separation of cwm(1) and
Extended Window Manager Hints.
* cwm(1) better integrated into the freedesktop.org Window Manager
Specification Project.
Changes made between OpenBSD 5.2 and 5.3
* Set the initial cwm(1) group to "1".
* Added cwm(1) per-group vert/horiz tiling support with new bind commands
"vtile" and "htile."
* Made cwm(1) screen font an Xft(3) font.
* Specific last match for autogroup in cwmrc(5).
* Tab completion support for cwm(1) menus.
* Allow cwm(1) clients to be resized from a max state.
* Multibyte input to cwm(1) menu code now possible.
Changes made between OpenBSD 5.3 and 5.4
* Added support for mouse based group {,r}cycle to cwmrc(5).
* Allow mouse button4 and button5 in cwmrc(5).
* Made cwm(1) check for, and honour, CWStackMode and CWSibling change requests
during a ConfigureRequest event.
* Honour PATH search order for cwm(1)'s exec.
Changes made between OpenBSD 5.5 and 5.4
* Only set the cwm(1) urgency flag if the client is not active.
* Allow the cwm(1) config parser continue parsing even after encountering an
error.
* cwm(1) now follows the EWMH spec: if the cardinal returned is 0xFFFFFFFF (-1)
then the window should appear on all desktops.
* Made cwm(1) supply a more useful title for windows launched via the ssh(1)
command menu ("[ssh] ").
* Allowed cwm(1) to accept _NET_WM_DESKTOP and _NET_CURRENT_DESKTOP
ClientMessage.
* Implemented cwm(1) support for _NET_WM_STATE_FULLSCREEN hint, with keybinding
changes: CM-f "fullscreen", CM-m "maximize".
* Instead of using the work area, use the Xinerama area for cwm(1) snap
calculations.
* Save-set when cwm(1) is re-exec'ing so as to not lose State on our hidden
clients.
* Added cwmrc(5) support for XUrgency and matching
_NET_WM_STATE_DEMANDS_ATTENTION ewmh hint, with configurable urgencyborder.
* Prepend the group shortcut in the cwm(1) client search menu;
prepend shortcut in unhide menu.
* If not hidden during an UnmapNotify event, cwm(1) will now un-manage the
client.
* Like "gap", made cwm(1) "snapdist" per-screen.
* Removed cwmrc(5) option to bind a key by keycode with brackets, which never
worked. Users should be using keysym names not keycodes.
* Re-added cwm(1) support for WM_TAKE_FOCUS. Solves keyboard input focus loss
for java apps.
* For cwm(1) clients that support WM_TAKE_FOCUS in their WM_PROTOCOLS property,
send a ClientMessage event.
2015-01-24: Third public release 5.6 of portable cwm.
* Support building on FreeBSD and OS X.
* Support for sticky windows (_NET_WM_STATE_STICKY).
* Internal cleanups and bug fixes.
Changes made between OpenBSD 5.6 and 5.7
* Implemented _NET_WM_STATE_STICKY in cwm(1). Allows client to "stick"
to all desktops or groups.
* Ensure cwm(1) client that wants to be in nogroup stays in nogroup
(thus stays in view), even when (re)reading NET_WM_DESKTOP.
Changes made between OpenBSD 5.7 and 5.8
* In cwm(1), introduce "groupsearch" for group menu search.
* In cwm(1), show an empty "ssh to" menu if the known_hosts file is missing.
* In cwm(1), replace screen region info gathering with XRandR
equivalent of Xinerama queries.
Changes made between OpenBSD 5.8 and 5.9
* Don't allow freeze operations on fullscreen.
* Implement _NET_CLIENT_LIST_STACKING.
2017-10-17: Fourth public release 6.2 of portable cwm.
--Leah Neukirchen <leah@vuxu.org>
[0]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/xenocara/app/cwm/

112
calmwm.c
View File

@ -19,7 +19,7 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <sys/wait.h>
#include <err.h>
@ -27,7 +27,7 @@
#include <getopt.h>
#include <limits.h>
#include <locale.h>
#include <poll.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@ -42,46 +42,36 @@ Atom cwmh[CWMH_NITEMS];
Atom ewmh[EWMH_NITEMS];
struct screen_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
struct conf Conf;
const char *homedir;
volatile sig_atomic_t cwm_status;
__dead void usage(void);
static void sighdlr(int);
static int x_errorhandler(Display *, XErrorEvent *);
static int x_init(const char *);
static void x_init(const char *);
static void x_teardown(void);
static int x_wmerrorhandler(Display *, XErrorEvent *);
int
main(int argc, char **argv)
{
char *display_name = NULL;
char *fallback;
int ch, xfd, nflag = 0;
struct pollfd pfd[1];
const char *conf_file = NULL;
char *conf_path, *display_name = NULL;
int ch;
struct passwd *pw;
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
warnx("no locale support");
mbtowc(NULL, NULL, MB_CUR_MAX);
conf_init(&Conf);
fallback = u_argv(argv);
Conf.wm_argv = u_argv(argv);
while ((ch = getopt(argc, argv, "c:d:nv")) != -1) {
while ((ch = getopt(argc, argv, "c:d:")) != -1) {
switch (ch) {
case 'c':
free(Conf.conf_file);
Conf.conf_file = xstrdup(optarg);
conf_file = optarg;
break;
case 'd':
display_name = optarg;
break;
case 'n':
nflag = 1;
break;
case 'v':
Conf.debug++;
break;
default:
usage();
}
@ -89,47 +79,53 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
if (signal(SIGCHLD, sighdlr) == SIG_ERR ||
signal(SIGHUP, sighdlr) == SIG_ERR ||
signal(SIGINT, sighdlr) == SIG_ERR ||
signal(SIGTERM, sighdlr) == SIG_ERR)
if (signal(SIGCHLD, sighdlr) == SIG_ERR)
err(1, "signal");
if (parse_config(Conf.conf_file, &Conf) == -1) {
warnx("error parsing config file");
if (nflag)
return 1;
if ((homedir = getenv("HOME")) == NULL || *homedir == '\0') {
pw = getpwuid(getuid());
if (pw != NULL && pw->pw_dir != NULL && *pw->pw_dir != '\0')
homedir = pw->pw_dir;
else
homedir = "/";
}
if (nflag)
return 0;
xfd = x_init(display_name);
if (conf_file == NULL)
xasprintf(&conf_path, "%s/%s", homedir, CONFFILE);
else
conf_path = xstrdup(conf_file);
if (access(conf_path, R_OK) != 0) {
if (conf_file != NULL)
warn("%s", conf_file);
free(conf_path);
conf_path = NULL;
}
conf_init(&Conf);
if (conf_path && (parse_config(conf_path, &Conf) == -1))
warnx("config file %s has errors", conf_path);
free(conf_path);
x_init(display_name);
cwm_status = CWM_RUNNING;
#ifdef __OpenBSD__
if (pledge("stdio rpath proc exec", NULL) == -1)
err(1, "pledge");
#endif
memset(&pfd, 0, sizeof(pfd));
pfd[0].fd = xfd;
pfd[0].events = POLLIN;
while (cwm_status == CWM_RUNNING) {
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) {
if (cwm_status == CWM_EXEC_WM)
u_exec(Conf.wm_argv);
warnx("'%s' failed to start, starting fallback", Conf.wm_argv);
u_exec(fallback);
}
return 0;
return(0);
}
static int
static void
x_init(const char *dpyname)
{
int i;
@ -144,13 +140,11 @@ x_init(const char *dpyname)
Conf.xrandr = XRRQueryExtension(X_Dpy, &Conf.xrandr_event_base, &i);
xu_atom_init();
conf_atoms();
conf_cursor(&Conf);
for (i = 0; i < ScreenCount(X_Dpy); i++)
screen_init(i);
return ConnectionNumber(X_Dpy);
}
static void
@ -167,6 +161,8 @@ x_teardown(void)
DefaultColormap(X_Dpy, sc->which),
&sc->xftcolor[i]);
XftFontClose(X_Dpy, sc->xftfont);
XftDrawDestroy(sc->menu.xftdraw);
XDestroyWindow(X_Dpy, sc->menu.win);
XUngrabKey(X_Dpy, AnyKey, AnyModifier, sc->rootwin);
}
XUngrabPointer(X_Dpy, CurrentTime);
@ -182,7 +178,8 @@ static int
x_wmerrorhandler(Display *dpy, XErrorEvent *e)
{
errx(1, "root window unavailable - perhaps another wm is running?");
return 0;
return(0);
}
static int
@ -198,7 +195,7 @@ x_errorhandler(Display *dpy, XErrorEvent *e)
warnx("%s(0x%x): %s", req, (unsigned int)e->resourceid, msg);
#endif
return 0;
return(0);
}
static void
@ -210,28 +207,21 @@ sighdlr(int sig)
switch (sig) {
case SIGCHLD:
/* Collect dead children. */
while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0 ||
while ((pid = waitpid(-1, &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
void
usage(void)
{
extern char *__progname;
(void)fprintf(stderr, "usage: %s [-nv] [-c file] [-d display]\n",
(void)fprintf(stderr, "usage: %s [-c file] [-d display]\n",
__progname);
exit(1);
}

245
calmwm.h
View File

@ -21,6 +21,27 @@
#ifndef _CALMWM_H_
#define _CALMWM_H_
#include <sys/param.h>
#include <stdio.h>
#include "queue.h"
/* prototypes for portable-included functions */
char *fgetln(FILE *, size_t *);
long long strtonum(const char *, long long, long long, const char **);
void *reallocarray(void *, size_t, size_t);
#ifdef strlcat
#define HAVE_STRLCAT
#else
size_t strlcat(char *, const char *, size_t);
#endif
#ifdef strlcpy
#define HAVE_STRLCPY
#else
size_t strlcpy(char *, const char *, size_t);
#endif
#include <X11/XKBlib.h>
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
@ -31,11 +52,6 @@
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
#define LOG_DEBUG0(...) log_debug(0, __func__, __VA_ARGS__)
#define LOG_DEBUG1(...) log_debug(1, __func__, __VA_ARGS__)
#define LOG_DEBUG2(...) log_debug(2, __func__, __VA_ARGS__)
#define LOG_DEBUG3(...) log_debug(3, __func__, __VA_ARGS__)
#undef MIN
#undef MAX
#define MIN(x, y) ((x) < (y) ? (x) : (y))
@ -45,8 +61,13 @@
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif
#define CONFFILE ".cwmrc"
#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
#define MENUMASK (MOUSEMASK | ButtonMotionMask | ExposureMask)
#define MENUGRABMASK (MOUSEMASK | ButtonMotionMask | StructureNotifyMask)
#define KEYMASK (KeyPressMask | ExposureMask)
#define IGNOREMODMASK (LockMask | Mod2Mask | 0x2000)
/* direction/amount */
@ -55,14 +76,7 @@
#define CWM_LEFT 0x0004
#define CWM_RIGHT 0x0008
#define CWM_BIGAMOUNT 0x0010
#define CWM_UP_BIG (CWM_UP | CWM_BIGAMOUNT)
#define CWM_DOWN_BIG (CWM_DOWN | CWM_BIGAMOUNT)
#define CWM_LEFT_BIG (CWM_LEFT | CWM_BIGAMOUNT)
#define CWM_RIGHT_BIG (CWM_RIGHT | CWM_BIGAMOUNT)
#define CWM_UP_RIGHT (CWM_UP | CWM_RIGHT)
#define CWM_UP_LEFT (CWM_UP | CWM_LEFT)
#define CWM_DOWN_RIGHT (CWM_DOWN | CWM_RIGHT)
#define CWM_DOWN_LEFT (CWM_DOWN | CWM_LEFT)
#define DIRECTIONMASK (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)
#define CWM_CYCLE_FORWARD 0x0001
#define CWM_CYCLE_REVERSE 0x0002
@ -99,6 +113,11 @@ struct geom {
int w;
int h;
};
enum apply_gap {
CWM_NOGAP = 0,
CWM_GAP
};
struct gap {
int top;
int bottom;
@ -115,12 +134,12 @@ TAILQ_HEAD(ignore_q, winname);
struct client_ctx {
TAILQ_ENTRY(client_ctx) entry;
TAILQ_ENTRY(client_ctx) group_entry;
struct screen_ctx *sc;
struct group_ctx *gc;
Window win;
Colormap colormap;
int bwidth; /* border width */
int obwidth; /* original border width */
struct geom geom, savegeom, fullgeom;
struct {
long flags; /* defined hints */
@ -157,11 +176,6 @@ struct client_ctx {
#define CLIENT_FULLSCREEN 0x0800
#define CLIENT_STICKY 0x1000
#define CLIENT_ACTIVE 0x2000
#define CLIENT_SKIP_PAGER 0x4000
#define CLIENT_SKIP_TASKBAR 0x8000
#define CLIENT_SKIP_CYCLE (CLIENT_HIDDEN | CLIENT_IGNORE | \
CLIENT_SKIP_TASKBAR | CLIENT_SKIP_PAGER)
#define CLIENT_HIGHLIGHT (CLIENT_GROUP | CLIENT_UNGROUP)
#define CLIENT_MAXFLAGS (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
#define CLIENT_MAXIMIZED (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
@ -170,9 +184,8 @@ struct client_ctx {
struct name_q nameq;
char *name;
char *label;
char *res_class; /* class hint */
char *res_name; /* class hint */
int initial_state; /* wm hint */
XClassHint ch;
XWMHints *wmh;
};
TAILQ_HEAD(client_q, client_ctx);
@ -181,6 +194,7 @@ struct group_ctx {
struct screen_ctx *sc;
char *name;
int num;
struct client_q clientq;
};
TAILQ_HEAD(group_q, group_ctx);
@ -195,6 +209,7 @@ TAILQ_HEAD(autogroup_q, autogroup);
struct region_ctx {
TAILQ_ENTRY(region_ctx) entry;
int num;
struct geom area;
struct geom view; /* viewable area */
struct geom work; /* workable area, gap-applied */
};
@ -214,13 +229,10 @@ struct screen_ctx {
struct region_q regionq;
struct group_q groupq;
struct group_ctx *group_active;
struct group_ctx *group_last;
Colormap colormap;
Visual *visual;
struct {
Window win;
XftDraw *xftdraw;
} prop;
} menu;
XftColor xftcolor[CWM_COLOR_NITEMS];
XftFont *xftfont;
};
@ -256,11 +268,14 @@ TAILQ_HEAD(mousebind_q, bind_ctx);
struct cmd_ctx {
TAILQ_ENTRY(cmd_ctx) entry;
char *name;
char *path;
char path[PATH_MAX];
};
TAILQ_HEAD(cmd_q, cmd_ctx);
TAILQ_HEAD(wm_q, cmd_ctx);
enum menu_exec {
CWM_MENU_EXEC_EXEC,
CWM_MENU_EXEC_WM
};
#define CWM_MENU_DUMMY 0x0001
#define CWM_MENU_FILE 0x0002
#define CWM_MENU_LIST 0x0004
@ -285,63 +300,49 @@ struct conf {
struct autogroup_q autogroupq;
struct ignore_q ignoreq;
struct cmd_q cmdq;
struct wm_q wmq;
int ngroups;
int stickygroups;
int nameqlen;
int bwidth;
int mamount;
int snapdist;
int htile;
int vtile;
struct gap gap;
char *color[CWM_COLOR_NITEMS];
char known_hosts[PATH_MAX];
char *font;
char *wmname;
Cursor cursor[CF_NITEMS];
int xrandr;
int xrandr_event_base;
char *conf_file;
char *known_hosts;
char *wm_argv;
int debug;
};
/* MWM hints */
struct mwm_hints {
#define MWM_HINTS_ELEMENTS 5L
#define MWM_HINTS_ELEMENTS 3L
#define MWM_FLAGS_STATUS (1<<3)
#define MWM_HINTS_FUNCTIONS (1L << 0)
#define MWM_HINTS_DECORATIONS (1L << 1)
#define MWM_HINTS_INPUT_MODE (1L << 2)
#define MWM_HINTS_STATUS (1L << 3)
#define MWM_FLAGS_FUNCTIONS (1<<0)
#define MWM_FLAGS_DECORATIONS (1<<1)
#define MWM_FLAGS_INPUT_MODE (1<<2)
unsigned long flags;
#define MWM_FUNC_ALL (1L << 0)
#define MWM_FUNC_RESIZE (1L << 1)
#define MWM_FUNC_MOVE (1L << 2)
#define MWM_FUNC_MINIMIZE (1L << 3)
#define MWM_FUNC_MAXIMIZE (1L << 4)
#define MWM_FUNC_CLOSE (1L << 5)
#define MWM_FUNCS_ALL (1<<0)
#define MWM_FUNCS_RESIZE (1<<1)
#define MWM_FUNCS_MOVE (1<<2)
#define MWM_FUNCS_MINIMIZE (1<<3)
#define MWM_FUNCS_MAXIMIZE (1<<4)
#define MWM_FUNCS_CLOSE (1<<5)
unsigned long functions;
#define MWM_DECOR_ALL (1L << 0)
#define MWM_DECOR_BORDER (1L << 1)
#define MWM_DECOR_RESIZEH (1L << 2)
#define MWM_DECOR_TITLE (1L << 3)
#define MWM_DECOR_MENU (1L << 4)
#define MWM_DECOR_MINIMIZE (1L << 5)
#define MWM_DECOR_MAXIMIZE (1L << 6)
#define MWM_DECOR_ALL (1<<0)
#define MWM_DECOR_BORDER (1<<1)
#define MWM_DECOR_RESIZE_HANDLE (1<<2)
#define MWM_DECOR_TITLEBAR (1<<3)
#define MWM_DECOR_MENU (1<<4)
#define MWM_DECOR_MINIMIZE (1<<5)
#define MWM_DECOR_MAXIMIZE (1<<6)
unsigned long decorations;
#define MWM_INPUT_MODELESS 0
#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
#define MWM_INPUT_SYSTEM_MODAL 2
#define MWM_INPUT_FULL_APPLICATION_MODAL 3
long inputMode;
#define MWM_TEAROFF_WINDOW (1L << 0)
unsigned long status;
};
enum cwmh {
@ -372,15 +373,13 @@ enum ewmh {
_NET_WM_DESKTOP,
_NET_CLOSE_WINDOW,
_NET_WM_STATE,
#define _NET_WM_STATES_NITEMS 9
#define _NET_WM_STATES_NITEMS 7
_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,
EWMH_NITEMS
};
@ -396,104 +395,96 @@ extern Atom cwmh[CWMH_NITEMS];
extern Atom ewmh[EWMH_NITEMS];
extern struct screen_q Screenq;
extern struct conf Conf;
extern const char *homedir;
void client_apply_sizehints(struct client_ctx *);
void client_close(struct client_ctx *);
void usage(void);
void client_applysizehints(struct client_ctx *);
void client_config(struct client_ctx *);
struct client_ctx *client_current(struct screen_ctx *);
struct client_ctx *client_current(void);
void client_cycle(struct screen_ctx *, int);
void client_cycle_leave(struct screen_ctx *);
void client_delete(struct client_ctx *);
void client_draw_border(struct client_ctx *);
struct client_ctx *client_find(Window);
void client_get_sizehints(struct client_ctx *);
long client_get_wm_state(struct client_ctx *);
void client_getsizehints(struct client_ctx *);
void client_hide(struct client_ctx *);
void client_htile(struct client_ctx *);
int client_inbound(struct client_ctx *, int, int);
struct client_ctx *client_init(Window, struct screen_ctx *);
void client_lower(struct client_ctx *);
void client_map(struct client_ctx *);
void client_msg(struct client_ctx *, Atom, Time);
void client_move(struct client_ctx *);
void client_mtf(struct client_ctx *);
struct client_ctx *client_next(struct client_ctx *);
struct client_ctx *client_prev(struct client_ctx *);
int client_inbound(struct client_ctx *, int, int);
struct client_ctx *client_init(Window, struct screen_ctx *, int);
void client_ptr_inbound(struct client_ctx *, int);
void client_ptr_save(struct client_ctx *);
void client_ptr_warp(struct client_ctx *);
void client_ptrsave(struct client_ctx *);
void client_ptrwarp(struct client_ctx *);
void client_raise(struct client_ctx *);
void client_remove(struct client_ctx *);
void client_resize(struct client_ctx *, int);
void client_set_active(struct client_ctx *);
void client_set_name(struct client_ctx *);
void client_show(struct client_ctx *);
void client_send_delete(struct client_ctx *);
void client_set_wm_state(struct client_ctx *, long);
void client_setactive(struct client_ctx *);
void client_setname(struct client_ctx *);
int client_snapcalc(int, int, int, int, int);
void client_toggle_freeze(struct client_ctx *);
void client_toggle_fullscreen(struct client_ctx *);
void client_toggle_hidden(struct client_ctx *);
void client_toggle_hmaximize(struct client_ctx *);
void client_toggle_fullscreen(struct client_ctx *);
void client_toggle_freeze(struct client_ctx *);
void client_toggle_maximize(struct client_ctx *);
void client_toggle_skip_pager(struct client_ctx *);
void client_toggle_skip_taskbar(struct client_ctx *);
void client_toggle_sticky(struct client_ctx *);
void client_toggle_vmaximize(struct client_ctx *);
void client_transient(struct client_ctx *);
void client_unhide(struct client_ctx *);
void client_urgency(struct client_ctx *);
void client_vtile(struct client_ctx *);
void client_wm_hints(struct client_ctx *);
void group_alltoggle(struct screen_ctx *);
void group_assign(struct group_ctx *, struct client_ctx *);
int group_autogroup(struct client_ctx *);
void group_cycle(struct screen_ctx *, int);
void group_hide(struct group_ctx *);
void group_hidetoggle(struct screen_ctx *, int);
int group_holds_only_hidden(struct group_ctx *);
int group_holds_only_sticky(struct group_ctx *);
void group_init(struct screen_ctx *, int, const char *);
void group_init(struct screen_ctx *, int);
void group_movetogroup(struct client_ctx *, int);
void group_only(struct screen_ctx *, int);
void group_close(struct screen_ctx *, int);
int group_restore(struct client_ctx *);
void group_show(struct group_ctx *);
void group_toggle(struct screen_ctx *, int);
void group_toggle_all(struct screen_ctx *);
void group_toggle_membership(struct client_ctx *);
void group_toggle_membership_enter(struct client_ctx *);
void group_toggle_membership_leave(struct client_ctx *);
void group_update_names(struct screen_ctx *);
void search_match_client(struct menu_q *, struct menu_q *,
char *);
void search_match_cmd(struct menu_q *, struct menu_q *,
char *);
void search_match_exec(struct menu_q *, struct menu_q *,
char *);
void search_match_group(struct menu_q *, struct menu_q *,
char *);
void search_match_path(struct menu_q *, struct menu_q *,
char *);
void search_match_text(struct menu_q *, struct menu_q *,
char *);
void search_match_wm(struct menu_q *, struct menu_q *,
char *);
void search_print_client(struct menu *, int);
void search_print_cmd(struct menu *, int);
void search_print_group(struct menu *, int);
void search_print_text(struct menu *, int);
void search_print_wm(struct menu *, int);
struct region_ctx *region_find(struct screen_ctx *, int, int);
void screen_assert_clients_within(struct screen_ctx *);
struct geom screen_area(struct screen_ctx *, int, int, int);
struct geom screen_apply_gap(struct screen_ctx *, struct geom);
struct screen_ctx *screen_find(Window);
struct geom screen_area(struct screen_ctx *, int, int,
enum apply_gap);
void screen_init(int);
void screen_prop_win_create(struct screen_ctx *, Window);
void screen_prop_win_destroy(struct screen_ctx *);
void screen_prop_win_draw(struct screen_ctx *,
const char *, ...)
__attribute__((__format__ (printf, 2, 3)))
__attribute__((__nonnull__ (2)));
void screen_update_geometry(struct screen_ctx *);
void screen_updatestackingorder(struct screen_ctx *);
void screen_assert_clients_within(struct screen_ctx *);
void kbfunc_cwm_status(void *, struct cargs *);
void kbfunc_ptrmove(void *, struct cargs *);
void kbfunc_client_snap(void *, struct cargs *);
void kbfunc_client_move(void *, struct cargs *);
void kbfunc_client_resize(void *, struct cargs *);
void kbfunc_client_close(void *, struct cargs *);
void kbfunc_client_delete(void *, struct cargs *);
void kbfunc_client_lower(void *, struct cargs *);
void kbfunc_client_raise(void *, struct cargs *);
void kbfunc_client_hide(void *, struct cargs *);
@ -511,14 +502,11 @@ void kbfunc_client_toggle_group(void *, struct cargs *);
void kbfunc_client_movetogroup(void *, struct cargs *);
void kbfunc_group_toggle(void *, struct cargs *);
void kbfunc_group_only(void *, struct cargs *);
void kbfunc_group_last(void *, struct cargs *);
void kbfunc_group_close(void *, struct cargs *);
void kbfunc_group_cycle(void *, struct cargs *);
void kbfunc_group_toggle_all(void *, struct cargs *);
void kbfunc_group_alltoggle(void *, struct cargs *);
void kbfunc_menu_client(void *, struct cargs *);
void kbfunc_menu_cmd(void *, struct cargs *);
void kbfunc_menu_group(void *, struct cargs *);
void kbfunc_menu_wm(void *, struct cargs *);
void kbfunc_menu_exec(void *, struct cargs *);
void kbfunc_menu_ssh(void *, struct cargs *);
void kbfunc_client_menu_label(void *, struct cargs *);
@ -526,16 +514,18 @@ void kbfunc_exec_cmd(void *, struct cargs *);
void kbfunc_exec_lock(void *, struct cargs *);
void kbfunc_exec_term(void *, struct cargs *);
void menu_windraw(struct screen_ctx *, Window,
const char *, ...);
struct menu *menu_filter(struct screen_ctx *, struct menu_q *,
const char *, const char *, int,
void (*)(struct menu_q *, struct menu_q *, char *),
void (*)(struct menu *, int));
void menuq_add(struct menu_q *, void *, const char *, ...)
__attribute__((__format__ (printf, 3, 4)));
void menuq_add(struct menu_q *, void *, const char *, ...);
void menuq_clear(struct menu_q *);
int parse_config(const char *, struct conf *);
void conf_atoms(void);
void conf_autogroup(struct conf *, int, const char *,
const char *);
int conf_bind_key(struct conf *, const char *,
@ -544,9 +534,7 @@ int conf_bind_mouse(struct conf *, const char *,
const char *);
void conf_clear(struct conf *);
void conf_client(struct client_ctx *);
void conf_cmd_add(struct conf *, const char *,
const char *);
void conf_wm_add(struct conf *, const char *,
int conf_cmd_add(struct conf *, const char *,
const char *);
void conf_cursor(struct conf *);
void conf_grab_kbd(Window);
@ -554,47 +542,40 @@ void conf_grab_mouse(Window);
void conf_init(struct conf *);
void conf_ignore(struct conf *, const char *);
void conf_screen(struct screen_ctx *);
void conf_group(struct screen_ctx *);
void xev_process(void);
int xu_get_prop(Window, Atom, Atom, long, unsigned char **);
int xu_get_strprop(Window, Atom, char **);
void xu_ptr_get(Window, int *, int *);
void xu_ptr_set(Window, int, int);
void xu_get_wm_state(Window, long *);
void xu_set_wm_state(Window, long);
void xu_send_clientmsg(Window, Atom, Time);
int xu_getprop(Window, Atom, Atom, long, unsigned char **);
int xu_getstrprop(Window, Atom, char **);
void xu_ptr_getpos(Window, int *, int *);
void xu_ptr_setpos(Window, int, int);
void xu_xorcolor(XftColor, XftColor, XftColor *);
void xu_atom_init(void);
void xu_ewmh_net_supported(struct screen_ctx *);
void xu_ewmh_net_supported_wm_check(struct screen_ctx *);
void xu_ewmh_net_desktop_geometry(struct screen_ctx *);
void xu_ewmh_net_desktop_viewport(struct screen_ctx *);
void xu_ewmh_net_workarea(struct screen_ctx *);
void xu_ewmh_net_client_list(struct screen_ctx *);
void xu_ewmh_net_client_list_stacking(struct screen_ctx *);
void xu_ewmh_net_active_window(struct screen_ctx *, Window);
void xu_ewmh_net_number_of_desktops(struct screen_ctx *);
Window xu_ewmh_get_net_active_window(struct screen_ctx *);
void xu_ewmh_net_wm_desktop_viewport(struct screen_ctx *);
void xu_ewmh_net_wm_number_of_desktops(struct screen_ctx *);
void xu_ewmh_net_showing_desktop(struct screen_ctx *);
void xu_ewmh_net_virtual_roots(struct screen_ctx *);
void xu_ewmh_net_current_desktop(struct screen_ctx *);
void xu_ewmh_net_desktop_names(struct screen_ctx *);
int xu_ewmh_get_net_wm_desktop(struct client_ctx *, long *);
void xu_ewmh_set_net_wm_desktop(struct client_ctx *);
void xu_ewmh_net_wm_desktop(struct client_ctx *);
Atom *xu_ewmh_get_net_wm_state(struct client_ctx *, int *);
void xu_ewmh_handle_net_wm_state_msg(struct client_ctx *,
int, Atom, Atom);
int, Atom , Atom);
void xu_ewmh_set_net_wm_state(struct client_ctx *);
void xu_ewmh_restore_net_wm_state(struct client_ctx *);
char *u_argv(char * const *);
void u_exec(char *);
void u_spawn(char *);
void log_debug(int, const char *, const char *, ...)
__attribute__((__format__ (printf, 3, 4)))
__attribute__((__nonnull__ (3)));
void *xcalloc(size_t, size_t);
void *xmalloc(size_t);
@ -603,7 +584,5 @@ char *xstrdup(const char *);
int xasprintf(char **, const char *, ...)
__attribute__((__format__ (printf, 2, 3)))
__attribute__((__nonnull__ (2)));
int xvasprintf(char **, const char *, va_list)
__attribute__((__nonnull__ (2)));
#endif /* _CALMWM_H_ */

585
client.c
View File

@ -19,7 +19,7 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <err.h>
#include <errno.h>
@ -31,87 +31,91 @@
#include "calmwm.h"
static void client_class_hint(struct client_ctx *);
static void client_placement(struct client_ctx *);
static void client_mwm_hints(struct client_ctx *);
static struct client_ctx *client_next(struct client_ctx *);
static struct client_ctx *client_prev(struct client_ctx *);
static void client_mtf(struct client_ctx *);
static void client_placecalc(struct client_ctx *);
static void client_wm_protocols(struct client_ctx *);
static void client_mwm_hints(struct client_ctx *);
struct client_ctx *
client_init(Window win, struct screen_ctx *sc)
client_init(Window win, struct screen_ctx *sc, int active)
{
struct client_ctx *cc;
XWindowAttributes wattr;
int mapped;
long state;
Window rwin, cwin;
int x, y, wx, wy;
unsigned int mask;
if (win == None)
return NULL;
return(NULL);
if (!XGetWindowAttributes(X_Dpy, win, &wattr))
return NULL;
return(NULL);
if (sc == NULL) {
if ((sc = screen_find(wattr.root)) == NULL)
return NULL;
return(NULL);
mapped = 1;
} else {
if (wattr.override_redirect || wattr.map_state != IsViewable)
return NULL;
return(NULL);
mapped = wattr.map_state != IsUnmapped;
}
cc = xmalloc(sizeof(*cc));
XGrabServer(X_Dpy);
cc = xmalloc(sizeof(*cc));
cc->sc = sc;
cc->win = win;
cc->name = NULL;
cc->label = NULL;
cc->gc = NULL;
cc->res_class = NULL;
cc->res_name = NULL;
cc->flags = 0;
cc->stackingorder = 0;
cc->initial_state = 0;
memset(&cc->hint, 0, sizeof(cc->hint));
memset(&cc->ch, 0, sizeof(cc->ch));
TAILQ_INIT(&cc->nameq);
client_setname(cc);
conf_client(cc);
XGetClassHint(X_Dpy, cc->win, &cc->ch);
client_wm_hints(cc);
client_wm_protocols(cc);
client_getsizehints(cc);
client_mwm_hints(cc);
cc->geom.x = wattr.x;
cc->geom.y = wattr.y;
cc->geom.w = wattr.width;
cc->geom.h = wattr.height;
cc->colormap = wattr.colormap;
cc->obwidth = wattr.border_width;
cc->bwidth = Conf.bwidth;
client_set_name(cc);
conf_client(cc);
client_wm_hints(cc);
client_class_hint(cc);
client_wm_protocols(cc);
client_get_sizehints(cc);
client_transient(cc);
client_mwm_hints(cc);
if ((cc->flags & CLIENT_IGNORE))
cc->bwidth = 0;
cc->dim.w = (cc->geom.w - cc->hint.basew) / cc->hint.incw;
cc->dim.h = (cc->geom.h - cc->hint.baseh) / cc->hint.inch;
cc->ptr.x = cc->geom.w / 2;
cc->ptr.y = cc->geom.h / 2;
cc->colormap = wattr.colormap;
if (wattr.map_state != IsViewable) {
client_placement(cc);
client_placecalc(cc);
client_resize(cc, 0);
if (cc->initial_state)
xu_set_wm_state(cc->win, cc->initial_state);
if ((cc->wmh) && (cc->wmh->flags & StateHint))
client_set_wm_state(cc, cc->wmh->initial_state);
} else {
if ((active == 0) && (XQueryPointer(X_Dpy, cc->win, &rwin, &cwin,
&x, &y, &wx, &wy, &mask)) && (cwin != None))
active = 1;
}
XSelectInput(X_Dpy, cc->win,
EnterWindowMask | PropertyChangeMask | KeyReleaseMask);
XSelectInput(X_Dpy, cc->win, ColormapChangeMask | EnterWindowMask |
PropertyChangeMask | KeyReleaseMask);
XAddToSaveSet(X_Dpy, cc->win);
client_transient(cc);
/* Notify client of its configuration. */
client_config(cc);
@ -121,17 +125,12 @@ client_init(Window win, struct screen_ctx *sc)
xu_ewmh_net_client_list_stacking(sc);
xu_ewmh_restore_net_wm_state(cc);
xu_get_wm_state(cc->win, &state);
if (state == IconicState)
if (client_get_wm_state(cc) == IconicState)
client_hide(cc);
else
client_show(cc);
client_unhide(cc);
if (mapped) {
if (cc->gc) {
group_movetogroup(cc, cc->gc->num);
goto out;
}
if (group_restore(cc))
goto out;
if (group_autogroup(cc))
@ -145,29 +144,10 @@ out:
XSync(X_Dpy, False);
XUngrabServer(X_Dpy);
return cc;
}
if (active)
client_setactive(cc);
struct client_ctx *
client_current(struct screen_ctx *sc)
{
struct screen_ctx *_sc;
struct client_ctx *cc;
if (sc) {
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->flags & CLIENT_ACTIVE)
return cc;
}
} else {
TAILQ_FOREACH(_sc, &Screenq, entry) {
TAILQ_FOREACH(cc, &_sc->clientq, entry) {
if (cc->flags & CLIENT_ACTIVE)
return cc;
}
}
}
return NULL;
return(cc);
}
struct client_ctx *
@ -179,34 +159,14 @@ client_find(Window win)
TAILQ_FOREACH(sc, &Screenq, entry) {
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->win == win)
return cc;
return(cc);
}
}
return NULL;
}
struct client_ctx *
client_next(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct client_ctx *newcc;
return(((newcc = TAILQ_NEXT(cc, entry)) != NULL) ?
newcc : TAILQ_FIRST(&sc->clientq));
}
struct client_ctx *
client_prev(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct client_ctx *newcc;
return(((newcc = TAILQ_PREV(cc, client_q, entry)) != NULL) ?
newcc : TAILQ_LAST(&sc->clientq, client_q));
return(NULL);
}
void
client_remove(struct client_ctx *cc)
client_delete(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct winname *wn;
@ -219,21 +179,27 @@ client_remove(struct client_ctx *cc)
if (cc->flags & CLIENT_ACTIVE)
xu_ewmh_net_active_window(sc, None);
if (cc->gc != NULL)
TAILQ_REMOVE(&cc->gc->clientq, cc, group_entry);
while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) {
TAILQ_REMOVE(&cc->nameq, wn, entry);
free(wn->name);
free(wn);
}
free(cc->name);
free(cc->label);
free(cc->res_class);
free(cc->res_name);
if (cc->ch.res_class)
XFree(cc->ch.res_class);
if (cc->ch.res_name)
XFree(cc->ch.res_name);
if (cc->wmh)
XFree(cc->wmh);
free(cc);
}
void
client_set_active(struct client_ctx *cc)
client_setactive(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct client_ctx *oldcc;
@ -249,14 +215,14 @@ client_set_active(struct client_ctx *cc)
RevertToPointerRoot, CurrentTime);
}
if (cc->flags & CLIENT_WM_TAKE_FOCUS)
xu_send_clientmsg(cc->win, cwmh[WM_TAKE_FOCUS], Last_Event_Time);
client_msg(cc, cwmh[WM_TAKE_FOCUS], Last_Event_Time);
if ((oldcc = client_current(sc)) != NULL) {
if ((oldcc = client_current()) != NULL) {
oldcc->flags &= ~CLIENT_ACTIVE;
client_draw_border(oldcc);
}
/* If we're in the middle of cycling, don't change the order. */
/* If we're in the middle of cycing, don't change the order. */
if (!sc->cycling)
client_mtf(cc);
@ -267,6 +233,21 @@ client_set_active(struct client_ctx *cc)
xu_ewmh_net_active_window(sc, cc->win);
}
struct client_ctx *
client_current(void)
{
struct screen_ctx *sc;
struct client_ctx *cc;
TAILQ_FOREACH(sc, &Screenq, entry) {
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->flags & CLIENT_ACTIVE)
return(cc);
}
}
return(NULL);
}
void
client_toggle_freeze(struct client_ctx *cc)
{
@ -284,20 +265,6 @@ client_toggle_hidden(struct client_ctx *cc)
xu_ewmh_set_net_wm_state(cc);
}
void
client_toggle_skip_pager(struct client_ctx *cc)
{
cc->flags ^= CLIENT_SKIP_PAGER;
xu_ewmh_set_net_wm_state(cc);
}
void
client_toggle_skip_taskbar(struct client_ctx *cc)
{
cc->flags ^= CLIENT_SKIP_TASKBAR;
xu_ewmh_set_net_wm_state(cc);
}
void
client_toggle_sticky(struct client_ctx *cc)
{
@ -327,7 +294,7 @@ client_toggle_fullscreen(struct client_ctx *cc)
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, 0);
cc->geom.y + cc->geom.h / 2, CWM_NOGAP);
cc->bwidth = 0;
cc->geom = area;
@ -336,7 +303,6 @@ client_toggle_fullscreen(struct client_ctx *cc)
resize:
client_resize(cc, 0);
xu_ewmh_set_net_wm_state(cc);
client_ptr_inbound(cc, 1);
}
void
@ -364,9 +330,14 @@ client_toggle_maximize(struct client_ctx *cc)
cc->savegeom.x = cc->geom.x;
}
/*
* pick screen that the middle of the window is on.
* that's probably more fair than if just the origin of
* a window is poking over a boundary
*/
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, 1);
cc->geom.y + cc->geom.h / 2, CWM_GAP);
cc->geom.x = area.x;
cc->geom.y = area.y;
@ -377,7 +348,6 @@ client_toggle_maximize(struct client_ctx *cc)
resize:
client_resize(cc, 0);
xu_ewmh_set_net_wm_state(cc);
client_ptr_inbound(cc, 1);
}
void
@ -401,7 +371,7 @@ client_toggle_vmaximize(struct client_ctx *cc)
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, 1);
cc->geom.y + cc->geom.h / 2, CWM_GAP);
cc->geom.y = area.y;
cc->geom.h = area.h - (cc->bwidth * 2);
@ -410,7 +380,6 @@ client_toggle_vmaximize(struct client_ctx *cc)
resize:
client_resize(cc, 0);
xu_ewmh_set_net_wm_state(cc);
client_ptr_inbound(cc, 1);
}
void
@ -434,7 +403,7 @@ client_toggle_hmaximize(struct client_ctx *cc)
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, 1);
cc->geom.y + cc->geom.h / 2, CWM_GAP);
cc->geom.x = area.x;
cc->geom.w = area.w - (cc->bwidth * 2);
@ -443,7 +412,6 @@ client_toggle_hmaximize(struct client_ctx *cc)
resize:
client_resize(cc, 0);
xu_ewmh_set_net_wm_state(cc);
client_ptr_inbound(cc, 1);
}
void
@ -506,7 +474,7 @@ void
client_ptr_inbound(struct client_ctx *cc, int getpos)
{
if (getpos)
xu_ptr_get(cc->win, &cc->ptr.x, &cc->ptr.y);
xu_ptr_getpos(cc->win, &cc->ptr.x, &cc->ptr.y);
if (cc->ptr.x < 0)
cc->ptr.x = 0;
@ -517,21 +485,21 @@ client_ptr_inbound(struct client_ctx *cc, int getpos)
else if (cc->ptr.y > cc->geom.h - 1)
cc->ptr.y = cc->geom.h - 1;
client_ptr_warp(cc);
client_ptrwarp(cc);
}
void
client_ptr_warp(struct client_ctx *cc)
client_ptrwarp(struct client_ctx *cc)
{
xu_ptr_set(cc->win, cc->ptr.x, cc->ptr.y);
xu_ptr_setpos(cc->win, cc->ptr.x, cc->ptr.y);
}
void
client_ptr_save(struct client_ctx *cc)
client_ptrsave(struct client_ctx *cc)
{
int x, y;
xu_ptr_get(cc->win, &x, &y);
xu_ptr_getpos(cc->win, &x, &y);
if (client_inbound(cc, x, y)) {
cc->ptr.x = x;
cc->ptr.y = y;
@ -546,21 +514,21 @@ client_hide(struct client_ctx *cc)
{
XUnmapWindow(X_Dpy, cc->win);
if (cc->flags & CLIENT_ACTIVE) {
cc->flags &= ~CLIENT_ACTIVE;
if (cc->flags & CLIENT_ACTIVE)
xu_ewmh_net_active_window(cc->sc, None);
}
cc->flags &= ~CLIENT_ACTIVE;
cc->flags |= CLIENT_HIDDEN;
xu_set_wm_state(cc->win, IconicState);
client_set_wm_state(cc, IconicState);
}
void
client_show(struct client_ctx *cc)
client_unhide(struct client_ctx *cc)
{
XMapRaised(X_Dpy, cc->win);
cc->flags &= ~CLIENT_HIDDEN;
xu_set_wm_state(cc->win, NormalState);
client_set_wm_state(cc, NormalState);
client_draw_border(cc);
}
@ -596,24 +564,7 @@ client_draw_border(struct client_ctx *cc)
pixel = sc->xftcolor[CWM_COLOR_BORDER_URGENCY].pixel;
XSetWindowBorderWidth(X_Dpy, cc->win, (unsigned int)cc->bwidth);
XSetWindowBorder(X_Dpy, cc->win, pixel | (0xffu << 24));
}
static void
client_class_hint(struct client_ctx *cc)
{
XClassHint ch;
if (XGetClassHint(X_Dpy, cc->win, &ch)) {
if (ch.res_class) {
cc->res_class = xstrdup(ch.res_class);
XFree(ch.res_class);
}
if (ch.res_name) {
cc->res_name = xstrdup(ch.res_name);
XFree(ch.res_name);
}
}
XSetWindowBorder(X_Dpy, cc->win, pixel);
}
static void
@ -636,109 +587,221 @@ client_wm_protocols(struct client_ctx *cc)
void
client_wm_hints(struct client_ctx *cc)
{
XWMHints *wmh;
if ((cc->wmh = XGetWMHints(X_Dpy, cc->win)) == NULL)
return;
if ((wmh = XGetWMHints(X_Dpy, cc->win)) != NULL) {
if ((wmh->flags & InputHint) && (wmh->input))
cc->flags |= CLIENT_INPUT;
if ((wmh->flags & XUrgencyHint))
client_urgency(cc);
if ((wmh->flags & StateHint))
cc->initial_state = wmh->initial_state;
XFree(wmh);
}
if ((cc->wmh->flags & InputHint) && (cc->wmh->input))
cc->flags |= CLIENT_INPUT;
if ((cc->wmh->flags & XUrgencyHint))
client_urgency(cc);
}
void
client_close(struct client_ctx *cc)
client_msg(struct client_ctx *cc, Atom proto, Time ts)
{
XClientMessageEvent cm;
(void)memset(&cm, 0, sizeof(cm));
cm.type = ClientMessage;
cm.window = cc->win;
cm.message_type = cwmh[WM_PROTOCOLS];
cm.format = 32;
cm.data.l[0] = proto;
cm.data.l[1] = ts;
XSendEvent(X_Dpy, cc->win, False, NoEventMask, (XEvent *)&cm);
}
void
client_send_delete(struct client_ctx *cc)
{
if (cc->flags & CLIENT_WM_DELETE_WINDOW)
xu_send_clientmsg(cc->win, cwmh[WM_DELETE_WINDOW], CurrentTime);
client_msg(cc, cwmh[WM_DELETE_WINDOW], CurrentTime);
else
XKillClient(X_Dpy, cc->win);
}
void
client_set_name(struct client_ctx *cc)
client_setname(struct client_ctx *cc)
{
struct winname *wn, *wnnxt;
struct winname *wn;
char *newname;
int i = 0;
free(cc->name);
if (!xu_get_strprop(cc->win, ewmh[_NET_WM_NAME], &cc->name))
if (!xu_get_strprop(cc->win, XA_WM_NAME, &cc->name))
cc->name = xstrdup("");
if (!xu_getstrprop(cc->win, ewmh[_NET_WM_NAME], &newname))
if (!xu_getstrprop(cc->win, XA_WM_NAME, &newname))
newname = xstrdup("");
TAILQ_FOREACH_SAFE(wn, &cc->nameq, entry, wnnxt) {
if (strcmp(wn->name, cc->name) == 0) {
TAILQ_FOREACH(wn, &cc->nameq, entry) {
if (strcmp(wn->name, newname) == 0) {
/* Move to the last since we got a hit. */
TAILQ_REMOVE(&cc->nameq, wn, entry);
free(wn->name);
free(wn);
TAILQ_INSERT_TAIL(&cc->nameq, wn, entry);
goto match;
}
i++;
}
wn = xmalloc(sizeof(*wn));
wn->name = xstrdup(cc->name);
wn->name = newname;
TAILQ_INSERT_TAIL(&cc->nameq, wn, entry);
/* Garbage collection. */
if ((i + 1) > Conf.nameqlen) {
match:
cc->name = wn->name;
/* Do some garbage collection. */
TAILQ_FOREACH(wn, &cc->nameq, entry)
i++;
if (i > Conf.nameqlen) {
wn = TAILQ_FIRST(&cc->nameq);
TAILQ_REMOVE(&cc->nameq, wn, entry);
free(wn->name);
free(wn);
i--;
}
}
static void
client_placement(struct client_ctx *cc)
void
client_cycle(struct screen_ctx *sc, int flags)
{
struct client_ctx *newcc, *oldcc, *prevcc;
int again = 1;
/* For X apps that ignore events. */
XGrabKeyboard(X_Dpy, sc->rootwin, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
if (TAILQ_EMPTY(&sc->clientq))
return;
prevcc = TAILQ_FIRST(&sc->clientq);
oldcc = client_current();
if (oldcc == NULL)
oldcc = (flags & CWM_CYCLE_REVERSE) ?
TAILQ_LAST(&sc->clientq, client_q) :
TAILQ_FIRST(&sc->clientq);
newcc = oldcc;
while (again) {
again = 0;
newcc = (flags & CWM_CYCLE_REVERSE) ? client_prev(newcc) :
client_next(newcc);
/* Only cycle visible and non-ignored windows. */
if ((newcc->flags & (CLIENT_HIDDEN | CLIENT_IGNORE))
|| ((flags & CWM_CYCLE_INGROUP) &&
(newcc->gc != oldcc->gc)))
again = 1;
/* Is oldcc the only non-hidden window? */
if (newcc == oldcc) {
if (again)
return; /* No windows visible. */
break;
}
}
/* reset when cycling mod is released. XXX I hate this hack */
sc->cycling = 1;
client_ptrsave(oldcc);
client_raise(prevcc);
client_raise(newcc);
if (!client_inbound(newcc, newcc->ptr.x, newcc->ptr.y)) {
newcc->ptr.x = newcc->geom.w / 2;
newcc->ptr.y = newcc->geom.h / 2;
}
client_ptrwarp(newcc);
}
void
client_cycle_leave(struct screen_ctx *sc)
{
struct client_ctx *cc;
sc->cycling = 0;
if ((cc = client_current()) != NULL) {
client_mtf(cc);
cc->flags &= ~CLIENT_HIGHLIGHT;
client_draw_border(cc);
XUngrabKeyboard(X_Dpy, CurrentTime);
}
}
static struct client_ctx *
client_next(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct client_ctx *newcc;
return(((newcc = TAILQ_NEXT(cc, entry)) != NULL) ?
newcc : TAILQ_FIRST(&sc->clientq));
}
static struct client_ctx *
client_prev(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct client_ctx *newcc;
return(((newcc = TAILQ_PREV(cc, client_q, entry)) != NULL) ?
newcc : TAILQ_LAST(&sc->clientq, client_q));
}
static void
client_placecalc(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
int xslack, yslack;
if (cc->hint.flags & (USPosition | PPosition)) {
if (cc->geom.x >= sc->view.w)
cc->geom.x = sc->view.w - cc->bwidth - 1;
int wmax, hmax;
wmax = DisplayWidth(X_Dpy, sc->which);
hmax = DisplayHeight(X_Dpy, sc->which);
if (cc->geom.x >= wmax)
cc->geom.x = wmax - cc->bwidth - 1;
if (cc->geom.x + cc->geom.w + cc->bwidth <= 0)
cc->geom.x = -(cc->geom.w + cc->bwidth - 1);
if (cc->geom.y >= sc->view.h)
cc->geom.x = sc->view.h - cc->bwidth - 1;
if (cc->geom.y >= hmax)
cc->geom.x = hmax - cc->bwidth - 1;
if (cc->geom.y + cc->geom.h + cc->bwidth <= 0)
cc->geom.y = -(cc->geom.h + cc->bwidth - 1);
if (cc->flags & CLIENT_IGNORE) {
if (((cc->obwidth * 2) + cc->geom.x + cc->geom.w) == sc->view.w)
cc->geom.x += cc->obwidth * 2;
if (((cc->obwidth * 2) + cc->geom.y + cc->geom.h) == sc->view.h)
cc->geom.y += cc->obwidth * 2;
}
} else {
struct geom area;
int xmouse, ymouse, xslack, yslack;
struct geom area;
int xmouse, ymouse;
xu_ptr_get(sc->rootwin, &xmouse, &ymouse);
area = screen_area(sc, xmouse, ymouse, 1);
xu_ptr_getpos(sc->rootwin, &xmouse, &ymouse);
area = screen_area(sc, xmouse, ymouse, CWM_GAP);
area.w += area.x;
area.h += area.y;
xmouse = MAX(xmouse, area.x) - cc->geom.w / 2;
ymouse = MAX(ymouse, area.y) - cc->geom.h / 2;
xmouse = MAX(MAX(xmouse, area.x) - cc->geom.w / 2, area.x);
ymouse = MAX(MAX(ymouse, area.y) - cc->geom.h / 2, area.y);
xmouse = MAX(xmouse, area.x);
ymouse = MAX(ymouse, area.y);
xslack = area.x + area.w - cc->geom.w - cc->bwidth * 2;
yslack = area.y + area.h - cc->geom.h - cc->bwidth * 2;
xslack = area.w - cc->geom.w - cc->bwidth * 2;
yslack = area.h - cc->geom.h - cc->bwidth * 2;
if (xslack >= area.x) {
cc->geom.x = MAX(MIN(xmouse, xslack), area.x);
} else {
cc->geom.x = area.x;
cc->geom.w = area.x + area.w;
cc->geom.w = area.w;
}
if (yslack >= area.y) {
cc->geom.y = MAX(MIN(ymouse, yslack), area.y);
} else {
cc->geom.y = area.y;
cc->geom.h = area.y + area.h;
cc->geom.h = area.h;
}
}
}
void
static void
client_mtf(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
@ -748,7 +811,7 @@ client_mtf(struct client_ctx *cc)
}
void
client_get_sizehints(struct client_ctx *cc)
client_getsizehints(struct client_ctx *cc)
{
long tmp;
XSizeHints size;
@ -796,7 +859,7 @@ client_get_sizehints(struct client_ctx *cc)
}
void
client_apply_sizehints(struct client_ctx *cc)
client_applysizehints(struct client_ctx *cc)
{
Bool baseismin;
@ -847,17 +910,14 @@ client_mwm_hints(struct client_ctx *cc)
{
struct mwm_hints *mwmh;
if (xu_get_prop(cc->win, cwmh[_MOTIF_WM_HINTS],
cwmh[_MOTIF_WM_HINTS], MWM_HINTS_ELEMENTS,
(unsigned char **)&mwmh) <= 0)
return;
if ((mwmh->flags & MWM_HINTS_DECORATIONS) &&
!(mwmh->decorations & MWM_DECOR_ALL)) {
if (!(mwmh->decorations & MWM_DECOR_BORDER))
if (xu_getprop(cc->win, cwmh[_MOTIF_WM_HINTS], cwmh[_MOTIF_WM_HINTS],
MWM_HINTS_ELEMENTS, (unsigned char **)&mwmh) == MWM_HINTS_ELEMENTS) {
if (mwmh->flags & MWM_FLAGS_DECORATIONS &&
!(mwmh->decorations & MWM_DECOR_ALL) &&
!(mwmh->decorations & MWM_DECOR_BORDER))
cc->bwidth = 0;
XFree(mwmh);
}
XFree(mwmh);
}
void
@ -867,11 +927,10 @@ client_transient(struct client_ctx *cc)
Window trans;
if (XGetTransientForHint(X_Dpy, cc->win, &trans)) {
if ((tc = client_find(trans)) != NULL) {
if (tc->flags & CLIENT_IGNORE) {
if ((tc = client_find(trans)) != NULL && tc->gc) {
group_movetogroup(cc, tc->gc->num);
if (tc->flags & CLIENT_IGNORE)
cc->flags |= CLIENT_IGNORE;
cc->bwidth = tc->bwidth;
}
}
}
}
@ -899,45 +958,43 @@ client_snapcalc(int n0, int n1, int e0, int e1, int snapdist)
/* possible to snap in both directions */
if (s0 != 0 && s1 != 0)
if (abs(s0) < abs(s1))
return s0;
return(s0);
else
return s1;
return(s1);
else if (s0 != 0)
return s0;
return(s0);
else if (s1 != 0)
return s1;
return(s1);
else
return 0;
return(0);
}
void
client_htile(struct client_ctx *cc)
{
struct client_ctx *ci;
struct group_ctx *gc = cc->gc;
struct screen_ctx *sc = cc->sc;
struct geom area;
int i, n, mh, x, w, h;
if (!gc)
return;
i = n = 0;
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, 1);
TAILQ_FOREACH(ci, &sc->clientq, entry) {
if (ci->gc != cc->gc)
continue;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
if (ci->flags & CLIENT_HIDDEN ||
ci->flags & CLIENT_IGNORE || (ci == cc) ||
ci->geom.x < area.x ||
ci->geom.x > (area.x + area.w) ||
ci->geom.y < area.y ||
ci->geom.y > (area.y + area.h))
ci->flags & CLIENT_IGNORE || (ci == cc))
continue;
n++;
}
if (n == 0)
return;
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, CWM_GAP);
if (cc->flags & CLIENT_VMAXIMIZED ||
cc->geom.h + (cc->bwidth * 2) >= area.h)
return;
@ -946,24 +1003,17 @@ client_htile(struct client_ctx *cc)
cc->geom.x = area.x;
cc->geom.y = area.y;
cc->geom.w = area.w - (cc->bwidth * 2);
if (Conf.htile > 0)
cc->geom.h = ((area.h - (cc->bwidth * 2)) * Conf.htile) / 100;
cc->geom.h = (area.h - (cc->bwidth * 2)) / 2;
client_resize(cc, 1);
client_ptr_warp(cc);
client_ptrwarp(cc);
mh = cc->geom.h + (cc->bwidth * 2);
x = area.x;
w = area.w / n;
h = area.h - mh;
TAILQ_FOREACH(ci, &sc->clientq, entry) {
if (ci->gc != cc->gc)
continue;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
if (ci->flags & CLIENT_HIDDEN ||
ci->flags & CLIENT_IGNORE || (ci == cc) ||
ci->geom.x < area.x ||
ci->geom.x > (area.x + area.w) ||
ci->geom.y < area.y ||
ci->geom.y > (area.y + area.h))
ci->flags & CLIENT_IGNORE || (ci == cc))
continue;
ci->bwidth = Conf.bwidth;
ci->geom.x = x;
@ -983,30 +1033,28 @@ void
client_vtile(struct client_ctx *cc)
{
struct client_ctx *ci;
struct group_ctx *gc = cc->gc;
struct screen_ctx *sc = cc->sc;
struct geom area;
int i, n, mw, y, w, h;
if (!gc)
return;
i = n = 0;
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, 1);
TAILQ_FOREACH(ci, &sc->clientq, entry) {
if (ci->gc != cc->gc)
continue;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
if (ci->flags & CLIENT_HIDDEN ||
ci->flags & CLIENT_IGNORE || (ci == cc) ||
ci->geom.x < area.x ||
ci->geom.x > (area.x + area.w) ||
ci->geom.y < area.y ||
ci->geom.y > (area.y + area.h))
ci->flags & CLIENT_IGNORE || (ci == cc))
continue;
n++;
}
if (n == 0)
return;
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, CWM_GAP);
if (cc->flags & CLIENT_HMAXIMIZED ||
cc->geom.w + (cc->bwidth * 2) >= area.w)
return;
@ -1014,25 +1062,18 @@ client_vtile(struct client_ctx *cc)
cc->flags &= ~CLIENT_VMAXIMIZED;
cc->geom.x = area.x;
cc->geom.y = area.y;
if (Conf.vtile > 0)
cc->geom.w = ((area.w - (cc->bwidth * 2)) * Conf.vtile) / 100;
cc->geom.w = (area.w - (cc->bwidth * 2)) / 2;
cc->geom.h = area.h - (cc->bwidth * 2);
client_resize(cc, 1);
client_ptr_warp(cc);
client_ptrwarp(cc);
mw = cc->geom.w + (cc->bwidth * 2);
y = area.y;
h = area.h / n;
w = area.w - mw;
TAILQ_FOREACH(ci, &sc->clientq, entry) {
if (ci->gc != cc->gc)
continue;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
if (ci->flags & CLIENT_HIDDEN ||
ci->flags & CLIENT_IGNORE || (ci == cc) ||
ci->geom.x < area.x ||
ci->geom.x > (area.x + area.w) ||
ci->geom.y < area.y ||
ci->geom.y > (area.y + area.h))
ci->flags & CLIENT_IGNORE || (ci == cc))
continue;
ci->bwidth = Conf.bwidth;
ci->geom.x = area.x + mw;
@ -1047,3 +1088,25 @@ client_vtile(struct client_ctx *cc)
client_resize(ci, 1);
}
}
long
client_get_wm_state(struct client_ctx *cc)
{
long *p, state = -1;
if (xu_getprop(cc->win, cwmh[WM_STATE], cwmh[WM_STATE], 2L,
(unsigned char **)&p) > 0) {
state = *p;
XFree(p);
}
return(state);
}
void
client_set_wm_state(struct client_ctx *cc, long state)
{
long data[] = { state, None };
XChangeProperty(X_Dpy, cc->win, cwmh[WM_STATE], cwmh[WM_STATE], 32,
PropModeReplace, (unsigned char *)data, 2);
}

448
conf.c
View File

@ -19,12 +19,12 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -32,25 +32,11 @@
#include "calmwm.h"
static const char *conf_bind_mask(const char *, unsigned int *);
static const char *conf_bind_getmask(const char *, unsigned int *);
static void conf_cmd_remove(struct conf *, const char *);
static void conf_unbind_key(struct conf *, struct bind_ctx *);
static void conf_unbind_mouse(struct conf *, struct bind_ctx *);
static const struct {
int num;
const char *name;
} group_binds[] = {
{ 0, "nogroup" },
{ 1, "one" },
{ 2, "two" },
{ 3, "three" },
{ 4, "four" },
{ 5, "five" },
{ 6, "six" },
{ 7, "seven" },
{ 8, "eight" },
{ 9, "nine" },
};
static int cursor_binds[] = {
XC_left_ptr, /* CF_NORMAL */
XC_fleur, /* CF_MOVE */
@ -74,122 +60,131 @@ static const struct {
enum context context;
int flag;
} name_to_func[] = {
#define FUNC_CC(t, h, n) \
#t, kbfunc_ ## h, CWM_CONTEXT_CC, n
#define FUNC_SC(t, h, n) \
#t, kbfunc_ ## h, CWM_CONTEXT_SC, n
{ "window-menu-label", kbfunc_client_menu_label, CWM_CONTEXT_CC, 0 },
{ "window-lower", kbfunc_client_lower, CWM_CONTEXT_CC, 0 },
{ "window-raise", kbfunc_client_raise, CWM_CONTEXT_CC, 0 },
{ "window-hide", kbfunc_client_hide, CWM_CONTEXT_CC, 0 },
{ "window-delete", kbfunc_client_delete, CWM_CONTEXT_CC, 0 },
{ "window-htile", kbfunc_client_htile, CWM_CONTEXT_CC, 0 },
{ "window-vtile", kbfunc_client_vtile, CWM_CONTEXT_CC, 0 },
{ "window-stick", kbfunc_client_toggle_sticky, CWM_CONTEXT_CC, 0 },
{ "window-fullscreen", kbfunc_client_toggle_fullscreen, CWM_CONTEXT_CC, 0 },
{ "window-maximize", kbfunc_client_toggle_maximize, CWM_CONTEXT_CC, 0 },
{ "window-vmaximize", kbfunc_client_toggle_vmaximize, CWM_CONTEXT_CC, 0 },
{ "window-hmaximize", kbfunc_client_toggle_hmaximize, CWM_CONTEXT_CC, 0 },
{ "window-freeze", kbfunc_client_toggle_freeze, CWM_CONTEXT_CC, 0 },
{ "window-cycle", kbfunc_client_cycle, CWM_CONTEXT_SC,
(CWM_CYCLE_FORWARD) },
{ "window-rcycle", kbfunc_client_cycle, CWM_CONTEXT_SC,
(CWM_CYCLE_REVERSE) },
{ "window-cycle-ingroup", kbfunc_client_cycle, CWM_CONTEXT_SC,
(CWM_CYCLE_FORWARD | CWM_CYCLE_INGROUP) },
{ "window-rcycle-ingroup", kbfunc_client_cycle, CWM_CONTEXT_SC,
(CWM_CYCLE_REVERSE | CWM_CYCLE_INGROUP) },
{ "window-group", kbfunc_client_toggle_group, CWM_CONTEXT_CC, 0 },
{ "window-movetogroup-1", kbfunc_client_movetogroup, CWM_CONTEXT_CC, 1 },
{ "window-movetogroup-2", kbfunc_client_movetogroup, CWM_CONTEXT_CC, 2 },
{ "window-movetogroup-3", kbfunc_client_movetogroup, CWM_CONTEXT_CC, 3 },
{ "window-movetogroup-4", kbfunc_client_movetogroup, CWM_CONTEXT_CC, 4 },
{ "window-movetogroup-5", kbfunc_client_movetogroup, CWM_CONTEXT_CC, 5 },
{ "window-movetogroup-6", kbfunc_client_movetogroup, CWM_CONTEXT_CC, 6 },
{ "window-movetogroup-7", kbfunc_client_movetogroup, CWM_CONTEXT_CC, 7 },
{ "window-movetogroup-8", kbfunc_client_movetogroup, CWM_CONTEXT_CC, 8 },
{ "window-movetogroup-9", kbfunc_client_movetogroup, CWM_CONTEXT_CC, 9 },
{ FUNC_CC(window-lower, client_lower, 0) },
{ FUNC_CC(window-raise, client_raise, 0) },
{ FUNC_CC(window-hide, client_hide, 0) },
{ FUNC_CC(window-close, client_close, 0) },
{ FUNC_CC(window-delete, client_close, 0) },
{ FUNC_CC(window-htile, client_htile, 0) },
{ FUNC_CC(window-vtile, client_vtile, 0) },
{ FUNC_CC(window-stick, client_toggle_sticky, 0) },
{ FUNC_CC(window-fullscreen, client_toggle_fullscreen, 0) },
{ FUNC_CC(window-maximize, client_toggle_maximize, 0) },
{ FUNC_CC(window-vmaximize, client_toggle_vmaximize, 0) },
{ FUNC_CC(window-hmaximize, client_toggle_hmaximize, 0) },
{ FUNC_CC(window-freeze, client_toggle_freeze, 0) },
{ FUNC_CC(window-group, client_toggle_group, 0) },
{ FUNC_CC(window-movetogroup-1, client_movetogroup, 1) },
{ FUNC_CC(window-movetogroup-2, client_movetogroup, 2) },
{ FUNC_CC(window-movetogroup-3, client_movetogroup, 3) },
{ FUNC_CC(window-movetogroup-4, client_movetogroup, 4) },
{ FUNC_CC(window-movetogroup-5, client_movetogroup, 5) },
{ FUNC_CC(window-movetogroup-6, client_movetogroup, 6) },
{ FUNC_CC(window-movetogroup-7, client_movetogroup, 7) },
{ FUNC_CC(window-movetogroup-8, client_movetogroup, 8) },
{ FUNC_CC(window-movetogroup-9, client_movetogroup, 9) },
{ FUNC_CC(window-snap-up, client_snap, (CWM_UP)) },
{ FUNC_CC(window-snap-down, client_snap, (CWM_DOWN)) },
{ FUNC_CC(window-snap-right, client_snap, (CWM_RIGHT)) },
{ FUNC_CC(window-snap-left, client_snap, (CWM_LEFT)) },
{ FUNC_CC(window-snap-up-right, client_snap, (CWM_UP_RIGHT)) },
{ FUNC_CC(window-snap-up-left, client_snap, (CWM_UP_LEFT)) },
{ FUNC_CC(window-snap-down-right, client_snap, (CWM_DOWN_RIGHT)) },
{ FUNC_CC(window-snap-down-left, client_snap, (CWM_DOWN_LEFT)) },
{ FUNC_CC(window-move, client_move, 0) },
{ FUNC_CC(window-move-up, client_move, (CWM_UP)) },
{ FUNC_CC(window-move-down, client_move, (CWM_DOWN)) },
{ FUNC_CC(window-move-right, client_move, (CWM_RIGHT)) },
{ FUNC_CC(window-move-left, client_move, (CWM_LEFT)) },
{ FUNC_CC(window-move-up-big, client_move, (CWM_UP_BIG)) },
{ FUNC_CC(window-move-down-big, client_move, (CWM_DOWN_BIG)) },
{ FUNC_CC(window-move-right-big, client_move, (CWM_RIGHT_BIG)) },
{ FUNC_CC(window-move-left-big, client_move, (CWM_LEFT_BIG)) },
{ FUNC_CC(window-resize, client_resize, 0) },
{ FUNC_CC(window-resize-up, client_resize, (CWM_UP)) },
{ FUNC_CC(window-resize-down, client_resize, (CWM_DOWN)) },
{ FUNC_CC(window-resize-right, client_resize, (CWM_RIGHT)) },
{ FUNC_CC(window-resize-left, client_resize, (CWM_LEFT)) },
{ FUNC_CC(window-resize-up-big, client_resize, (CWM_UP_BIG)) },
{ FUNC_CC(window-resize-down-big, client_resize, (CWM_DOWN_BIG)) },
{ FUNC_CC(window-resize-right-big, client_resize, (CWM_RIGHT_BIG)) },
{ FUNC_CC(window-resize-left-big, client_resize, (CWM_LEFT_BIG)) },
{ FUNC_CC(window-menu-label, client_menu_label, 0) },
{ "window-move", kbfunc_client_move, CWM_CONTEXT_CC, 0 },
{ "window-move-up", kbfunc_client_move, CWM_CONTEXT_CC,
(CWM_UP) },
{ "window-move-down", kbfunc_client_move, CWM_CONTEXT_CC,
(CWM_DOWN) },
{ "window-move-right", kbfunc_client_move, CWM_CONTEXT_CC,
(CWM_RIGHT) },
{ "window-move-left", kbfunc_client_move, CWM_CONTEXT_CC,
(CWM_LEFT) },
{ "window-move-up-big", kbfunc_client_move, CWM_CONTEXT_CC,
(CWM_UP | CWM_BIGAMOUNT) },
{ "window-move-down-big", kbfunc_client_move, CWM_CONTEXT_CC,
(CWM_DOWN | CWM_BIGAMOUNT) },
{ "window-move-right-big", kbfunc_client_move, CWM_CONTEXT_CC,
(CWM_RIGHT | CWM_BIGAMOUNT) },
{ "window-move-left-big", kbfunc_client_move, CWM_CONTEXT_CC,
(CWM_LEFT | CWM_BIGAMOUNT) },
{ "window-resize", kbfunc_client_resize, CWM_CONTEXT_CC, 0 },
{ "window-resize-up", kbfunc_client_resize, CWM_CONTEXT_CC,
(CWM_UP) },
{ "window-resize-down", kbfunc_client_resize, CWM_CONTEXT_CC,
(CWM_DOWN) },
{ "window-resize-right", kbfunc_client_resize, CWM_CONTEXT_CC,
(CWM_RIGHT) },
{ "window-resize-left", kbfunc_client_resize, CWM_CONTEXT_CC,
(CWM_LEFT) },
{ "window-resize-up-big", kbfunc_client_resize, CWM_CONTEXT_CC,
(CWM_UP | CWM_BIGAMOUNT) },
{ "window-resize-down-big", kbfunc_client_resize, CWM_CONTEXT_CC,
(CWM_DOWN | CWM_BIGAMOUNT) },
{ "window-resize-right-big", kbfunc_client_resize, CWM_CONTEXT_CC,
(CWM_RIGHT | CWM_BIGAMOUNT) },
{ "window-resize-left-big", kbfunc_client_resize, CWM_CONTEXT_CC,
(CWM_LEFT | CWM_BIGAMOUNT) },
{ FUNC_SC(window-cycle, client_cycle, (CWM_CYCLE_FORWARD)) },
{ FUNC_SC(window-rcycle, client_cycle, (CWM_CYCLE_REVERSE)) },
{ FUNC_SC(window-cycle-ingroup, client_cycle,
(CWM_CYCLE_FORWARD | CWM_CYCLE_INGROUP)) },
{ FUNC_SC(window-rcycle-ingroup, client_cycle,
(CWM_CYCLE_REVERSE | CWM_CYCLE_INGROUP)) },
{ "group-cycle", kbfunc_group_cycle, CWM_CONTEXT_SC,
(CWM_CYCLE_FORWARD) },
{ "group-rcycle", kbfunc_group_cycle, CWM_CONTEXT_SC,
(CWM_CYCLE_REVERSE) },
{ "group-toggle-all", kbfunc_group_alltoggle, CWM_CONTEXT_SC, 0 },
{ "group-toggle-1", kbfunc_group_toggle, CWM_CONTEXT_SC, 1 },
{ "group-toggle-2", kbfunc_group_toggle, CWM_CONTEXT_SC, 2 },
{ "group-toggle-3", kbfunc_group_toggle, CWM_CONTEXT_SC, 3 },
{ "group-toggle-4", kbfunc_group_toggle, CWM_CONTEXT_SC, 4 },
{ "group-toggle-5", kbfunc_group_toggle, CWM_CONTEXT_SC, 5 },
{ "group-toggle-6", kbfunc_group_toggle, CWM_CONTEXT_SC, 6 },
{ "group-toggle-7", kbfunc_group_toggle, CWM_CONTEXT_SC, 7 },
{ "group-toggle-8", kbfunc_group_toggle, CWM_CONTEXT_SC, 8 },
{ "group-toggle-9", kbfunc_group_toggle, CWM_CONTEXT_SC, 9 },
{ "group-only-1", kbfunc_group_only, CWM_CONTEXT_SC, 1 },
{ "group-only-2", kbfunc_group_only, CWM_CONTEXT_SC, 2 },
{ "group-only-3", kbfunc_group_only, CWM_CONTEXT_SC, 3 },
{ "group-only-4", kbfunc_group_only, CWM_CONTEXT_SC, 4 },
{ "group-only-5", kbfunc_group_only, CWM_CONTEXT_SC, 5 },
{ "group-only-6", kbfunc_group_only, CWM_CONTEXT_SC, 6 },
{ "group-only-7", kbfunc_group_only, CWM_CONTEXT_SC, 7 },
{ "group-only-8", kbfunc_group_only, CWM_CONTEXT_SC, 8 },
{ "group-only-9", kbfunc_group_only, CWM_CONTEXT_SC, 9 },
{ FUNC_SC(group-cycle, group_cycle, (CWM_CYCLE_FORWARD)) },
{ FUNC_SC(group-rcycle, group_cycle, (CWM_CYCLE_REVERSE)) },
{ FUNC_SC(group-last, group_last, 0) },
{ FUNC_SC(group-toggle-all, group_toggle_all, 0) },
{ FUNC_SC(group-toggle-1, group_toggle, 1) },
{ FUNC_SC(group-toggle-2, group_toggle, 2) },
{ FUNC_SC(group-toggle-3, group_toggle, 3) },
{ FUNC_SC(group-toggle-4, group_toggle, 4) },
{ FUNC_SC(group-toggle-5, group_toggle, 5) },
{ FUNC_SC(group-toggle-6, group_toggle, 6) },
{ FUNC_SC(group-toggle-7, group_toggle, 7) },
{ FUNC_SC(group-toggle-8, group_toggle, 8) },
{ FUNC_SC(group-toggle-9, group_toggle, 9) },
{ FUNC_SC(group-only-1, group_only, 1) },
{ FUNC_SC(group-only-2, group_only, 2) },
{ FUNC_SC(group-only-3, group_only, 3) },
{ FUNC_SC(group-only-4, group_only, 4) },
{ FUNC_SC(group-only-5, group_only, 5) },
{ FUNC_SC(group-only-6, group_only, 6) },
{ FUNC_SC(group-only-7, group_only, 7) },
{ FUNC_SC(group-only-8, group_only, 8) },
{ FUNC_SC(group-only-9, group_only, 9) },
{ FUNC_SC(group-close-1, group_close, 1) },
{ FUNC_SC(group-close-2, group_close, 2) },
{ FUNC_SC(group-close-3, group_close, 3) },
{ FUNC_SC(group-close-4, group_close, 4) },
{ FUNC_SC(group-close-5, group_close, 5) },
{ FUNC_SC(group-close-6, group_close, 6) },
{ FUNC_SC(group-close-7, group_close, 7) },
{ FUNC_SC(group-close-8, group_close, 8) },
{ FUNC_SC(group-close-9, group_close, 9) },
{ "pointer-move-up", kbfunc_ptrmove, CWM_CONTEXT_SC,
(CWM_UP) },
{ "pointer-move-down", kbfunc_ptrmove, CWM_CONTEXT_SC,
(CWM_DOWN) },
{ "pointer-move-left", kbfunc_ptrmove, CWM_CONTEXT_SC,
(CWM_LEFT) },
{ "pointer-move-right", kbfunc_ptrmove, CWM_CONTEXT_SC,
(CWM_RIGHT) },
{ "pointer-move-up-big", kbfunc_ptrmove, CWM_CONTEXT_SC,
(CWM_UP | CWM_BIGAMOUNT) },
{ "pointer-move-down-big", kbfunc_ptrmove, CWM_CONTEXT_SC,
(CWM_DOWN | CWM_BIGAMOUNT) },
{ "pointer-move-left-big", kbfunc_ptrmove, CWM_CONTEXT_SC,
(CWM_LEFT | CWM_BIGAMOUNT) },
{ "pointer-move-right-big", kbfunc_ptrmove, CWM_CONTEXT_SC,
(CWM_RIGHT | CWM_BIGAMOUNT) },
{ FUNC_SC(pointer-move-up, ptrmove, (CWM_UP)) },
{ FUNC_SC(pointer-move-down, ptrmove, (CWM_DOWN)) },
{ FUNC_SC(pointer-move-left, ptrmove, (CWM_LEFT)) },
{ FUNC_SC(pointer-move-right, ptrmove, (CWM_RIGHT)) },
{ FUNC_SC(pointer-move-up-big, ptrmove, (CWM_UP_BIG)) },
{ FUNC_SC(pointer-move-down-big, ptrmove, (CWM_DOWN_BIG)) },
{ FUNC_SC(pointer-move-left-big, ptrmove, (CWM_LEFT_BIG)) },
{ FUNC_SC(pointer-move-right-big, ptrmove, (CWM_RIGHT_BIG)) },
{ "menu-cmd", kbfunc_menu_cmd, CWM_CONTEXT_SC, 0 },
{ "menu-group", kbfunc_menu_group, CWM_CONTEXT_SC, 0 },
{ "menu-ssh", kbfunc_menu_ssh, CWM_CONTEXT_SC, 0 },
{ "menu-window", kbfunc_menu_client, CWM_CONTEXT_SC,
CWM_MENU_WINDOW_ALL },
{ "menu-window-hidden", kbfunc_menu_client, CWM_CONTEXT_SC,
CWM_MENU_WINDOW_HIDDEN },
{ "menu-exec", kbfunc_menu_exec, CWM_CONTEXT_SC,
CWM_MENU_EXEC_EXEC },
{ "menu-exec-wm", kbfunc_menu_exec, CWM_CONTEXT_SC,
CWM_MENU_EXEC_WM },
{ FUNC_SC(menu-cmd, menu_cmd, 0) },
{ FUNC_SC(menu-group, menu_group, 0) },
{ FUNC_SC(menu-ssh, menu_ssh, 0) },
{ FUNC_SC(menu-window, menu_client, CWM_MENU_WINDOW_ALL) },
{ FUNC_SC(menu-window-hidden, menu_client, CWM_MENU_WINDOW_HIDDEN) },
{ FUNC_SC(menu-exec, menu_exec, 0) },
{ FUNC_SC(menu-exec-wm, menu_wm, 0) },
{ "terminal", kbfunc_exec_term, CWM_CONTEXT_SC, 0 },
{ "lock", kbfunc_exec_lock, CWM_CONTEXT_SC, 0 },
{ "restart", kbfunc_cwm_status, CWM_CONTEXT_SC, CWM_EXEC_WM },
{ "quit", kbfunc_cwm_status, CWM_CONTEXT_SC, CWM_QUIT },
{ FUNC_SC(terminal, exec_term, 0) },
{ FUNC_SC(lock, exec_lock, 0) },
{ FUNC_SC(restart, cwm_status, CWM_EXEC_WM) },
{ FUNC_SC(quit, cwm_status, CWM_QUIT) },
};
static unsigned int ignore_mods[] = {
0, LockMask, Mod2Mask, Mod2Mask | LockMask
@ -198,11 +193,10 @@ static const struct {
const char ch;
int mask;
} bind_mods[] = {
{ 'S', ShiftMask },
{ 'C', ControlMask },
{ 'M', Mod1Mask },
{ '4', Mod4Mask },
{ '5', Mod5Mask },
{ 'S', ShiftMask },
};
static const struct {
const char *key;
@ -221,7 +215,7 @@ static const struct {
{ "M-Tab", "window-cycle" },
{ "MS-Tab", "window-rcycle" },
{ "CM-n", "window-menu-label" },
{ "CM-x", "window-close" },
{ "CM-x", "window-delete" },
{ "CM-a", "group-toggle-all" },
{ "CM-0", "group-toggle-all" },
{ "CM-1", "group-toggle-1" },
@ -275,25 +269,20 @@ mouse_binds[] = {
void
conf_init(struct conf *c)
{
const char *home;
struct passwd *pw;
unsigned int i;
c->stickygroups = 0;
c->bwidth = 1;
c->mamount = 1;
c->htile = 50;
c->vtile = 50;
c->snapdist = 0;
c->ngroups = 0;
c->ngroups = 10;
c->nameqlen = 5;
TAILQ_INIT(&c->ignoreq);
TAILQ_INIT(&c->autogroupq);
TAILQ_INIT(&c->keybindq);
TAILQ_INIT(&c->mousebindq);
TAILQ_INIT(&c->cmdq);
TAILQ_INIT(&c->wmq);
TAILQ_INIT(&c->keybindq);
TAILQ_INIT(&c->autogroupq);
TAILQ_INIT(&c->mousebindq);
for (i = 0; i < nitems(key_binds); i++)
conf_bind_key(c, key_binds[i].key, key_binds[i].func);
@ -306,21 +295,12 @@ conf_init(struct conf *c)
conf_cmd_add(c, "lock", "xlock");
conf_cmd_add(c, "term", "xterm");
conf_wm_add(c, "cwm", "cwm");
(void)snprintf(c->known_hosts, sizeof(c->known_hosts), "%s/%s",
homedir, ".ssh/known_hosts");
c->font = xstrdup("sans-serif:pixelsize=14:bold");
c->wmname = xstrdup("CWM");
home = getenv("HOME");
if ((home == NULL) || (*home == '\0')) {
pw = getpwuid(getuid());
if (pw != NULL && pw->pw_dir != NULL && *pw->pw_dir != '\0')
home = pw->pw_dir;
else
home = "/";
}
xasprintf(&c->conf_file, "%s/%s", home, ".cwmrc");
xasprintf(&c->known_hosts, "%s/%s", home, ".ssh/known_hosts");
}
void
@ -329,21 +309,14 @@ conf_clear(struct conf *c)
struct autogroup *ag;
struct bind_ctx *kb, *mb;
struct winname *wn;
struct cmd_ctx *cmd, *wm;
struct cmd_ctx *cmd;
int i;
while ((cmd = TAILQ_FIRST(&c->cmdq)) != NULL) {
TAILQ_REMOVE(&c->cmdq, cmd, entry);
free(cmd->name);
free(cmd->path);
free(cmd);
}
while ((wm = TAILQ_FIRST(&c->wmq)) != NULL) {
TAILQ_REMOVE(&c->wmq, wm, entry);
free(wm->name);
free(wm->path);
free(wm);
}
while ((kb = TAILQ_FIRST(&c->keybindq)) != NULL) {
TAILQ_REMOVE(&c->keybindq, kb, entry);
free(kb);
@ -366,50 +339,40 @@ conf_clear(struct conf *c)
for (i = 0; i < CWM_COLOR_NITEMS; i++)
free(c->color[i]);
free(c->conf_file);
free(c->known_hosts);
free(c->font);
free(c->wmname);
}
void
int
conf_cmd_add(struct conf *c, const char *name, const char *path)
{
struct cmd_ctx *cmd, *cmdtmp = NULL, *cmdnxt;
struct cmd_ctx *cmd;
cmd = xmalloc(sizeof(*cmd));
cmd->name = xstrdup(name);
cmd->path = xstrdup(path);
TAILQ_FOREACH_SAFE(cmdtmp, &c->cmdq, entry, cmdnxt) {
if (strcmp(cmdtmp->name, name) == 0) {
TAILQ_REMOVE(&c->cmdq, cmdtmp, entry);
free(cmdtmp->name);
free(cmdtmp->path);
free(cmdtmp);
}
if (strlcpy(cmd->path, path, sizeof(cmd->path)) >= sizeof(cmd->path)) {
free(cmd->name);
free(cmd);
return(0);
}
conf_cmd_remove(c, name);
TAILQ_INSERT_TAIL(&c->cmdq, cmd, entry);
return(1);
}
void
conf_wm_add(struct conf *c, const char *name, const char *path)
static void
conf_cmd_remove(struct conf *c, const char *name)
{
struct cmd_ctx *wm, *wmtmp = NULL, *wmnxt;
struct cmd_ctx *cmd = NULL, *cmdnxt;
wm = xmalloc(sizeof(*wm));
wm->name = xstrdup(name);
wm->path = xstrdup(path);
TAILQ_FOREACH_SAFE(wmtmp, &c->cmdq, entry, wmnxt) {
if (strcmp(wmtmp->name, name) == 0) {
TAILQ_REMOVE(&c->wmq, wmtmp, entry);
free(wmtmp->name);
free(wmtmp->path);
free(wmtmp);
TAILQ_FOREACH_SAFE(cmd, &c->cmdq, entry, cmdnxt) {
if (strcmp(cmd->name, name) == 0) {
TAILQ_REMOVE(&c->cmdq, cmd, entry);
free(cmd->name);
free(cmd);
}
}
TAILQ_INSERT_TAIL(&c->wmq, wm, entry);
}
void
@ -462,13 +425,16 @@ void
conf_client(struct client_ctx *cc)
{
struct winname *wn;
int ignore = 0;
TAILQ_FOREACH(wn, &Conf.ignoreq, entry) {
if (strncasecmp(wn->name, cc->name, strlen(wn->name)) == 0) {
cc->flags |= CLIENT_IGNORE;
ignore = 1;
break;
}
}
cc->bwidth = (ignore) ? 0 : Conf.bwidth;
cc->flags |= (ignore) ? CLIENT_IGNORE : 0;
}
void
@ -476,6 +442,8 @@ conf_screen(struct screen_ctx *sc)
{
unsigned int i;
XftColor xc;
Colormap colormap = DefaultColormap(X_Dpy, sc->which);
Visual *visual = DefaultVisual(X_Dpy, sc->which);
sc->gap = Conf.gap;
sc->snapdist = Conf.snapdist;
@ -492,35 +460,36 @@ conf_screen(struct screen_ctx *sc)
xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_BG],
sc->xftcolor[CWM_COLOR_MENU_FG], &xc);
xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_FONT], xc, &xc);
if (!XftColorAllocValue(X_Dpy, sc->visual, sc->colormap,
if (!XftColorAllocValue(X_Dpy, visual, colormap,
&xc.color, &sc->xftcolor[CWM_COLOR_MENU_FONT_SEL]))
warnx("XftColorAllocValue: %s", Conf.color[i]);
break;
}
if (!XftColorAllocName(X_Dpy, sc->visual, sc->colormap,
Conf.color[i], &sc->xftcolor[i])) {
if (XftColorAllocName(X_Dpy, visual, colormap,
Conf.color[i], &xc)) {
sc->xftcolor[i] = xc;
XftColorFree(X_Dpy, visual, colormap, &xc);
} else {
warnx("XftColorAllocName: %s", Conf.color[i]);
XftColorAllocName(X_Dpy, sc->visual, sc->colormap,
XftColorAllocName(X_Dpy, visual, colormap,
color_binds[i], &sc->xftcolor[i]);
}
}
sc->menu.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);
sc->menu.xftdraw = XftDrawCreate(X_Dpy, sc->menu.win, visual, colormap);
if (sc->menu.xftdraw == NULL)
errx(1, "%s: XftDrawCreate", __func__);
conf_grab_kbd(sc->rootwin);
}
void
conf_group(struct screen_ctx *sc)
{
unsigned int i;
for (i = 0; i < nitems(group_binds); i++) {
group_init(sc, group_binds[i].num, group_binds[i].name);
Conf.ngroups++;
}
}
static const char *
conf_bind_mask(const char *name, unsigned int *mask)
conf_bind_getmask(const char *name, unsigned int *mask)
{
char *dash;
const char *ch;
@ -528,13 +497,13 @@ conf_bind_mask(const char *name, unsigned int *mask)
*mask = 0;
if ((dash = strchr(name, '-')) == NULL)
return name;
return(name);
for (i = 0; i < nitems(bind_mods); i++) {
if ((ch = strchr(name, bind_mods[i].ch)) != NULL && ch < dash)
*mask |= bind_mods[i].mask;
}
/* Skip past modifiers. */
return (dash + 1);
return(dash + 1);
}
int
@ -547,20 +516,20 @@ conf_bind_key(struct conf *c, const char *bind, const char *cmd)
if ((strcmp(bind, "all") == 0) && (cmd == NULL)) {
conf_unbind_key(c, NULL);
return 1;
return(1);
}
kb = xmalloc(sizeof(*kb));
key = conf_bind_mask(bind, &kb->modmask);
key = conf_bind_getmask(bind, &kb->modmask);
kb->press.keysym = XStringToKeysym(key);
if (kb->press.keysym == NoSymbol) {
warnx("unknown symbol: %s", key);
free(kb);
return 0;
return(0);
}
conf_unbind_key(c, kb);
if (cmd == NULL) {
free(kb);
return 1;
return(1);
}
cargs = xcalloc(1, sizeof(*cargs));
for (i = 0; i < nitems(name_to_func); i++) {
@ -578,7 +547,7 @@ conf_bind_key(struct conf *c, const char *bind, const char *cmd)
out:
kb->cargs = cargs;
TAILQ_INSERT_TAIL(&c->keybindq, kb, entry);
return 1;
return(1);
}
static void
@ -608,20 +577,20 @@ conf_bind_mouse(struct conf *c, const char *bind, const char *cmd)
if ((strcmp(bind, "all") == 0) && (cmd == NULL)) {
conf_unbind_mouse(c, NULL);
return 1;
return(1);
}
mb = xmalloc(sizeof(*mb));
button = conf_bind_mask(bind, &mb->modmask);
button = conf_bind_getmask(bind, &mb->modmask);
mb->press.button = strtonum(button, Button1, Button5, &errstr);
if (errstr) {
warnx("button number is %s: %s", errstr, button);
free(mb);
return 0;
return(0);
}
conf_unbind_mouse(c, mb);
if (cmd == NULL) {
free(mb);
return 1;
return(1);
}
cargs = xcalloc(1, sizeof(*cargs));
for (i = 0; i < nitems(name_to_func); i++) {
@ -639,7 +608,7 @@ conf_bind_mouse(struct conf *c, const char *bind, const char *cmd)
out:
mb->cargs = cargs;
TAILQ_INSERT_TAIL(&c->mousebindq, mb, entry);
return 1;
return(1);
}
static void
@ -648,7 +617,7 @@ conf_unbind_mouse(struct conf *c, struct bind_ctx *unbind)
struct bind_ctx *mb = NULL, *mbnxt;
TAILQ_FOREACH_SAFE(mb, &c->mousebindq, entry, mbnxt) {
if ((unbind == NULL) ||
if ((unbind == NULL) ||
((mb->modmask == unbind->modmask) &&
(mb->press.button == unbind->press.button))) {
TAILQ_REMOVE(&c->mousebindq, mb, entry);
@ -670,8 +639,6 @@ conf_grab_kbd(Window win)
TAILQ_FOREACH(kb, &Conf.keybindq, entry) {
kc = XKeysymToKeycode(X_Dpy, kb->press.keysym);
if (kc == 0)
continue;
if ((XkbKeycodeToKeysym(X_Dpy, kc, 0, 0) != kb->press.keysym) &&
(XkbKeycodeToKeysym(X_Dpy, kc, 0, 1) == kb->press.keysym))
kb->modmask |= ShiftMask;
@ -701,3 +668,46 @@ conf_grab_mouse(Window win)
}
}
}
static char *cwmhints[] = {
"WM_STATE",
"WM_DELETE_WINDOW",
"WM_TAKE_FOCUS",
"WM_PROTOCOLS",
"_MOTIF_WM_HINTS",
"UTF8_STRING",
"WM_CHANGE_STATE",
};
static 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",
"_CWM_WM_STATE_FREEZE",
};
void
conf_atoms(void)
{
XInternAtoms(X_Dpy, cwmhints, nitems(cwmhints), False, cwmh);
XInternAtoms(X_Dpy, ewmhints, nitems(ewmhints), False, ewmh);
}

29
cwm.1
View File

@ -23,7 +23,6 @@
.Sh SYNOPSIS
.\" For a program: program [-abc] file ...
.Nm cwm
.Op Fl nv
.Op Fl c Ar file
.Op Fl d Ar display
.Sh DESCRIPTION
@ -48,14 +47,6 @@ however,
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
@ -103,7 +94,7 @@ Cycle through currently visible windows.
.It Ic MS-Tab
Reverse cycle through currently visible windows.
.It Ic CM-x
Close current window.
Delete current window.
.It Ic CM-[n]
Toggle visibility of group n, where n is 1-9.
.It Ic CM-a
@ -152,7 +143,7 @@ will be executed via the configured terminal emulator.
.It Ic CM-w
Spawn
.Dq exec WindowManager
menu, allowing a switch to another window manager.
dialog, allowing a switch to another window manager.
.It Ic CMS-r
Restart.
.It Ic CMS-q
@ -193,14 +184,6 @@ List all available items.
.It Ic [Esc]
Cancel.
.El
.Pp
.Nm
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,
@ -219,11 +202,6 @@ Window is currently focused.
.It &
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
@ -247,7 +225,8 @@ Selecting an item will warp to that window, unhiding it if necessary.
Show list of currently defined groups.
Selecting an item will hide/unhide that group.
.It Ic M3
Show list of applications as defined in the configuration file.
Show list of applications as defined in
.Pa ~/.cwmrc .
Selecting an item will spawn that application.
.El
.Sh ENVIRONMENT

2
cwm.pub Normal file
View File

@ -0,0 +1,2 @@
untrusted comment: portable cwm release key public key
RWTdOib0PoIM0pmDAPnV2S9/AMRqTOVfTY/KAkFemdH13cqBDHdduTas

99
cwmrc.5
View File

@ -37,8 +37,10 @@ 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
.Pp
.Bl -tag -width Ds -compact
.It Ic autogroup Ar group windowclass
.It Ic autogroup Ar group windowname,windowclass
Automatically add new windows to
.Ar group
if their class property matches
@ -60,6 +62,7 @@ used to override
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 .
.Pp
.It Ic bind-key Ar key function
Bind or rebind key
.Ar key
@ -81,8 +84,6 @@ Meta key.
Shift key.
.It Ic 4
Mod4 (windows) key.
.It Ic 5
Mod5 (AltGr) key.
.El
.Pp
The
@ -90,6 +91,7 @@ The
may either be one from the
.Sx BIND FUNCTION LIST
(see below) or the command line that is to be executed.
.Pp
.It Ic bind-mouse Ar button function
Bind or rebind button
.Ar button
@ -99,10 +101,18 @@ 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 .
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.
.El
.Pp
The following buttons are recognised:
.Pp
@ -124,27 +134,38 @@ The
may be taken from the
.Sx BIND FUNCTION LIST
(see below) or the command line that is to be executed.
.Pp
.It Ic borderwidth Ar pixels
Set the window border width to
.Ar pixels .
.Pp
.It Ic color activeborder Ar color
Set the color of the active border.
.Pp
.It Ic color font Ar color
Set menu font color.
.Pp
.It Ic color selfont Ar color
Set font color for selected menu item.
.Pp
.It Ic color groupborder Ar color
Set the color of the border while grouping a window.
.Pp
.It Ic color inactiveborder Ar color
Set the color of the inactive border.
.Pp
.It Ic color menubg Ar color
Set menu background color.
.Pp
.It Ic color menufg Ar color
Set menu foreground color.
.Pp
.It Ic color urgencyborder Ar color
Set the color of the border of a window indicating urgency.
.Pp
.It Ic color ungroupborder Ar color
Set the color of the border while ungrouping a window.
.Pp
.It Ic command Ar name path
Every
.Ar name
@ -152,7 +173,7 @@ entry is shown in the application menu.
When selected, the defined
.Ar path
is executed with
.Xr execvp 3 .
.Xr execve 2 .
.Pp
The
.Ar name
@ -168,11 +189,13 @@ The defaults are
and
.Xr xlock 1 ,
respectively.
.Pp
.It Ic fontname Ar font
Change the default
.Ar font
for
.Xr Xft 3 .
.Pp
.It Ic gap Ar top bottom left right
Define a
.Dq gap
@ -183,30 +206,28 @@ This
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.
.Pp
.It Ic ignore Ar windowname
Ignore, and do not warp to, windows with the name
.Ar windowname
when drawing borders and cycling through windows.
.Pp
.It Ic moveamount Ar pixels
Set a default size for the keyboard movement bindings,
in pixels.
The default is 1.
.Pp
.It Ic snapdist Ar pixels
Minimum distance to snap-to adjacent edge, in pixels.
The default is 0.
.Pp
.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.
.Pp
.It Ic unbind-key Ar key
Unbind function bound to
.Ar key .
@ -215,6 +236,7 @@ A special
keyword
.Dq all
can be used to unbind all keys.
.Pp
.It Ic unbind-mouse Ar button
Unbind function bound to
.Ar button .
@ -223,19 +245,6 @@ A special
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
@ -273,10 +282,6 @@ menu.
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
@ -295,8 +300,8 @@ Reverse cycle through windows.
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-delete
Delete current window.
.It window-hide
Hide current window.
.It window-lower
@ -319,15 +324,11 @@ Vertically maximize current window (gap + border honored).
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.
horizontally and resized to 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.
and resized to half of the horizontal screen space.
Other windows in its group share remaining screen space.
.It window-move
Move current window.
@ -397,22 +398,6 @@ pixels right.
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

221
group.c
View File

@ -20,7 +20,7 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <err.h>
#include <errno.h>
@ -35,32 +35,39 @@
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 *);
static void group_setactive(struct group_ctx *);
const char *num_to_name[] = {
"nogroup", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine"
};
void
group_assign(struct group_ctx *gc, struct client_ctx *cc)
{
if (cc->gc != NULL)
TAILQ_REMOVE(&cc->gc->clientq, cc, group_entry);
if ((gc != NULL) && (gc->num == 0))
gc = NULL;
cc->gc = gc;
xu_ewmh_set_net_wm_desktop(cc);
if (cc->gc != NULL)
TAILQ_INSERT_TAIL(&gc->clientq, cc, group_entry);
xu_ewmh_net_wm_desktop(cc);
}
void
group_hide(struct group_ctx *gc)
{
struct screen_ctx *sc = gc->sc;
struct client_ctx *cc;
screen_updatestackingorder(gc->sc);
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (!(cc->flags & CLIENT_STICKY) &&
!(cc->flags & CLIENT_HIDDEN))
TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
if (!(cc->flags & CLIENT_STICKY))
client_hide(cc);
}
}
@ -68,41 +75,33 @@ group_hide(struct group_ctx *gc)
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);
TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
if (!(cc->flags & CLIENT_STICKY))
client_unhide(cc);
}
group_restack(gc);
group_set_active(gc);
group_setactive(gc);
}
static void
group_restack(struct group_ctx *gc)
{
struct screen_ctx *sc = gc->sc;
struct client_ctx *cc;
Window *winlist;
int i, lastempty = -1;
int nwins = 0, highstack = 0;
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
if (cc->stackingorder > highstack)
highstack = cc->stackingorder;
}
winlist = xreallocarray(NULL, (highstack + 1), sizeof(*winlist));
/* Invert the stacking order for XRestackWindows(). */
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
winlist[highstack - cc->stackingorder] = cc->win;
nwins++;
}
@ -123,22 +122,24 @@ group_restack(struct group_ctx *gc)
}
void
group_init(struct screen_ctx *sc, int num, const char *name)
group_init(struct screen_ctx *sc, int num)
{
struct group_ctx *gc;
gc = xmalloc(sizeof(*gc));
gc->sc = sc;
gc->name = xstrdup(name);
gc->name = xstrdup(num_to_name[num]);
gc->num = num;
TAILQ_INIT(&gc->clientq);
TAILQ_INSERT_TAIL(&sc->groupq, gc, entry);
if (num == 1)
group_set_active(gc);
group_setactive(gc);
}
void
group_set_active(struct group_ctx *gc)
group_setactive(struct group_ctx *gc)
{
struct screen_ctx *sc = gc->sc;
@ -153,61 +154,90 @@ group_movetogroup(struct client_ctx *cc, int idx)
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
if (idx < 0 || idx >= Conf.ngroups)
errx(1, "%s: index out of range (%d)", __func__, idx);
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);
}
if (gc->num == idx)
break;
}
if (cc->gc == gc)
return;
if (gc->num != 0 && group_holds_only_hidden(gc))
client_hide(cc);
group_assign(gc, cc);
}
void
group_toggle_membership(struct client_ctx *cc)
group_toggle_membership_enter(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc = sc->group_active;
if (cc->gc == gc) {
if (gc == cc->gc) {
group_assign(NULL, cc);
cc->flags |= CLIENT_UNGROUP;
} else {
group_assign(gc, cc);
cc->flags |= CLIENT_GROUP;
}
client_draw_border(cc);
}
void
group_toggle_membership_leave(struct client_ctx *cc)
{
cc->flags &= ~CLIENT_HIGHLIGHT;
client_draw_border(cc);
}
int
group_holds_only_sticky(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;
TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
if (!(cc->flags & CLIENT_STICKY))
return 0;
return(0);
}
return 1;
return(1);
}
int
group_holds_only_hidden(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;
TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
if (!(cc->flags & (CLIENT_HIDDEN | CLIENT_STICKY)))
return 0;
return(0);
}
return(1);
}
void
group_hidetoggle(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
if (idx < 0 || idx >= Conf.ngroups)
errx(1, "%s: index out of range (%d)", __func__, idx);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == idx)
break;
}
if (group_holds_only_hidden(gc))
group_show(gc);
else {
group_hide(gc);
/* make clients stick to empty group */
if (TAILQ_EMPTY(&gc->clientq))
group_setactive(gc);
}
return 1;
}
void
@ -215,8 +245,8 @@ 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;
if (idx < 0 || idx >= Conf.ngroups)
errx(1, "%s: index out of range (%d)", __func__, idx);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == idx)
@ -226,52 +256,6 @@ group_only(struct screen_ctx *sc, int idx)
}
}
void
group_toggle(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == idx) {
if (group_holds_only_hidden(gc))
group_show(gc);
else
group_hide(gc);
}
}
}
void
group_toggle_all(struct screen_ctx *sc)
{
struct group_ctx *gc;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (sc->hideall)
group_show(gc);
else
group_hide(gc);
}
sc->hideall = !sc->hideall;
}
void
group_close(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
struct client_ctx *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);
}
}
}
}
void
group_cycle(struct screen_ctx *sc, int flags)
{
@ -292,6 +276,7 @@ group_cycle(struct screen_ctx *sc, int flags)
else if (!group_holds_only_hidden(newgc))
group_hide(newgc);
}
if (showgroup == NULL)
return;
@ -300,7 +285,7 @@ group_cycle(struct screen_ctx *sc, int flags)
if (group_holds_only_hidden(showgroup))
group_show(showgroup);
else
group_set_active(showgroup);
group_setactive(showgroup);
}
static struct group_ctx *
@ -323,27 +308,43 @@ group_prev(struct group_ctx *gc)
newgc : TAILQ_LAST(&sc->groupq, group_q));
}
void
group_alltoggle(struct screen_ctx *sc)
{
struct group_ctx *gc;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (sc->hideall)
group_show(gc);
else
group_hide(gc);
}
sc->hideall = !sc->hideall;
}
int
group_restore(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
int num;
long grpnum;
long *grpnum;
if (!xu_ewmh_get_net_wm_desktop(cc, &grpnum))
return 0;
if (xu_getprop(cc->win, ewmh[_NET_WM_DESKTOP], XA_CARDINAL, 1L,
(unsigned char **)&grpnum) <= 0)
return(0);
num = (grpnum == -1) ? 0 : grpnum;
num = (*grpnum == -1) ? 0 : *grpnum;
num = MIN(num, (Conf.ngroups - 1));
XFree(grpnum);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == num) {
group_assign(gc, cc);
return 1;
return(1);
}
}
return 0;
return(0);
}
int
@ -354,13 +355,13 @@ group_autogroup(struct client_ctx *cc)
struct group_ctx *gc;
int num = -1, both_match = 0;
if (cc->res_class == NULL || cc->res_name == NULL)
return 0;
if (cc->ch.res_class == NULL || cc->ch.res_name == NULL)
return(0);
TAILQ_FOREACH(ag, &Conf.autogroupq, entry) {
if (strcmp(ag->class, cc->res_class) == 0) {
if (strcmp(ag->class, cc->ch.res_class) == 0) {
if ((ag->name != NULL) &&
(strcmp(ag->name, cc->res_name) == 0)) {
(strcmp(ag->name, cc->ch.res_name) == 0)) {
num = ag->num;
both_match = 1;
} else if (ag->name == NULL && !both_match)
@ -371,8 +372,8 @@ group_autogroup(struct client_ctx *cc)
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == num) {
group_assign(gc, cc);
return 1;
return(1);
}
}
return 0;
return(0);
}

320
kbfunc.c
View File

@ -18,9 +18,11 @@
* $OpenBSD$
*/
/* For FreeBSD. */
#define _WITH_GETLINE
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include "queue.h"
#include <dirent.h>
#include <err.h>
@ -59,7 +61,7 @@ kbfunc_amount(int flags, int amt, int *mx, int *my)
if (flags & CWM_BIGAMOUNT)
amt *= CWM_FACTOR;
switch (flags & (CWM_UP | CWM_DOWN | CWM_LEFT | CWM_RIGHT)) {
switch (flags & DIRECTIONMASK) {
case CWM_UP:
*my -= amt;
break;
@ -84,8 +86,8 @@ kbfunc_ptrmove(void *ctx, struct cargs *cargs)
kbfunc_amount(cargs->flag, Conf.mamount, &mx, &my);
xu_ptr_get(sc->rootwin, &x, &y);
xu_ptr_set(sc->rootwin, x + mx, y + my);
xu_ptr_getpos(sc->rootwin, &x, &y);
xu_ptr_setpos(sc->rootwin, x + mx, y + my);
}
void
@ -132,7 +134,7 @@ kbfunc_client_move_kb(void *ctx, struct cargs *cargs)
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, 1);
cc->geom.y + cc->geom.h / 2, CWM_GAP);
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.x + cc->geom.w + (cc->bwidth * 2),
area.x, area.x + area.w, sc->snapdist);
@ -142,7 +144,6 @@ kbfunc_client_move_kb(void *ctx, struct cargs *cargs)
client_move(cc);
client_ptr_inbound(cc, 1);
XSync(X_Dpy, True);
}
static void
@ -167,10 +168,10 @@ kbfunc_client_move_mb(void *ctx, struct cargs *cargs)
CurrentTime) != GrabSuccess)
return;
screen_prop_win_create(sc, cc->win);
screen_prop_win_draw(sc, "%+5d%+5d", cc->geom.x, cc->geom.y);
menu_windraw(sc, cc->win, "%4d, %-4d", cc->geom.x, cc->geom.y);
while (move) {
XMaskEvent(X_Dpy, MOUSEMASK, &ev);
XWindowEvent(X_Dpy, cc->win, MOUSEMASK, &ev);
switch (ev.type) {
case MotionNotify:
/* not more than 60 times / second */
@ -183,7 +184,7 @@ kbfunc_client_move_mb(void *ctx, struct cargs *cargs)
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, 1);
cc->geom.y + cc->geom.h / 2, CWM_GAP);
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.x + cc->geom.w + (cc->bwidth * 2),
area.x, area.x + area.w, sc->snapdist);
@ -191,8 +192,8 @@ kbfunc_client_move_mb(void *ctx, struct cargs *cargs)
cc->geom.y + cc->geom.h + (cc->bwidth * 2),
area.y, area.y + area.h, sc->snapdist);
client_move(cc);
screen_prop_win_draw(sc,
"%+5d%+5d", cc->geom.x, cc->geom.y);
menu_windraw(sc, cc->win,
"%4d, %-4d", cc->geom.x, cc->geom.y);
break;
case ButtonRelease:
move = 0;
@ -201,7 +202,8 @@ kbfunc_client_move_mb(void *ctx, struct cargs *cargs)
}
if (ltime)
client_move(cc);
screen_prop_win_destroy(sc);
XUnmapWindow(X_Dpy, sc->menu.win);
XReparentWindow(X_Dpy, sc->menu.win, sc->rootwin, 0, 0);
XUngrabPointer(X_Dpy, CurrentTime);
}
@ -231,7 +233,6 @@ kbfunc_client_resize_kb(void *ctx, struct cargs *cargs)
client_resize(cc, 1);
client_ptr_inbound(cc, 1);
XSync(X_Dpy, True);
}
static void
@ -247,19 +248,18 @@ kbfunc_client_resize_mb(void *ctx, struct cargs *cargs)
return;
client_raise(cc);
client_ptr_save(cc);
client_ptrsave(cc);
xu_ptr_set(cc->win, cc->geom.w, cc->geom.h);
xu_ptr_setpos(cc->win, cc->geom.w, cc->geom.h);
if (XGrabPointer(X_Dpy, cc->win, False, MOUSEMASK,
GrabModeAsync, GrabModeAsync, None, Conf.cursor[CF_RESIZE],
CurrentTime) != GrabSuccess)
return;
screen_prop_win_create(sc, cc->win);
screen_prop_win_draw(sc, "%4d x %-4d", cc->dim.w, cc->dim.h);
menu_windraw(sc, cc->win, "%4d x %-4d", cc->dim.w, cc->dim.h);
while (resize) {
XMaskEvent(X_Dpy, MOUSEMASK, &ev);
XWindowEvent(X_Dpy, cc->win, MOUSEMASK, &ev);
switch (ev.type) {
case MotionNotify:
/* not more than 60 times / second */
@ -269,9 +269,9 @@ kbfunc_client_resize_mb(void *ctx, struct cargs *cargs)
cc->geom.w = ev.xmotion.x;
cc->geom.h = ev.xmotion.y;
client_apply_sizehints(cc);
client_applysizehints(cc);
client_resize(cc, 1);
screen_prop_win_draw(sc,
menu_windraw(sc, cc->win,
"%4d x %-4d", cc->dim.w, cc->dim.h);
break;
case ButtonRelease:
@ -281,7 +281,8 @@ kbfunc_client_resize_mb(void *ctx, struct cargs *cargs)
}
if (ltime)
client_resize(cc, 1);
screen_prop_win_destroy(sc);
XUnmapWindow(X_Dpy, sc->menu.win);
XReparentWindow(X_Dpy, sc->menu.win, sc->rootwin, 0, 0);
XUngrabPointer(X_Dpy, CurrentTime);
/* Make sure the pointer stays within the window. */
@ -289,52 +290,15 @@ kbfunc_client_resize_mb(void *ctx, struct cargs *cargs)
}
void
kbfunc_client_snap(void *ctx, struct cargs *cargs)
kbfunc_client_delete(void *ctx, struct cargs *cargs)
{
struct client_ctx *cc = ctx;
struct screen_ctx *sc = cc->sc;
struct geom area;
int flags;
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, 1);
flags = cargs->flag;
while (flags) {
if (flags & CWM_UP) {
cc->geom.y = area.y;
flags &= ~CWM_UP;
}
if (flags & CWM_LEFT) {
cc->geom.x = area.x;
flags &= ~CWM_LEFT;
}
if (flags & CWM_RIGHT) {
cc->geom.x = area.x + area.w - cc->geom.w -
(cc->bwidth * 2);
flags &= ~CWM_RIGHT;
}
if (flags & CWM_DOWN) {
cc->geom.y = area.y + area.h - cc->geom.h -
(cc->bwidth * 2);
flags &= ~CWM_DOWN;
}
}
client_move(cc);
client_ptr_inbound(cc, 1);
}
void
kbfunc_client_close(void *ctx, struct cargs *cargs)
{
client_close(ctx);
client_send_delete(ctx);
}
void
kbfunc_client_lower(void *ctx, struct cargs *cargs)
{
client_ptr_save(ctx);
client_ptrsave(ctx);
client_lower(ctx);
}
@ -401,65 +365,7 @@ kbfunc_client_vtile(void *ctx, struct cargs *cargs)
void
kbfunc_client_cycle(void *ctx, struct cargs *cargs)
{
struct screen_ctx *sc = ctx;
struct client_ctx *newcc, *oldcc, *prevcc;
int again = 1, flags = cargs->flag;
/* For X apps that ignore/steal events. */
if (cargs->xev == CWM_XEV_KEY)
XGrabKeyboard(X_Dpy, sc->rootwin, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
if (TAILQ_EMPTY(&sc->clientq))
return;
prevcc = TAILQ_FIRST(&sc->clientq);
oldcc = client_current(sc);
if (oldcc == NULL)
oldcc = (flags & CWM_CYCLE_REVERSE) ?
TAILQ_LAST(&sc->clientq, client_q) :
TAILQ_FIRST(&sc->clientq);
newcc = oldcc;
while (again) {
again = 0;
newcc = (flags & CWM_CYCLE_REVERSE) ? client_prev(newcc) :
client_next(newcc);
/* Only cycle visible and non-ignored windows. */
if ((newcc->flags & (CLIENT_SKIP_CYCLE)) ||
((flags & CWM_CYCLE_INGROUP) &&
(newcc->gc != oldcc->gc)))
again = 1;
/* Is oldcc the only non-hidden window? */
if (newcc == oldcc) {
if (again)
return; /* No windows visible. */
break;
}
}
/* Reset when cycling mod is released. XXX I hate this hack */
sc->cycling = 1;
client_ptr_save(oldcc);
client_raise(prevcc);
client_raise(newcc);
if (!client_inbound(newcc, newcc->ptr.x, newcc->ptr.y)) {
newcc->ptr.x = newcc->geom.w / 2;
newcc->ptr.y = newcc->geom.h / 2;
}
/* When no client is active, warp pointer to last active. */
if (oldcc->flags & (CLIENT_ACTIVE))
client_ptr_warp(newcc);
else if (oldcc->flags & (CLIENT_SKIP_CYCLE))
client_ptr_warp(newcc);
else {
client_raise(oldcc);
client_ptr_warp(oldcc);
}
client_cycle(ctx, cargs->flag);
}
void
@ -467,12 +373,12 @@ kbfunc_client_toggle_group(void *ctx, struct cargs *cargs)
{
struct client_ctx *cc = ctx;
/* For X apps that ignore/steal events. */
/* For X apps that steal events. */
if (cargs->xev == CWM_XEV_KEY)
XGrabKeyboard(X_Dpy, cc->win, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
group_toggle_membership(cc);
group_toggle_membership_enter(cc);
}
void
@ -481,44 +387,30 @@ kbfunc_client_movetogroup(void *ctx, struct cargs *cargs)
group_movetogroup(ctx, cargs->flag);
}
void
kbfunc_group_toggle(void *ctx, struct cargs *cargs)
{
group_hidetoggle(ctx, cargs->flag);
}
void
kbfunc_group_only(void *ctx, struct cargs *cargs)
{
group_only(ctx, cargs->flag);
}
void
kbfunc_group_last(void *ctx, struct cargs *cargs)
{
struct screen_ctx *sc = ctx;
group_only(ctx, sc->group_last->num);
}
void
kbfunc_group_toggle(void *ctx, struct cargs *cargs)
{
group_toggle(ctx, cargs->flag);
}
void
kbfunc_group_toggle_all(void *ctx, struct cargs *cargs)
{
group_toggle_all(ctx);
}
void
kbfunc_group_close(void *ctx, struct cargs *cargs)
{
group_close(ctx, cargs->flag);
}
void
kbfunc_group_cycle(void *ctx, struct cargs *cargs)
{
group_cycle(ctx, cargs->flag);
}
void
kbfunc_group_alltoggle(void *ctx, struct cargs *cargs)
{
group_alltoggle(ctx);
}
void
kbfunc_menu_client(void *ctx, struct cargs *cargs)
{
@ -526,25 +418,32 @@ kbfunc_menu_client(void *ctx, struct cargs *cargs)
struct client_ctx *cc, *old_cc;
struct menu *mi;
struct menu_q menuq;
int mflags = 0;
int m = (cargs->xev == CWM_XEV_BTN);
int all = (cargs->flag & CWM_MENU_WINDOW_ALL);
if (cargs->xev == CWM_XEV_BTN)
mflags |= CWM_MENU_LIST;
old_cc = client_current();
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if ((cargs->flag & CWM_MENU_WINDOW_ALL) ||
(cc->flags & CLIENT_HIDDEN))
if (!all) {
if (cc->flags & CLIENT_HIDDEN)
menuq_add(&menuq, cc, NULL);
} else
menuq_add(&menuq, cc, NULL);
}
if ((mi = menu_filter(sc, &menuq, "window", NULL, mflags,
if ((mi = menu_filter(sc, &menuq,
(m) ? NULL : "window", NULL,
((m) ? CWM_MENU_LIST : 0),
search_match_client, search_print_client)) != NULL) {
cc = (struct client_ctx *)mi->ctx;
client_show(cc);
if ((old_cc = client_current(sc)) != NULL)
client_ptr_save(old_cc);
client_ptr_warp(cc);
if (cc->flags & CLIENT_HIDDEN)
client_unhide(cc);
else
client_raise(cc);
if (old_cc)
client_ptrsave(old_cc);
client_ptrwarp(cc);
}
menuq_clear(&menuq);
@ -557,21 +456,21 @@ kbfunc_menu_cmd(void *ctx, struct cargs *cargs)
struct cmd_ctx *cmd;
struct menu *mi;
struct menu_q menuq;
int mflags = 0;
if (cargs->xev == CWM_XEV_BTN)
mflags |= CWM_MENU_LIST;
int m = (cargs->xev == CWM_XEV_BTN);
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
if ((strcmp(cmd->name, "lock") == 0) ||
(strcmp(cmd->name, "term") == 0))
continue;
menuq_add(&menuq, cmd, NULL);
/* search_match_text() needs mi->text */
menuq_add(&menuq, cmd, "%s", cmd->name);
}
if ((mi = menu_filter(sc, &menuq, "application", NULL, mflags,
search_match_cmd, search_print_cmd)) != NULL) {
if ((mi = menu_filter(sc, &menuq,
(m) ? NULL : "application", NULL,
((m) ? CWM_MENU_LIST : 0),
search_match_text, search_print_cmd)) != NULL) {
cmd = (struct cmd_ctx *)mi->ctx;
u_spawn(cmd->path);
}
@ -586,20 +485,18 @@ kbfunc_menu_group(void *ctx, struct cargs *cargs)
struct group_ctx *gc;
struct menu *mi;
struct menu_q menuq;
int mflags = 0;
if (cargs->xev == CWM_XEV_BTN)
mflags |= CWM_MENU_LIST;
int m = (cargs->xev == CWM_XEV_BTN);
TAILQ_INIT(&menuq);
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (group_holds_only_sticky(gc))
continue;
menuq_add(&menuq, gc, NULL);
menuq_add(&menuq, gc, "%d %s", gc->num, gc->name);
}
if ((mi = menu_filter(sc, &menuq, "group", NULL, mflags,
search_match_group, search_print_group)) != NULL) {
if ((mi = menu_filter(sc, &menuq,
(m) ? NULL : "group", NULL, (CWM_MENU_LIST),
search_match_text, search_print_group)) != NULL) {
gc = (struct group_ctx *)mi->ctx;
(group_holds_only_hidden(gc)) ?
group_show(gc) : group_hide(gc);
@ -608,33 +505,6 @@ kbfunc_menu_group(void *ctx, struct cargs *cargs)
menuq_clear(&menuq);
}
void
kbfunc_menu_wm(void *ctx, struct cargs *cargs)
{
struct screen_ctx *sc = ctx;
struct cmd_ctx *wm;
struct menu *mi;
struct menu_q menuq;
int mflags = 0;
if (cargs->xev == CWM_XEV_BTN)
mflags |= CWM_MENU_LIST;
TAILQ_INIT(&menuq);
TAILQ_FOREACH(wm, &Conf.wmq, entry)
menuq_add(&menuq, wm, NULL);
if ((mi = menu_filter(sc, &menuq, "wm", NULL, mflags,
search_match_wm, search_print_wm)) != NULL) {
wm = (struct cmd_ctx *)mi->ctx;
free(Conf.wm_argv);
Conf.wm_argv = xstrdup(wm->path);
cwm_status = CWM_EXEC_WM;
}
menuq_clear(&menuq);
}
void
kbfunc_menu_exec(void *ctx, struct cargs *cargs)
{
@ -643,12 +513,24 @@ kbfunc_menu_exec(void *ctx, struct cargs *cargs)
char **ap, *paths[NPATHS], *path, *pathcpy;
char tpath[PATH_MAX];
struct stat sb;
const char *label;
DIR *dirp;
struct dirent *dp;
struct menu *mi;
struct menu_q menuq;
int l, i;
int mflags = (CWM_MENU_DUMMY | CWM_MENU_FILE);
int l, i, cmd = cargs->flag;
switch (cmd) {
case CWM_MENU_EXEC_EXEC:
label = "exec";
break;
case CWM_MENU_EXEC_WM:
label = "wm";
break;
default:
errx(1, "%s: invalid cmd %d", __func__, cmd);
/* NOTREACHED */
}
TAILQ_INIT(&menuq);
@ -677,7 +559,7 @@ kbfunc_menu_exec(void *ctx, struct cargs *cargs)
/* lstat(2) in case d_type isn't supported. */
if (lstat(tpath, &sb) == -1)
continue;
if (!S_ISREG(sb.st_mode) &&
if (!S_ISREG(sb.st_mode) &&
!S_ISLNK(sb.st_mode))
continue;
}
@ -688,11 +570,24 @@ kbfunc_menu_exec(void *ctx, struct cargs *cargs)
}
free(path);
if ((mi = menu_filter(sc, &menuq, "exec", NULL, mflags,
if ((mi = menu_filter(sc, &menuq, label, NULL,
(CWM_MENU_DUMMY | CWM_MENU_FILE),
search_match_exec, search_print_text)) != NULL) {
if (mi->text[0] == '\0')
goto out;
u_spawn(mi->text);
switch (cmd) {
case CWM_MENU_EXEC_EXEC:
u_spawn(mi->text);
break;
case CWM_MENU_EXEC_WM:
cwm_status = CWM_EXEC_WM;
free(Conf.wm_argv);
Conf.wm_argv = xstrdup(mi->text);
break;
default:
errx(1, "%s: egad, cmd changed value!", __func__);
/* NOTREACHED */
}
}
out:
if (mi != NULL && mi->dummy)
@ -709,12 +604,11 @@ kbfunc_menu_ssh(void *ctx, struct cargs *cargs)
struct menu_q menuq;
FILE *fp;
char *buf, *lbuf, *p;
char hostbuf[HOST_NAME_MAX+1];
char hostbuf[_POSIX_HOST_NAME_MAX+1];
char path[PATH_MAX];
int l;
size_t len;
ssize_t slen;
int mflags = (CWM_MENU_DUMMY);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
if (strcmp(cmd->name, "term") == 0)
@ -737,8 +631,9 @@ kbfunc_menu_ssh(void *ctx, struct cargs *cargs)
/* skip hashed hosts */
if (strncmp(buf, HASH_MARKER, strlen(HASH_MARKER)) == 0)
continue;
for (p = buf; *p != ',' && *p != ' ' && p != buf + slen; p++)
;
for (p = buf; *p != ',' && *p != ' ' && p != buf + slen; p++) {
/* do nothing */
}
/* ignore badness */
if (p - buf + 1 > sizeof(hostbuf))
continue;
@ -750,7 +645,7 @@ kbfunc_menu_ssh(void *ctx, struct cargs *cargs)
err(1, "%s", path);
(void)fclose(fp);
menu:
if ((mi = menu_filter(sc, &menuq, "ssh", NULL, mflags,
if ((mi = menu_filter(sc, &menuq, "ssh", NULL, (CWM_MENU_DUMMY),
search_match_text, search_print_text)) != NULL) {
if (mi->text[0] == '\0')
goto out;
@ -772,12 +667,11 @@ kbfunc_client_menu_label(void *ctx, struct cargs *cargs)
struct client_ctx *cc = ctx;
struct menu *mi;
struct menu_q menuq;
int mflags = (CWM_MENU_DUMMY);
TAILQ_INIT(&menuq);
/* dummy is set, so this will always return */
mi = menu_filter(cc->sc, &menuq, "label", cc->label, mflags,
mi = menu_filter(cc->sc, &menuq, "label", cc->label, (CWM_MENU_DUMMY),
search_match_text, search_print_text);
if (!mi->abort) {

203
menu.c
View File

@ -20,7 +20,7 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <ctype.h>
#include <err.h>
@ -37,10 +37,6 @@
#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,
@ -49,12 +45,10 @@ enum ctltype {
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 hasprompt;
int list;
int listing;
int changed;
@ -62,6 +56,7 @@ struct menu_ctx {
int entry;
int num;
int flags;
struct geom geom;
void (*match)(struct menu_q *, struct menu_q *, char *);
void (*print)(struct menu *, int);
};
@ -90,13 +85,15 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, const char *prompt,
struct menu *mi = NULL;
XEvent e;
Window focuswin;
int focusrevert, xsave, ysave, xcur, ycur;
int evmask, focusrevert;
int xsave, ysave, xcur, ycur;
TAILQ_INIT(&resultq);
xu_ptr_get(sc->rootwin, &xsave, &ysave);
(void)memset(&mc, 0, sizeof(mc));
xu_ptr_getpos(sc->rootwin, &xsave, &ysave);
mc.sc = sc;
mc.flags = flags;
mc.match = match;
@ -108,41 +105,39 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, const char *prompt,
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);
evmask = MENUMASK;
if (prompt != NULL) {
evmask |= KEYMASK; /* accept keys as well */
(void)strlcpy(mc.promptstr, prompt, sizeof(mc.promptstr));
mc.hasprompt = 1;
}
XSelectInput(X_Dpy, mc.win, MENUMASK);
XMapRaised(X_Dpy, mc.win);
XSelectInput(X_Dpy, sc->menu.win, evmask);
XMapRaised(X_Dpy, sc->menu.win);
if (XGrabPointer(X_Dpy, mc.win, False, MENUGRABMASK,
if (XGrabPointer(X_Dpy, sc->menu.win, False, MENUGRABMASK,
GrabModeAsync, GrabModeAsync, None, Conf.cursor[CF_QUESTION],
CurrentTime) != GrabSuccess) {
XftDrawDestroy(mc.xftdraw);
XDestroyWindow(X_Dpy, mc.win);
return NULL;
XUnmapWindow(X_Dpy, sc->menu.win);
return(NULL);
}
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, mc.win, RevertToPointerRoot, CurrentTime);
XSetInputFocus(X_Dpy, sc->menu.win, RevertToPointerRoot, CurrentTime);
/* make sure keybindings don't remove keys from the menu stream */
XGrabKeyboard(X_Dpy, mc.win, True,
XGrabKeyboard(X_Dpy, sc->menu.win, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
for (;;) {
mc.changed = 0;
XWindowEvent(X_Dpy, mc.win, MENUMASK, &e);
XWindowEvent(X_Dpy, sc->menu.win, evmask, &e);
switch (e.type) {
case KeyPress:
@ -173,19 +168,18 @@ out:
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);
xu_ptr_getpos(sc->rootwin, &xcur, &ycur);
if (xcur == mc.geom.x && ycur == mc.geom.y)
xu_ptr_set(sc->rootwin, xsave, ysave);
xu_ptr_setpos(sc->rootwin, xsave, ysave);
XUngrabPointer(X_Dpy, CurrentTime);
XMoveResizeWindow(X_Dpy, sc->menu.win, 0, 0, 1, 1);
XUnmapWindow(X_Dpy, sc->menu.win);
XUngrabKeyboard(X_Dpy, CurrentTime);
return mi;
return(mi);
}
static struct menu *
@ -194,14 +188,13 @@ 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) {
if ((mi = menu_filter(sc, &menuq, mc->searchstr, NULL,
(CWM_MENU_DUMMY), search_match_path, search_print_text)) != NULL) {
mr->abort = mi->abort;
mr->dummy = mi->dummy;
if (mi->text[0] != '\0')
@ -213,7 +206,7 @@ menu_complete_path(struct menu_ctx *mc)
menuq_clear(&menuq);
return mr;
return(mr);
}
static struct menu *
@ -228,7 +221,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
wchar_t wc;
if (menu_keycode(&e->xkey, &ctl, chr) < 0)
return NULL;
return(NULL);
switch (ctl) {
case CTL_ERASEONE:
@ -269,7 +262,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
mi->dummy = 1;
}
mi->abort = 0;
return mi;
return(mi);
case CTL_WIPE:
mc->searchstr[0] = '\0';
mc->changed = 1;
@ -284,7 +277,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
if ((mc->flags & CWM_MENU_FILE) &&
(strncmp(mc->searchstr, mi->text,
strlen(mi->text))) == 0)
return menu_complete_path(mc);
return(menu_complete_path(mc));
/*
* Put common prefix of the results into searchstr
@ -309,7 +302,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
mi->text[0] = '\0';
mi->dummy = 1;
mi->abort = 1;
return mi;
return(mi);
default:
break;
}
@ -327,7 +320,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
mc->listing = 0;
}
return NULL;
return(NULL);
}
static void
@ -350,25 +343,34 @@ menu_draw(struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq)
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;
mc->num = 0;
mc->geom.w = 0;
mc->geom.h = 0;
if (mc->hasprompt) {
(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->height + 1;
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->geom.h += sc->xftfont->height + 1;
mc->num++;
}
area = screen_area(sc, mc->geom.x, mc->geom.y, 1);
area = screen_area(sc, mc->geom.x, mc->geom.y, CWM_GAP);
area.w += area.x - Conf.bwidth * 2;
area.h += area.y - Conf.bwidth * 2;
@ -390,32 +392,35 @@ menu_draw(struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq)
}
if (mc->geom.x != xsave || mc->geom.y != ysave)
xu_ptr_set(sc->rootwin, mc->geom.x, mc->geom.y);
xu_ptr_setpos(sc->rootwin, mc->geom.x, mc->geom.y);
XClearWindow(X_Dpy, mc->win);
XMoveResizeWindow(X_Dpy, mc->win, mc->geom.x, mc->geom.y,
XClearWindow(X_Dpy, sc->menu.win);
XMoveResizeWindow(X_Dpy, sc->menu.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));
n = 0;
if (mc->hasprompt) {
XftDrawStringUtf8(sc->menu.xftdraw,
&sc->xftcolor[CWM_COLOR_MENU_FONT], sc->xftfont,
0, sc->xftfont->ascent,
(const FcChar8*)mc->dispstr, strlen(mc->dispstr));
n++;
}
TAILQ_FOREACH(mi, resultq, resultentry) {
int y = n * (sc->xftfont->ascent + sc->xftfont->descent);
int y = n * (sc->xftfont->height + 1) + sc->xftfont->ascent + 1;
/* Stop drawing when menu doesn't fit inside the screen. */
if (mc->geom.y + y >= area.h)
if (mc->geom.y + y > area.h)
break;
XftDrawStringUtf8(mc->xftdraw,
XftDrawStringUtf8(sc->menu.xftdraw,
&sc->xftcolor[CWM_COLOR_MENU_FONT], sc->xftfont,
0, y + sc->xftfont->ascent,
0, y,
(const FcChar8*)mi->print, strlen(mi->print));
n++;
}
if (n > 1)
if (mc->hasprompt && n > 1)
menu_draw_entry(mc, resultq, 1, 1);
}
@ -425,7 +430,10 @@ menu_draw_entry(struct menu_ctx *mc, struct menu_q *resultq,
{
struct screen_ctx *sc = mc->sc;
struct menu *mi;
int color, i = 1, y;
int color, i = 0;
if (mc->hasprompt)
i = 1;
TAILQ_FOREACH(mi, resultq, resultentry)
if (entry == i++)
@ -433,13 +441,14 @@ menu_draw_entry(struct menu_ctx *mc, struct menu_q *resultq,
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);
XftDrawRect(sc->menu.xftdraw, &sc->xftcolor[color], 0,
(sc->xftfont->height + 1) * entry, mc->geom.w,
(sc->xftfont->height + 1) + 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,
XftDrawStringUtf8(sc->menu.xftdraw,
&sc->xftcolor[color], sc->xftfont,
0, (sc->xftfont->height + 1) * entry + sc->xftfont->ascent + 1,
(const FcChar8*)mi->print, strlen(mi->print));
}
@ -465,10 +474,13 @@ 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;
int entry, i = 0;
entry = menu_calc_entry(mc, x, y);
if (mc->hasprompt)
i = 1;
TAILQ_FOREACH(mi, resultq, resultentry)
if (entry == i++)
break;
@ -477,7 +489,7 @@ menu_handle_release(struct menu_ctx *mc, struct menu_q *resultq, int x, int y)
mi->text[0] = '\0';
mi->dummy = 1;
}
return mi;
return(mi);
}
static int
@ -486,18 +498,18 @@ 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);
entry = y / (sc->xftfont->height + 1);
/* in bounds? */
if (x < 0 || x > mc->geom.w || y < 0 ||
y > (sc->xftfont->ascent + sc->xftfont->descent) * mc->num ||
y > (sc->xftfont->height + 1) * mc->num ||
entry < 0 || entry >= mc->num)
entry = -1;
if (entry == 0)
if (mc->hasprompt && entry == 0)
entry = -1;
return entry;
return(entry);
}
static int
@ -580,12 +592,12 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr)
}
if (*ctl != CTL_NONE)
return 0;
return(0);
if (XLookupString(ev, chr, 32, &ks, NULL) < 0)
return -1;
return(-1);
return 0;
return(0);
}
void
@ -617,3 +629,34 @@ menuq_clear(struct menu_q *mq)
free(mi);
}
}
void
menu_windraw(struct screen_ctx *sc, Window win, const char *fmt, ...)
{
va_list ap;
int i;
char *text;
XGlyphInfo extents;
va_start(ap, fmt);
i = vasprintf(&text, fmt, ap);
va_end(ap);
if (i < 0 || text == NULL)
err(1, "vasprintf");
XftTextExtentsUtf8(X_Dpy, sc->xftfont, (const FcChar8*)text,
strlen(text), &extents);
XReparentWindow(X_Dpy, sc->menu.win, win, 0, 0);
XMoveResizeWindow(X_Dpy, sc->menu.win, 0, 0,
extents.xOff, sc->xftfont->height);
XMapWindow(X_Dpy, sc->menu.win);
XClearWindow(X_Dpy, sc->menu.win);
XftDrawStringUtf8(sc->menu.xftdraw, &sc->xftcolor[CWM_COLOR_MENU_FONT],
sc->xftfont, 0, sc->xftfont->ascent + 1,
(const FcChar8*)text, strlen(text));
free(text);
}

74
migrate-config.pl Executable file
View File

@ -0,0 +1,74 @@
#!/usr/bin/perl -p
# Originally by Stuart Henderson in
# <20161206120601.vmimohqh4nafaeah@symphytum.spacehopper.org>
# Ported to Perl and slightly tweaked by Leah Neukirchen.
s/\bbind\b(.*)\bunmap/unbind-key \1/;
s/\bmousebind\b(.*)unmap/unbind-mouse \1/;
s/\bresize\b/window-resize/;
s/\bresizedown\b/window-resize-down/;
s/\bresizeleft\b/window-resize-left/;
s/\bresizeright\b/window-resize-right/;
s/\bresizeup\b/window-resize-up/;
s/\bmove\b/window-move/;
s/\bmovedown\b/window-move-down/;
s/\bmoveleft\b/window-move-left/;
s/\bmoveright\b/window-move-right/;
s/\bmoveup\b/window-move-up/;
s/\bbigmovedown\b/window-move-down-big/;
s/\bbigmoveleft\b/window-move-left-big/;
s/\bbigmoveright\b/window-move-right-big/;
s/\bbigmoveup\b/window-move-up-big/;
s/\bbigptrmovedown\b/pointer-move-down-big/;
s/\bbigptrmoveleft\b/pointer-move-left-big/;
s/\bbigptrmoveright\b/pointer-move-right-big/;
s/\bbigptrmoveup\b/pointer-move-up-big/;
s/\bbigresizedown\b/window-resize-down-big/;
s/\bbigresizeleft\b/window-resize-left-big/;
s/\bbigresizeright\b/window-resize-right-big/;
s/\bbigresizeup\b/window-resize-up-big/;
s/\bbind\b/bind-key/;
s/\bcycle\b/window-cycle/;
s/\bcyclegroup\b/group-cycle/;
s/\bcycleingroup\b/window-cycle-ingroup/;
s/\bdelete\b/window-delete/;
s/\bexec\b/menu-exec/;
s/\bexec_wm\b/menu-exec-wm/;
s/\bfreeze\b/window-freeze/;
s/\bfullscreen\b/window-fullscreen/;
s/\bgroupsearch\b/menu-group/;
s/\bgrouptoggle\b/window-group/;
s/\bhide\b/window-hide/;
s/\bhmaximize\b/window-hmaximize/;
s/\bhtile\b/window-htile/;
s/\blabel\b/window-menu-label/;
s/\blower\b/window-lower/;
s/\bmaximize\b/window-maximize/;
s/\bmenu_cmd\b/menu-cmd/;
s/\bmenu_group\b/menu-group/;
s/\bmenu_unhide\b/menu-window/;
s/\bmenusearch\b/menu-cmd/;
s/\bmousebind\b/bind-mouse/;
s/\bnogroup\b/group-toggle-all/;
s/\bptrmovedown\b/pointer-move-down/;
s/\bptrmoveleft\b/pointer-move-left/;
s/\bptrmoveright\b/pointer-move-right/;
s/\bptrmoveup\b/pointer-move-up/;
s/\braise\b/window-raise/;
s/\brcycle\b/window-rcycle/;
s/\brcyclegroup\b/group-rcycle/;
s/\brcycleingroup\b/window-rcycle-ingroup/;
s/\bsearch\b/menu-window/;
s/\bssh\b/menu-ssh/;
s/\bstick\b/window-stick/;
s/\bvmaximize\b/window-vmaximize/;
s/\bvtile\b/window-vtile/;
s/\bwindow_grouptoggle\b/window-group/;
s/\bwindow_move\b/window-move/;
s/\bwindow_resize\b/window-resize/;
s/\bwindow_hide\b/window-hide/;
s/\bwindow_lower\b/window-lower/;
s/\bwindow_raise\b/window-raise/;
s/\bmovetogroup([1-9])\b/window-movetogroup-\1/;
s/\bgrouponly([1-9])\b/group-only-\1/;
s/\bgroup([1-9])\b/group-toggle-\1/;

105
parse.y
View File

@ -35,6 +35,8 @@
#include "calmwm.h"
#define YYSTYPE_IS_DECLARED
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
static struct file {
TAILQ_ENTRY(file) entry;
@ -43,7 +45,7 @@ static struct file {
int lineno;
int errors;
} *file, *topfile;
struct file *pushfile(const char *, FILE *);
struct file *pushfile(const char *);
int popfile(void);
int yyparse(void);
int yylex(void);
@ -70,8 +72,8 @@ typedef struct {
%token BINDKEY UNBINDKEY BINDMOUSE UNBINDMOUSE
%token FONTNAME STICKY GAP
%token AUTOGROUP COMMAND IGNORE WM
%token YES NO BORDERWIDTH MOVEAMOUNT HTILE VTILE
%token AUTOGROUP COMMAND IGNORE
%token YES NO BORDERWIDTH MOVEAMOUNT
%token COLOR SNAPDIST
%token ACTIVEBORDER INACTIVEBORDER URGENCYBORDER
%token GROUPBORDER UNGROUPBORDER
@ -81,7 +83,7 @@ typedef struct {
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.number> yesno
%type <v.string> string numberstring
%type <v.string> string
%%
grammar : /* empty */
@ -104,17 +106,6 @@ string : string STRING {
| STRING
;
numberstring : NUMBER {
char *s;
if (asprintf(&s, "%lld", $1) == -1) {
yyerror("string: asprintf");
YYERROR;
}
$$ = s;
}
| STRING
;
yesno : YES { $$ = 1; }
| NO { $$ = 0; }
;
@ -133,20 +124,6 @@ main : FONTNAME STRING {
}
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");
@ -162,24 +139,12 @@ main : FONTNAME STRING {
conf->snapdist = $2;
}
| COMMAND STRING string {
if (strlen($3) >= PATH_MAX) {
yyerror("%s command path too long", $2);
if (!conf_cmd_add(conf, $2, $3)) {
yyerror("command name/path too long");
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);
}
@ -220,7 +185,7 @@ main : FONTNAME STRING {
conf->gap.left = $4;
conf->gap.right = $5;
}
| BINDKEY numberstring string {
| BINDKEY STRING string {
if (!conf_bind_key(conf, $2, $3)) {
yyerror("invalid bind-key: %s %s", $2, $3);
free($2);
@ -230,7 +195,7 @@ main : FONTNAME STRING {
free($2);
free($3);
}
| UNBINDKEY numberstring {
| UNBINDKEY STRING {
if (!conf_bind_key(conf, $2, NULL)) {
yyerror("invalid unbind-key: %s", $2);
free($2);
@ -238,7 +203,7 @@ main : FONTNAME STRING {
}
free($2);
}
| BINDMOUSE numberstring string {
| BINDMOUSE STRING string {
if (!conf_bind_mouse(conf, $2, $3)) {
yyerror("invalid bind-mouse: %s %s", $2, $3);
free($2);
@ -248,7 +213,7 @@ main : FONTNAME STRING {
free($2);
free($3);
}
| UNBINDMOUSE numberstring {
| UNBINDMOUSE STRING {
if (!conf_bind_mouse(conf, $2, NULL)) {
yyerror("invalid unbind-mouse: %s", $2);
free($2);
@ -341,7 +306,6 @@ lookup(char *s)
{ "fontname", FONTNAME},
{ "gap", GAP},
{ "groupborder", GROUPBORDER},
{ "htile", HTILE},
{ "ignore", IGNORE},
{ "inactiveborder", INACTIVEBORDER},
{ "menubg", MENUBG},
@ -355,8 +319,6 @@ lookup(char *s)
{ "unbind-mouse", UNBINDMOUSE},
{ "ungroupborder", UNGROUPBORDER},
{ "urgencyborder", URGENCYBORDER},
{ "vtile", VTILE},
{ "wm", WM},
{ "yes", YES}
};
const struct keywords *p;
@ -385,7 +347,7 @@ lgetc(int quotec)
if (parsebuf) {
/* Read character from the parsebuffer instead of input. */
if (parseindex >= 0) {
c = (unsigned char)parsebuf[parseindex++];
c = parsebuf[parseindex++];
if (c != '\0')
return (c);
parsebuf = NULL;
@ -394,7 +356,7 @@ lgetc(int quotec)
}
if (pushback_index)
return ((unsigned char)pushback_buffer[--pushback_index]);
return (pushback_buffer[--pushback_index]);
if (quotec) {
if ((c = getc(file->stream)) == EOF) {
@ -435,10 +397,10 @@ lungetc(int c)
if (parseindex >= 0)
return (c);
}
if (pushback_index + 1 >= MAXPUSHBACK)
if (pushback_index < MAXPUSHBACK-1)
return (pushback_buffer[pushback_index++] = c);
else
return (EOF);
pushback_buffer[pushback_index++] = c;
return (c);
}
int
@ -451,7 +413,7 @@ findeol(void)
/* skip to either EOF or the first real EOL */
while (1) {
if (pushback_index)
c = (unsigned char)pushback_buffer[--pushback_index];
c = pushback_buffer[--pushback_index];
else
c = lgetc(0);
if (c == '\n') {
@ -494,8 +456,7 @@ yylex(void)
} else if (c == '\\') {
if ((next = lgetc(quotec)) == EOF)
return (0);
if (next == quotec || next == ' ' ||
next == '\t')
if (next == quotec || c == ' ' || c == '\t')
c = next;
else if (next == '\n') {
file->lineno++;
@ -513,7 +474,7 @@ yylex(void)
yyerror("string too long");
return (findeol());
}
*p++ = c;
*p++ = (char)c;
}
yylval.v.string = xstrdup(buf);
return (STRING);
@ -525,7 +486,7 @@ yylex(void)
if (c == '-' || isdigit(c)) {
do {
*p++ = c;
if ((size_t)(p-buf) >= sizeof(buf)) {
if ((unsigned)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
@ -548,8 +509,8 @@ yylex(void)
} else {
nodigits:
while (p > buf + 1)
lungetc((unsigned char)*--p);
c = (unsigned char)*--p;
lungetc(*--p);
c = *--p;
if (c == '-')
return (c);
}
@ -564,7 +525,7 @@ nodigits:
if (isalnum(c) || c == ':' || c == '_' || c == '*' || c == '/') {
do {
*p++ = c;
if ((size_t)(p-buf) >= sizeof(buf)) {
if ((unsigned)(p-buf) >= sizeof(buf)) {
yyerror("string too long");
return (findeol());
}
@ -585,13 +546,19 @@ nodigits:
}
struct file *
pushfile(const char *name, FILE *stream)
pushfile(const char *name)
{
struct file *nfile;
nfile = xcalloc(1, sizeof(struct file));
nfile->name = xstrdup(name);
nfile->stream = stream;
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
warn("%s", nfile->name);
free(nfile->name);
free(nfile);
return (NULL);
}
nfile->lineno = 1;
TAILQ_INSERT_TAIL(&files, nfile, entry);
return (nfile);
@ -616,19 +583,13 @@ popfile(void)
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);
if ((file = pushfile(filename)) == NULL) {
return (-1);
}
file = pushfile(filename, stream);
topfile = file;
yyparse();

648
queue.h Normal file
View File

@ -0,0 +1,648 @@
/* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST(head); \
(var) && ((tvar) = SLIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
\
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
_Q_INVALIDATE((elm)->field.sle_next); \
} \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST(head); \
(var) && ((tvar) = LIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SIMPLEQ_FIRST(head); \
(var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
== NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
/*
* XOR Simple queue definitions.
*/
#define XSIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqx_first; /* first element */ \
struct type **sqx_last; /* addr of last next element */ \
unsigned long sqx_cookie; \
}
#define XSIMPLEQ_ENTRY(type) \
struct { \
struct type *sqx_next; /* next element */ \
}
/*
* XOR Simple queue access methods.
*/
#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
(unsigned long)(ptr)))
#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
#define XSIMPLEQ_END(head) NULL
#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
#define XSIMPLEQ_FOREACH(var, head, field) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) != XSIMPLEQ_END(head); \
(var) = XSIMPLEQ_NEXT(head, var, field))
#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
(var) = (tvar))
/*
* XOR Simple queue functions.
*/
#define XSIMPLEQ_INIT(head) do { \
arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
(head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqx_next = (head)->sqx_first) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
(head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
(elm)->field.sqx_next)->field.sqx_next) \
== XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = \
XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_NEXT(var, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue access methods
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
#define CIRCLEQ_FOREACH(var, head, field) \
for((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_NEXT(var, field))
#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_NEXT(var, field), 1); \
(var) = (tvar))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for((var) = CIRCLEQ_LAST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_PREV(var, field))
#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = CIRCLEQ_LAST(head, headname); \
(var) != CIRCLEQ_END(head) && \
((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(head)->cqh_last = (elm2); \
else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \
(head)->cqh_first = (elm2); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#endif /* !_SYS_QUEUE_H_ */

38
reallocarray.c Normal file
View File

@ -0,0 +1,38 @@
/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
/*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*
* 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 <errno.h>
#include <stdint.h>
#include <stdlib.h>
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
void *
reallocarray(void *optr, size_t nmemb, size_t size)
{
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
errno = ENOMEM;
return NULL;
}
return realloc(optr, size * nmemb);
}

137
screen.c
View File

@ -19,12 +19,11 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -32,14 +31,13 @@
#include "calmwm.h"
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;
Window *wins, w0, w1, active = None;
XSetWindowAttributes rootattr;
unsigned int nwins, i;
sc = xmalloc(sizeof(*sc));
@ -49,8 +47,6 @@ screen_init(int which)
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;
@ -59,54 +55,43 @@ screen_init(int which)
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);
for (i = 0; i < Conf.ngroups; i++)
group_init(sc, i);
xu_ewmh_net_desktop_names(sc);
xu_ewmh_net_number_of_desktops(sc);
xu_ewmh_net_wm_desktop_viewport(sc);
xu_ewmh_net_wm_number_of_desktops(sc);
xu_ewmh_net_showing_desktop(sc);
xu_ewmh_net_virtual_roots(sc);
active = xu_ewmh_get_net_active_window(sc);
attr.cursor = Conf.cursor[CF_NORMAL];
attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask |
EnterWindowMask | PropertyChangeMask | ButtonPressMask;
XChangeWindowAttributes(X_Dpy, sc->rootwin, (CWEventMask | CWCursor), &attr);
rootattr.cursor = Conf.cursor[CF_NORMAL];
rootattr.event_mask = SubstructureRedirectMask |
SubstructureNotifyMask | PropertyChangeMask | EnterWindowMask |
LeaveWindowMask | ColormapChangeMask | BUTTONMASK;
XChangeWindowAttributes(X_Dpy, sc->rootwin,
(CWEventMask | CWCursor), &rootattr);
/* Deal with existing clients. */
if (XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) {
for (i = 0; i < nwins; i++)
(void)client_init(wins[i], sc, (active == wins[i]));
XFree(wins);
}
screen_updatestackingorder(sc);
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
screen_scan(struct screen_ctx *sc)
{
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_find(Window win)
{
@ -114,10 +99,10 @@ screen_find(Window win)
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->rootwin == win)
return sc;
return(sc);
}
warnx("%s: failure win 0x%lx", __func__, win);
return NULL;
warnx("%s: failure win 0x%lu\n", __func__, win);
return(NULL);
}
void
@ -151,25 +136,25 @@ region_find(struct screen_ctx *sc, int x, int y)
break;
}
}
return rc;
return(rc);
}
struct geom
screen_area(struct screen_ctx *sc, int x, int y, int apply_gap)
screen_area(struct screen_ctx *sc, int x, int y, enum apply_gap apply_gap)
{
struct region_ctx *rc;
struct geom area = sc->view;
struct geom area = sc->work;
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;
if ((x >= rc->area.x) && (x < (rc->area.x + rc->area.w)) &&
(y >= rc->area.y) && (y < (rc->area.y + rc->area.h))) {
area = rc->area;
break;
}
}
if (apply_gap)
area = screen_apply_gap(sc, area);
return area;
return(area);
}
void
@ -205,6 +190,10 @@ screen_update_geometry(struct screen_ctx *sc)
rc = xmalloc(sizeof(*rc));
rc->num = i;
rc->area.x = ci->x;
rc->area.y = ci->y;
rc->area.w = ci->width;
rc->area.h = ci->height;
rc->view.x = ci->x;
rc->view.y = ci->y;
rc->view.w = ci->width;
@ -227,11 +216,10 @@ screen_update_geometry(struct screen_ctx *sc)
}
xu_ewmh_net_desktop_geometry(sc);
xu_ewmh_net_desktop_viewport(sc);
xu_ewmh_net_workarea(sc);
}
static struct geom
struct geom
screen_apply_gap(struct screen_ctx *sc, struct geom geom)
{
geom.x += sc->gap.left;
@ -239,7 +227,7 @@ screen_apply_gap(struct screen_ctx *sc, struct geom geom)
geom.w -= (sc->gap.left + sc->gap.right);
geom.h -= (sc->gap.top + sc->gap.bottom);
return geom;
return(geom);
}
/* Bring back clients which are beyond the screen. */
@ -264,44 +252,3 @@ screen_assert_clients_within(struct screen_ctx *sc)
}
}
}
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);
XMapWindow(X_Dpy, sc->prop.win);
}
void
screen_prop_win_destroy(struct screen_ctx *sc)
{
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);
}

260
search.c
View File

@ -19,7 +19,7 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <err.h>
#include <errno.h>
@ -36,66 +36,40 @@
#define PATH_ANY 0x0001
#define PATH_EXEC 0x0002
static void match_path_type(struct menu_q *, char *, int);
static int match_substr(char *, char *, int);
static int
match_substr(char *sub, char *str, int zeroidx)
{
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;
}
static void search_match_path_type(struct menu_q *, struct menu_q *,
char *, int);
static int strsubmatch(char *, char *, int);
void
search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi, *tierp[3], *before = NULL;
struct client_ctx *cc;
struct winname *wn;
struct winname *wn;
struct menu *mi, *tierp[4], *before = NULL;
TAILQ_INIT(resultq);
(void)memset(tierp, 0, sizeof(tierp));
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry) {
int tier = -1, t;
cc = (struct client_ctx *)mi->ctx;
struct client_ctx *cc = (struct client_ctx *)mi->ctx;
/* Match on label. */
if (match_substr(search, cc->label, 0))
if (strsubmatch(search, cc->label, 0))
tier = 0;
/* Match on window name history, from present to past. */
if (tier < 0) {
TAILQ_FOREACH_REVERSE(wn, &cc->nameq, name_q, entry)
if (match_substr(search, wn->name, 0)) {
tier = 1;
if (strsubmatch(search, wn->name, 0)) {
tier = 2;
break;
}
}
/* Match on window resource class. */
if ((tier < 0) && match_substr(search, cc->res_class, 0))
tier = 2;
if ((tier < 0) && strsubmatch(search, cc->ch.res_class, 0))
tier = 3;
if (tier < 0)
continue;
@ -108,6 +82,9 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
if ((tier > 0) && (cc->flags & CLIENT_HIDDEN))
tier--;
if (tier >= nitems(tierp))
errx(1, "%s: invalid tier", __func__);
/*
* If you have a tierp, insert after it, and make it
* the new tierp. If you don't have a tierp, find the
@ -128,115 +105,27 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
}
void
search_match_cmd(struct menu_q *menuq, struct menu_q *resultq, char *search)
search_print_text(struct menu *mi, int listing)
{
struct menu *mi;
struct cmd_ctx *cmd;
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)snprintf(mi->print, sizeof(mi->print), "%s", mi->text);
}
void
search_match_group(struct menu_q *menuq, struct menu_q *resultq, char *search)
search_print_cmd(struct menu *mi, int listing)
{
struct menu *mi;
struct group_ctx *gc;
char *s;
struct cmd_ctx *cmd = (struct cmd_ctx *)mi->ctx;
TAILQ_INIT(resultq);
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)snprintf(mi->print, sizeof(mi->print), "%s", cmd->name);
}
void
search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
search_print_group(struct menu *mi, int listing)
{
struct menu *mi, *mj;
int r;
struct group_ctx *gc = (struct group_ctx *)mi->ctx;
TAILQ_INIT(resultq);
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_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
TAILQ_INIT(resultq);
match_path_type(resultq, search, PATH_ANY);
}
void
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct menu *mi;
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)snprintf(mi->print, sizeof(mi->print),
(group_holds_only_hidden(gc)) ? "%d: [%s]" : "%d: %s",
gc->num, gc->name);
}
void
@ -255,35 +144,100 @@ search_print_client(struct menu *mi, int listing)
(cc->label) ? cc->label : "", cc->name);
}
void
search_print_cmd(struct menu *mi, int listing)
static void
search_match_path_type(struct menu_q *menuq, struct menu_q *resultq,
char *search, int flag)
{
struct cmd_ctx *cmd = (struct cmd_ctx *)mi->ctx;
struct menu *mi;
char pattern[PATH_MAX];
glob_t g;
int i;
(void)snprintf(mi->print, sizeof(mi->print), "%s", cmd->name);
(void)strlcpy(pattern, search, sizeof(pattern));
(void)strlcat(pattern, "*", sizeof(pattern));
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);
}
void
search_print_group(struct menu *mi, int listing)
search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct group_ctx *gc = (struct group_ctx *)mi->ctx;
TAILQ_INIT(resultq);
(void)snprintf(mi->print, sizeof(mi->print),
(group_holds_only_hidden(gc)) ? "%d: [%s]" : "%d: %s",
gc->num, gc->name);
search_match_path_type(menuq, resultq, search, PATH_ANY);
}
void
search_print_text(struct menu *mi, int listing)
search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
(void)snprintf(mi->print, sizeof(mi->print), "%s", mi->text);
struct menu *mi;
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry)
if (strsubmatch(search, mi->text, 0))
TAILQ_INSERT_TAIL(resultq, mi, resultentry);
}
void
search_print_wm(struct menu *mi, int listing)
search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
{
struct cmd_ctx *wm = (struct cmd_ctx *)mi->ctx;
struct menu *mi, *mj;
int r;
(void)snprintf(mi->print, sizeof(mi->print), "%s [%s]",
wm->name, wm->path);
TAILQ_INIT(resultq);
TAILQ_FOREACH(mi, menuq, entry) {
if (strsubmatch(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))
search_match_path_type(menuq, resultq, search, PATH_EXEC);
}
static int
strsubmatch(char *sub, char *str, int zeroidx)
{
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 = len - sublen;
else
flen = 0;
for (n = 0; n <= flen; n++)
if (strncasecmp(sub, str + n, sublen) == 0)
return(1);
return(0);
}

62
strlcat.c Normal file
View File

@ -0,0 +1,62 @@
/* $OpenBSD: strlcat.c,v 1.14 2015/01/15 03:54:12 millert Exp $ */
/*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 ORIGINAL: lib/libc/string/strlcat.c */
#include <sys/types.h>
#include <string.h>
#include "calmwm.h"
#ifndef HAVE_STRLCAT
/*
* Appends src to string dst of size dsize (unlike strncat, dsize is the
* full size of dst, not space left). At most dsize-1 characters
* will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
* Returns strlen(src) + MIN(dsize, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
strlcat(char *dst, const char *src, size_t dsize)
{
const char *odst = dst;
const char *osrc = src;
size_t n = dsize;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end. */
while (n-- != 0 && *dst != '\0')
dst++;
dlen = dst - odst;
n = dsize - dlen;
if (n-- == 0)
return(dlen + strlen(src));
while (*src != '\0') {
if (n != 0) {
*dst++ = *src;
n--;
}
src++;
}
*dst = '\0';
return(dlen + (src - osrc)); /* count does not include NUL */
}
#endif /* !HAVE_STRLCAT */

57
strlcpy.c Normal file
View File

@ -0,0 +1,57 @@
/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */
/*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 ORIGINAL: lib/libc/string/strlcpy.c */
#include <sys/types.h>
#include <string.h>
#include "calmwm.h"
#ifndef HAVE_STRLCPY
/*
* Copy string src to buffer dst of size dsize. At most dsize-1
* chars will be copied. Always NUL terminates (unless dsize == 0).
* Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t dsize)
{
const char *osrc = src;
size_t nleft = dsize;
/* Copy as many bytes as will fit. */
if (nleft != 0) {
while (--nleft != 0) {
if ((*dst++ = *src++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src. */
if (nleft == 0) {
if (dsize != 0)
*dst = '\0'; /* NUL-terminate dst */
while (*src++)
;
}
return(src - osrc - 1); /* count does not include NUL */
}
#endif /* !HAVE_STRLCPY */

70
strtonum.c Normal file
View File

@ -0,0 +1,70 @@
/* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $ */
/*
* Copyright (c) 2004 Ted Unangst and Todd Miller
* 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.
*/
/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */
#ifndef HAVE_STRTONUM
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#define INVALID 1
#define TOOSMALL 2
#define TOOLARGE 3
long long
strtonum(const char *numstr, long long minval, long long maxval,
const char **errstrp)
{
long long ll = 0;
int error = 0;
char *ep;
struct errval {
const char *errstr;
int err;
} ev[4] = {
{ NULL, 0 },
{ "invalid", EINVAL },
{ "too small", ERANGE },
{ "too large", ERANGE },
};
ev[0].err = errno;
errno = 0;
if (minval > maxval) {
error = INVALID;
} else {
ll = strtoll(numstr, &ep, 10);
if (numstr == ep || *ep != '\0')
error = INVALID;
else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
error = TOOSMALL;
else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
error = TOOLARGE;
}
if (errstrp != NULL)
*errstrp = ev[error].errstr;
errno = ev[error].err;
if (error)
ll = 0;
return (ll);
}
#endif /* HAVE_STRTONUM */

2
update.sh Executable file
View File

@ -0,0 +1,2 @@
#GIT_MERGE_AUTOEDIT=no git cvsimport -o master -v -k -m -d anoncvs@openbsd.cs.fau.de:/cvs xenocara/app/cwm
GIT_MERGE_AUTOEDIT=no git cvsimport -o master -v -k -m -d anoncvs@mirror.osn.de:/cvs xenocara/app/cwm

48
util.c
View File

@ -19,12 +19,11 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -32,15 +31,13 @@
#include "calmwm.h"
static void log_msg(const char *, va_list);
void
u_spawn(char *argstr)
{
switch (fork()) {
case 0:
u_exec(argstr);
exit(1);
break;
case -1:
warn("fork");
default:
@ -53,7 +50,7 @@ u_exec(char *argstr)
{
#define MAXARGLEN 20
char *args[MAXARGLEN], **ap = args;
char **end = &args[MAXARGLEN - 2], *tmp;
char **end = &args[MAXARGLEN - 1], *tmp;
char *s = argstr;
while (ap < end && (*ap = strsep(&argstr, " \t")) != NULL) {
@ -81,7 +78,7 @@ u_exec(char *argstr)
(void)setsid();
(void)execvp(args[0], args);
warn("%s", s);
err(1, "%s", s);
}
char *
@ -92,12 +89,12 @@ u_argv(char * const *argv)
char *p;
if (argv == 0)
return NULL;
return(NULL);
for (i = 0; argv[i]; i++)
siz += strlen(argv[i]) + 1;
if (siz == 0)
return NULL;
return(NULL);
p = xmalloc(siz);
strlcpy(p, argv[0], siz);
@ -105,36 +102,5 @@ u_argv(char * const *argv)
strlcat(p, " ", siz);
strlcat(p, argv[i], siz);
}
return p;
}
static void
log_msg(const char *msg, va_list ap)
{
char *fmt;
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);
return(p);
}

165
xevents.c
View File

@ -25,7 +25,7 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <err.h>
#include <errno.h>
@ -69,28 +69,22 @@ void (*xev_handlers[LASTEvent])(XEvent *) = {
};
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 };
XK_Control_L, XK_Control_R };
static void
xev_handle_maprequest(XEvent *ee)
{
XMapRequestEvent *e = &ee->xmaprequest;
struct screen_ctx *sc;
struct client_ctx *cc, *old_cc;
struct client_ctx *cc = NULL, *old_cc;
LOG_DEBUG3("parent: 0x%lx window: 0x%lx", e->parent, e->window);
if ((sc = screen_find(e->parent)) == NULL)
return;
if ((old_cc = client_current(sc)) != NULL)
client_ptr_save(old_cc);
if ((old_cc = client_current()) != NULL)
client_ptrsave(old_cc);
if ((cc = client_find(e->window)) == NULL)
cc = client_init(e->window, NULL);
cc = client_init(e->window, NULL, 0);
if ((cc != NULL) && (!(cc->flags & CLIENT_IGNORE)))
client_ptr_warp(cc);
client_ptrwarp(cc);
}
static void
@ -99,14 +93,12 @@ xev_handle_unmapnotify(XEvent *ee)
XUnmapEvent *e = &ee->xunmap;
struct client_ctx *cc;
LOG_DEBUG3("window: 0x%lx", e->window);
if ((cc = client_find(e->window)) != NULL) {
if (e->send_event) {
xu_set_wm_state(cc->win, WithdrawnState);
client_set_wm_state(cc, WithdrawnState);
} else {
if (!(cc->flags & CLIENT_HIDDEN))
client_remove(cc);
client_delete(cc);
}
}
}
@ -117,10 +109,8 @@ xev_handle_destroynotify(XEvent *ee)
XDestroyWindowEvent *e = &ee->xdestroywindow;
struct client_ctx *cc;
LOG_DEBUG3("window: 0x%lx", e->window);
if ((cc = client_find(e->window)) != NULL)
client_remove(cc);
client_delete(cc);
}
static void
@ -131,8 +121,6 @@ xev_handle_configurerequest(XEvent *ee)
struct screen_ctx *sc;
XWindowChanges wc;
LOG_DEBUG3("window: 0x%lx", e->window);
if ((cc = client_find(e->window)) != NULL) {
sc = cc->sc;
@ -186,15 +174,13 @@ xev_handle_propertynotify(XEvent *ee)
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) {
case XA_WM_NORMAL_HINTS:
client_get_sizehints(cc);
client_getsizehints(cc);
break;
case XA_WM_NAME:
client_set_name(cc);
client_setname(cc);
break;
case XA_WM_HINTS:
client_wm_hints(cc);
@ -202,19 +188,17 @@ xev_handle_propertynotify(XEvent *ee)
break;
case XA_WM_TRANSIENT_FOR:
client_transient(cc);
client_draw_border(cc);
if (cc->gc)
group_movetogroup(cc, cc->gc->num);
break;
default:
if (e->atom == ewmh[_NET_WM_NAME])
client_set_name(cc);
/* do nothing */
break;
}
} else {
if (e->atom == ewmh[_NET_DESKTOP_NAMES]) {
if ((sc = screen_find(e->window)) != NULL)
xu_ewmh_net_desktop_names(sc);
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->rootwin == e->window) {
if (e->atom == ewmh[_NET_DESKTOP_NAMES])
xu_ewmh_net_desktop_names(sc);
}
}
}
}
@ -225,12 +209,10 @@ xev_handle_enternotify(XEvent *ee)
XCrossingEvent *e = &ee->xcrossing;
struct client_ctx *cc;
LOG_DEBUG3("window: 0x%lx", e->window);
Last_Event_Time = e->time;
if ((cc = client_find(e->window)) != NULL)
client_set_active(cc);
client_setactive(cc);
}
static void
@ -241,29 +223,28 @@ xev_handle_buttonpress(XEvent *ee)
struct screen_ctx *sc;
struct bind_ctx *mb;
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;
e->state &= ~IGNOREMODMASK;
TAILQ_FOREACH(mb, &Conf.mousebindq, entry) {
if (e->button == mb->press.button && e->state == mb->modmask)
break;
}
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))
(cc = client_current()) == NULL)
return;
(*mb->callback)(cc, mb->cargs);
break;
case CWM_CONTEXT_SC:
if (e->window != e->root)
return;
if ((sc = screen_find(e->window)) == NULL)
return;
(*mb->callback)(sc, mb->cargs);
break;
case CWM_CONTEXT_NONE:
@ -278,14 +259,9 @@ xev_handle_buttonrelease(XEvent *ee)
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc;
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);
}
if (cc->flags & CLIENT_ACTIVE)
group_toggle_membership_leave(cc);
}
}
@ -299,12 +275,6 @@ xev_handle_keypress(XEvent *ee)
KeySym keysym, skeysym;
unsigned int modshift;
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);
@ -322,17 +292,20 @@ xev_handle_keypress(XEvent *ee)
if (kb->press.keysym == ((modshift == 0) ? keysym : skeysym))
break;
}
if (kb == NULL)
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))
if (((cc = client_find(e->window)) == NULL) &&
(cc = client_current()) == NULL)
return;
(*kb->callback)(cc, kb->cargs);
break;
case CWM_CONTEXT_SC:
if ((sc = screen_find(e->window)) == NULL)
return;
(*kb->callback)(sc, kb->cargs);
break;
case CWM_CONTEXT_NONE:
@ -349,30 +322,16 @@ xev_handle_keyrelease(XEvent *ee)
{
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc;
struct client_ctx *cc;
KeySym keysym;
unsigned int i;
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);
client_cycle_leave(sc);
break;
}
}
@ -385,8 +344,6 @@ xev_handle_clientmessage(XEvent *ee)
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)
@ -394,14 +351,17 @@ xev_handle_clientmessage(XEvent *ee)
}
} else if (e->message_type == ewmh[_NET_CLOSE_WINDOW]) {
if ((cc = client_find(e->window)) != NULL) {
client_close(cc);
client_send_delete(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);
if ((old_cc = client_current()) != NULL)
client_ptrsave(old_cc);
if (cc->flags & CLIENT_HIDDEN)
client_unhide(cc);
else
client_raise(cc);
client_ptrwarp(cc);
}
} else if (e->message_type == ewmh[_NET_WM_DESKTOP]) {
if ((cc = client_find(e->window)) != NULL) {
@ -413,9 +373,7 @@ xev_handle_clientmessage(XEvent *ee)
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]);
group_movetogroup(cc, e->data.l[0]);
}
} else if (e->message_type == ewmh[_NET_WM_STATE]) {
if ((cc = client_find(e->window)) != NULL) {
@ -424,9 +382,7 @@ xev_handle_clientmessage(XEvent *ee)
}
} 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]);
group_only(sc, e->data.l[0]);
}
}
}
@ -434,17 +390,18 @@ xev_handle_clientmessage(XEvent *ee)
static void
xev_handle_randr(XEvent *ee)
{
XRRScreenChangeNotifyEvent *e = (XRRScreenChangeNotifyEvent *)ee;
XRRScreenChangeNotifyEvent *rev = (XRRScreenChangeNotifyEvent *)ee;
struct screen_ctx *sc;
int i;
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);
i = XRRRootToScreen(X_Dpy, rev->root);
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->which == i) {
XRRUpdateConfiguration(ee);
screen_update_geometry(sc);
screen_assert_clients_within(sc);
}
}
}
/*
@ -457,8 +414,6 @@ 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)
@ -472,8 +427,6 @@ 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);
}
@ -483,11 +436,9 @@ xev_process(void)
{
XEvent e;
while (XPending(X_Dpy)) {
XNextEvent(X_Dpy, &e);
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);
}
XNextEvent(X_Dpy, &e);
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);
}

View File

@ -19,7 +19,7 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <err.h>
#include <errno.h>
@ -43,7 +43,7 @@ xmalloc(size_t siz)
if ((p = malloc(siz)) == NULL)
err(1, "malloc");
return p;
return(p);
}
void *
@ -58,7 +58,7 @@ xcalloc(size_t no, size_t siz)
if ((p = calloc(no, siz)) == NULL)
err(1, "calloc");
return p;
return(p);
}
void *
@ -70,7 +70,7 @@ xreallocarray(void *ptr, size_t nmemb, size_t size)
if (p == NULL)
errx(1, "xreallocarray: out of memory (new_size %zu bytes)",
nmemb * size);
return p;
return(p);
}
char *
@ -81,7 +81,7 @@ xstrdup(const char *str)
if ((p = strdup(str)) == NULL)
err(1, "strdup");
return p;
return(p);
}
int
@ -91,20 +91,11 @@ xasprintf(char **ret, const char *fmt, ...)
int i;
va_start(ap, fmt);
i = xvasprintf(ret, fmt, ap);
i = vasprintf(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;
if (i < 0 || *ret == NULL)
err(1, "asprintf");
return(i);
}

212
xutil.c
View File

@ -19,7 +19,7 @@
*/
#include <sys/types.h>
#include <sys/queue.h>
#include "queue.h"
#include <err.h>
#include <errno.h>
@ -32,7 +32,7 @@
#include "calmwm.h"
void
xu_ptr_get(Window win, int *x, int *y)
xu_ptr_getpos(Window win, int *x, int *y)
{
Window w0, w1;
int tmp0, tmp1;
@ -42,13 +42,13 @@ xu_ptr_get(Window win, int *x, int *y)
}
void
xu_ptr_set(Window win, int x, int y)
xu_ptr_setpos(Window win, int x, int y)
{
XWarpPointer(X_Dpy, None, win, 0, 0, 0, 0, x, y);
}
int
xu_get_prop(Window win, Atom atm, Atom type, long len, unsigned char **p)
xu_getprop(Window win, Atom atm, Atom type, long len, unsigned char **p)
{
Atom realtype;
unsigned long n, extra;
@ -56,16 +56,16 @@ xu_get_prop(Window win, Atom atm, Atom type, long len, unsigned char **p)
if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,
&realtype, &format, &n, &extra, p) != Success || *p == NULL)
return -1;
return(-1);
if (n == 0)
XFree(*p);
return n;
return(n);
}
int
xu_get_strprop(Window win, Atom atm, char **text) {
xu_getstrprop(Window win, Atom atm, char **text) {
XTextProperty prop;
char **list;
int nitems = 0;
@ -73,10 +73,8 @@ xu_get_strprop(Window win, Atom atm, char **text) {
*text = NULL;
XGetTextProperty(X_Dpy, win, &prop, atm);
if (!prop.nitems) {
XFree(prop.value);
return 0;
}
if (!prop.nitems)
return(0);
if (Xutf8TextPropertyToTextList(X_Dpy, &prop, &list,
&nitems) == Success && nitems > 0 && *list) {
@ -92,101 +90,10 @@ xu_get_strprop(Window win, Atom atm, char **text) {
}
XFreeStringList(list);
}
XFree(prop.value);
return nitems;
}
void
xu_send_clientmsg(Window win, Atom proto, Time ts)
{
XClientMessageEvent cm;
(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;
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);
return(nitems);
}
/* Root Window Properties */
@ -221,16 +128,6 @@ xu_ewmh_net_desktop_geometry(struct screen_ctx *sc)
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)
{
@ -298,8 +195,34 @@ xu_ewmh_net_active_window(struct screen_ctx *sc, Window w)
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
}
Window
xu_ewmh_get_net_active_window(struct screen_ctx *sc)
{
long *p;
Window win;
if ((xu_getprop(sc->rootwin, ewmh[_NET_ACTIVE_WINDOW],
XA_WINDOW, 32, (unsigned char **)&p)) <= 0)
return(None);
win = (Window)*p;
XFree(p);
return(win);
}
void
xu_ewmh_net_number_of_desktops(struct screen_ctx *sc)
xu_ewmh_net_wm_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_wm_number_of_desktops(struct screen_ctx *sc)
{
long ndesks = Conf.ngroups;
@ -347,7 +270,7 @@ xu_ewmh_net_desktop_names(struct screen_ctx *sc)
/* Let group names be overwritten if _NET_DESKTOP_NAMES is set. */
if ((j = xu_get_prop(sc->rootwin, ewmh[_NET_DESKTOP_NAMES],
if ((j = xu_getprop(sc->rootwin, ewmh[_NET_DESKTOP_NAMES],
cwmh[UTF8_STRING], 0xffffff, (unsigned char **)&prop_ret)) > 0) {
prop_ret[j - 1] = '\0'; /* paranoia */
while (i < j) {
@ -389,21 +312,8 @@ xu_ewmh_net_desktop_names(struct screen_ctx *sc)
}
/* 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)
xu_ewmh_net_wm_desktop(struct client_ctx *cc)
{
long num = 0xffffffff;
@ -419,15 +329,15 @@ 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,
if ((*n = xu_getprop(cc->win, ewmh[_NET_WM_STATE], XA_ATOM, 64L,
(unsigned char **)&p)) <= 0)
return NULL;
return(NULL);
state = xreallocarray(NULL, *n, sizeof(Atom));
(void)memcpy(state, p, *n * sizeof(Atom));
XFree((char *)p);
return state;
return(state);
}
void
@ -435,9 +345,9 @@ 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;
static struct handlers {
int atom;
int property;
void (*toggle)(struct client_ctx *);
} handlers[] = {
{ _NET_WM_STATE_STICKY,
@ -458,12 +368,6 @@ xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action,
{ _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 },
@ -475,11 +379,11 @@ xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action,
continue;
switch (action) {
case _NET_WM_STATE_ADD:
if (!(cc->flags & handlers[i].flag))
if (!(cc->flags & handlers[i].property))
handlers[i].toggle(cc);
break;
case _NET_WM_STATE_REMOVE:
if (cc->flags & handlers[i].flag)
if (cc->flags & handlers[i].property)
handlers[i].toggle(cc);
break;
case _NET_WM_STATE_TOGGLE:
@ -508,10 +412,6 @@ xu_ewmh_restore_net_wm_state(struct client_ctx *cc)
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);
}
@ -533,8 +433,6 @@ xu_ewmh_set_net_wm_state(struct client_ctx *cc)
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];
}
@ -553,10 +451,6 @@ xu_ewmh_set_net_wm_state(struct client_ctx *cc)
}
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)
@ -566,3 +460,13 @@ xu_ewmh_set_net_wm_state(struct client_ctx *cc)
XDeleteProperty(X_Dpy, cc->win, ewmh[_NET_WM_STATE]);
free(atoms);
}
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;
}