48 Commits

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ok oga@
2011-08-22 16:18:05 +00:00
15 changed files with 735 additions and 546 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,19 +157,21 @@ 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);
group_init(sc);
font_init(sc);
conf_font(&Conf, sc);
TAILQ_INIT(&sc->mruq);
@ -177,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;
@ -200,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);
}
@ -222,6 +213,7 @@ x_wmerrorhandler(Display *dpy, XErrorEvent *e)
return (0);
}
static int
x_errorhandler(Display *dpy, XErrorEvent *e)
{

134
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>
@ -68,8 +69,9 @@
#define CWM_EXEC_WM 0x0002
/* cycle */
#define CWM_CYCLE 0
#define CWM_RCYCLE 1
#define CWM_CYCLE 0x0001
#define CWM_RCYCLE 0x0002
#define CWM_INGROUP 0x0004
#define KBTOGROUP(X) ((X) - 1)
@ -85,12 +87,20 @@ enum cwmcolor {
CWM_COLOR_BORDER_UNGROUP,
CWM_COLOR_FG_MENU,
CWM_COLOR_BG_MENU,
CWM_COLOR_FONT,
CWM_COLOR_MAX
};
struct color {
unsigned long pixel;
char *name;
unsigned long pixel;
};
struct geom {
int x;
int y;
int w;
int h;
};
struct gap {
@ -115,11 +125,8 @@ struct client_ctx {
XSizeHints *size;
Colormap cmap;
u_int bwidth; /* border width */
struct geom geom, savegeom;
struct {
int x; /* x position */
int y; /* y position */
int width; /* width */
int height;/* height */
int basew; /* desired width */
int baseh; /* desired height */
int minw; /* minimum width */
@ -130,7 +137,7 @@ struct client_ctx {
int inch; /* height increment progression */
float mina; /* minimum aspect ratio */
float maxa; /* maximum aspect ratio */
} geom, savegeom;
} hint;
struct {
int x; /* x position */
int y; /* y position */
@ -140,10 +147,12 @@ struct client_ctx {
int xproto;
#define CLIENT_HIDDEN 0x0001
#define CLIENT_IGNORE 0x0002
#define CLIENT_MAXIMIZED 0x0004
#define CLIENT_VMAXIMIZED 0x0008
#define CLIENT_HMAXIMIZED 0x0010
#define CLIENT_FREEZE 0x0020
#define CLIENT_VMAXIMIZED 0x0004
#define CLIENT_HMAXIMIZED 0x0008
#define CLIENT_FREEZE 0x0010
#define CLIENT_MAXFLAGS (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
#define CLIENT_MAXIMIZED (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
int flags;
int state;
int active;
@ -196,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;
@ -276,17 +285,11 @@ struct conf {
#define CONF_SNAPDIST 0
int snapdist;
struct gap gap;
#define CONF_COLOR_ACTIVEBORDER "#CCCCCC"
#define CONF_COLOR_INACTIVEBORDER "#666666"
#define CONF_COLOR_GROUPBORDER "blue"
#define CONF_COLOR_UNGROUPBORDER "red"
#define CONF_COLOR_MENUFG "black"
#define CONF_COLOR_MENUBG "white"
struct color color[CWM_COLOR_MAX];
char termpath[MAXPATHLEN];
char lockpath[MAXPATHLEN];
#define DEFAULTFONTNAME "sans-serif:pixelsize=14:bold"
char *DefaultFontName;
#define CONF_FONT "sans-serif:pixelsize=14:bold"
char *font;
};
/* MWM hints */
@ -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);
@ -328,6 +332,7 @@ void client_send_delete(struct client_ctx *);
void client_setactive(struct client_ctx *, int);
void client_setname(struct client_ctx *);
int client_snapcalc(int, int, int, int, int);
void client_transient(struct client_ctx *);
void client_unhide(struct client_ctx *);
void client_vertmaximize(struct client_ctx *);
void client_warp(struct client_ctx *);
@ -357,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 *);
@ -436,7 +440,7 @@ int font_descent(struct screen_ctx *);
void font_draw(struct screen_ctx *, const char *, int,
Drawable, int, int);
u_int font_height(struct screen_ctx *);
void font_init(struct screen_ctx *);
void font_init(struct screen_ctx *, const char *);
int font_width(struct screen_ctx *, const char *, int);
XftFont *font_make(struct screen_ctx *, const char *);
@ -460,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 *);
@ -485,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_ */

400
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) {
@ -113,6 +113,8 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
XAddToSaveSet(X_Dpy, cc->win);
client_transient(cc);
/* Notify client of its configuration. */
xu_configure(cc);
@ -124,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);
@ -141,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);
@ -157,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);
@ -226,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);
@ -234,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;
@ -251,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;
}
@ -275,45 +256,56 @@ 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;
if (cc->flags & CLIENT_MAXIMIZED) {
if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_MAXIMIZED) {
cc->flags &= ~CLIENT_MAXIMIZED;
cc->geom = cc->savegeom;
cc->bwidth = Conf.bwidth;
cc->flags &= ~CLIENT_MAXIMIZED;
} else {
if (!(cc->flags & (CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)))
cc->savegeom = cc->geom;
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;
x_org = xine->x_org;
y_org = xine->y_org;
xmax = xine->width;
ymax = xine->height;
}
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->bwidth = 0;
cc->flags |= CLIENT_MAXIMIZED;
goto resize;
}
if ((cc->flags & CLIENT_VMAXIMIZED) == 0) {
cc->savegeom.h = cc->geom.h;
cc->savegeom.y = cc->geom.y;
}
if ((cc->flags & CLIENT_HMAXIMIZED) == 0) {
cc->savegeom.w = cc->geom.w;
cc->savegeom.x = cc->geom.x;
}
/*
* pick screen that the middle of the window is on.
* that's probably more fair than if just the origin of
* a window is poking over a boundary
*/
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;
}
cc->geom.x = x_org + sc->gap.left;
cc->geom.y = y_org + sc->gap.top;
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;
resize:
client_resize(cc);
}
@ -321,36 +313,48 @@ 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.w -= cc->bwidth * 2;
cc->flags &= ~CLIENT_VMAXIMIZED;
} else {
if (!(cc->flags & (CLIENT_MAXIMIZED | CLIENT_HMAXIMIZED)))
cc->savegeom = cc->geom;
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;
y_org = xine->y_org;
ymax = xine->height;
}
calc:
cc->geom.y = y_org + sc->gap.top;
cc->geom.height = ymax - (cc->bwidth * 2) - (sc->gap.top +
sc->gap.bottom);
cc->flags |= CLIENT_VMAXIMIZED;
goto resize;
}
cc->savegeom.y = cc->geom.y;
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.w += Conf.bwidth * 2;
cc->bwidth = 0;
}
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;
}
cc->geom.y = y_org + sc->gap.top;
cc->geom.h = ymax - (cc->bwidth * 2) - (sc->gap.top +
sc->gap.bottom);
cc->flags |= CLIENT_VMAXIMIZED;
resize:
client_resize(cc);
}
@ -358,36 +362,48 @@ 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.h -= cc->bwidth * 2;
cc->flags &= ~CLIENT_HMAXIMIZED;
} else {
if (!(cc->flags & (CLIENT_MAXIMIZED | CLIENT_VMAXIMIZED)))
cc->savegeom = cc->geom;
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;
x_org = xine->x_org;
xmax = xine->width;
}
calc:
cc->geom.x = x_org + sc->gap.left;
cc->geom.width = xmax - (cc->bwidth * 2) - (sc->gap.left +
sc->gap.right);
cc->flags |= CLIENT_HMAXIMIZED;
goto resize;
}
cc->savegeom.x = cc->geom.x;
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.h += cc->bwidth * 2;
cc->bwidth = 0;
}
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;
}
cc->geom.x = x_org + sc->gap.left;
cc->geom.w = xmax - (cc->bwidth * 2) - (sc->gap.left +
sc->gap.right);
cc->flags |= CLIENT_HMAXIMIZED;
resize:
client_resize(cc);
}
@ -397,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);
}
@ -426,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);
@ -506,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);
@ -523,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);
}
@ -534,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;
@ -567,7 +584,7 @@ match:
}
void
client_cycle(struct screen_ctx *sc, int reverse)
client_cycle(struct screen_ctx *sc, int flags)
{
struct client_ctx *oldcc, *newcc;
int again = 1;
@ -579,18 +596,20 @@ client_cycle(struct screen_ctx *sc, int reverse)
return;
if (oldcc == NULL)
oldcc = (reverse ? TAILQ_LAST(&sc->mruq, cycle_entry_q) :
oldcc = (flags & CWM_RCYCLE ?
TAILQ_LAST(&sc->mruq, cycle_entry_q) :
TAILQ_FIRST(&sc->mruq));
newcc = oldcc;
while (again) {
again = 0;
newcc = (reverse ? client_mruprev(newcc) :
newcc = (flags & CWM_RCYCLE ? client_mruprev(newcc) :
client_mrunext(newcc));
/* Only cycle visible and non-ignored windows. */
if (newcc->flags & (CLIENT_HIDDEN|CLIENT_IGNORE))
if ((newcc->flags & (CLIENT_HIDDEN|CLIENT_IGNORE))
|| ((flags & CWM_INGROUP) && (newcc->group != oldcc->group)))
again = 1;
/* Is oldcc the only non-hidden window? */
@ -602,12 +621,24 @@ client_cycle(struct screen_ctx *sc, int reverse)
}
}
/* 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)
{
@ -642,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)
@ -654,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),
@ -684,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),
@ -693,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;
}
}
}
@ -724,86 +752,87 @@ client_getsizehints(struct client_ctx *cc)
cc->size->flags = PSize;
if (cc->size->flags & PBaseSize) {
cc->geom.basew = cc->size->base_width;
cc->geom.baseh = cc->size->base_height;
cc->hint.basew = cc->size->base_width;
cc->hint.baseh = cc->size->base_height;
} else if (cc->size->flags & PMinSize) {
cc->geom.basew = cc->size->min_width;
cc->geom.baseh = cc->size->min_height;
cc->hint.basew = cc->size->min_width;
cc->hint.baseh = cc->size->min_height;
}
if (cc->size->flags & PMinSize) {
cc->geom.minw = cc->size->min_width;
cc->geom.minh = cc->size->min_height;
cc->hint.minw = cc->size->min_width;
cc->hint.minh = cc->size->min_height;
} else if (cc->size->flags & PBaseSize) {
cc->geom.minw = cc->size->base_width;
cc->geom.minh = cc->size->base_height;
cc->hint.minw = cc->size->base_width;
cc->hint.minh = cc->size->base_height;
}
if (cc->size->flags & PMaxSize) {
cc->geom.maxw = cc->size->max_width;
cc->geom.maxh = cc->size->max_height;
cc->hint.maxw = cc->size->max_width;
cc->hint.maxh = cc->size->max_height;
}
if (cc->size->flags & PResizeInc) {
cc->geom.incw = cc->size->width_inc;
cc->geom.inch = cc->size->height_inc;
cc->hint.incw = cc->size->width_inc;
cc->hint.inch = cc->size->height_inc;
}
cc->geom.incw = MAX(1, cc->geom.incw);
cc->geom.inch = MAX(1, cc->geom.inch);
cc->hint.incw = MAX(1, cc->hint.incw);
cc->hint.inch = MAX(1, cc->hint.inch);
if (cc->size->flags & PAspect) {
if (cc->size->min_aspect.x > 0)
cc->geom.mina = (float)cc->size->min_aspect.y /
cc->hint.mina = (float)cc->size->min_aspect.y /
cc->size->min_aspect.x;
if (cc->size->max_aspect.y > 0)
cc->geom.maxa = (float)cc->size->max_aspect.x /
cc->hint.maxa = (float)cc->size->max_aspect.x /
cc->size->max_aspect.y;
}
}
void
client_applysizehints(struct client_ctx *cc)
{
Bool baseismin;
baseismin = (cc->geom.basew == cc->geom.minw) &&
(cc->geom.baseh == cc->geom.minh);
baseismin = (cc->hint.basew == cc->hint.minw) &&
(cc->hint.baseh == cc->hint.minh);
/* temporarily remove base dimensions, ICCCM 4.1.2.3 */
if (!baseismin) {
cc->geom.width -= cc->geom.basew;
cc->geom.height -= cc->geom.baseh;
cc->geom.w -= cc->hint.basew;
cc->geom.h -= cc->hint.baseh;
}
/* adjust for aspect limits */
if (cc->geom.mina > 0 && cc->geom.maxa > 0) {
if (cc->geom.maxa <
(float)cc->geom.width / cc->geom.height)
cc->geom.width = cc->geom.height * cc->geom.maxa;
else if (cc->geom.mina <
(float)cc->geom.height / cc->geom.width)
cc->geom.height = cc->geom.width * cc->geom.mina;
if (cc->hint.mina > 0 && cc->hint.maxa > 0) {
if (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.h / cc->geom.w)
cc->geom.h = cc->geom.w * cc->hint.mina;
}
/* remove base dimensions for increment */
if (baseismin) {
cc->geom.width -= cc->geom.basew;
cc->geom.height -= cc->geom.baseh;
cc->geom.w -= cc->hint.basew;
cc->geom.h -= cc->hint.baseh;
}
/* adjust for increment value */
cc->geom.width -= cc->geom.width % cc->geom.incw;
cc->geom.height -= cc->geom.height % cc->geom.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->geom.basew;
cc->geom.height += cc->geom.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->geom.minw);
cc->geom.height = MAX(cc->geom.height, cc->geom.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->geom.maxw)
cc->geom.width = MIN(cc->geom.width, cc->geom.maxw);
if (cc->geom.maxh)
cc->geom.height = MIN(cc->geom.height, cc->geom.maxh);
if (cc->hint.maxw)
cc->geom.w = MIN(cc->geom.w, cc->hint.maxw);
if (cc->hint.maxh)
cc->geom.h = MIN(cc->geom.h, cc->hint.maxh);
}
static void
@ -819,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) &&
@ -836,11 +865,26 @@ client_freehints(struct client_ctx *cc)
XFree(cc->app_class);
}
void
client_transient(struct client_ctx *cc)
{
struct client_ctx *tc;
Window trans;
if (XGetTransientForHint(X_Dpy, cc->win, &trans)) {
if ((tc = client_find(trans)) && tc->group) {
group_movetogroup(cc, tc->group->shortcut - 1);
if (tc->flags & CLIENT_IGNORE)
cc->flags |= CLIENT_IGNORE;
}
}
}
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
@ -861,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);
}

