48 Commits
v6.3 ... v6.6

Author SHA1 Message Date
669e3406ec README: update 2020-01-04 21:45:17 +01:00
f2a2839cec Makefile: use gpg2 2020-01-04 21:45:05 +01:00
4154b9b194 cvsimport
* refs/heads/master:
  Because cwm warps the pointer during a client move (to stay within the client), there's a window of time where an expose or enternotify event will get generated for a lower client; use a hammer and drain events after keyboard move/resize, until such a time that cwm doesn't warp the pointer.  Behavior noticed by kn.
  Fix regression from r1.107 (lost a return); kettenis@ pointed out the high potential for a use-after-free (true!) where kn@ ran into the regression using an app that actually exercised the XGrabPointer() failure path.
  Add application section
  command uses execvp(3) not execve(2)
  Plug a memory leak in log_debug(); OK okan@
  Handle _NET_WM_NAME changes.
2019-08-13 18:45:38 +00:00
781af9c998 Because cwm warps the pointer during a client move (to stay within the client),
there's a window of time where an expose or enternotify event will get
generated for a lower client; use a hammer and drain events after keyboard
move/resize, until such a time that cwm doesn't warp the pointer.  Behavior
noticed by kn.

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

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

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

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

Window offset noticed by at least Andre Stoebe via bugs@, and others since
(and likely before). Thanks!
2018-11-08 15:49:42 +00:00
b4d4eba6af cvsimport
* refs/heads/master:
  Remove unused prototype; from Ross L Richardson.
2018-07-16 14:19:23 +00:00
9999c3e6e0 Remove unused prototype; from Ross L Richardson. 2018-07-16 14:19:23 +00:00
16 changed files with 463 additions and 348 deletions

View File

@ -48,6 +48,6 @@ release:
sign:
VERSION=$$(git describe --tags | sed 's/^v//;s/-[^.]*$$//') && \
gpg --armor --detach-sign cwm-$$VERSION.tar.gz && \
gpg2 --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

15
README
View File

@ -1,5 +1,4 @@
This is a port of OpenBSD's excellent cwm[0] to Linux and other
Unices.
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
@ -13,8 +12,8 @@ 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
The revision controlled version is at https://github.com/leahneukirchen/cwm
Releases can be found at http://leahneukirchen.org/releases
You are welcome to join the IRC channel ##cwm on Freenode to talk about cwm.
@ -115,6 +114,14 @@ Changes made between OpenBSD 6.2 and 6.3
2018-05-14: Fifth public release 6.3 of portable cwm.
2020-01-04: Sixth public release 6.6 of portable cwm.
Changes made between OpenBSD 6.4 and 6.5
* Added a configtest flag (-n) to cwm(1).
* Introduced 'group-close-[n]' action to cwm(1) to close all windows
within a specified group.
--Leah Neukirchen <leah@vuxu.org>
[0]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/xenocara/app/cwm/

View File

