27 Commits

Author SHA1 Message Date
okan
013497c79c Further simplify Xinerama init and re-init on XRR events.
While testing for Xinerama during setup was done display-wide, each time
XineramaQueryScreens() is called either in start-up or due to an XRR
event, the library re-tests for the Xinerama extension anyway before
moving on; so the initial test is redundant and allows another global to
go away with one other change: always fill in sc->xinerama (and _no),
regardless of the success of malloc in XineramaQueryScreens(), and use
it to see if Xinerama dimensions exist when asked by client and/or menu
code.
2012-07-18 21:53:22 +00:00
okan
3f956098d9 unify various max routines to match client placement and partially menu ones
when calculating screen dimensions.
2012-07-16 01:53:14 +00:00
okan
57af364a21 check value 2012-07-16 01:42:00 +00:00
okan
e42d1c7f01 move the HasXinerama check into screen_find_xinerama and simplify logic;
moves closer to logic in menu code.
2012-07-16 01:36:30 +00:00
okan
0e8815dfb0 re-use geom struct in client_ctx (saved)geometry. 2012-07-13 17:01:04 +00:00
okan
186a78ff1e convert xmax/ymax uses to view geometry. 2012-07-13 15:21:35 +00:00
okan
cc08aef0df introduce screen "view" area and "work" area (gap applied) to simplify
various blocks that require understanding the screen geometry.
2012-07-13 14:18:04 +00:00
okan
2450e309ea fix atom for setting WM_STATE. 2012-07-08 02:55:01 +00:00
okan
6faef40c55 fix atom for retrieving WM_STATE between re-exec's. 2012-07-08 02:50:41 +00:00
okan
c8a17ef536 remove a redundant assignment and another one up. 2012-07-08 01:00:24 +00:00
okan
cb893d0aa9 querying for Xinerama should be done per display, not per screen, so
move chuck to display init; allows some shuffling to occur limiting
screen_init_xinerama()'s scope while keeping order intact.
2012-07-06 14:18:00 +00:00
dcoppa
315f25f7ab Add a couple examples of keybindings using keysyms, as discussed
with okan@ and sthen@.

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

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

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

ok sthen@
2012-05-16 01:09:17 +00:00
okan
dd5bfdb064 convert from deprecated XKeycodeToKeysym to XkbKeycodeToKeysym
ok sthen@
2012-05-16 01:04:36 +00:00
okan
57766d8606 altpersist->cycling to be more clear that this is for cycling mod
persistence; based on a diff from Alexander Polakov, in preparation for
looping through other potential cycling modifiers.
2012-05-13 15:17:13 +00:00
okan
fb4936d0f7 knf, some from a diff from Tiago Cunha. 2012-05-13 15:15:54 +00:00
okan
63b59e44c1 wrap long lines; from Tiago Cunha. 2012-05-10 00:39:47 +00:00
okan
1d8839e8ad fix section order: move AUTHORS below HISTORY; from Tiago Cunha
ok jmc@
2012-05-09 18:37:39 +00:00
pascal
26c391b3dd kill useless .Pp
ok jmc@
2012-05-07 21:25:29 +00:00
13 changed files with 514 additions and 415 deletions

View File