69
conf.c
View File

@ -31,13 +31,6 @@
#include "calmwm.h"
#ifndef timespeccmp
#define timespeccmp(tsp, usp, cmp) \
(((tsp)->tv_sec == (usp)->tv_sec) ? \
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
((tsp)->tv_sec cmp (usp)->tv_sec))
#endif
static void conf_mouseunbind(struct conf *, struct mousebinding *);
static void conf_unbind(struct conf *, struct keybinding *);
@ -69,9 +62,20 @@ conf_gap(struct conf *c, struct screen_ctx *sc)
void
conf_font(struct conf *c, struct screen_ctx *sc)
{
sc->font = font_make(sc, c->DefaultFontName);
font_init(sc, c->color[CWM_COLOR_FONT].name);
sc->font = font_make(sc, c->font);
}
static struct color color_binds[] = {
{ "#CCCCCC", 0 }, /* CWM_COLOR_BORDER_ACTIVE */
{ "#666666", 0 }, /* CWM_COLOR_BORDER_INACTIVE */
{ "blue", 0 }, /* CWM_COLOR_BORDER_GROUP */
{ "red", 0 }, /* CWM_COLOR_BORDER_UNGROUP */
{ "black", 0 }, /* CWM_COLOR_FG_MENU */
{ "white", 0 }, /* CWM_COLOR_BG_MENU */
{ "black", 0 }, /* CWM_COLOR_FONT */
};
void
conf_color(struct conf *c, struct screen_ctx *sc)
{
@ -98,6 +102,7 @@ conf_reload(struct conf *c)
conf_gap(c, sc);
conf_color(c, sc);
conf_font(c, sc);
menu_init(sc);
}
TAILQ_FOREACH(cc, &Clientq, entry)
client_draw_border(cc);
@ -198,24 +203,14 @@ conf_init(struct conf *c)
for (i = 0; i < nitems(m_binds); i++)
conf_mousebind(c, m_binds[i].key, m_binds[i].func);
for (i = 0; i < nitems(color_binds); i++)
c->color[i].name = xstrdup(color_binds[i].name);
/* Default term/lock */
(void)strlcpy(c->termpath, "xterm", sizeof(c->termpath));
(void)strlcpy(c->lockpath, "xlock", sizeof(c->lockpath));
c->color[CWM_COLOR_BORDER_ACTIVE].name =
xstrdup(CONF_COLOR_ACTIVEBORDER);
c->color[CWM_COLOR_BORDER_INACTIVE].name =
xstrdup(CONF_COLOR_INACTIVEBORDER);
c->color[CWM_COLOR_BORDER_GROUP].name =
xstrdup(CONF_COLOR_GROUPBORDER);
c->color[CWM_COLOR_BORDER_UNGROUP].name =
xstrdup(CONF_COLOR_UNGROUPBORDER);
c->color[CWM_COLOR_FG_MENU].name =
xstrdup(CONF_COLOR_MENUFG);
c->color[CWM_COLOR_BG_MENU].name =
xstrdup(CONF_COLOR_MENUBG);
c->DefaultFontName = xstrdup(DEFAULTFONTNAME);
c->font = xstrdup(CONF_FONT);
}
void
@ -259,32 +254,38 @@ conf_clear(struct conf *c)
for (i = 0; i < CWM_COLOR_MAX; i++)
xfree(c->color[i].name);
xfree(c->DefaultFontName);
xfree(c->font);
}
void
conf_setup(struct conf *c, const char *conf_file)
{
char *home;
struct stat sb;
int parse = 0;
conf_init(c);
if (conf_file == NULL) {
char *home = getenv("HOME");
if (home == NULL)
if ((home = getenv("HOME")) == NULL)
errx(1, "No HOME directory.");
(void)snprintf(c->conf_path, sizeof(c->conf_path), "%s/%s",
home, CONFFILE);
} else
if (stat(c->conf_path, &sb) == 0 && (sb.st_mode & S_IFREG))
parse = 1;
} else {
if (stat(conf_file, &sb) == -1 || !(sb.st_mode & S_IFREG))
errx(1, "%s: %s", conf_file, strerror(errno));
else
else {
(void)strlcpy(c->conf_path, conf_file,
sizeof(c->conf_path));
parse = 1;
}
}
conf_init(c);
if (parse_config(c->conf_path, c) == -1)
if (parse && (parse_config(c->conf_path, c) == -1))
warnx("config file %s has errors, not loading", c->conf_path);
}
@ -360,6 +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} },
{ "grouptoggle", kbfunc_client_grouptoggle, KBFLAG_NEEDCLIENT, {0}},
{ "maximize", kbfunc_client_maximize, KBFLAG_NEEDCLIENT, {0} },
{ "vmaximize", kbfunc_client_vmaximize, KBFLAG_NEEDCLIENT, {0} },
@ -637,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.