@ -55,7 +55,7 @@ main(int argc, char **argv)
{
char *display_name = NULL;
char *fallback;
int ch, xfd;
int ch, xfd, nflag = 0;
struct pollfd pfd[1];
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
@ -66,7 +66,7 @@ main(int argc, char **argv)
fallback = u_argv(argv);
Conf.wm_argv = u_argv(argv);
while ((ch = getopt(argc, argv, "c:d:v")) != -1) {
while ((ch = getopt(argc, argv, "c:d:nv")) != -1) {
switch (ch) {
case 'c':
free(Conf.conf_file);
@ -75,6 +75,9 @@ main(int argc, char **argv)
case 'd':
display_name = optarg;
break;
case 'n':
nflag = 1;
break;
case 'v':
Conf.debug++;
break;
@ -90,8 +93,13 @@ main(int argc, char **argv)
if (signal(SIGHUP, sighdlr) == SIG_ERR)
err(1, "signal");
if (parse_config(Conf.conf_file, &Conf) == -1)
if (parse_config(Conf.conf_file, &Conf) == -1) {
warnx("error parsing config file");
if (nflag)
return 1;
}
if (nflag)
return 0;
xfd = x_init(display_name);
cwm_status = CWM_RUNNING;
@ -159,8 +167,6 @@ 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);
@ -221,7 +227,7 @@ usage(void)
{
extern char *__progname;
(void)fprintf(stderr, "usage: %s [-v] [-c file] [-d display]\n",
(void)fprintf(stderr, "usage: %s [-nv] [-c file] [-d display]\n",
__progname);
exit(1);
}

View File

@ -68,9 +68,6 @@ size_t strlcpy(char *, const char *, size_t);
#define BUTTONMASK (ButtonPressMask | ButtonReleaseMask)
#define MOUSEMASK (BUTTONMASK | PointerMotionMask)
#define MENUMASK (MOUSEMASK | ButtonMotionMask | KeyPressMask | \
ExposureMask)
#define MENUGRABMASK (MOUSEMASK | ButtonMotionMask | StructureNotifyMask)
#define IGNOREMODMASK (LockMask | Mod2Mask | 0x2000)
/* direction/amount */
@ -145,12 +142,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 */
@ -210,7 +207,6 @@ struct group_ctx {
struct screen_ctx *sc;
char *name;
int num;
struct client_q clientq;
};
TAILQ_HEAD(group_q, group_ctx);
@ -249,7 +245,7 @@ struct screen_ctx {
struct {
Window win;
XftDraw *xftdraw;
} menu;
} prop;
XftColor xftcolor[CWM_COLOR_NITEMS];
XftFont *xftfont;
};
@ -419,9 +415,9 @@ void usage(void);
void client_applysizehints(struct client_ctx *);
void client_config(struct client_ctx *);
struct client_ctx *client_current(void);
struct client_ctx *client_current(struct screen_ctx *);
void client_cycle(struct screen_ctx *, int);
void client_delete(struct client_ctx *);
void client_remove(struct client_ctx *);
void client_draw_border(struct client_ctx *);
struct client_ctx *client_find(Window);
long client_get_wm_state(struct client_ctx *);
@ -429,7 +425,6 @@ void client_getsizehints(struct client_ctx *);
void client_hide(struct client_ctx *);
void client_htile(struct client_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 *);
@ -440,7 +435,7 @@ void client_ptrsave(struct client_ctx *);
void client_ptrwarp(struct client_ctx *);
void client_raise(struct client_ctx *);
void client_resize(struct client_ctx *, int);
void client_send_delete(struct client_ctx *);
void client_close(struct client_ctx *);
void client_set_wm_state(struct client_ctx *, long);
void client_setactive(struct client_ctx *);
void client_setname(struct client_ctx *);
@ -456,24 +451,24 @@ 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);
void group_init(struct screen_ctx *, int, const char *);
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_update_names(struct screen_ctx *);
@ -505,13 +500,19 @@ void screen_init(int);
void screen_update_geometry(struct screen_ctx *);
void screen_updatestackingorder(struct screen_ctx *);
void screen_assert_clients_within(struct screen_ctx *);
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 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_delete(void *, struct cargs *);
void kbfunc_client_close(void *, struct cargs *);
void kbfunc_client_lower(void *, struct cargs *);
void kbfunc_client_raise(void *, struct cargs *);
void kbfunc_client_hide(void *, struct cargs *);
@ -529,8 +530,9 @@ 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_close(void *, struct cargs *);
void kbfunc_group_cycle(void *, struct cargs *);
void kbfunc_group_alltoggle(void *, struct cargs *);
void kbfunc_group_toggle_all(void *, struct cargs *);
void kbfunc_menu_client(void *, struct cargs *);
void kbfunc_menu_cmd(void *, struct cargs *);
void kbfunc_menu_group(void *, struct cargs *);
@ -542,10 +544,6 @@ 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 *, ...)
__attribute__((__format__ (printf, 3, 4)))
__attribute__((__nonnull__ (3)));
struct menu *menu_filter(struct screen_ctx *, struct menu_q *,
const char *, const char *, int,
void (*)(struct menu_q *, struct menu_q *, char *),
@ -575,6 +573,7 @@ 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);
@ -587,13 +586,13 @@ void xu_xorcolor(XftColor, XftColor, XftColor *);
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);
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_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 *);

166
client.c
View File