@@ -44,7 +44,7 @@ Cursor Cursor_resize;
struct screen_ctx_q Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
struct client_ctx_q Clientq = TAILQ_HEAD_INITIALIZER(Clientq);
int HasXinerama, HasRandr, Randr_ev;
int HasRandr, Randr_ev;
struct conf Conf;
static void sigchld_cb(int);
@@ -157,14 +157,17 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
Window *wins, w0, w1;
XWindowAttributes winattr;
XSetWindowAttributes rootattr;
int fake;
u_int nwins, i;
sc->which = which;
sc->rootwin = RootWindow(X_Dpy, sc->which);
xu_ewmh_net_supported(sc);
xu_ewmh_net_supported_wm_check(sc);
conf_gap(&Conf, sc);
screen_update_geometry(sc, DisplayWidth(X_Dpy, sc->which),
DisplayHeight(X_Dpy, sc->which));
screen_update_geometry(sc);
conf_color(&Conf, sc);
@@ -176,8 +179,6 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
/* Initialize menu window. */
menu_init(sc);
xu_setwmname(sc);
rootattr.cursor = Cursor_normal;
rootattr.event_mask = CHILDMASK|PropertyChangeMask|EnterWindowMask|
LeaveWindowMask|ColormapChangeMask|BUTTONMASK;
@@ -199,17 +200,8 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
screen_updatestackingorder(sc);
if (XineramaQueryExtension(X_Dpy, &fake, &fake) == 1 &&
((HasXinerama = XineramaIsActive(X_Dpy)) == 1))
HasXinerama = 1;
if (HasRandr)
XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask);
/*
* initial setup of xinerama screens, if we're using RandR then we'll
* redo this whenever the screen changes since a CTRC may have been
* added or removed
*/
screen_init_xinerama(sc);
XSync(X_Dpy, False);
}
@@ -221,6 +213,7 @@ x_wmerrorhandler(Display *dpy, XErrorEvent *e)
return (0);
}
static int
x_errorhandler(Display *dpy, XErrorEvent *e)
{

103
calmwm.h
View File

@@ -21,6 +21,7 @@
#ifndef _CALMWM_H_
#define _CALMWM_H_
#include <X11/XKBlib.h>
#include <X11/Xatom.h>
#include <X11/Xft/Xft.h>
#include <X11/Xlib.h>
@@ -95,6 +96,13 @@ struct color {
unsigned long pixel;
};
struct geom {
int x;
int y;
int w;
int h;
};
struct gap {
int top;
int bottom;
@@ -117,12 +125,7 @@ struct client_ctx {
XSizeHints *size;
Colormap cmap;
u_int bwidth; /* border width */
struct {
int x; /* x position */
int y; /* y position */
int width; /* width */
int height;/* height */
} geom, savegeom;
struct geom geom, savegeom;
struct {
int basew; /* desired width */
int baseh; /* desired height */
@@ -202,9 +205,9 @@ struct screen_ctx {
Window menuwin;
struct color color[CWM_COLOR_MAX];
GC gc;
int altpersist;
int xmax;
int ymax;
int cycling;
struct geom view; /* viewable area */
struct geom work; /* workable area, gap-applied */
struct gap gap;
struct cycle_entry_q mruq;
XftColor xftcolor;
@@ -306,6 +309,7 @@ __dead void usage(void);
void client_applysizehints(struct client_ctx *);
struct client_ctx *client_current(void);
void client_cycle(struct screen_ctx *, int);
void client_cycle_leave(struct screen_ctx *, struct client_ctx *);
void client_delete(struct client_ctx *);
void client_draw_border(struct client_ctx *);
struct client_ctx *client_find(Window);
@@ -358,8 +362,7 @@ void search_print_client(struct menu *, int);
XineramaScreenInfo *screen_find_xinerama(struct screen_ctx *, int, int);
struct screen_ctx *screen_fromroot(Window);
void screen_init_xinerama(struct screen_ctx *);
void screen_update_geometry(struct screen_ctx *, int, int);
void screen_update_geometry(struct screen_ctx *);
void screen_updatestackingorder(struct screen_ctx *);
void kbfunc_client_cycle(struct client_ctx *, union arg *);
@@ -461,7 +464,22 @@ void xu_ptr_setpos(Window, int, int);
void xu_ptr_ungrab(void);
void xu_sendmsg(Window, Atom, long);
void xu_setstate(struct client_ctx *, int);
void xu_setwmname(struct screen_ctx *);
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_workarea(struct screen_ctx *);
void xu_ewmh_net_client_list(struct screen_ctx *);
void xu_ewmh_net_active_window(struct screen_ctx *, Window);
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 *, long);
void xu_ewmh_net_desktop_names(struct screen_ctx *, unsigned char *, int);
void xu_ewmh_net_wm_desktop(struct client_ctx *);
void u_exec(char *);
void u_spawn(char *);
@@ -486,34 +504,37 @@ extern struct conf Conf;
extern int HasXinerama, HasRandr, Randr_ev;
#define WM_STATE cwm_atoms[0]
#define WM_DELETE_WINDOW cwm_atoms[1]
#define WM_TAKE_FOCUS cwm_atoms[2]
#define WM_PROTOCOLS cwm_atoms[3]
#define _MOTIF_WM_HINTS cwm_atoms[4]
#define UTF8_STRING cwm_atoms[5]
/*
* please make all hints below this point netwm hints, starting with
* _NET_SUPPORTED. If you change other hints make sure you update
* CWM_NETWM_START
*/
#define _NET_SUPPORTED cwm_atoms[6]
#define _NET_SUPPORTING_WM_CHECK cwm_atoms[7]
#define _NET_WM_NAME cwm_atoms[8]
#define _NET_ACTIVE_WINDOW cwm_atoms[9]
#define _NET_CLIENT_LIST cwm_atoms[10]
#define _NET_NUMBER_OF_DESKTOPS cwm_atoms[11]
#define _NET_CURRENT_DESKTOP cwm_atoms[12]
#define _NET_DESKTOP_VIEWPORT cwm_atoms[13]
#define _NET_DESKTOP_GEOMETRY cwm_atoms[14]
#define _NET_VIRTUAL_ROOTS cwm_atoms[15]
#define _NET_SHOWING_DESKTOP cwm_atoms[16]
#define _NET_DESKTOP_NAMES cwm_atoms[17]
#define _NET_WM_DESKTOP cwm_atoms[18]
#define _NET_WORKAREA cwm_atoms[19]
#define CWM_NO_ATOMS 20
#define CWM_NETWM_START 6
extern Atom cwm_atoms[CWM_NO_ATOMS];
enum {
WM_STATE,
WM_DELETE_WINDOW,
WM_TAKE_FOCUS,
WM_PROTOCOLS,
_MOTIF_WM_HINTS,
UTF8_STRING,
CWMH_NITEMS
};
enum {
_NET_SUPPORTED,
_NET_SUPPORTING_WM_CHECK,
_NET_ACTIVE_WINDOW,
_NET_CLIENT_LIST,
_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,
EWMH_NITEMS
};
struct atom_ctx {
char *name;
Atom atom;
};
extern struct atom_ctx cwmh[CWMH_NITEMS];
extern struct atom_ctx ewmh[EWMH_NITEMS];
#endif /* _CALMWM_H_ */

252
client.c
View File

@@ -89,8 +89,8 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
XGetWindowAttributes(X_Dpy, cc->win, &wattr);
cc->geom.x = wattr.x;
cc->geom.y = wattr.y;
cc->geom.width = wattr.width;
cc->geom.height = wattr.height;
cc->geom.w = wattr.width;
cc->geom.h = wattr.height;
cc->cmap = wattr.colormap;
if (wattr.map_state != IsViewable) {
@@ -126,9 +126,8 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
TAILQ_INSERT_TAIL(&sc->mruq, cc, mru_entry);
TAILQ_INSERT_TAIL(&Clientq, cc, entry);
/* append to the client list */
XChangeProperty(X_Dpy, sc->rootwin, _NET_CLIENT_LIST, XA_WINDOW, 32,
PropModeAppend, (unsigned char *)&cc->win, 1);
xu_ewmh_net_client_list(sc);
client_gethints(cc);
client_update(cc);
@@ -143,10 +142,7 @@ void
client_delete(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct client_ctx *tcc;
struct winname *wn;
Window *winlist;
int i, j;
group_client_delete(cc);
@@ -159,23 +155,8 @@ client_delete(struct client_ctx *cc)
TAILQ_REMOVE(&sc->mruq, cc, mru_entry);
TAILQ_REMOVE(&Clientq, cc, entry);
/*
* Sadly we can't remove just one entry from a property, so we must
* redo the whole thing from scratch. this is the stupid way, the other
* way incurs many roundtrips to the server.
*/
i = j = 0;
TAILQ_FOREACH(tcc, &Clientq, entry)
i++;
if (i > 0) {
winlist = xmalloc(i * sizeof(*winlist));
TAILQ_FOREACH(tcc, &Clientq, entry)
winlist[j++] = tcc->win;
XChangeProperty(X_Dpy, sc->rootwin, _NET_CLIENT_LIST,
XA_WINDOW, 32, PropModeReplace,
(unsigned char *)winlist, i);
xfree(winlist);
}
xu_ewmh_net_client_list(sc);
if (_curcc == cc)
client_none(sc);
@@ -228,7 +209,7 @@ client_setactive(struct client_ctx *cc, int fg)
* If we're in the middle of alt-tabbing, don't change
* the order please.
*/
if (!sc->altpersist)
if (!sc->cycling)
client_mtf(cc);
} else
client_leave(cc);
@@ -236,9 +217,7 @@ client_setactive(struct client_ctx *cc, int fg)
if (fg && _curcc != cc) {
client_setactive(NULL, 0);
_curcc = cc;
XChangeProperty(X_Dpy, sc->rootwin, _NET_ACTIVE_WINDOW,
XA_WINDOW, 32, PropModeReplace,
(unsigned char *)&cc->win, 1);
xu_ewmh_net_active_window(sc, cc->win);
}
cc->active = fg;
@@ -253,8 +232,8 @@ client_none(struct screen_ctx *sc)
{
Window none = None;
XChangeProperty(X_Dpy, sc->rootwin, _NET_ACTIVE_WINDOW,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&none, 1);
xu_ewmh_net_active_window(sc, none);
_curcc = NULL;
}
@@ -277,8 +256,8 @@ void
client_maximize(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
int xmax = sc->xmax, ymax = sc->ymax;
int x_org = 0, y_org = 0;
int x_org, y_org, xmax, ymax;
XineramaScreenInfo *xine;
if (cc->flags & CLIENT_FREEZE)
return;
@@ -291,37 +270,38 @@ client_maximize(struct client_ctx *cc)
}
if ((cc->flags & CLIENT_VMAXIMIZED) == 0) {
cc->savegeom.height = cc->geom.height;
cc->savegeom.h = cc->geom.h;
cc->savegeom.y = cc->geom.y;
}
if ((cc->flags & CLIENT_HMAXIMIZED) == 0) {
cc->savegeom.width = cc->geom.width;
cc->savegeom.w = cc->geom.w;
cc->savegeom.x = cc->geom.x;
}
if (HasXinerama) {
XineramaScreenInfo *xine;
/*
* 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
*/
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
/*
* 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
*/
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2);
if (xine) {
x_org = xine->x_org;
y_org = xine->y_org;
xmax = xine->width;
ymax = xine->height;
} else {
x_org = y_org = 0;
xmax = sc->view.w;
ymax = sc->view.h;
}
calc:
cc->geom.x = x_org + sc->gap.left;
cc->geom.y = y_org + sc->gap.top;
cc->geom.height = ymax - (sc->gap.top + sc->gap.bottom);
cc->geom.width = xmax - (sc->gap.left + sc->gap.right);
cc->geom.h = ymax - (sc->gap.top + sc->gap.bottom);
cc->geom.w = xmax - (sc->gap.left + sc->gap.right);
cc->bwidth = 0;
cc->flags |= CLIENT_MAXIMIZED;
@@ -333,43 +313,44 @@ void
client_vertmaximize(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
int y_org = 0, ymax = sc->ymax;
int y_org, ymax;
XineramaScreenInfo *xine;
if (cc->flags & CLIENT_FREEZE)
return;
if (cc->flags & CLIENT_VMAXIMIZED) {
cc->geom.y = cc->savegeom.y;
cc->geom.height = cc->savegeom.height;
cc->geom.h = cc->savegeom.h;
cc->bwidth = Conf.bwidth;
if (cc->flags & CLIENT_HMAXIMIZED)
cc->geom.width -= cc->bwidth * 2;
cc->geom.w -= cc->bwidth * 2;
cc->flags &= ~CLIENT_VMAXIMIZED;
goto resize;
}
cc->savegeom.y = cc->geom.y;
cc->savegeom.height = cc->geom.height;
cc->savegeom.h = cc->geom.h;
/* if this will make us fully maximized then remove boundary */
if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_HMAXIMIZED) {
cc->geom.width += Conf.bwidth * 2;
cc->geom.w += Conf.bwidth * 2;
cc->bwidth = 0;
}
if (HasXinerama) {
XineramaScreenInfo *xine;
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2);
if (xine) {
y_org = xine->y_org;
ymax = xine->height;
} else {
y_org = 0;
ymax = sc->view.h;
}
calc:
cc->geom.y = y_org + sc->gap.top;
cc->geom.height = ymax - (cc->bwidth * 2) - (sc->gap.top +
cc->geom.h = ymax - (cc->bwidth * 2) - (sc->gap.top +
sc->gap.bottom);
cc->flags |= CLIENT_VMAXIMIZED;
@@ -381,43 +362,44 @@ void
client_horizmaximize(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
int x_org = 0, xmax = sc->xmax;
int x_org, xmax;
XineramaScreenInfo *xine;
if (cc->flags & CLIENT_FREEZE)
return;
if (cc->flags & CLIENT_HMAXIMIZED) {
cc->geom.x = cc->savegeom.x;
cc->geom.width = cc->savegeom.width;
cc->geom.w = cc->savegeom.w;
cc->bwidth = Conf.bwidth;
if (cc->flags & CLIENT_VMAXIMIZED)
cc->geom.height -= cc->bwidth * 2;
cc->geom.h -= cc->bwidth * 2;
cc->flags &= ~CLIENT_HMAXIMIZED;
goto resize;
}
}
cc->savegeom.x = cc->geom.x;
cc->savegeom.width = cc->geom.width;
cc->savegeom.w = cc->geom.w;
/* if this will make us fully maximized then remove boundary */
if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_VMAXIMIZED) {
cc->geom.height += cc->bwidth * 2;
cc->geom.h += cc->bwidth * 2;
cc->bwidth = 0;
}
if (HasXinerama) {
XineramaScreenInfo *xine;
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.width / 2,
cc->geom.y + cc->geom.height / 2);
if (xine == NULL)
goto calc;
xine = screen_find_xinerama(sc,
cc->geom.x + cc->geom.w / 2,
cc->geom.y + cc->geom.h / 2);
if (xine) {
x_org = xine->x_org;
xmax = xine->width;
} else {
x_org = 0;
xmax = sc->view.w;
}
calc:
cc->geom.x = x_org + sc->gap.left;
cc->geom.width = xmax - (cc->bwidth * 2) - (sc->gap.left +
cc->geom.w = xmax - (cc->bwidth * 2) - (sc->gap.left +
sc->gap.right);
cc->flags |= CLIENT_HMAXIMIZED;
@@ -431,7 +413,7 @@ client_resize(struct client_ctx *cc)
client_draw_border(cc);
XMoveResizeWindow(X_Dpy, cc->win, cc->geom.x,
cc->geom.y, cc->geom.width, cc->geom.height);
cc->geom.y, cc->geom.w, cc->geom.h);
xu_configure(cc);
}
@@ -460,8 +442,8 @@ client_ptrwarp(struct client_ctx *cc)
int x = cc->ptr.x, y = cc->ptr.y;
if (x == -1 || y == -1) {
x = cc->geom.width / 2;
y = cc->geom.height / 2;
x = cc->geom.w / 2;
y = cc->geom.h / 2;
}
(cc->state == IconicState) ? client_unhide(cc) : client_raise(cc);
@@ -540,14 +522,14 @@ client_update(struct client_ctx *cc)
int i;
long n;
if ((n = xu_getprop(cc->win, WM_PROTOCOLS,
if ((n = xu_getprop(cc->win, cwmh[WM_PROTOCOLS].atom,
XA_ATOM, 20L, (u_char **)&p)) <= 0)
return;
for (i = 0; i < n; i++)
if (p[i] == WM_DELETE_WINDOW)
if (p[i] == cwmh[WM_DELETE_WINDOW].atom)
cc->xproto |= CLIENT_PROTO_DELETE;
else if (p[i] == WM_TAKE_FOCUS)
else if (p[i] == cwmh[WM_TAKE_FOCUS].atom)
cc->xproto |= CLIENT_PROTO_TAKEFOCUS;
XFree(p);
@@ -557,7 +539,8 @@ void
client_send_delete(struct client_ctx *cc)
{
if (cc->xproto & CLIENT_PROTO_DELETE)
xu_sendmsg(cc->win, WM_PROTOCOLS, WM_DELETE_WINDOW);
xu_sendmsg(cc->win,
cwmh[WM_PROTOCOLS].atom, cwmh[WM_DELETE_WINDOW].atom);
else
XKillClient(X_Dpy, cc->win);
}
@@ -568,7 +551,7 @@ client_setname(struct client_ctx *cc)
struct winname *wn;
char *newname;
if (!xu_getstrprop(cc->win, _NET_WM_NAME, &newname))
if (!xu_getstrprop(cc->win, ewmh[_NET_WM_NAME].atom, &newname))
if (!xu_getstrprop(cc->win, XA_WM_NAME, &newname))
newname = emptystring;
@@ -613,7 +596,8 @@ client_cycle(struct screen_ctx *sc, int flags)
return;
if (oldcc == NULL)
oldcc = (flags & CWM_RCYCLE ? TAILQ_LAST(&sc->mruq, cycle_entry_q) :
oldcc = (flags & CWM_RCYCLE ?
TAILQ_LAST(&sc->mruq, cycle_entry_q) :
TAILQ_FIRST(&sc->mruq));
newcc = oldcc;
@@ -637,12 +621,24 @@ client_cycle(struct screen_ctx *sc, int flags)
}
}
/* reset when alt is released. XXX I hate this hack */
sc->altpersist = 1;
/* reset when cycling mod is released. XXX I hate this hack */
sc->cycling = 1;
client_ptrsave(oldcc);
client_ptrwarp(newcc);
}
void
client_cycle_leave(struct screen_ctx *sc, struct client_ctx *cc)
{
sc->cycling = 0;
client_mtf(NULL);
if (cc) {
group_sticky_toggle_exit(cc);
XUngrabKeyboard(X_Dpy, CurrentTime);
}
}
static struct client_ctx *
client_mrunext(struct client_ctx *cc)
{
@@ -677,8 +673,8 @@ client_placecalc(struct client_ctx *cc)
* XRandR bits mean that {x,y}max shouldn't be outside what's
* currently there.
*/
xslack = sc->xmax - cc->geom.width - cc->bwidth * 2;
yslack = sc->ymax - cc->geom.height - cc->bwidth * 2;
xslack = sc->view.w - cc->geom.w - cc->bwidth * 2;
yslack = sc->view.h - cc->geom.h - cc->bwidth * 2;
if (cc->size->x > 0)
cc->geom.x = MIN(cc->size->x, xslack);
if (cc->size->y > 0)
@@ -689,28 +685,25 @@ client_placecalc(struct client_ctx *cc)
int xmax, ymax;
xu_ptr_getpos(sc->rootwin, &xmouse, &ymouse);
if (HasXinerama) {
info = screen_find_xinerama(sc, xmouse, ymouse);
if (info == NULL)
goto noxine;
info = screen_find_xinerama(sc, xmouse, ymouse);
if (info) {
xorig = info->x_org;
yorig = info->y_org;
xmax = xorig + info->width;
ymax = yorig + info->height;
} else {
noxine:
xorig = yorig = 0;
xmax = sc->xmax;
ymax = sc->ymax;
xmax = sc->view.w;
ymax = sc->view.h;
}
xmouse = MAX(xmouse, xorig) - cc->geom.width / 2;
ymouse = MAX(ymouse, yorig) - cc->geom.height / 2;
xmouse = MAX(xmouse, xorig) - cc->geom.w / 2;
ymouse = MAX(ymouse, yorig) - cc->geom.h / 2;
xmouse = MAX(xmouse, xorig);
ymouse = MAX(ymouse, yorig);
xslack = xmax - cc->geom.width - cc->bwidth * 2;
yslack = ymax - cc->geom.height - cc->bwidth * 2;
xslack = xmax - cc->geom.w - cc->bwidth * 2;
yslack = ymax - cc->geom.h - cc->bwidth * 2;
if (xslack >= xorig) {
cc->geom.x = MAX(MIN(xmouse, xslack),
@@ -719,7 +712,7 @@ noxine:
cc->geom.x -= sc->gap.right;
} else {
cc->geom.x = xorig + sc->gap.left;
cc->geom.width = xmax - sc->gap.left;
cc->geom.w = xmax - sc->gap.left;
}
if (yslack >= yorig) {
cc->geom.y = MAX(MIN(ymouse, yslack),
@@ -728,7 +721,7 @@ noxine:
cc->geom.y -= sc->gap.bottom;
} else {
cc->geom.y = yorig + sc->gap.top;
cc->geom.height = ymax - sc->gap.top;
cc->geom.h = ymax - sc->gap.top;
}
}
}
@@ -792,6 +785,7 @@ client_getsizehints(struct client_ctx *cc)
cc->size->max_aspect.y;
}
}
void
client_applysizehints(struct client_ctx *cc)
{
@@ -802,43 +796,43 @@ client_applysizehints(struct client_ctx *cc)
/* temporarily remove base dimensions, ICCCM 4.1.2.3 */
if (!baseismin) {
cc->geom.width -= cc->hint.basew;
cc->geom.height -= cc->hint.baseh;
cc->geom.w -= cc->hint.basew;
cc->geom.h -= cc->hint.baseh;
}
/* adjust for aspect limits */
if (cc->hint.mina > 0 && cc->hint.maxa > 0) {
if (cc->hint.maxa <
(float)cc->geom.width / cc->geom.height)
cc->geom.width = cc->geom.height * cc->hint.maxa;
(float)cc->geom.w / cc->geom.h)
cc->geom.w = cc->geom.h * cc->hint.maxa;
else if (cc->hint.mina <
(float)cc->geom.height / cc->geom.width)
cc->geom.height = cc->geom.width * cc->hint.mina;
(float)cc->geom.h / cc->geom.w)
cc->geom.h = cc->geom.w * cc->hint.mina;
}
/* remove base dimensions for increment */
if (baseismin) {
cc->geom.width -= cc->hint.basew;
cc->geom.height -= cc->hint.baseh;
cc->geom.w -= cc->hint.basew;
cc->geom.h -= cc->hint.baseh;
}
/* adjust for increment value */
cc->geom.width -= cc->geom.width % cc->hint.incw;
cc->geom.height -= cc->geom.height % cc->hint.inch;
cc->geom.w -= cc->geom.w % cc->hint.incw;
cc->geom.h -= cc->geom.h % cc->hint.inch;
/* restore base dimensions */
cc->geom.width += cc->hint.basew;
cc->geom.height += cc->hint.baseh;
cc->geom.w += cc->hint.basew;
cc->geom.h += cc->hint.baseh;
/* adjust for min width/height */
cc->geom.width = MAX(cc->geom.width, cc->hint.minw);
cc->geom.height = MAX(cc->geom.height, cc->hint.minh);
cc->geom.w = MAX(cc->geom.w, cc->hint.minw);
cc->geom.h = MAX(cc->geom.h, cc->hint.minh);
/* adjust for max width/height */
if (cc->hint.maxw)
cc->geom.width = MIN(cc->geom.width, cc->hint.maxw);
cc->geom.w = MIN(cc->geom.w, cc->hint.maxw);
if (cc->hint.maxh)
cc->geom.height = MIN(cc->geom.height, cc->hint.maxh);
cc->geom.h = MIN(cc->geom.h, cc->hint.maxh);
}
static void
@@ -854,7 +848,7 @@ client_gethints(struct client_ctx *cc)
cc->app_class = xch.res_class;
}
if (xu_getprop(cc->win, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS,
if (xu_getprop(cc->win, cwmh[_MOTIF_WM_HINTS].atom, _MOTIF_WM_HINTS,
PROP_MWM_HINTS_ELEMENTS, (u_char **)&mwmh) == MWM_NUMHINTS)
if (mwmh->flags & MWM_HINTS_DECORATIONS &&
!(mwmh->decorations & MWM_DECOR_ALL) &&
@@ -889,8 +883,8 @@ client_transient(struct client_ctx *cc)
static int
client_inbound(struct client_ctx *cc, int x, int y)
{
return (x < cc->geom.width && x >= 0 &&
y < cc->geom.height && y >= 0);
return (x < cc->geom.w && x >= 0 &&
y < cc->geom.h && y >= 0);
}
int
@@ -911,13 +905,13 @@ client_snapcalc(int n, int dn, int nmax, int bwidth, 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);
}

8
conf.c
View File

@@ -361,8 +361,10 @@ static struct {
{ "nogroup", kbfunc_client_nogroup, 0, {0} },
{ "cyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_CYCLE} },
{ "rcyclegroup", kbfunc_client_cyclegroup, 0, {.i = CWM_RCYCLE} },
{ "cycleingroup", kbfunc_client_cycle, KBFLAG_NEEDCLIENT, {.i = CWM_CYCLE|CWM_INGROUP} },
{ "rcycleingroup", kbfunc_client_cycle, KBFLAG_NEEDCLIENT, {.i = CWM_RCYCLE|CWM_INGROUP} },
{ "cycleingroup", kbfunc_client_cycle, KBFLAG_NEEDCLIENT,
{.i = CWM_CYCLE|CWM_INGROUP} },
{ "rcycleingroup", kbfunc_client_cycle, KBFLAG_NEEDCLIENT,
{.i = CWM_RCYCLE|CWM_INGROUP} },
{ "grouptoggle", kbfunc_client_grouptoggle, KBFLAG_NEEDCLIENT, {0}},
{ "maximize", kbfunc_client_maximize, KBFLAG_NEEDCLIENT, {0} },
{ "vmaximize", kbfunc_client_vmaximize, KBFLAG_NEEDCLIENT, {0} },
@@ -640,7 +642,7 @@ conf_grab_mouse(struct client_ctx *cc)
TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
if (mb->context != MOUSEBIND_CTX_WIN)
continue;
continue;
switch(mb->button) {
case 1:

25
cwm.1
View File

@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: September 25 2010 $
.Dd $Mdocdate: May 7 2012 $
.Dt CWM 1
.Os
.Sh NAME
@@ -258,18 +258,6 @@ option is given.
.El
.Sh SEE ALSO
.Xr cwmrc 5
.Sh AUTHORS
.An -nosplit
.Pp
.Nm
was developed by
.An Marius Aamodt Eriksen Aq marius@monkey.org
with contributions from
.An Andy Adamson Aq dros@monkey.org ,
.An Niels Provos Aq provos@monkey.org ,
and
.An Antti Nyk\(:anen Aq aon@iki.fi .
Ideas, discussion with many others.
.Sh HISTORY
.Nm
was originally inspired by evilwm, but was rewritten from scratch
@@ -280,3 +268,14 @@ has since been removed or rewritten.
.Nm
first appeared in
.Ox 4.2 .
.Sh AUTHORS
.An -nosplit
.Nm
was developed by
.An Marius Aamodt Eriksen Aq marius@monkey.org
with contributions from
.An Andy Adamson Aq dros@monkey.org ,
.An Niels Provos Aq provos@monkey.org ,
and
.An Antti Nyk\(:anen Aq aon@iki.fi .
Ideas, discussion with many others.

View File

@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: September 8 2011 $
.Dd $Mdocdate: November 6 2011 $
.Dt CWMRC 5
.Os
.Sh NAME
@@ -244,6 +244,10 @@ ignore xclock
bind CM-r label
bind CS-Return "xterm -e top"
bind 4-o unmap
bind CM-equal unmap
bind CMS-equal unmap
bind C4-equal vmaximize
bind C4S-equal hmaximize
bind M-1 grouponly1
bind M-2 grouponly2
bind M-3 grouponly3

67
group.c
View File

@@ -48,38 +48,31 @@ const char *shortcut_to_name[] = {
static void
group_add(struct group_ctx *gc, struct client_ctx *cc)
{
long no;
if (cc == NULL || gc == NULL)
errx(1, "group_add: a ctx is NULL");
no = gc->shortcut - 1;
if (cc->group == gc)
return;
if (cc->group != NULL)
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
cc->group = gc;
xu_ewmh_net_wm_desktop(cc);
}
static void
group_remove(struct client_ctx *cc)
{
long no = 0xffffffff;
if (cc == NULL || cc->group == NULL)
errx(1, "group_remove: a ctx is NULL");
XChangeProperty(X_Dpy, cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
32, PropModeReplace, (unsigned char *)&no, 1);
TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
cc->group = NULL;
xu_ewmh_net_wm_desktop(cc);
}
static void
@@ -146,13 +139,12 @@ void
group_init(struct screen_ctx *sc)
{
int i;
long viewports[2] = {0, 0};
long ndesks = CALMWM_NGROUPS, zero = 0;
TAILQ_INIT(&sc->groupq);
sc->group_hideall = 0;
/* see if any group names have already been set and update the property
* with ours if they'll have changed.
/*
* See if any group names have already been set and update the
* property with ours if they'll have changed.
*/
group_update_names(sc);
@@ -163,23 +155,11 @@ group_init(struct screen_ctx *sc)
TAILQ_INSERT_TAIL(&sc->groupq, &sc->groups[i], entry);
}
/* we don't support large desktops, so this is always (0, 0) */
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_VIEWPORT,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)viewports, 2);
XChangeProperty(X_Dpy, sc->rootwin, _NET_NUMBER_OF_DESKTOPS,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&ndesks, 1);
/*
* we don't use virtual roots, so make sure it's not there from a
* previous wm.
*/
XDeleteProperty(X_Dpy, sc->rootwin, _NET_VIRTUAL_ROOTS);
/*
* We don't really have a ``showing desktop'' mode, so this is zero
* always. XXX Note that when we hide all groups, or when all groups
* are hidden we could technically set this later on.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SHOWING_DESKTOP,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&zero, 1);
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);
group_setactive(sc, 0);
}
@@ -208,8 +188,8 @@ static void
group_setactive(struct screen_ctx *sc, long idx)
{
sc->group_active = &sc->groups[idx];
XChangeProperty(X_Dpy, sc->rootwin, _NET_CURRENT_DESKTOP,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&idx, 1);
xu_ewmh_net_current_desktop(sc, idx);
}
void
@@ -438,8 +418,8 @@ group_autogroup(struct client_ctx *cc)
if (cc->app_class == NULL || cc->app_name == NULL)
return;
if (xu_getprop(cc->win, _NET_WM_DESKTOP, XA_CARDINAL,
1, (unsigned char **)&grpno) > 0) {
if (xu_getprop(cc->win, ewmh[_NET_WM_DESKTOP].atom,
XA_CARDINAL, 1, (unsigned char **)&grpno) > 0) {
if (*grpno == 0xffffffff)
no = 0;
else if (*grpno > CALMWM_NGROUPS || *grpno < 0)
@@ -479,11 +459,12 @@ group_update_names(struct screen_ctx *sc)
char **strings, *p;
unsigned char *prop_ret;
Atom type_ret;
int format_ret, i = 0, nstrings = 0, n, setnames = 0;
int format_ret, i = 0, nstrings = 0, n = 0, setnames = 0;
unsigned long bytes_after, num_ret;
if (XGetWindowProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES, 0,
0xffffff, False, UTF8_STRING, &type_ret, &format_ret,
if (XGetWindowProperty(X_Dpy, sc->rootwin,
ewmh[_NET_DESKTOP_NAMES].atom, 0, 0xffffff, False,
cwmh[UTF8_STRING].atom, &type_ret, &format_ret,
&num_ret, &bytes_after, &prop_ret) == Success &&
prop_ret != NULL && format_ret == 8) {
/* failure, just set defaults */
@@ -497,7 +478,6 @@ group_update_names(struct screen_ctx *sc)
strings = xmalloc((nstrings < CALMWM_NGROUPS ? CALMWM_NGROUPS :
nstrings) * sizeof(*strings));
i = n = 0;
p = prop_ret;
while (n < nstrings) {
strings[n++] = xstrdup(p);
@@ -543,7 +523,6 @@ group_set_names(struct screen_ctx *sc)
tlen -= slen;
q += slen;
}
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_NAMES,
UTF8_STRING, 8, PropModeReplace, p, len);
xu_ewmh_net_desktop_names(sc, p, len);
}

View File

@@ -54,14 +54,13 @@ kbfunc_client_raise(struct client_ctx *cc, union arg *arg)
void
kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc;
struct screen_ctx *sc = cc->sc;
int x, y, flags, amt;
u_int mx, my;
if (cc->flags & CLIENT_FREEZE)
return;
sc = cc->sc;
mx = my = 0;
flags = arg->i;
@@ -89,22 +88,22 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
switch (flags & TYPEMASK) {
case CWM_MOVE:
cc->geom.y += my;
if (cc->geom.y + cc->geom.height < 0)
cc->geom.y = -cc->geom.height;
if (cc->geom.y > cc->sc->ymax - 1)
cc->geom.y = cc->sc->ymax - 1;
if (cc->geom.y + cc->geom.h < 0)
cc->geom.y = -cc->geom.h;
if (cc->geom.y > sc->view.h - 1)
cc->geom.y = sc->view.h - 1;
cc->geom.x += mx;
if (cc->geom.x + cc->geom.width < 0)
cc->geom.x = -cc->geom.width;
if (cc->geom.x > cc->sc->xmax - 1)
cc->geom.x = cc->sc->xmax - 1;
if (cc->geom.x + cc->geom.w < 0)
cc->geom.x = -cc->geom.w;
if (cc->geom.x > sc->view.w - 1)
cc->geom.x = sc->view.w - 1;
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.width, cc->sc->xmax,
cc->geom.w, sc->view.w,
cc->bwidth, Conf.snapdist);
cc->geom.y += client_snapcalc(cc->geom.y,
cc->geom.height, cc->sc->ymax,
cc->geom.h, sc->view.h,
cc->bwidth, Conf.snapdist);
client_move(cc);
@@ -114,18 +113,18 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
client_ptrwarp(cc);
break;
case CWM_RESIZE:
if ((cc->geom.height += my) < 1)
cc->geom.height = 1;
if ((cc->geom.width += mx) < 1)
cc->geom.width = 1;
if ((cc->geom.h += my) < 1)
cc->geom.h = 1;
if ((cc->geom.w += mx) < 1)
cc->geom.w = 1;
client_resize(cc);
/* Make sure the pointer stays within the window. */
xu_ptr_getpos(cc->win, &cc->ptr.x, &cc->ptr.y);
if (cc->ptr.x > cc->geom.width)
cc->ptr.x = cc->geom.width - cc->bwidth;
if (cc->ptr.y > cc->geom.height)
cc->ptr.y = cc->geom.height - cc->bwidth;
if (cc->ptr.x > cc->geom.w)
cc->ptr.x = cc->geom.w - cc->bwidth;
if (cc->ptr.y > cc->geom.h)
cc->ptr.y = cc->geom.h - cc->bwidth;
client_ptrwarp(cc);
break;
case CWM_PTRMOVE:
@@ -140,12 +139,11 @@ kbfunc_moveresize(struct client_ctx *cc, union arg *arg)
void
kbfunc_client_search(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc;
struct screen_ctx *sc = cc->sc;
struct client_ctx *old_cc;
struct menu *mi;
struct menu_q menuq;
sc = cc->sc;
old_cc = client_current();
TAILQ_INIT(&menuq);
@@ -177,12 +175,11 @@ kbfunc_client_search(struct client_ctx *cc, union arg *arg)
void
kbfunc_menu_search(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc;
struct screen_ctx *sc = cc->sc;
struct cmd *cmd;
struct menu *mi;
struct menu_q menuq;
sc = cc->sc;
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
@@ -205,9 +202,7 @@ kbfunc_menu_search(struct client_ctx *cc, union arg *arg)
void
kbfunc_client_cycle(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc;
sc = cc->sc;
struct screen_ctx *sc = cc->sc;
/* XXX for X apps that ignore events */
XGrabKeyboard(X_Dpy, sc->rootwin, True,
@@ -244,7 +239,7 @@ void
kbfunc_exec(struct client_ctx *cc, union arg *arg)
{
#define NPATHS 256
struct screen_ctx *sc;
struct screen_ctx *sc = cc->sc;
char **ap, *paths[NPATHS], *path, *pathcpy, *label;
char tpath[MAXPATHLEN];
DIR *dirp;
@@ -253,7 +248,6 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg)
struct menu_q menuq;
int l, i, cmd = arg->i;
sc = cc->sc;
switch (cmd) {
case CWM_EXEC_PROGRAM:
label = "exec";
@@ -332,7 +326,7 @@ out:
void
kbfunc_ssh(struct client_ctx *cc, union arg *arg)
{
struct screen_ctx *sc;
struct screen_ctx *sc = cc->sc;
struct menu *mi;
struct menu_q menuq;
FILE *fp;
@@ -342,8 +336,6 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
int l;
size_t len;
sc = cc->sc;
if ((home = getenv("HOME")) == NULL)
return;

6
menu.c
View File

@@ -349,8 +349,8 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
ymax = xine->y_org + xine->height;
} else {
xmin = ymin = 0;
xmax = sc->xmax;
ymax = sc->ymax;
xmax = sc->view.w;
ymax = sc->view.h;
}
xsave = mc->x;
@@ -466,7 +466,7 @@ menu_keycode(KeyCode kc, u_int state, enum ctltype *ctl, char *chr)
*ctl = CTL_NONE;
*chr = '\0';
ks = XKeycodeToKeysym(X_Dpy, kc, (state & ShiftMask) ? 1 : 0);
ks = XkbKeycodeToKeysym(X_Dpy, kc, 0, (state & ShiftMask) ? 1 : 0);
/* Look for control characters. */
switch (ks) {

View File

@@ -37,17 +37,17 @@ static void mousefunc_sweep_draw(struct client_ctx *);
static int
mousefunc_sweep_calc(struct client_ctx *cc, int x, int y, int mx, int my)
{
int width = cc->geom.width, height = cc->geom.height;
int width = cc->geom.w, height = cc->geom.h;
cc->geom.width = abs(x - mx) - cc->bwidth;
cc->geom.height = abs(y - my) - cc->bwidth;
cc->geom.w = abs(x - mx) - cc->bwidth;
cc->geom.h = abs(y - my) - cc->bwidth;
client_applysizehints(cc);
cc->geom.x = x <= mx ? x : x - cc->geom.width;
cc->geom.y = y <= my ? y : y - cc->geom.height;
cc->geom.x = x <= mx ? x : x - cc->geom.w;
cc->geom.y = y <= my ? y : y - cc->geom.h;
return (width != cc->geom.width || height != cc->geom.height);
return (width != cc->geom.w || height != cc->geom.h);
}
static void
@@ -58,8 +58,8 @@ mousefunc_sweep_draw(struct client_ctx *cc)
int width, width_size, width_name;
(void)snprintf(asize, sizeof(asize), "%dx%d",
(cc->geom.width - cc->hint.basew) / cc->hint.incw,
(cc->geom.height - cc->hint.baseh) / cc->hint.inch);
(cc->geom.w - cc->hint.basew) / cc->hint.incw,
(cc->geom.h - cc->hint.baseh) / cc->hint.inch);
width_size = font_width(sc, asize, strlen(asize)) + 4;
width_name = font_width(sc, cc->name, strlen(cc->name)) + 4;
width = MAX(width_size, width_name);
@@ -91,7 +91,7 @@ mousefunc_window_resize(struct client_ctx *cc, void *arg)
if (xu_ptr_grab(cc->win, MOUSEMASK, Cursor_resize) < 0)
return;
xu_ptr_setpos(cc->win, cc->geom.width, cc->geom.height);
xu_ptr_setpos(cc->win, cc->geom.w, cc->geom.h);
mousefunc_sweep_draw(cc);
for (;;) {
@@ -121,10 +121,10 @@ mousefunc_window_resize(struct client_ctx *cc, void *arg)
xu_ptr_ungrab();
/* Make sure the pointer stays within the window. */
if (cc->ptr.x > cc->geom.width)
cc->ptr.x = cc->geom.width - cc->bwidth;
if (cc->ptr.y > cc->geom.height)
cc->ptr.y = cc->geom.height - cc->bwidth;
if (cc->ptr.x > cc->geom.w)
cc->ptr.x = cc->geom.w - cc->bwidth;
if (cc->ptr.y > cc->geom.h)
cc->ptr.y = cc->geom.h - cc->bwidth;
client_ptrwarp(cc);
return;
}
@@ -137,6 +137,7 @@ mousefunc_window_move(struct client_ctx *cc, void *arg)
{
XEvent ev;
Time ltime = 0;
struct screen_ctx *sc = cc->sc;
int px, py;
client_raise(cc);
@@ -161,10 +162,10 @@ mousefunc_window_move(struct client_ctx *cc, void *arg)
cc->geom.y = ev.xmotion.y_root - py - cc->bwidth;
cc->geom.x += client_snapcalc(cc->geom.x,
cc->geom.width, cc->sc->xmax,
cc->geom.w, sc->view.w,
cc->bwidth, Conf.snapdist);
cc->geom.y += client_snapcalc(cc->geom.y,
cc->geom.height, cc->sc->ymax,
cc->geom.h, sc->view.h,
cc->bwidth, Conf.snapdist);
/* don't move more than 60 times / second */
@@ -217,13 +218,12 @@ mousefunc_menu_group(struct client_ctx *cc, void *arg)
void
mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
{
struct screen_ctx *sc;
struct screen_ctx *sc = cc->sc;
struct client_ctx *old_cc;
struct menu *mi;
struct menu_q menuq;
char *wname;
sc = cc->sc;
old_cc = client_current();
TAILQ_INIT(&menuq);
@@ -261,13 +261,11 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
void
mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
{
struct screen_ctx *sc;
struct screen_ctx *sc = cc->sc;
struct menu *mi;
struct menu_q menuq;
struct cmd *cmd;
sc = cc->sc;
TAILQ_INIT(&menuq);
TAILQ_FOREACH(cmd, &Conf.cmdq, entry) {
mi = xcalloc(1, sizeof(*mi));

View File

@@ -30,6 +30,8 @@
#include "calmwm.h"
static void screen_init_xinerama(struct screen_ctx *);
struct screen_ctx *
screen_fromroot(Window rootwin)
{
@@ -65,24 +67,18 @@ screen_updatestackingorder(struct screen_ctx *sc)
XFree(wins);
}
/*
* If we're using RandR then we'll redo this whenever the screen
* changes since a CTRC may have been added or removed
*/
void
screen_init_xinerama(struct screen_ctx *sc)
{
XineramaScreenInfo *info;
int no;
XineramaScreenInfo *info = NULL;
int no = 0;
if (HasXinerama == 0 || XineramaIsActive(X_Dpy) == 0) {
HasXinerama = 0;
sc->xinerama_no = 0;
}
info = XineramaQueryScreens(X_Dpy, &no);
if (info == NULL) {
/* Is xinerama actually off, instead of a malloc failure? */
if (sc->xinerama == NULL)
HasXinerama = 0;
return;
}
if (XineramaIsActive(X_Dpy))
info = XineramaQueryScreens(X_Dpy, &no);
if (sc->xinerama != NULL)
XFree(sc->xinerama);
@@ -99,6 +95,9 @@ screen_find_xinerama(struct screen_ctx *sc, int x, int y)
XineramaScreenInfo *info;
int i;
if (sc->xinerama == NULL)
return (NULL);
for (i = 0; i < sc->xinerama_no; i++) {
info = &sc->xinerama[i];
if (x >= info->x_org && x < info->x_org + info->width &&
@@ -109,25 +108,20 @@ screen_find_xinerama(struct screen_ctx *sc, int x, int y)
}
void
screen_update_geometry(struct screen_ctx *sc, int width, int height)
screen_update_geometry(struct screen_ctx *sc)
{
long geom[2], workareas[CALMWM_NGROUPS][4];
int i;
sc->view.x = 0;
sc->view.y = 0;
sc->view.w = DisplayWidth(X_Dpy, sc->which);
sc->view.h = DisplayHeight(X_Dpy, sc->which);
sc->xmax = geom[0] = width;
sc->ymax = geom[1] = height;
XChangeProperty(X_Dpy, sc->rootwin, _NET_DESKTOP_GEOMETRY,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);
sc->work.x = sc->view.x + sc->gap.left;
sc->work.y = sc->view.y + sc->gap.top;
sc->work.w = sc->view.w - (sc->gap.left + sc->gap.right);
sc->work.h = sc->view.h - (sc->gap.top + sc->gap.bottom);
/* x, y, width, height. */
for (i = 0; i < CALMWM_NGROUPS; i++) {
workareas[i][0] = sc->gap.left;
workareas[i][1] = sc->gap.top;
workareas[i][2] = width - (sc->gap.left + sc->gap.right);
workareas[i][3] = height - (sc->gap.top + sc->gap.bottom);
}
screen_init_xinerama(sc);
XChangeProperty(X_Dpy, sc->rootwin, _NET_WORKAREA,
XA_CARDINAL, 32, PropModeReplace,
(unsigned char *)workareas, CALMWM_NGROUPS * 4);
xu_ewmh_net_desktop_geometry(sc);
xu_ewmh_net_workarea(sc);
}

View File

@@ -70,6 +70,9 @@ void (*xev_handlers[LASTEvent])(XEvent *) = {
[MappingNotify] = xev_handle_mappingnotify,
};
static KeySym modkeys[] = { XK_Alt_L, XK_Alt_R, XK_Super_L, XK_Super_R,
XK_Control_L, XK_Control_R };
static void
xev_handle_maprequest(XEvent *ee)
{
@@ -138,9 +141,9 @@ xev_handle_configurerequest(XEvent *ee)
sc = cc->sc;
if (e->value_mask & CWWidth)
cc->geom.width = e->width;
cc->geom.w = e->width;
if (e->value_mask & CWHeight)
cc->geom.height = e->height;
cc->geom.h = e->height;
if (e->value_mask & CWX)
cc->geom.x = e->x;
if (e->value_mask & CWY)
@@ -148,16 +151,16 @@ xev_handle_configurerequest(XEvent *ee)
if (e->value_mask & CWBorderWidth)
wc.border_width = e->border_width;
if (cc->geom.x == 0 && cc->geom.width >= sc->xmax)
if (cc->geom.x == 0 && cc->geom.w >= sc->view.w)
cc->geom.x -= cc->bwidth;
if (cc->geom.y == 0 && cc->geom.height >= sc->ymax)
if (cc->geom.y == 0 && cc->geom.h >= sc->view.h)
cc->geom.y -= cc->bwidth;
wc.x = cc->geom.x;
wc.y = cc->geom.y;
wc.width = cc->geom.width;
wc.height = cc->geom.height;
wc.width = cc->geom.w;
wc.height = cc->geom.h;
wc.border_width = cc->bwidth;
XConfigureWindow(X_Dpy, cc->win, e->value_mask, &wc);
@@ -203,12 +206,10 @@ xev_handle_propertynotify(XEvent *ee)
if (sc->rootwin == e->window)
goto test;
return;
test:
if (e->atom == _NET_DESKTOP_NAMES)
if (e->atom == ewmh[_NET_DESKTOP_NAMES].atom)
group_update_names(sc);
}
}
static void
@@ -278,8 +279,8 @@ xev_handle_keypress(XEvent *ee)
KeySym keysym, skeysym;
int modshift;
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
skeysym = XKeycodeToKeysym(X_Dpy, e->keycode, 1);
keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);
skeysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 1);
/* we don't care about caps lock and numlock here */
e->state &= ~(LockMask | Mod2Mask);
@@ -314,7 +315,7 @@ xev_handle_keypress(XEvent *ee)
}
/*
* This is only used for the alt suppression detection.
* This is only used for the modifier suppression detection.
*/
static void
xev_handle_keyrelease(XEvent *ee)
@@ -322,26 +323,17 @@ xev_handle_keyrelease(XEvent *ee)
XKeyEvent *e = &ee->xkey;
struct screen_ctx *sc;
struct client_ctx *cc;
int keysym;
int i, keysym;
sc = screen_fromroot(e->root);
cc = client_current();
keysym = XKeycodeToKeysym(X_Dpy, e->keycode, 0);
if (keysym != XK_Alt_L && keysym != XK_Alt_R)
return;
sc->altpersist = 0;
/*
* XXX - better interface... xevents should not know about
* how/when to mtf.
*/
client_mtf(NULL);
if (cc != NULL) {
group_sticky_toggle_exit(cc);
XUngrabKeyboard(X_Dpy, CurrentTime);
keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);
for (i = 0; i < nitems(modkeys); i++) {
if (keysym == modkeys[i]) {
client_cycle_leave(sc, cc);
break;
}
}
}
@@ -373,8 +365,7 @@ xev_handle_randr(XEvent *ee)
TAILQ_FOREACH(sc, &Screenq, entry) {
if (sc->which == (u_int)i) {
XRRUpdateConfiguration(ee);
screen_update_geometry(sc, rev->width, rev->height);
screen_init_xinerama(sc);
screen_update_geometry(sc);
}
}
}

238
xutil.c
View File

@@ -94,8 +94,8 @@ xu_key_grab(Window win, int mask, int keysym)
int i;
code = XKeysymToKeycode(X_Dpy, keysym);
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
if ((XkbKeycodeToKeysym(X_Dpy, code, 0, 0) != keysym) &&
(XkbKeycodeToKeysym(X_Dpy, code, 0, 1) == keysym))
mask |= ShiftMask;
for (i = 0; i < nitems(ign_mods); i++)
@@ -110,8 +110,8 @@ xu_key_ungrab(Window win, int mask, int keysym)
int i;
code = XKeysymToKeycode(X_Dpy, keysym);
if ((XKeycodeToKeysym(X_Dpy, code, 0) != keysym) &&
(XKeycodeToKeysym(X_Dpy, code, 1) == keysym))
if ((XkbKeycodeToKeysym(X_Dpy, code, 0, 0) != keysym) &&
(XkbKeycodeToKeysym(X_Dpy, code, 0, 1) == keysym))
mask |= ShiftMask;
for (i = 0; i < nitems(ign_mods); i++)
@@ -128,8 +128,8 @@ xu_configure(struct client_ctx *cc)
ce.window = cc->win;
ce.x = cc->geom.x;
ce.y = cc->geom.y;
ce.width = cc->geom.width;
ce.height = cc->geom.height;
ce.width = cc->geom.w;
ce.height = cc->geom.h;
ce.border_width = cc->bwidth;
ce.above = None;
ce.override_redirect = 0;
@@ -207,7 +207,8 @@ xu_getstate(struct client_ctx *cc, int *state)
{
long *p = NULL;
if (xu_getprop(cc->win, WM_STATE, WM_STATE, 2L, (u_char **)&p) <= 0)
if (xu_getprop(cc->win, cwmh[WM_STATE].atom, cwmh[WM_STATE].atom, 2L,
(u_char **)&p) <= 0)
return (-1);
*state = (int)*p;
@@ -225,63 +226,194 @@ xu_setstate(struct client_ctx *cc, int state)
dat[1] = None;
cc->state = state;
XChangeProperty(X_Dpy, cc->win, WM_STATE, WM_STATE, 32,
XChangeProperty(X_Dpy, cc->win,
cwmh[WM_STATE].atom, cwmh[WM_STATE].atom, 32,
PropModeReplace, (unsigned char *)dat, 2);
}
Atom cwm_atoms[CWM_NO_ATOMS];
char *atoms[CWM_NO_ATOMS] = {
"WM_STATE",
"WM_DELETE_WINDOW",
"WM_TAKE_FOCUS",
"WM_PROTOCOLS",
"_MOTIF_WM_HINTS",
"UTF8_STRING",
"_NET_SUPPORTED",
"_NET_SUPPORTING_WM_CHECK",
"_NET_WM_NAME",
"_NET_ACTIVE_WINDOW",
"_NET_CLIENT_LIST",
"_NET_NUMBER_OF_DESKTOPS",
"_NET_CURRENT_DESKTOP",
"_NET_DESKTOP_VIEWPORT",
"_NET_DESKTOP_GEOMETRY",
"_NET_VIRTUAL_ROOTS",
"_NET_SHOWING_DESKTOP",
"_NET_DESKTOP_NAMES",
"_NET_WM_DESKTOP",
"_NET_WORKAREA",
struct atom_ctx cwmh[CWMH_NITEMS] = {
{"WM_STATE", None},
{"WM_DELETE_WINDOW", None},
{"WM_TAKE_FOCUS", None},
{"WM_PROTOCOLS", None},
{"_MOTIF_WM_HINTS", None},
{"UTF8_STRING", None},
};
struct atom_ctx ewmh[EWMH_NITEMS] = {
{"_NET_SUPPORTED", None},
{"_NET_SUPPORTING_WM_CHECK", None},
{"_NET_ACTIVE_WINDOW", None},
{"_NET_CLIENT_LIST", None},
{"_NET_NUMBER_OF_DESKTOPS", None},
{"_NET_CURRENT_DESKTOP", None},
{"_NET_DESKTOP_VIEWPORT", None},
{"_NET_DESKTOP_GEOMETRY", None},
{"_NET_VIRTUAL_ROOTS", None},
{"_NET_SHOWING_DESKTOP", None},
{"_NET_DESKTOP_NAMES", None},
{"_NET_WORKAREA", None},
{"_NET_WM_NAME", None},
{"_NET_WM_DESKTOP", None},
};
void
xu_getatoms(void)
{
XInternAtoms(X_Dpy, atoms, CWM_NO_ATOMS, False, cwm_atoms);
int i;
for (i = 0; i < nitems(cwmh); i++)
cwmh[i].atom = XInternAtom(X_Dpy, cwmh[i].name, False);
for (i = 0; i < nitems(ewmh); i++)
ewmh[i].atom = XInternAtom(X_Dpy, ewmh[i].name, False);
}
/* Root Window Properties */
void
xu_ewmh_net_supported(struct screen_ctx *sc)
{
Atom atom[EWMH_NITEMS];
int i;
for (i = 0; i < nitems(ewmh); i++)
atom[i] = ewmh[i].atom;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTED].atom,
XA_ATOM, 32, PropModeReplace, (unsigned char *)atom, EWMH_NITEMS);
}
void
xu_setwmname(struct screen_ctx *sc)
xu_ewmh_net_supported_wm_check(struct screen_ctx *sc)
{
/*
* set up the _NET_SUPPORTED hint with all netwm atoms that we
* know about.
Window w;
w = XCreateSimpleWindow(X_Dpy, sc->rootwin, -1, -1, 1, 1, 0, 0, 0);
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SUPPORTING_WM_CHECK].atom,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
XChangeProperty(X_Dpy, w, ewmh[_NET_SUPPORTING_WM_CHECK].atom,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
XChangeProperty(X_Dpy, w, ewmh[_NET_WM_NAME].atom,
XA_WM_NAME, 8, PropModeReplace, WMNAME, strlen(WMNAME));
}
void
xu_ewmh_net_desktop_geometry(struct screen_ctx *sc)
{
long geom[2] = { sc->view.w, sc->view.h };
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_GEOMETRY].atom,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)geom , 2);
}
void
xu_ewmh_net_workarea(struct screen_ctx *sc)
{
long workareas[CALMWM_NGROUPS][4];
int i;
for (i = 0; i < CALMWM_NGROUPS; i++) {
workareas[i][0] = sc->work.x;
workareas[i][1] = sc->work.y;
workareas[i][2] = sc->work.w;
workareas[i][3] = sc->work.h;
}
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_WORKAREA].atom,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)workareas,
CALMWM_NGROUPS * 4);
}
void
xu_ewmh_net_client_list(struct screen_ctx *sc)
{
struct client_ctx *cc;
Window *winlist;
int i = 0, j = 0;
TAILQ_FOREACH(cc, &Clientq, entry)
i++;
if (i == 0)
return;
winlist = xmalloc(i * sizeof(*winlist));
TAILQ_FOREACH(cc, &Clientq, entry)
winlist[j++] = cc->win;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST].atom,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);
xfree(winlist);
}
void
xu_ewmh_net_active_window(struct screen_ctx *sc, Window w)
{
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_ACTIVE_WINDOW].atom,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&w, 1);
}
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].atom,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)viewports, 2);
}
void
xu_ewmh_net_wm_number_of_desktops(struct screen_ctx *sc)
{
long ndesks = CALMWM_NGROUPS;
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_NUMBER_OF_DESKTOPS].atom,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&ndesks, 1);
}
void
xu_ewmh_net_showing_desktop(struct screen_ctx *sc)
{
long zero = 0;
/* We don't support `showing desktop' mode, so this is zero.
* Note that when we hide all groups, or when all groups are
* hidden we could technically set this later on.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTED, XA_ATOM, 32,
PropModeReplace, (unsigned char *)&_NET_SUPPORTED,
CWM_NO_ATOMS - CWM_NETWM_START);
/*
* netwm spec says that to prove that the hint is not stale you must
* provide _NET_SUPPORTING_WM_CHECK containing a window (we use the
* menu window). The property must be set on the root window and the
* window itself, the window also must have _NET_WM_NAME set with the
* window manager name.
*/
XChangeProperty(X_Dpy, sc->rootwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_SUPPORTING_WM_CHECK,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&sc->menuwin, 1);
XChangeProperty(X_Dpy, sc->menuwin, _NET_WM_NAME, UTF8_STRING,
8, PropModeReplace, WMNAME, strlen(WMNAME));
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_SHOWING_DESKTOP].atom,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&zero, 1);
}
void
xu_ewmh_net_virtual_roots(struct screen_ctx *sc)
{
/* We don't support virtual roots, so delete if set by previous wm. */
XDeleteProperty(X_Dpy, sc->rootwin, ewmh[_NET_VIRTUAL_ROOTS].atom);
}
void
xu_ewmh_net_current_desktop(struct screen_ctx *sc, long idx)
{
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CURRENT_DESKTOP].atom,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&idx, 1);
}
void
xu_ewmh_net_desktop_names(struct screen_ctx *sc, unsigned char *data, int n)
{
XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_DESKTOP_NAMES].atom,
cwmh[UTF8_STRING].atom, 8, PropModeReplace, data, n);
}
/* Application Window Properties */
void
xu_ewmh_net_wm_desktop(struct client_ctx *cc)
{
struct group_ctx *gc = cc->group;
long no = 0xffffffff;
if (gc)
no = gc->shortcut - 1;
XChangeProperty(X_Dpy, cc->win, ewmh[_NET_WM_DESKTOP].atom,
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&no, 1);
}
unsigned long
@@ -292,10 +424,10 @@ xu_getcolor(struct screen_ctx *sc, char *name)
if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
name, &color, &tmp)) {
warnx("XAllocNamedColor error: '%s'", name);
return 0;
return (0);
}
return color.pixel;
return (color.pixel);
}
void