25
cwmrc.5
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: June 24 2011 $
.Dd $Mdocdate: November 6 2011 $
.Dt CWMRC 5
.Os
.Sh NAME
@ -99,12 +99,21 @@ Set the window border width to
.It Ic color activeborder Ar color
Set the color of the active border.
.Pp
.It Ic color font Ar color
Set menu font color.
.Pp
.It Ic color groupborder Ar color
Set the color of the border while grouping a window.
.Pp
.It Ic color inactiveborder Ar color
Set the color of the inactive border.
.Pp
.It Ic color menubg Ar color
Set menu background color.
.Pp
.It Ic color menufg Ar color
Set menu foreground color.
.Pp
.It Ic color ungroupborder Ar color
Set the color of the border while ungrouping a window.
.Pp
@ -197,6 +206,10 @@ Set a default size for the keyboard movement bindings,
in pixels.
The default is 1.
.Pp
.It Ic snapdist Ar pixels
Minimum distance to snap-to adjacent edge, in pixels.
The default is 0.
.Pp
.It Ic sticky Ic yes Ns \&| Ns Ic no
Toggle sticky group mode.
The default behavior for new windows is to not assign any group.
@ -231,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
@ -289,8 +306,10 @@ Reverse cycle through groups.
Forward cycle through windows.
.It rcycle
Reverse cycle through windows.
.It snapdist
Minimum distance to snap-to adjacent edge.
.It cycleingroup
Forward cycle through windows in current group.
.It rcycleingroup
Reverse cycle through windows in current group.
.It delete
Delete current window.
.It hide