@ -62,10 +62,9 @@ client_init(Window win, struct screen_ctx *sc, int active)
mapped = wattr.map_state != IsUnmapped;
}
cc = xmalloc(sizeof(*cc));
XGrabServer(X_Dpy);
cc = xmalloc(sizeof(*cc));
cc->sc = sc;
cc->win = win;
cc->label = NULL;
@ -74,29 +73,33 @@ client_init(Window win, struct screen_ctx *sc, int active)
cc->stackingorder = 0;
memset(&cc->hint, 0, sizeof(cc->hint));
memset(&cc->ch, 0, sizeof(cc->ch));
TAILQ_INIT(&cc->nameq);
client_setname(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_setname(cc);
conf_client(cc);
XGetClassHint(X_Dpy, cc->win, &cc->ch);
client_wm_hints(cc);
client_wm_protocols(cc);
client_getsizehints(cc);
client_transient(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;
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_placecalc(cc);
client_resize(cc, 0);
@ -113,8 +116,6 @@ client_init(Window win, struct screen_ctx *sc, int active)
XAddToSaveSet(X_Dpy, cc->win);
client_transient(cc);
/* Notify client of its configuration. */
client_config(cc);
@ -127,9 +128,13 @@ client_init(Window win, struct screen_ctx *sc, int active)
if (client_get_wm_state(cc) == IconicState)
client_hide(cc);
else
client_unhide(cc);
client_show(cc);
if (mapped) {
if (cc->gc) {
group_movetogroup(cc, cc->gc->num);
goto out;
}
if (group_restore(cc))
goto out;
if (group_autogroup(cc))
@ -165,7 +170,7 @@ client_find(Window win)
}
void
client_delete(struct client_ctx *cc)
client_remove(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct winname *wn;
@ -178,9 +183,6 @@ client_delete(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);
@ -216,7 +218,7 @@ client_setactive(struct client_ctx *cc)
if (cc->flags & CLIENT_WM_TAKE_FOCUS)
client_msg(cc, cwmh[WM_TAKE_FOCUS], Last_Event_Time);
if ((oldcc = client_current()) != NULL) {
if ((oldcc = client_current(sc)) != NULL) {
oldcc->flags &= ~CLIENT_ACTIVE;
client_draw_border(oldcc);
}
@ -233,16 +235,23 @@ client_setactive(struct client_ctx *cc)
}
struct client_ctx *
client_current(void)
client_current(struct screen_ctx *sc)
{
struct screen_ctx *sc;
struct screen_ctx *_sc;
struct client_ctx *cc;
TAILQ_FOREACH(sc, &Screenq, entry) {
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);
}
@ -522,25 +531,16 @@ client_hide(struct client_ctx *cc)
{
XUnmapWindow(X_Dpy, cc->win);
if (cc->flags & CLIENT_ACTIVE)
if (cc->flags & CLIENT_ACTIVE) {
cc->flags &= ~CLIENT_ACTIVE;
xu_ewmh_net_active_window(cc->sc, None);
cc->flags &= ~CLIENT_ACTIVE;
}
cc->flags |= CLIENT_HIDDEN;
client_set_wm_state(cc, IconicState);
}
void
client_show(struct client_ctx *cc)
{
if (cc->flags & CLIENT_HIDDEN)
client_unhide(cc);
else
client_raise(cc);
}
void
client_unhide(struct client_ctx *cc)
{
XMapRaised(X_Dpy, cc->win);
@ -631,7 +631,7 @@ client_msg(struct client_ctx *cc, Atom proto, Time ts)
}
void
client_send_delete(struct client_ctx *cc)
client_close(struct client_ctx *cc)
{
if (cc->flags & CLIENT_WM_DELETE_WINDOW)
client_msg(cc, cwmh[WM_DELETE_WINDOW], CurrentTime);
@ -686,7 +686,7 @@ client_cycle(struct screen_ctx *sc, int flags)
return;
prevcc = TAILQ_FIRST(&sc->clientq);
oldcc = client_current();
oldcc = client_current(sc);
if (oldcc == NULL)
oldcc = (flags & CWM_CYCLE_REVERSE) ?
TAILQ_LAST(&sc->clientq, client_q) :
@ -749,7 +749,6 @@ 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)
@ -760,34 +759,36 @@ client_placecalc(struct client_ctx *cc)
cc->geom.x = sc->view.h - 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;
struct geom area;
int xmouse, ymouse, xslack, yslack;
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(xmouse, area.x);
ymouse = MAX(ymouse, area.y);
xmouse = MAX(MAX(xmouse, area.x) - cc->geom.w / 2, area.x);
ymouse = MAX(MAX(ymouse, area.y) - cc->geom.h / 2, area.y);
xslack = area.w - cc->geom.w - cc->bwidth * 2;
yslack = area.h - cc->geom.h - cc->bwidth * 2;
xslack = area.x + area.w - cc->geom.w - cc->bwidth * 2;
yslack = area.y + 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.w;
cc->geom.w = area.x + 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.h;
cc->geom.h = area.y + area.h;
}
}
}
@ -919,10 +920,11 @@ client_transient(struct client_ctx *cc)
Window trans;
if (XGetTransientForHint(X_Dpy, cc->win, &trans)) {
if ((tc = client_find(trans)) != NULL && tc->gc) {
group_movetogroup(cc, tc->gc->num);
if (tc->flags & CLIENT_IGNORE)
if ((tc = client_find(trans)) != NULL) {
if (tc->flags & CLIENT_IGNORE) {
cc->flags |= CLIENT_IGNORE;
cc->bwidth = tc->bwidth;
}
}
}
}
@ -965,28 +967,33 @@ 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)
if (!cc->gc)
return;
i = n = 0;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, CWM_GAP);
TAILQ_FOREACH(ci, &sc->clientq, entry) {
if (ci->gc != cc->gc)
continue;
if (ci->flags & CLIENT_HIDDEN ||
ci->flags & CLIENT_IGNORE || (ci == cc))
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))
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;
@ -1003,9 +1010,15 @@ client_htile(struct client_ctx *cc)
x = area.x;
w = area.w / n;
h = area.h - mh;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
TAILQ_FOREACH(ci, &sc->clientq, entry) {
if (ci->gc != cc->gc)
continue;
if (ci->flags & CLIENT_HIDDEN ||
ci->flags & CLIENT_IGNORE || (ci == cc))
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))
continue;
ci->bwidth = Conf.bwidth;
ci->geom.x = x;
@ -1025,28 +1038,33 @@ 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)
if (!cc->gc)
return;
i = n = 0;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
area = screen_area(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2, CWM_GAP);
TAILQ_FOREACH(ci, &sc->clientq, entry) {
if (ci->gc != cc->gc)
continue;
if (ci->flags & CLIENT_HIDDEN ||
ci->flags & CLIENT_IGNORE || (ci == cc))
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))
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;
@ -1063,9 +1081,15 @@ client_vtile(struct client_ctx *cc)
y = area.y;
h = area.h / n;
w = area.w - mw;
TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
TAILQ_FOREACH(ci, &sc->clientq, entry) {
if (ci->gc != cc->gc)
continue;
if (ci->flags & CLIENT_HIDDEN ||
ci->flags & CLIENT_IGNORE || (ci == cc))
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))
continue;
ci->bwidth = Conf.bwidth;
ci->geom.x = area.x + mw;

67
conf.c
View File

@ -20,7 +20,6 @@
#include <sys/types.h>
#include "queue.h"
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
@ -37,6 +36,21 @@ static const char *conf_bind_getmask(const char *, unsigned int *);
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 */
@ -68,7 +82,8 @@ static const struct {
{ FUNC_CC(window-lower, client_lower, 0) },
{ FUNC_CC(window-raise, client_raise, 0) },
{ FUNC_CC(window-hide, client_hide, 0) },
{ FUNC_CC(window-delete, client_delete, 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) },
@ -124,7 +139,7 @@ static const struct {
{ FUNC_SC(group-cycle, group_cycle, (CWM_CYCLE_FORWARD)) },
{ FUNC_SC(group-rcycle, group_cycle, (CWM_CYCLE_REVERSE)) },
{ FUNC_SC(group-toggle-all, group_alltoggle, 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) },
@ -143,6 +158,15 @@ static const struct {
{ 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) },
{ FUNC_SC(pointer-move-up, ptrmove, (CWM_UP)) },
{ FUNC_SC(pointer-move-down, ptrmove, (CWM_DOWN)) },
@ -195,7 +219,7 @@ static const struct {
{ "M-Tab", "window-cycle" },
{ "MS-Tab", "window-rcycle" },
{ "CM-n", "window-menu-label" },
{ "CM-x", "window-delete" },
{ "CM-x", "window-close" },
{ "CM-a", "group-toggle-all" },
{ "CM-0", "group-toggle-all" },
{ "CM-1", "group-toggle-1" },
@ -257,7 +281,7 @@ conf_init(struct conf *c)
c->bwidth = 1;
c->mamount = 1;
c->snapdist = 0;
c->ngroups = 10;
c->ngroups = 0;
c->nameqlen = 5;
TAILQ_INIT(&c->ignoreq);
@ -434,16 +458,13 @@ 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) {
ignore = 1;
cc->flags |= CLIENT_IGNORE;
break;
}
}
cc->bwidth = (ignore) ? 0 : Conf.bwidth;
cc->flags |= (ignore) ? CLIENT_IGNORE : 0;
}
void
@ -472,30 +493,28 @@ conf_screen(struct screen_ctx *sc)
warnx("XftColorAllocValue: %s", Conf.color[i]);
break;
}
if (XftColorAllocName(X_Dpy, sc->visual, sc->colormap,
Conf.color[i], &xc)) {
sc->xftcolor[i] = xc;
XftColorFree(X_Dpy, sc->visual, sc->colormap, &xc);
} else {
if (!XftColorAllocName(X_Dpy, sc->visual, sc->colormap,
Conf.color[i], &sc->xftcolor[i])) {
warnx("XftColorAllocName: %s", Conf.color[i]);
XftColorAllocName(X_Dpy, sc->visual, sc->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,
sc->visual, sc->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_getmask(const char *name, unsigned int *mask)
{

15
cwm.1
View File

@ -23,7 +23,7 @@
.Sh SYNOPSIS
.\" For a program: program [-abc] file ...
.Nm cwm
.Op Fl v
.Op Fl nv
.Op Fl c Ar file
.Op Fl d Ar display
.Sh DESCRIPTION
@ -48,6 +48,9 @@ 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
@ -100,7 +103,7 @@ Cycle through currently visible windows.
.It Ic MS-Tab
Reverse cycle through currently visible windows.
.It Ic CM-x
Delete current window.
Close current window.
.It Ic CM-[n]
Toggle visibility of group n, where n is 1-9.
.It Ic CM-a
@ -216,6 +219,11 @@ 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
@ -239,8 +247,7 @@ 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
.Pa ~/.cwmrc .
Show list of applications as defined in the configuration file.
Selecting an item will spawn that application.
.El
.Sh ENVIRONMENT

View File

@ -173,7 +173,7 @@ entry is shown in the application menu.
When selected, the defined
.Ar path
is executed with
.Xr execve 2 .
.Xr execvp 3 .
.Pp
The
.Ar name
@ -288,6 +288,8 @@ 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-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
@ -306,8 +308,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-delete
Delete current window.
.It window-close
Close current window.
.It window-hide
Hide current window.
.It window-lower

163
group.c
View File

@ -37,37 +37,30 @@ static struct group_ctx *group_prev(struct group_ctx *);
static void group_restack(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;
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, &gc->clientq, group_entry) {
if (!(cc->flags & CLIENT_STICKY))
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (!(cc->flags & CLIENT_STICKY) &&
!(cc->flags & CLIENT_HIDDEN))
client_hide(cc);
}
}
@ -75,13 +68,16 @@ 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, &gc->clientq, group_entry) {
if (!(cc->flags & CLIENT_STICKY))
client_unhide(cc);
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (!(cc->flags & CLIENT_STICKY) &&
(cc->flags & CLIENT_HIDDEN))
client_show(cc);
}
group_restack(gc);
group_setactive(gc);
}
@ -89,19 +85,24 @@ group_show(struct group_ctx *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, &gc->clientq, group_entry) {
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (cc->stackingorder > highstack)
highstack = cc->stackingorder;
}
winlist = xreallocarray(NULL, (highstack + 1), sizeof(*winlist));
/* Invert the stacking order for XRestackWindows(). */
TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
winlist[highstack - cc->stackingorder] = cc->win;
nwins++;
}
@ -122,16 +123,14 @@ group_restack(struct group_ctx *gc)
}
void
group_init(struct screen_ctx *sc, int num)
group_init(struct screen_ctx *sc, int num, const char *name)
{
struct group_ctx *gc;
gc = xmalloc(sizeof(*gc));
gc->sc = sc;
gc->name = xstrdup(num_to_name[num]);
gc->name = xstrdup(name);
gc->num = num;
TAILQ_INIT(&gc->clientq);
TAILQ_INSERT_TAIL(&sc->groupq, gc, entry);
if (num == 1)
@ -154,19 +153,15 @@ group_movetogroup(struct client_ctx *cc, int idx)
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
if (idx < 0 || idx >= Conf.ngroups)
return;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == idx)
break;
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 (cc->gc == gc)
return;
if (gc->num != 0 && group_holds_only_hidden(gc))
client_hide(cc);
group_assign(gc, cc);
}
void
@ -175,23 +170,25 @@ group_toggle_membership(struct client_ctx *cc)
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc = sc->group_active;
if (gc == cc->gc) {
if (cc->gc == gc) {
group_assign(NULL, cc);
cc->flags |= CLIENT_UNGROUP;
} else {
group_assign(gc, cc);
cc->flags |= CLIENT_GROUP;
}
client_draw_border(cc);
}
int
group_holds_only_sticky(struct group_ctx *gc)
{
struct screen_ctx *sc = gc->sc;
struct client_ctx *cc;
TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (!(cc->flags & CLIENT_STICKY))
return(0);
}
@ -201,46 +198,23 @@ group_holds_only_sticky(struct group_ctx *gc)
int
group_holds_only_hidden(struct group_ctx *gc)
{
struct screen_ctx *sc = gc->sc;
struct client_ctx *cc;
TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
TAILQ_FOREACH(cc, &sc->clientq, entry) {
if (cc->gc != gc)
continue;
if (!(cc->flags & (CLIENT_HIDDEN | CLIENT_STICKY)))
return(0);
}
return(1);
}
void
group_hidetoggle(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
if (idx < 0 || idx >= Conf.ngroups)
return;
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);
}
}
void
group_only(struct screen_ctx *sc, int idx)
{
struct group_ctx *gc;
if (idx < 0 || idx >= Conf.ngroups)
return;
TAILQ_FOREACH(gc, &sc->groupq, entry) {
if (gc->num == idx)
group_show(gc);
@ -249,6 +223,52 @@ 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)
{
@ -269,7 +289,6 @@ group_cycle(struct screen_ctx *sc, int flags)
else if (!group_holds_only_hidden(newgc))
group_hide(newgc);
}
if (showgroup == NULL)
return;
@ -301,20 +320,6 @@ 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)
{

View File

@ -23,6 +23,7 @@
#include <sys/types.h>
#include "queue.h"
#include <sys/stat.h>
#include <dirent.h>
#include <err.h>
@ -144,6 +145,7 @@ kbfunc_client_move_kb(void *ctx, struct cargs *cargs)
client_move(cc);
client_ptr_inbound(cc, 1);
XSync(X_Dpy, True);
}
static void
@ -168,8 +170,8 @@ kbfunc_client_move_mb(void *ctx, struct cargs *cargs)
CurrentTime) != GrabSuccess)
return;
menu_windraw(sc, cc->win, "%4d, %-4d", cc->geom.x, cc->geom.y);
screen_prop_win_create(sc, cc->win);
screen_prop_win_draw(sc, "%+5d%+5d", cc->geom.x, cc->geom.y);
while (move) {
XMaskEvent(X_Dpy, MOUSEMASK, &ev);
switch (ev.type) {
@ -192,8 +194,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);
menu_windraw(sc, cc->win,
"%4d, %-4d", cc->geom.x, cc->geom.y);
screen_prop_win_draw(sc,
"%+5d%+5d", cc->geom.x, cc->geom.y);
break;
case ButtonRelease:
move = 0;
@ -202,8 +204,7 @@ kbfunc_client_move_mb(void *ctx, struct cargs *cargs)
}
if (ltime)
client_move(cc);
XUnmapWindow(X_Dpy, sc->menu.win);
XReparentWindow(X_Dpy, sc->menu.win, sc->rootwin, 0, 0);
screen_prop_win_destroy(sc);
XUngrabPointer(X_Dpy, CurrentTime);
}
@ -233,6 +234,7 @@ kbfunc_client_resize_kb(void *ctx, struct cargs *cargs)
client_resize(cc, 1);
client_ptr_inbound(cc, 1);
XSync(X_Dpy, True);
}
static void
@ -257,7 +259,8 @@ kbfunc_client_resize_mb(void *ctx, struct cargs *cargs)
CurrentTime) != GrabSuccess)
return;
menu_windraw(sc, cc->win, "%4d x %-4d", cc->dim.w, cc->dim.h);
screen_prop_win_create(sc, cc->win);
screen_prop_win_draw(sc, "%4d x %-4d", cc->dim.w, cc->dim.h);
while (resize) {
XMaskEvent(X_Dpy, MOUSEMASK, &ev);
switch (ev.type) {
@ -271,7 +274,7 @@ kbfunc_client_resize_mb(void *ctx, struct cargs *cargs)
cc->geom.h = ev.xmotion.y;
client_applysizehints(cc);
client_resize(cc, 1);
menu_windraw(sc, cc->win,
screen_prop_win_draw(sc,
"%4d x %-4d", cc->dim.w, cc->dim.h);
break;
case ButtonRelease:
@ -281,8 +284,7 @@ kbfunc_client_resize_mb(void *ctx, struct cargs *cargs)
}
if (ltime)
client_resize(cc, 1);
XUnmapWindow(X_Dpy, sc->menu.win);
XReparentWindow(X_Dpy, sc->menu.win, sc->rootwin, 0, 0);
screen_prop_win_destroy(sc);
XUngrabPointer(X_Dpy, CurrentTime);
/* Make sure the pointer stays within the window. */
@ -326,9 +328,9 @@ kbfunc_client_snap(void *ctx, struct cargs *cargs)
}
void
kbfunc_client_delete(void *ctx, struct cargs *cargs)
kbfunc_client_close(void *ctx, struct cargs *cargs)
{
client_send_delete(ctx);
client_close(ctx);
}
void
@ -430,12 +432,6 @@ 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)
{
@ -443,15 +439,27 @@ kbfunc_group_only(void *ctx, struct cargs *cargs)
}
void
kbfunc_group_cycle(void *ctx, struct cargs *cargs)
kbfunc_group_toggle(void *ctx, struct cargs *cargs)
{
group_cycle(ctx, cargs->flag);
group_toggle(ctx, cargs->flag);
}
void
kbfunc_group_alltoggle(void *ctx, struct cargs *cargs)
kbfunc_group_toggle_all(void *ctx, struct cargs *cargs)
{
group_alltoggle(ctx);
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
@ -467,7 +475,7 @@ kbfunc_menu_client(void *ctx, struct cargs *cargs)
if (cargs->xev == CWM_XEV_BTN)
mflags |= CWM_MENU_LIST;
old_cc = client_current();
old_cc = client_current(sc);
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cc, &sc->clientq, entry) {

80
menu.c
View File

@ -37,6 +37,10 @@
#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,
@ -45,6 +49,9 @@ 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];
@ -55,7 +62,6 @@ 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);
};
@ -108,27 +114,35 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, const char *prompt,
else
mc.searchstr[0] = '\0';
XSelectInput(X_Dpy, sc->menu.win, MENUMASK);
XMapRaised(X_Dpy, sc->menu.win);
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);
if (XGrabPointer(X_Dpy, sc->menu.win, False, MENUGRABMASK,
XSelectInput(X_Dpy, mc.win, MENUMASK);
XMapRaised(X_Dpy, mc.win);
if (XGrabPointer(X_Dpy, mc.win, False, MENUGRABMASK,
GrabModeAsync, GrabModeAsync, None, Conf.cursor[CF_QUESTION],
CurrentTime) != GrabSuccess) {
XUnmapWindow(X_Dpy, sc->menu.win);
XftDrawDestroy(mc.xftdraw);
XDestroyWindow(X_Dpy, mc.win);
return(NULL);
}
XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
XSetInputFocus(X_Dpy, sc->menu.win, RevertToPointerRoot, CurrentTime);
XSetInputFocus(X_Dpy, mc.win, RevertToPointerRoot, CurrentTime);
/* make sure keybindings don't remove keys from the menu stream */
XGrabKeyboard(X_Dpy, sc->menu.win, True,
XGrabKeyboard(X_Dpy, mc.win, True,
GrabModeAsync, GrabModeAsync, CurrentTime);
for (;;) {
mc.changed = 0;
XWindowEvent(X_Dpy, sc->menu.win, MENUMASK, &e);
XWindowEvent(X_Dpy, mc.win, MENUMASK, &e);
switch (e.type) {
case KeyPress:
@ -159,15 +173,16 @@ 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_getpos(sc->rootwin, &xcur, &ycur);
if (xcur == mc.geom.x && ycur == mc.geom.y)
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);
XUngrabPointer(X_Dpy, CurrentTime);
XUngrabKeyboard(X_Dpy, CurrentTime);
return(mi);
@ -377,12 +392,12 @@ 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_setpos(sc->rootwin, mc->geom.x, mc->geom.y);
XClearWindow(X_Dpy, sc->menu.win);
XMoveResizeWindow(X_Dpy, sc->menu.win, mc->geom.x, mc->geom.y,
XClearWindow(X_Dpy, mc->win);
XMoveResizeWindow(X_Dpy, mc->win, mc->geom.x, mc->geom.y,
mc->geom.w, mc->geom.h);
n = 1;
XftDrawStringUtf8(sc->menu.xftdraw,
XftDrawStringUtf8(mc->xftdraw,
&sc->xftcolor[CWM_COLOR_MENU_FONT], sc->xftfont,
0, sc->xftfont->ascent,
(const FcChar8*)mc->dispstr, strlen(mc->dispstr));
@ -394,7 +409,7 @@ menu_draw(struct menu_ctx *mc, struct menu_q *menuq, struct menu_q *resultq)
if (mc->geom.y + y > area.h)
break;
XftDrawStringUtf8(sc->menu.xftdraw,
XftDrawStringUtf8(mc->xftdraw,
&sc->xftcolor[CWM_COLOR_MENU_FONT], sc->xftfont,
0, y,
(const FcChar8*)mi->print, strlen(mi->print));
@ -419,11 +434,11 @@ menu_draw_entry(struct menu_ctx *mc, struct menu_q *resultq,
return;
color = (active) ? CWM_COLOR_MENU_FG : CWM_COLOR_MENU_BG;
XftDrawRect(sc->menu.xftdraw, &sc->xftcolor[color], 0,
XftDrawRect(mc->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(sc->menu.xftdraw,
XftDrawStringUtf8(mc->xftdraw,
&sc->xftcolor[color], sc->xftfont,
0, (sc->xftfont->height + 1) * entry + sc->xftfont->ascent + 1,
(const FcChar8*)mi->print, strlen(mi->print));
@ -603,34 +618,3 @@ 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);
}

View File

@ -469,7 +469,8 @@ yylex(void)
} else if (c == '\\') {
if ((next = lgetc(quotec)) == EOF)
return (0);
if (next == quotec || c == ' ' || c == '\t')
if (next == quotec || next == ' ' ||
next == '\t')
c = next;
else if (next == '\n') {
file->lineno++;

View File

@ -24,6 +24,7 @@
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -40,7 +41,6 @@ screen_init(int which)
Window *wins, w0, w1, active = None;
XSetWindowAttributes rootattr;
unsigned int nwins, w;
int i;
sc = xmalloc(sizeof(*sc));
@ -60,14 +60,11 @@ screen_init(int which)
xu_ewmh_net_supported(sc);
xu_ewmh_net_supported_wm_check(sc);
conf_group(sc);
screen_update_geometry(sc);
for (i = 0; i < Conf.ngroups; i++)
group_init(sc, i);
xu_ewmh_net_desktop_names(sc);
xu_ewmh_net_wm_desktop_viewport(sc);
xu_ewmh_net_wm_number_of_desktops(sc);
xu_ewmh_net_number_of_desktops(sc);
xu_ewmh_net_showing_desktop(sc);
xu_ewmh_net_virtual_roots(sc);
active = xu_ewmh_get_net_active_window(sc);
@ -106,7 +103,7 @@ screen_find(Window win)
if (sc->rootwin == win)
return(sc);
}
warnx("%s: failure win 0x%lu\n", __func__, win);
warnx("%s: failure win 0x%lx", __func__, win);
return(NULL);
}
@ -217,6 +214,7 @@ screen_update_geometry(struct screen_ctx *sc)
}
xu_ewmh_net_desktop_geometry(sc);
xu_ewmh_net_desktop_viewport(sc);
xu_ewmh_net_workarea(sc);
}
@ -253,3 +251,47 @@ 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;
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);
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);
}

2
util.c
View File

@ -24,6 +24,7 @@
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -134,5 +135,6 @@ log_debug(int level, const char *func, const char *msg, ...)
va_start(ap, msg);
xasprintf(&fmt, "debug%d: %s: %s", level, func, msg);
log_msg(fmt, ap);
free(fmt);
va_end(ap);
}

View File

@ -75,11 +75,15 @@ static void
xev_handle_maprequest(XEvent *ee)
{
XMapRequestEvent *e = &ee->xmaprequest;
struct client_ctx *cc = NULL, *old_cc;
struct screen_ctx *sc;
struct client_ctx *cc, *old_cc;
LOG_DEBUG3("window: 0x%lx", e->window);
LOG_DEBUG3("parent: 0x%lx window: 0x%lx", e->parent, e->window);
if ((old_cc = client_current()) != NULL)
if ((sc = screen_find(e->parent)) == NULL)
return;
if ((old_cc = client_current(sc)) != NULL)
client_ptrsave(old_cc);
if ((cc = client_find(e->window)) == NULL)
@ -102,7 +106,7 @@ xev_handle_unmapnotify(XEvent *ee)
client_set_wm_state(cc, WithdrawnState);
} else {
if (!(cc->flags & CLIENT_HIDDEN))
client_delete(cc);
client_remove(cc);
}
}
}
@ -116,7 +120,7 @@ xev_handle_destroynotify(XEvent *ee)
LOG_DEBUG3("window: 0x%lx", e->window);
if ((cc = client_find(e->window)) != NULL)
client_delete(cc);
client_remove(cc);
}
static void
@ -198,17 +202,19 @@ 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:
/* do nothing */
if (e->atom == ewmh[_NET_WM_NAME])
client_setname(cc);
break;
}
} else {
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->rootwin == e->window) {
if (e->atom == ewmh[_NET_DESKTOP_NAMES])
xu_ewmh_net_desktop_names(sc);
}
if (e->atom == ewmh[_NET_DESKTOP_NAMES]) {
if ((sc = screen_find(e->window)) != NULL)
xu_ewmh_net_desktop_names(sc);
}
}
}
@ -235,7 +241,11 @@ xev_handle_buttonpress(XEvent *ee)
struct screen_ctx *sc;
struct bind_ctx *mb;
LOG_DEBUG3("window: 0x%lx", e->window);
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;
@ -243,22 +253,17 @@ xev_handle_buttonpress(XEvent *ee)
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()) == NULL)
((cc = client_current(sc)) == 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:
@ -273,7 +278,8 @@ xev_handle_buttonrelease(XEvent *ee)
XButtonEvent *e = &ee->xbutton;
struct client_ctx *cc;
LOG_DEBUG3("window: 0x%lx", ee->xbutton.window);
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)) {
@ -293,7 +299,11 @@ xev_handle_keypress(XEvent *ee)
KeySym keysym, skeysym;
unsigned int modshift;
LOG_DEBUG3("window: 0x%lx", e->window);
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);
@ -312,20 +322,17 @@ 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->window)) == NULL) &&
(cc = client_current()) == NULL)
if (((cc = client_find(e->subwindow)) == NULL) &&
((cc = client_current(sc)) == 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:
@ -346,7 +353,8 @@ xev_handle_keyrelease(XEvent *ee)
KeySym keysym;
unsigned int i;
LOG_DEBUG3("window: 0x%lx", e->window);
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;
@ -354,7 +362,7 @@ xev_handle_keyrelease(XEvent *ee)
keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);
for (i = 0; i < nitems(modkeys); i++) {
if (keysym == modkeys[i]) {
if ((cc = client_current()) != NULL) {
if ((cc = client_current(sc)) != NULL) {
if (sc->cycling) {
sc->cycling = 0;
client_mtf(cc);
@ -386,11 +394,11 @@ xev_handle_clientmessage(XEvent *ee)
}
} else if (e->message_type == ewmh[_NET_CLOSE_WINDOW]) {
if ((cc = client_find(e->window)) != NULL) {
client_send_delete(cc);
client_close(cc);
}
} else if (e->message_type == ewmh[_NET_ACTIVE_WINDOW]) {
if ((cc = client_find(e->window)) != NULL) {
if ((old_cc = client_current()) != NULL)
if ((old_cc = client_current(NULL)) != NULL)
client_ptrsave(old_cc);
client_show(cc);
client_ptrwarp(cc);
@ -405,7 +413,9 @@ xev_handle_clientmessage(XEvent *ee)
if (e->data.l[0] == (unsigned long)-1)
group_movetogroup(cc, 0);
else
group_movetogroup(cc, e->data.l[0]);
if (e->data.l[0] >= 0 &&
e->data.l[0] < Conf.ngroups)
group_movetogroup(cc, e->data.l[0]);
}
} else if (e->message_type == ewmh[_NET_WM_STATE]) {
if ((cc = client_find(e->window)) != NULL) {
@ -414,7 +424,9 @@ xev_handle_clientmessage(XEvent *ee)
}
} else if (e->message_type == ewmh[_NET_CURRENT_DESKTOP]) {
if ((sc = screen_find(e->window)) != NULL) {
group_only(sc, e->data.l[0]);
if (e->data.l[0] >= 0 &&
e->data.l[0] < Conf.ngroups)
group_only(sc, e->data.l[0]);
}
}
}
@ -422,20 +434,17 @@ xev_handle_clientmessage(XEvent *ee)
static void
xev_handle_randr(XEvent *ee)
{
XRRScreenChangeNotifyEvent *rev = (XRRScreenChangeNotifyEvent *)ee;
XRRScreenChangeNotifyEvent *e = (XRRScreenChangeNotifyEvent *)ee;
struct screen_ctx *sc;
int i;
LOG_DEBUG3("new size: %d/%d", rev->width, rev->height);
LOG_DEBUG3("size: %d/%d", e->width, e->height);
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);
}
}
if ((sc = screen_find(e->root)) == NULL)
return;
XRRUpdateConfiguration(ee);
screen_update_geometry(sc);
screen_assert_clients_within(sc);
}
/*
@ -476,9 +485,9 @@ xev_process(void)
while (XPending(X_Dpy)) {
XNextEvent(X_Dpy, &e);
if (e.type - Conf.xrandr_event_base == RRScreenChangeNotify)
if ((e.type - Conf.xrandr_event_base) == RRScreenChangeNotify)
xev_handle_randr(&e);
else if (e.type < LASTEvent && xev_handlers[e.type] != NULL)
else if ((e.type < LASTEvent) && (xev_handlers[e.type] != NULL))
(*xev_handlers[e.type])(&e);
}
}

22
xutil.c
View File

@ -128,6 +128,16 @@ 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)
{
@ -212,17 +222,7 @@ xu_ewmh_get_net_active_window(struct screen_ctx *sc)
}
void
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)
xu_ewmh_net_number_of_desktops(struct screen_ctx *sc)
{
long ndesks = Conf.ngroups;