9
font.c
View File

@ -49,15 +49,20 @@ font_height(struct screen_ctx *sc)
}
void
font_init(struct screen_ctx *sc)
font_init(struct screen_ctx *sc, const char *color)
{
if (sc->xftdraw)
XftDrawDestroy(sc->xftdraw);
sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
if (sc->xftdraw == NULL)
errx(1, "XftDrawCreate");
if (sc->xftcolor.pixel)
XftColorFree(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), &sc->xftcolor);
if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
DefaultColormap(X_Dpy, sc->which), "black", &sc->xftcolor))
DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor))
errx(1, "XftColorAllocName");
}

89
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,21 +188,27 @@ 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
group_movetogroup(struct client_ctx *cc, int idx)
{
struct screen_ctx *sc = cc->sc;
struct group_ctx *gc;
if (idx < 0 || idx >= CALMWM_NGROUPS)
err(1, "group_movetogroup: index out of range (%d)", idx);
if(sc->group_active != &sc->groups[idx])
gc = &sc->groups[idx];
if (cc->group == gc)
return;
if (gc->hidden) {
client_hide(cc);
group_add(&sc->groups[idx], cc);
gc->nhidden++;
}
group_add(gc, cc);
}
/*
@ -313,7 +299,7 @@ group_only(struct screen_ctx *sc, int idx)
* Cycle through active groups. If none exist, then just stay put.
*/
void
group_cycle(struct screen_ctx *sc, int reverse)
group_cycle(struct screen_ctx *sc, int flags)
{
struct group_ctx *gc, *showgroup = NULL;
@ -321,11 +307,11 @@ group_cycle(struct screen_ctx *sc, int reverse)
gc = sc->group_active;
for (;;) {
gc = reverse ? TAILQ_PREV(gc, group_ctx_q, entry) :
TAILQ_NEXT(gc, entry);
gc = (flags & CWM_RCYCLE) ? TAILQ_PREV(gc, group_ctx_q,
entry) : TAILQ_NEXT(gc, entry);
if (gc == NULL)
gc = reverse ? TAILQ_LAST(&sc->groupq, group_ctx_q) :
TAILQ_FIRST(&sc->groupq);
gc = (flags & CWM_RCYCLE) ? TAILQ_LAST(&sc->groupq,
group_ctx_q) : TAILQ_FIRST(&sc->groupq);
if (gc == sc->group_active)
break;
@ -432,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)
@ -473,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 */
@ -491,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);
@ -511,7 +497,7 @@ group_update_names(struct screen_ctx *sc)
if (prop_ret != NULL)
XFree(prop_ret);
if (sc->group_nonames != 0)
free(sc->group_names);
xfree(sc->group_names);
sc->group_names = strings;
sc->group_nonames = n;
@ -537,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,28 +113,23 @@ 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:
if (cc) {
xu_ptr_getpos(cc->win, &x, &y);
xu_ptr_setpos(cc->win, x + mx, y + my);
} else {
xu_ptr_getpos(sc->rootwin, &x, &y);
xu_ptr_setpos(sc->rootwin, x + mx, y + my);
}
xu_ptr_getpos(sc->rootwin, &x, &y);
xu_ptr_setpos(sc->rootwin, x + mx, y + my);
break;
default:
warnx("invalid flags passed to kbfunc_client_moveresize");
@ -145,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);
@ -182,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) {
@ -210,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,
@ -249,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;
@ -258,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";
@ -337,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;
@ -347,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;

10
menu.c
View File

@ -76,6 +76,8 @@ menu_init(struct screen_ctx *sc)
{
XGCValues gv;
if (sc->menuwin)
XDestroyWindow(X_Dpy, sc->menuwin);
sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1,
Conf.bwidth,
sc->color[CWM_COLOR_FG_MENU].pixel,
@ -86,6 +88,8 @@ menu_init(struct screen_ctx *sc)
gv.background = sc->color[CWM_COLOR_BG_MENU].pixel;
gv.function = GXxor;
if (sc->gc)
XFreeGC(X_Dpy, sc->gc);
sc->gc = XCreateGC(X_Dpy, sc->menuwin,
GCForeground|GCBackground|GCFunction, &gv);
}
@ -345,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;
@ -462,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->geom.basew) / cc->geom.incw,
(cc->geom.height - cc->geom.baseh) / cc->geom.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);
@ -78,7 +78,7 @@ void
mousefunc_window_resize(struct client_ctx *cc, void *arg)
{
XEvent ev;
Time time = 0;
Time ltime = 0;
struct screen_ctx *sc = cc->sc;
int x = cc->geom.x, y = cc->geom.y;
@ -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 (;;) {
@ -108,23 +108,23 @@ mousefunc_window_resize(struct client_ctx *cc, void *arg)
mousefunc_sweep_draw(cc);
/* don't resize more than 60 times / second */
if ((ev.xmotion.time - time) > (1000 / 60)) {
time = ev.xmotion.time;
if ((ev.xmotion.time - ltime) > (1000 / 60)) {
ltime = ev.xmotion.time;
client_resize(cc);
}
break;
case ButtonRelease:
if (time)
if (ltime)
client_resize(cc);
XUnmapWindow(X_Dpy, sc->menuwin);
XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0);
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;
}
@ -136,7 +136,8 @@ void
mousefunc_window_move(struct client_ctx *cc, void *arg)
{
XEvent ev;
Time time = 0;
Time ltime = 0;
struct screen_ctx *sc = cc->sc;
int px, py;
client_raise(cc);
@ -161,20 +162,20 @@ 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 */
if ((ev.xmotion.time - time) > (1000 / 60)) {
time = ev.xmotion.time;
if ((ev.xmotion.time - ltime) > (1000 / 60)) {
ltime = ev.xmotion.time;
client_move(cc);
}
break;
case ButtonRelease:
if (time)
if (ltime)
client_move(cc);
xu_ptr_ungrab();
return;
@ -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));

24
parse.y
View File

@ -73,6 +73,7 @@ typedef struct {
%token COLOR SNAPDIST
%token ACTIVEBORDER INACTIVEBORDER
%token GROUPBORDER UNGROUPBORDER
%token MENUBG MENUFG FONTCOLOR
%token ERROR
%token <v.string> STRING
%token <v.number> NUMBER
@ -105,8 +106,8 @@ yesno : YES { $$ = 1; }
;
main : FONTNAME STRING {
free(conf->DefaultFontName);
conf->DefaultFontName = $2;
free(conf->font);
conf->font = $2;
}
| STICKY yesno {
if ($2 == 0)
@ -184,6 +185,18 @@ colors : ACTIVEBORDER STRING {
free(conf->color[CWM_COLOR_BORDER_UNGROUP].name);
conf->color[CWM_COLOR_BORDER_UNGROUP].name = $2;
}
| MENUBG STRING {
free(conf->color[CWM_COLOR_BG_MENU].name);
conf->color[CWM_COLOR_BG_MENU].name = $2;
}
| MENUFG STRING {
free(conf->color[CWM_COLOR_FG_MENU].name);
conf->color[CWM_COLOR_FG_MENU].name = $2;
}
| FONTCOLOR STRING {
free(conf->color[CWM_COLOR_FONT].name);
conf->color[CWM_COLOR_FONT].name = $2;
}
;
%%
@ -223,11 +236,14 @@ lookup(char *s)
{ "borderwidth", BORDERWIDTH},
{ "color", COLOR},
{ "command", COMMAND},
{ "font", FONTCOLOR},
{ "fontname", FONTNAME},
{ "gap", GAP},
{ "groupborder", GROUPBORDER},
{ "ignore", IGNORE},
{ "inactiveborder", INACTIVEBORDER},
{ "menubg", MENUBG},
{ "menufg", MENUFG},
{ "mousebind", MOUSEBIND},
{ "moveamount", MOVEAMOUNT},
{ "no", NO},
@ -462,8 +478,6 @@ pushfile(const char *name)
nfile->name = xstrdup(name);
if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
if (errno != ENOENT)
warn("%s", nfile->name);
free(nfile->name);
free(nfile);
return (NULL);
@ -563,7 +577,7 @@ parse_config(const char *filename, struct conf *xconf)
for (i = 0; i < CWM_COLOR_MAX; i++)
xconf->color[i].name = conf->color[i].name;
xconf->DefaultFontName = conf->DefaultFontName;
xconf->font = conf->font;
}
free(conf);

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,13 +70,15 @@ 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)
{
XMapRequestEvent *e = &ee->xmaprequest;
struct client_ctx *cc = NULL, *old_cc;
XWindowAttributes xattr;
struct winmatch *wm;
if ((old_cc = client_current()) != NULL)
client_ptrsave(old_cc);
@ -86,10 +88,6 @@ xev_handle_maprequest(XEvent *ee)
cc = client_new(e->window, screen_fromroot(xattr.root), 1);
}
TAILQ_FOREACH(wm, &Conf.ignoreq, entry) {
if (strncasecmp(wm->title, cc->name, strlen(wm->title)) == 0)
return;
}
if ((cc->flags & CLIENT_IGNORE) == 0)
client_ptrwarp(cc);
}
@ -143,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)
@ -153,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);
@ -196,6 +194,9 @@ xev_handle_propertynotify(XEvent *ee)
case XA_WM_NAME:
client_setname(cc);
break;
case XA_WM_TRANSIENT_FOR:
client_transient(cc);
break;
default:
/* do nothing */
break;
@ -205,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
@ -280,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);
@ -316,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)
@ -324,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;
}
}
}
@ -375,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