Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richardgv/5547743 to your computer and use it in GitHub Desktop.
Save richardgv/5547743 to your computer and use it in GitHub Desktop.
richardgv/skippy-xd #2: Custom window actions and bindings, work in progress
diff --git a/skippy-xd.rc-default b/skippy-xd.rc-default
index ce2fb75..a4a1258 100644
--- a/skippy-xd.rc-default
+++ b/skippy-xd.rc-default
@@ -55,3 +55,8 @@ opacity = 128
text = #ffffff
textShadow = black
font = fixed-11:weight=bold
+
+[bindings]
+miwMouse1 = focus
+miwMouse2 = close-ewmh
+miwMouse3 = iconify
diff --git a/src/clientwin.c b/src/clientwin.c
index d298a39..84f4310 100644
--- a/src/clientwin.c
+++ b/src/clientwin.c
@@ -23,6 +23,9 @@
(((x1 >= x2 && x1 < (x2 + w2)) || (x2 >= x1 && x2 < (x1 + w1))) && \
((y1 >= y2 && y1 < (y2 + h2)) || (y2 >= y1 && y2 < (y1 + h1))))
+static int
+wm_action(ClientWin *cw, enum miwop action);
+
int
clientwin_cmp_func(dlist *l, void *data)
{
@@ -34,7 +37,7 @@ clientwin_validate_func(dlist *l, void *data)
{
ClientWin *cw = (ClientWin *)l->data;
CARD32 desktop = (*(CARD32*)data),
- w_desktop = wm_get_window_desktop(cw->mainwin->dpy, cw->client.window);
+ w_desktop = wm_get_window_desktop(cw->mainwin->ps->dpy, cw->client.window);
#ifdef CFG_XINERAMA
if(cw->mainwin->xin_active && ! INTERSECTS(cw->client.x, cw->client.y, cw->client.width, cw->client.height,
@@ -44,14 +47,14 @@ clientwin_validate_func(dlist *l, void *data)
#endif
return (w_desktop == (CARD32)-1 || desktop == w_desktop) &&
- wm_validate_window(cw->mainwin->dpy, cw->client.window);
+ wm_validate_window(cw->mainwin->ps->dpy, cw->client.window);
}
int
clientwin_check_group_leader_func(dlist *l, void *data)
{
ClientWin *cw = (ClientWin *)l->data;
- return wm_get_group_leader(cw->mainwin->dpy, cw->client.window) == *((Window*)data);
+ return wm_get_group_leader(cw->mainwin->ps->dpy, cw->client.window) == *((Window*)data);
}
int
@@ -96,11 +99,11 @@ clientwin_create(MainWin *mw, Window client)
ExposureMask |
FocusChangeMask;
- sattr.override_redirect = mw->lazy_trans;
+ sattr.override_redirect = mw->ps->o.lazyTrans;
cw->client.window = client;
cw->mini.format = mw->format;
- cw->mini.window = XCreateWindow(mw->dpy, mw->lazy_trans ? mw->root : mw->window, 0, 0, 1, 1, 0,
+ cw->mini.window = XCreateWindow(mw->ps->dpy, mw->ps->o.lazyTrans ? mw->ps->root : mw->window, 0, 0, 1, 1, 0,
mw->depth, InputOutput, mw->visual,
CWColormap | CWBackPixel | CWBorderPixel | CWEventMask | CWOverrideRedirect, &sattr);
if (!cw->mini.window)
@@ -109,30 +112,30 @@ clientwin_create(MainWin *mw, Window client)
wm_wid_set_info(cw->mainwin->ps, cw->mini.window, "mini window", None);
// Listen to events on the window. We don't want to miss any changes so
// this is to be done as early as possible
- XSelectInput(cw->mainwin->dpy, cw->client.window, SubstructureNotifyMask | StructureNotifyMask);
+ XSelectInput(cw->mainwin->ps->dpy, cw->client.window, SubstructureNotifyMask | StructureNotifyMask);
- XGetWindowAttributes(mw->dpy, client, &attr);
- cw->client.format = XRenderFindVisualFormat(mw->dpy, attr.visual);
+ XGetWindowAttributes(mw->ps->dpy, client, &attr);
+ cw->client.format = XRenderFindVisualFormat(mw->ps->dpy, attr.visual);
// Get window pixmap
// Seemingly we could only redirect IsViewable windows
if (mw->ps->o.useNameWindowPixmap && IsViewable == attr.map_state) {
- XCompositeRedirectWindow(mw->dpy, cw->client.window, CompositeRedirectAutomatic);
+ XCompositeRedirectWindow(mw->ps->dpy, cw->client.window, CompositeRedirectAutomatic);
cw->redirected = true;
- cw->cpixmap = XCompositeNameWindowPixmap(mw->dpy, cw->client.window);
+ cw->cpixmap = XCompositeNameWindowPixmap(mw->ps->dpy, cw->client.window);
}
// Create window picture
{
Drawable draw = cw->cpixmap;
if (!draw) draw = cw->client.window;
XRenderPictureAttributes pa = { .subwindow_mode = IncludeInferiors };
- cw->origin = XRenderCreatePicture (cw->mainwin->dpy,
+ cw->origin = XRenderCreatePicture (cw->mainwin->ps->dpy,
draw, cw->client.format, CPSubwindowMode, &pa);
}
if (!cw->origin)
goto clientwin_create_err;
- XRenderSetPictureFilter(cw->mainwin->dpy, cw->origin, FilterBest, 0, 0);
+ XRenderSetPictureFilter(cw->mainwin->ps->dpy, cw->origin, FilterBest, 0, 0);
return cw;
@@ -150,10 +153,10 @@ clientwin_update(ClientWin *cw)
Window tmpwin;
XWindowAttributes wattr;
- XGetWindowAttributes(cw->mainwin->dpy, cw->client.window, &wattr);
+ XGetWindowAttributes(cw->mainwin->ps->dpy, cw->client.window, &wattr);
- cw->client.format = XRenderFindVisualFormat(cw->mainwin->dpy, wattr.visual);
- XTranslateCoordinates(cw->mainwin->dpy, cw->client.window, wattr.root,
+ cw->client.format = XRenderFindVisualFormat(cw->mainwin->ps->dpy, wattr.visual);
+ XTranslateCoordinates(cw->mainwin->ps->dpy, cw->client.window, wattr.root,
-wattr.border_width,
-wattr.border_width,
&cw->client.x, &cw->client.y, &tmpwin);
@@ -177,10 +180,10 @@ clientwin_destroy(ClientWin *cw, Bool parentDestroyed)
if (cw->client.window) {
// Stop listening to events, this should be safe because we don't
// monitor window re-map anyway
- XSelectInput(mw->dpy, cw->client.window, 0);
+ XSelectInput(mw->ps->dpy, cw->client.window, 0);
if (cw->redirected)
- XCompositeUnredirectWindow(mw->dpy, cw->client.window, CompositeRedirectAutomatic);
+ XCompositeUnredirectWindow(mw->ps->dpy, cw->client.window, CompositeRedirectAutomatic);
}
}
free_picture(mw->ps, &cw->destination);
@@ -188,7 +191,7 @@ clientwin_destroy(ClientWin *cw, Bool parentDestroyed)
free_pixmap(mw->ps, &cw->cpixmap);
if (cw->mini.window)
- XDestroyWindow(mw->dpy, cw->mini.window);
+ XDestroyWindow(mw->ps->dpy, cw->mini.window);
free(cw);
}
@@ -202,24 +205,24 @@ clientwin_repaint(ClientWin *cw, XRectangle *rect)
s_w = (double)rect->width * cw->factor,
s_h = (double)rect->height * cw->factor;
- if(cw->mainwin->lazy_trans)
+ if(cw->mainwin->ps->o.lazyTrans)
{
- XRenderComposite(cw->mainwin->dpy, PictOpSrc, cw->origin,
+ XRenderComposite(cw->mainwin->ps->dpy, PictOpSrc, cw->origin,
cw->focused ? cw->mainwin->highlightPicture : cw->mainwin->normalPicture,
cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h);
}
else
{
- XRenderComposite(cw->mainwin->dpy, PictOpSrc, cw->mainwin->background, None, cw->destination, cw->mini.x + s_x, cw->mini.y + s_y, 0, 0, s_x, s_y, s_w, s_h);
- XRenderComposite(cw->mainwin->dpy, PictOpOver, cw->origin,
+ XRenderComposite(cw->mainwin->ps->dpy, PictOpSrc, cw->mainwin->background, None, cw->destination, cw->mini.x + s_x, cw->mini.y + s_y, 0, 0, s_x, s_y, s_w, s_h);
+ XRenderComposite(cw->mainwin->ps->dpy, PictOpOver, cw->origin,
cw->focused ? cw->mainwin->highlightPicture : cw->mainwin->normalPicture,
cw->destination, s_x, s_y, 0, 0, s_x, s_y, s_w, s_h);
}
if(tint->alpha)
- XRenderFillRectangle(cw->mainwin->dpy, PictOpOver, cw->destination, tint, s_x, s_y, s_w, s_h);
+ XRenderFillRectangle(cw->mainwin->ps->dpy, PictOpOver, cw->destination, tint, s_x, s_y, s_w, s_h);
- XClearArea(cw->mainwin->dpy, cw->mini.window, s_x, s_y, s_w, s_h, False);
+ XClearArea(cw->mainwin->ps->dpy, cw->mini.window, s_x, s_y, s_w, s_h, False);
}
void
@@ -237,12 +240,12 @@ clientwin_repair(ClientWin *cw)
{
int nrects, i;
XRectangle *rects;
- XserverRegion rgn = XFixesCreateRegion(cw->mainwin->dpy, 0, 0);
+ XserverRegion rgn = XFixesCreateRegion(cw->mainwin->ps->dpy, 0, 0);
- XDamageSubtract(cw->mainwin->dpy, cw->damage, None, rgn);
+ XDamageSubtract(cw->mainwin->ps->dpy, cw->damage, None, rgn);
- rects = XFixesFetchRegion(cw->mainwin->dpy, rgn, &nrects);
- XFixesDestroyRegion(cw->mainwin->dpy, rgn);
+ rects = XFixesFetchRegion(cw->mainwin->ps->dpy, rgn, &nrects);
+ XFixesDestroyRegion(cw->mainwin->ps->dpy, rgn);
for(i = 0; i < nrects; i++)
clientwin_repaint(cw, &rects[i]);
@@ -264,44 +267,44 @@ clientwin_move(ClientWin *cw, float f, int x, int y)
{
/* int border = MAX(1, (double)DISTANCE(cw->mainwin) * f * 0.25); */
int border = 0;
- XSetWindowBorderWidth(cw->mainwin->dpy, cw->mini.window, border);
+ XSetWindowBorderWidth(cw->mainwin->ps->dpy, cw->mini.window, border);
cw->factor = f;
cw->mini.x = x + (int)cw->x * f;
cw->mini.y = y + (int)cw->y * f;
- if(cw->mainwin->lazy_trans)
+ if(cw->mainwin->ps->o.lazyTrans)
{
cw->mini.x += cw->mainwin->x;
cw->mini.y += cw->mainwin->y;
}
cw->mini.width = MAX(1, (int)cw->client.width * f);
cw->mini.height = MAX(1, (int)cw->client.height * f);
- XMoveResizeWindow(cw->mainwin->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height);
+ XMoveResizeWindow(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.x - border, cw->mini.y - border, cw->mini.width, cw->mini.height);
if(cw->pixmap)
- XFreePixmap(cw->mainwin->dpy, cw->pixmap);
+ XFreePixmap(cw->mainwin->ps->dpy, cw->pixmap);
if(cw->destination)
- XRenderFreePicture(cw->mainwin->dpy, cw->destination);
+ XRenderFreePicture(cw->mainwin->ps->dpy, cw->destination);
- cw->pixmap = XCreatePixmap(cw->mainwin->dpy, cw->mini.window, cw->mini.width, cw->mini.height, cw->mainwin->depth);
- XSetWindowBackgroundPixmap(cw->mainwin->dpy, cw->mini.window, cw->pixmap);
+ cw->pixmap = XCreatePixmap(cw->mainwin->ps->dpy, cw->mini.window, cw->mini.width, cw->mini.height, cw->mainwin->depth);
+ XSetWindowBackgroundPixmap(cw->mainwin->ps->dpy, cw->mini.window, cw->pixmap);
- cw->destination = XRenderCreatePicture(cw->mainwin->dpy, cw->pixmap, cw->mini.format, 0, 0);
+ cw->destination = XRenderCreatePicture(cw->mainwin->ps->dpy, cw->pixmap, cw->mini.format, 0, 0);
}
void
clientwin_map(ClientWin *cw)
{
if(cw->damage)
- XDamageDestroy(cw->mainwin->dpy, cw->damage);
+ XDamageDestroy(cw->mainwin->ps->dpy, cw->damage);
- cw->damage = XDamageCreate(cw->mainwin->dpy, cw->client.window, XDamageReportDeltaRectangles);
- XRenderSetPictureTransform(cw->mainwin->dpy, cw->origin, &cw->mainwin->transform);
+ cw->damage = XDamageCreate(cw->mainwin->ps->dpy, cw->client.window, XDamageReportDeltaRectangles);
+ XRenderSetPictureTransform(cw->mainwin->ps->dpy, cw->origin, &cw->mainwin->transform);
clientwin_render(cw);
- XMapWindow(cw->mainwin->dpy, cw->mini.window);
+ XMapWindow(cw->mainwin->ps->dpy, cw->mini.window);
}
void
@@ -309,24 +312,24 @@ clientwin_unmap(ClientWin *cw)
{
if(cw->damage)
{
- XDamageDestroy(cw->mainwin->dpy, cw->damage);
+ XDamageDestroy(cw->mainwin->ps->dpy, cw->damage);
cw->damage = None;
}
if(cw->destination)
{
- XRenderFreePicture(cw->mainwin->dpy, cw->destination);
+ XRenderFreePicture(cw->mainwin->ps->dpy, cw->destination);
cw->destination = None;
}
if(cw->pixmap)
{
- XFreePixmap(cw->mainwin->dpy, cw->pixmap);
+ XFreePixmap(cw->mainwin->ps->dpy, cw->pixmap);
cw->pixmap = None;
}
- XUnmapWindow(cw->mainwin->dpy, cw->mini.window);
- XSetWindowBackgroundPixmap(cw->mainwin->dpy, cw->mini.window, None);
+ XUnmapWindow(cw->mainwin->ps->dpy, cw->mini.window);
+ XSetWindowBackgroundPixmap(cw->mainwin->ps->dpy, cw->mini.window, None);
cw->focused = 0;
}
@@ -334,19 +337,23 @@ clientwin_unmap(ClientWin *cw)
static void
childwin_focus(ClientWin *cw)
{
- XWarpPointer(cw->mainwin->dpy, None, cw->client.window, 0, 0, 0, 0, cw->client.width / 2, cw->client.height / 2);
- XRaiseWindow(cw->mainwin->dpy, cw->client.window);
- XSetInputFocus(cw->mainwin->dpy, cw->client.window, RevertToParent, CurrentTime);
+ XWarpPointer(cw->mainwin->ps->dpy, None, cw->client.window, 0, 0, 0, 0, cw->client.width / 2, cw->client.height / 2);
+ XRaiseWindow(cw->mainwin->ps->dpy, cw->client.window);
+ XSetInputFocus(cw->mainwin->ps->dpy, cw->client.window, RevertToParent, CurrentTime);
}
int
clientwin_handle(ClientWin *cw, XEvent *ev)
{
- if((ev->type == ButtonRelease && ev->xbutton.button == 1 && cw->mainwin->pressed == cw)) {
- if((ev->xbutton.x >= 0 && ev->xbutton.y >= 0 && ev->xbutton.x < cw->mini.width && ev->xbutton.y < cw->mini.height))
- childwin_focus(cw);
- cw->mainwin->pressed = 0;
- return 1;
+ if(ev->type == ButtonPress) {
+ const unsigned button = ev->xbutton.button;
+ if (button < MAX_MOUSE_BUTTONS) {
+ int ret = wm_action(cw, cw->mainwin->ps->o.bindings_miwMouse[button]);
+ if (ret) {
+ printfef("(): Quitting.");
+ return ret;
+ }
+ }
} else if(ev->type == KeyRelease) {
if(ev->xkey.keycode == cw->mainwin->key_up)
focus_up(cw);
@@ -365,11 +372,11 @@ clientwin_handle(ClientWin *cw, XEvent *ev)
} else if(ev->type == FocusIn) {
cw->focused = 1;
clientwin_render(cw);
- XFlush(cw->mainwin->dpy);
+ XFlush(cw->mainwin->ps->dpy);
} else if(ev->type == FocusOut) {
cw->focused = 0;
clientwin_render(cw);
- XFlush(cw->mainwin->dpy);
+ XFlush(cw->mainwin->ps->dpy);
} else if(ev->type == EnterNotify) {
if(cw->mainwin->tooltip)
{
@@ -389,3 +396,34 @@ clientwin_handle(ClientWin *cw, XEvent *ev)
}
return 0;
}
+
+static int
+wm_action(ClientWin *cw, enum miwop action) {
+ session_t * const ps = cw->mainwin->ps;
+ const Window wid = cw->client.window;
+
+ switch (action) {
+ case CLIENTOP_NO:
+ break;
+ case CLIENTOP_FOCUS:
+ childwin_focus(cw);
+ return 1;
+ case CLIENTOP_ICONIFY:
+ XIconifyWindow(ps->dpy, wid, ps->screen);
+ break;
+ case CLIENTOP_SHADE_EWMH:
+ wm_shade_window_ewmh(ps, wid);
+ break;
+ case CLIENTOP_CLOSE_ICCWM:
+ wm_close_window_iccwm(ps, wid);
+ break;
+ case CLIENTOP_CLOSE_EWMH:
+ wm_close_window_ewmh(ps, wid);
+ break;
+ case CLIENTOP_DESTROY:
+ XDestroyWindow(cw->mainwin->ps->dpy, cw->client.window);
+ break;
+ }
+
+ return 0;
+}
diff --git a/src/focus.c b/src/focus.c
index 7d1c3f2..cb6c8b7 100644
--- a/src/focus.c
+++ b/src/focus.c
@@ -44,8 +44,8 @@ dir_focus(ClientWin *cw, match_func match, dist_func func)
}
}
- XWarpPointer(candidate->mainwin->dpy, None, candidate->mini.window, 0, 0, 0, 0, candidate->mini.width / 2, candidate->mini.height / 2);
- XSetInputFocus(candidate->mainwin->dpy, candidate->mini.window, RevertToParent, CurrentTime);
+ XWarpPointer(candidate->mainwin->ps->dpy, None, candidate->mini.window, 0, 0, 0, 0, candidate->mini.width / 2, candidate->mini.height / 2);
+ XSetInputFocus(candidate->mainwin->ps->dpy, candidate->mini.window, RevertToParent, CurrentTime);
dlist_free(candidates);
}
diff --git a/src/mainwin.c b/src/mainwin.c
index 10f4984..09a3818 100644
--- a/src/mainwin.c
+++ b/src/mainwin.c
@@ -59,29 +59,22 @@ mainwin_create(session_t *ps)
XRenderPictureAttributes pa;
XRenderColor clear;
- MainWin *mw = (MainWin *)malloc(sizeof(MainWin));
+ MainWin *mw = allocchk(malloc(sizeof(MainWin)));
mw->ps = ps;
- mw->dpy = dpy;
- mw->screen = DefaultScreen(dpy);
- mw->root = RootWindow(dpy, mw->screen);
- mw->lazy_trans = ps->o.lazyTrans;
- if(mw->lazy_trans)
- {
+ if (ps->o.lazyTrans) {
mw->depth = 32;
mw->visual = find_argb_visual(dpy, DefaultScreen(dpy));
- if(! mw->visual)
- {
- fprintf(stderr, "WARNING: Couldn't find argb visual, disabling lazy transparency.\n");
- mw->lazy_trans = False;
+ if (!mw->visual) {
+ printfef("(): Couldn't find ARGB visual, lazy transparency can't work.");
+ goto mainwin_create_err;
}
}
- if(! mw->lazy_trans)
- {
- mw->depth = DefaultDepth(dpy, mw->screen);
- mw->visual = DefaultVisual(dpy, mw->screen);
+ if (!ps->o.lazyTrans) {
+ mw->depth = DefaultDepth(dpy, ps->screen);
+ mw->visual = DefaultVisual(dpy, ps->screen);
}
- mw->colormap = XCreateColormap(dpy, mw->root, mw->visual, AllocNone);
+ mw->colormap = XCreateColormap(dpy, ps->root, mw->visual, AllocNone);
mw->bg_pixmap = None;
mw->background = None;
mw->format = XRenderFindVisualFormat(dpy, mw->visual);
@@ -102,7 +95,7 @@ mainwin_create(session_t *ps)
mw->key_escape = XKeysymToKeycode(dpy, XK_Escape);
mw->key_q = XKeysymToKeycode(dpy, XK_q);
- XGetWindowAttributes(dpy, mw->root, &rootattr);
+ XGetWindowAttributes(dpy, ps->root, &rootattr);
mw->x = mw->y = 0;
mw->width = rootattr.width;
mw->height = rootattr.height;
@@ -114,7 +107,7 @@ mainwin_create(session_t *ps)
wattr.event_mask = VisibilityChangeMask | ButtonPressMask
| ButtonReleaseMask | KeyReleaseMask;
- mw->window = XCreateWindow(dpy, mw->root, 0, 0, mw->width, mw->height, 0,
+ mw->window = XCreateWindow(dpy, ps->root, 0, 0, mw->width, mw->height, 0,
mw->depth, InputOutput, mw->visual,
CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wattr);
if(mw->window == None) {
@@ -125,14 +118,14 @@ mainwin_create(session_t *ps)
#ifdef CFG_XINERAMA
if (ps->xinfo.xinerama_exist && XineramaIsActive(dpy)) {
- mw->xin_info = XineramaQueryScreens(mw->dpy, &mw->xin_screens);
+ mw->xin_info = XineramaQueryScreens(mw->ps->dpy, &mw->xin_screens);
# ifdef DEBUG_XINERAMA
printfef("(): Xinerama is enabled (%d screens).", mw->xin_screens);
# endif /* DEBUG_XINERAMA */
}
#endif /* CFG_XINERAMA */
- XCompositeRedirectSubwindows (mw->dpy, mw->root, CompositeRedirectAutomatic);
+ XCompositeRedirectSubwindows (mw->ps->dpy, ps->root, CompositeRedirectAutomatic);
tmp_d = ps->o.updateFreq;
if(tmp_d != 0.0)
@@ -140,7 +133,7 @@ mainwin_create(session_t *ps)
else
mw->poll_time = 0;
- if(!XParseColor(mw->dpy, mw->colormap, ps->o.normal_tint, &exact_color)) {
+ if(!XParseColor(mw->ps->dpy, mw->colormap, ps->o.normal_tint, &exact_color)) {
printfef("(): Couldn't look up color '%s', reverting to black.", ps->o.normal_tint);
mw->normalTint.red = mw->normalTint.green = mw->normalTint.blue = 0;
}
@@ -153,7 +146,7 @@ mainwin_create(session_t *ps)
mw->normalTint.alpha = alphaconv(ps->o.normal_tintOpacity);
tmp = ps->o.highlight_tint;
- if(! XParseColor(mw->dpy, mw->colormap, tmp, &exact_color))
+ if(! XParseColor(mw->ps->dpy, mw->colormap, tmp, &exact_color))
{
fprintf(stderr, "Couldn't look up color '%s', reverting to #101020", tmp);
mw->highlightTint.red = mw->highlightTint.green = 0x10;
@@ -169,14 +162,14 @@ mainwin_create(session_t *ps)
pa.repeat = True;
clear.alpha = alphaconv(ps->o.normal_opacity);
- mw->normalPixmap = XCreatePixmap(mw->dpy, mw->window, 1, 1, 8);
- mw->normalPicture = XRenderCreatePicture(mw->dpy, mw->normalPixmap, XRenderFindStandardFormat(mw->dpy, PictStandardA8), CPRepeat, &pa);
- XRenderFillRectangle(mw->dpy, PictOpSrc, mw->normalPicture, &clear, 0, 0, 1, 1);
+ mw->normalPixmap = XCreatePixmap(mw->ps->dpy, mw->window, 1, 1, 8);
+ mw->normalPicture = XRenderCreatePicture(mw->ps->dpy, mw->normalPixmap, XRenderFindStandardFormat(mw->ps->dpy, PictStandardA8), CPRepeat, &pa);
+ XRenderFillRectangle(mw->ps->dpy, PictOpSrc, mw->normalPicture, &clear, 0, 0, 1, 1);
clear.alpha = alphaconv(ps->o.highlight_opacity);
- mw->highlightPixmap = XCreatePixmap(mw->dpy, mw->window, 1, 1, 8);
- mw->highlightPicture = XRenderCreatePicture(mw->dpy, mw->highlightPixmap, XRenderFindStandardFormat(mw->dpy, PictStandardA8), CPRepeat, &pa);
- XRenderFillRectangle(mw->dpy, PictOpSrc, mw->highlightPicture, &clear, 0, 0, 1, 1);
+ mw->highlightPixmap = XCreatePixmap(mw->ps->dpy, mw->window, 1, 1, 8);
+ mw->highlightPicture = XRenderCreatePicture(mw->ps->dpy, mw->highlightPixmap, XRenderFindStandardFormat(mw->ps->dpy, PictStandardA8), CPRepeat, &pa);
+ XRenderFillRectangle(mw->ps->dpy, PictOpSrc, mw->highlightPicture, &clear, 0, 0, 1, 1);
mw->distance = mw->ps->o.distance;
@@ -184,40 +177,47 @@ mainwin_create(session_t *ps)
mw->tooltip = tooltip_create(mw);
return mw;
+
+mainwin_create_err:
+ if (mw)
+ free(mw);
+ return NULL;
}
void
mainwin_update_background(MainWin *mw)
{
- Pixmap root = wm_get_root_pmap(mw->dpy);
+ Pixmap root = wm_get_root_pmap(mw->ps->dpy);
XRenderColor black = { 0, 0, 0, 65535};
XRenderPictureAttributes pa;
if(mw->bg_pixmap)
- XFreePixmap(mw->dpy, mw->bg_pixmap);
+ XFreePixmap(mw->ps->dpy, mw->bg_pixmap);
if(mw->background)
- XRenderFreePicture(mw->dpy, mw->background);
+ XRenderFreePicture(mw->ps->dpy, mw->background);
- mw->bg_pixmap = XCreatePixmap(mw->dpy, mw->window, mw->width, mw->height, mw->depth);
+ mw->bg_pixmap = XCreatePixmap(mw->ps->dpy, mw->window, mw->width, mw->height, mw->depth);
pa.repeat = True;
- mw->background = XRenderCreatePicture(mw->dpy, mw->bg_pixmap, mw->format, CPRepeat, &pa);
+ mw->background = XRenderCreatePicture(mw->ps->dpy, mw->bg_pixmap, mw->format, CPRepeat, &pa);
if(root == None)
- XRenderFillRectangle(mw->dpy, PictOpSrc, mw->background, &black, 0, 0, mw->width, mw->height);
+ XRenderFillRectangle(mw->ps->dpy, PictOpSrc, mw->background, &black, 0, 0, mw->width, mw->height);
else
{
- Picture from = XRenderCreatePicture(mw->dpy, root, XRenderFindVisualFormat(mw->dpy, DefaultVisual(mw->dpy, mw->screen)), 0, 0);
- XRenderComposite(mw->dpy, PictOpSrc, from, None, mw->background, mw->x, mw->y, 0, 0, 0, 0, mw->width, mw->height);
- XRenderFreePicture(mw->dpy, from);
+ Picture from = XRenderCreatePicture(mw->ps->dpy, root, XRenderFindVisualFormat(mw->ps->dpy, DefaultVisual(mw->ps->dpy, mw->ps->screen)), 0, 0);
+ XRenderComposite(mw->ps->dpy, PictOpSrc, from, None, mw->background, mw->x, mw->y, 0, 0, 0, 0, mw->width, mw->height);
+ XRenderFreePicture(mw->ps->dpy, from);
}
- XSetWindowBackgroundPixmap(mw->dpy, mw->window, mw->bg_pixmap);
- XClearWindow(mw->dpy, mw->window);
+ XSetWindowBackgroundPixmap(mw->ps->dpy, mw->window, mw->bg_pixmap);
+ XClearWindow(mw->ps->dpy, mw->window);
}
void
mainwin_update(MainWin *mw)
{
+ session_t * const ps = mw->ps;
+
#ifdef CFG_XINERAMA
XineramaScreenInfo *iter;
int i;
@@ -234,7 +234,7 @@ mainwin_update(MainWin *mw)
# ifdef DEBUG
fprintf(stderr, "--> querying pointer... ");
# endif /* DEBUG */
- XQueryPointer(mw->dpy, mw->root, &dummy_w, &dummy_w, &root_x, &root_y, &dummy_i, &dummy_i, &dummy_u);
+ XQueryPointer(ps->dpy, ps->root, &dummy_w, &dummy_w, &root_x, &root_y, &dummy_i, &dummy_i, &dummy_u);
# ifdef DEBUG
fprintf(stderr, "+%i+%i\n", root_x, root_y);
@@ -264,7 +264,7 @@ mainwin_update(MainWin *mw)
mw->y = iter->y_org;
mw->width = iter->width;
mw->height = iter->height;
- XMoveResizeWindow(mw->dpy, mw->window, iter->x_org, iter->y_org, mw->width, mw->height);
+ XMoveResizeWindow(ps->dpy, mw->window, iter->x_org, iter->y_org, mw->width, mw->height);
mw->xin_active = iter;
#endif /* CFG_XINERAMA */
mainwin_update_background(mw);
@@ -273,10 +273,10 @@ mainwin_update(MainWin *mw)
void
mainwin_map(MainWin *mw)
{
- wm_set_fullscreen(mw->dpy, mw->window, mw->x, mw->y, mw->width, mw->height);
+ wm_set_fullscreen(mw->ps->dpy, mw->window, mw->x, mw->y, mw->width, mw->height);
mw->pressed = 0;
- XMapWindow(mw->dpy, mw->window);
- XRaiseWindow(mw->dpy, mw->window);
+ XMapWindow(mw->ps->dpy, mw->window);
+ XRaiseWindow(mw->ps->dpy, mw->window);
}
void
@@ -286,10 +286,10 @@ mainwin_unmap(MainWin *mw)
tooltip_unmap(mw->tooltip);
if(mw->bg_pixmap)
{
- XFreePixmap(mw->dpy, mw->bg_pixmap);
+ XFreePixmap(mw->ps->dpy, mw->bg_pixmap);
mw->bg_pixmap = None;
}
- XUnmapWindow(mw->dpy, mw->window);
+ XUnmapWindow(mw->ps->dpy, mw->window);
}
void
@@ -299,24 +299,24 @@ mainwin_destroy(MainWin *mw)
tooltip_destroy(mw->tooltip);
if(mw->background != None)
- XRenderFreePicture(mw->dpy, mw->background);
+ XRenderFreePicture(mw->ps->dpy, mw->background);
if(mw->bg_pixmap != None)
- XFreePixmap(mw->dpy, mw->bg_pixmap);
+ XFreePixmap(mw->ps->dpy, mw->bg_pixmap);
if(mw->normalPicture != None)
- XRenderFreePicture(mw->dpy, mw->normalPicture);
+ XRenderFreePicture(mw->ps->dpy, mw->normalPicture);
if(mw->highlightPicture != None)
- XRenderFreePicture(mw->dpy, mw->highlightPicture);
+ XRenderFreePicture(mw->ps->dpy, mw->highlightPicture);
if(mw->normalPixmap != None)
- XFreePixmap(mw->dpy, mw->normalPixmap);
+ XFreePixmap(mw->ps->dpy, mw->normalPixmap);
if(mw->highlightPixmap != None)
- XFreePixmap(mw->dpy, mw->highlightPixmap);
+ XFreePixmap(mw->ps->dpy, mw->highlightPixmap);
- XDestroyWindow(mw->dpy, mw->window);
+ XDestroyWindow(mw->ps->dpy, mw->window);
#ifdef CFG_XINERAMA
if(mw->xin_info)
@@ -346,16 +346,16 @@ mainwin_handle(MainWin *mw, XEvent *ev)
switch(ev->type)
{
case KeyPress:
- if(ev->xkey.keycode == XKeysymToKeycode(mw->dpy, XK_q))
+ if(ev->xkey.keycode == XKeysymToKeycode(mw->ps->dpy, XK_q))
return 2;
break;
- case ButtonRelease:
+ case ButtonPress:
+ printfef("(): Detected mouse button press on main window, exiting.");
return 1;
- break;
case VisibilityNotify:
if(ev->xvisibility.state && mw->focus)
{
- XSetInputFocus(mw->dpy, mw->focus->mini.window, RevertToParent, CurrentTime);
+ XSetInputFocus(mw->ps->dpy, mw->focus->mini.window, RevertToParent, CurrentTime);
mw->focus = 0;
}
break;
diff --git a/src/mainwin.h b/src/mainwin.h
index b53b60a..ba51e24 100644
--- a/src/mainwin.h
+++ b/src/mainwin.h
@@ -25,15 +25,11 @@ struct _Tooltip;
struct _MainWin
{
session_t *ps;
- Display *dpy;
- int screen;
Visual *visual;
Colormap colormap;
int depth;
- Window root;
int poll_time;
- Bool lazy_trans;
Window window;
Picture background;
diff --git a/src/skippy.c b/src/skippy.c
index 2bc9394..8ad2d92 100644
--- a/src/skippy.c
+++ b/src/skippy.c
@@ -28,12 +28,36 @@ session_t *ps_g = NULL;
static int DIE_NOW = 0;
+/**
+ * @brief Parse a string representation of enum miwop.
+ */
+static bool
+parse_miwop(session_t *ps, const char *str, enum miwop *dest) {
+ static const char * const STRS_CLIENTOP[] = {
+ [ CLIENTOP_NO ] = "no",
+ [ CLIENTOP_FOCUS ] = "focus",
+ [ CLIENTOP_ICONIFY ] = "iconify",
+ [ CLIENTOP_SHADE_EWMH ] = "shade-ewmh",
+ [ CLIENTOP_CLOSE_ICCWM ] = "close-iccwm",
+ [ CLIENTOP_CLOSE_EWMH ] = "close-ewmh",
+ [ CLIENTOP_DESTROY ] = "destroy",
+ };
+ for (int i = 0; i < sizeof(STRS_CLIENTOP) / sizeof(STRS_CLIENTOP[0]); ++i)
+ if (!strcmp(STRS_CLIENTOP[i], str)) {
+ *dest = i;
+ return true;
+ }
+
+ printfef("(\"%s\"): Unrecognized operation.", str);
+ return false;
+}
+
static dlist *
update_clients(MainWin *mw, dlist *clients, Bool *touched)
{
dlist *stack, *iter;
- stack = dlist_first(wm_get_stack(mw->dpy));
+ stack = dlist_first(wm_get_stack(mw->ps->dpy));
iter = clients = dlist_first(clients);
if(touched)
@@ -82,7 +106,7 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader)
{
session_t * const ps = mw->ps;
- CARD32 desktop = wm_get_current_desktop(mw->dpy);
+ CARD32 desktop = wm_get_current_desktop(ps->dpy);
unsigned int width, height;
float factor;
int xoff, yoff;
@@ -130,7 +154,7 @@ do_layout(MainWin *mw, dlist *clients, Window focus, Window leader)
for(iter = mw->cod; iter; iter = iter->next)
clientwin_map((ClientWin*)iter->data);
if (ps->o.movePointerOnStart)
- XWarpPointer(mw->dpy, None, mw->focus->mini.window, 0, 0, 0, 0,
+ XWarpPointer(mw->ps->dpy, None, mw->focus->mini.window, 0, 0, 0, 0,
mw->focus->mini.width / 2, mw->focus->mini.height / 2);
return clients;
@@ -185,7 +209,7 @@ ev_dump(session_t *ps, const MainWin *mw, const XEvent *ev) {
Window wid = ev->xany.window;
const char *wextra = "";
- if (mw && mw->root == wid) wextra = "(Root)";
+ if (mw && ps->root == wid) wextra = "(Root)";
if (mw && mw->window == wid) wextra = "(Main)";
print_timestamp(ps);
@@ -211,10 +235,9 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
#endif /* CFG_XINERAMA */
/* Map the main window and run our event loop */
- if(mw->lazy_trans)
- {
+ if (ps->o.lazyTrans) {
mainwin_map(mw);
- XFlush(mw->dpy);
+ XFlush(ps->dpy);
}
clients = do_layout(mw, clients, focus, leader);
@@ -222,7 +245,7 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
return clients;
/* Map the main window and run our event loop */
- if(! mw->lazy_trans)
+ if (!ps->o.lazyTrans)
mainwin_map(mw);
last_rendered = time_in_millis();
@@ -231,9 +254,9 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
int move_x = -1, move_y = -1;
struct pollfd r_fd;
- XFlush(mw->dpy);
+ XFlush(ps->dpy);
- r_fd.fd = ConnectionNumber(mw->dpy);
+ r_fd.fd = ConnectionNumber(ps->dpy);
r_fd.events = POLLIN;
if(mw->poll_time > 0)
timeout = MAX(0, mw->poll_time + last_rendered - time_in_millis());
@@ -248,10 +271,10 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
last_rendered = now;
}
- i = XPending(mw->dpy);
+ i = XPending(ps->dpy);
for(j = 0; j < i; ++j)
{
- XNextEvent(mw->dpy, &ev);
+ XNextEvent(ps->dpy, &ev);
#ifdef DEBUG_EVENTS
ev_dump(ps, mw, &ev);
#endif
@@ -271,8 +294,8 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
if(iter)
mw->cod = dlist_first(dlist_remove(iter));
clientwin_destroy(cw, True);
- if(! mw->cod)
- {
+ if (!mw->cod) {
+ printfef("(): Last client window destroyed/unmapped, exiting.");
die = 1;
break;
}
@@ -340,7 +363,7 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
/* Unmap the main window and clean up */
mainwin_unmap(mw);
- XFlush(mw->dpy);
+ XFlush(ps->dpy);
REDUCE(clientwin_unmap((ClientWin*)iter->data), mw->cod);
dlist_free(mw->cod);
@@ -351,7 +374,7 @@ skippy_run(MainWin *mw, dlist *clients, Window focus, Window leader, Bool all_xi
if(refocus)
{
- XSetInputFocus(mw->dpy, focus, RevertToPointerRoot, CurrentTime);
+ XSetInputFocus(ps->dpy, focus, RevertToPointerRoot, CurrentTime);
}
return clients;
@@ -624,6 +647,10 @@ int main(int argc, char *argv[])
ps->o.tooltip_text = mstrdup(config_get(config, "tooltip", "text", "#e0e0e0"));
ps->o.tooltip_textShadow = mstrdup(config_get(config, "tooltip", "textShadow", "black"));
ps->o.tooltip_font = mstrdup(config_get(config, "tooltip", "font", "fixed-11:weight=bold"));
+ if (!parse_miwop(ps, config_get(config, "bindings", "miwMouse1", "focus"), &ps->o.bindings_miwMouse[1])
+ || !parse_miwop(ps, config_get(config, "bindings", "miwMouse2", "close-ewmh"), &ps->o.bindings_miwMouse[2])
+ || !parse_miwop(ps, config_get(config, "bindings", "miwMouse3", "iconify"), &ps->o.bindings_miwMouse[3]))
+ return RET_BADARG;
if (config) {
config_get_int_wrap(config, "general", "distance", &ps->o.distance, 1, INT_MAX);
config_get_bool_wrap(config, "general", "useNetWMFullscreen", &ps->o.useNetWMFullscreen);
@@ -703,6 +730,9 @@ int main(int argc, char *argv[])
XSynchronize(ps->dpy, True);
XSetErrorHandler(xerror);
+ ps->screen = DefaultScreen(dpy);
+ ps->root = RootWindow(dpy, ps->screen);
+
wm_get_atoms(ps);
if(! wm_check(dpy)) {
@@ -715,8 +745,7 @@ int main(int argc, char *argv[])
wm_ignore_skip_taskbar(ps->o.ignoreSkipTaskbar);
mw = mainwin_create(ps);
- if(! mw)
- {
+ if (!mw) {
fprintf(stderr, "FATAL: Couldn't create main window.\n");
ret = 1;
goto main_end;
@@ -724,7 +753,7 @@ int main(int argc, char *argv[])
invertShift = !ps->o.xinerama_showAll;
- XSelectInput(mw->dpy, mw->root, PropertyChangeMask);
+ XSelectInput(ps->dpy, ps->root, PropertyChangeMask);
if (runAsDaemon)
{
@@ -767,7 +796,7 @@ int main(int argc, char *argv[])
switch (piped_input)
{
case ACTIVATE_WINDOW_PICKER:
- leader = None, focused = wm_get_focused(mw->dpy);
+ leader = None, focused = wm_get_focused(ps->dpy);
clients = skippy_run(mw, clients, focused, leader, !invertShift);
break;
@@ -794,7 +823,7 @@ int main(int argc, char *argv[])
else
{
printf("running once then quitting...\n");
- leader = None, focused = wm_get_focused(mw->dpy);
+ leader = None, focused = wm_get_focused(ps->dpy);
clients = skippy_run(mw, clients, focused, leader, !invertShift);
}
diff --git a/src/skippy.h b/src/skippy.h
index 08dedf8..4e8b78d 100644
--- a/src/skippy.h
+++ b/src/skippy.h
@@ -61,6 +61,8 @@
#include "dlist.h"
+#define MAX_MOUSE_BUTTONS 4
+
/// @brief Possible return values.
enum {
RET_SUCCESS = 0,
@@ -70,6 +72,16 @@ enum {
RET_BADALLOC,
};
+enum miwop {
+ CLIENTOP_NO,
+ CLIENTOP_FOCUS,
+ CLIENTOP_ICONIFY,
+ CLIENTOP_SHADE_EWMH,
+ CLIENTOP_CLOSE_ICCWM,
+ CLIENTOP_CLOSE_EWMH,
+ CLIENTOP_DESTROY,
+};
+
/// @brief Option structure.
typedef struct {
int distance;
@@ -98,6 +110,8 @@ typedef struct {
char *tooltip_text;
char *tooltip_textShadow;
char *tooltip_font;
+
+ enum miwop bindings_miwMouse[MAX_MOUSE_BUTTONS];
} options_t;
#define OPTIONST_INIT { \
@@ -151,6 +165,10 @@ typedef struct {
options_t o;
/// @brief X display.
Display *dpy;
+ /// @brief Current screen.
+ int screen;
+ /// @brief Root window ID.
+ Window root;
/// @brief Information about X.
xinfo_t xinfo;
/// @brief Time the program was started, in milliseconds.
diff --git a/src/tooltip.c b/src/tooltip.c
index 2e5631e..85e56c2 100644
--- a/src/tooltip.c
+++ b/src/tooltip.c
@@ -22,34 +22,36 @@
void
tooltip_destroy(Tooltip *tt)
{
+ session_t * const ps = tt->mainwin->ps;
+
if(tt->text)
free(tt->text);
if(tt->font)
- XftFontClose(tt->mainwin->dpy, tt->font);
+ XftFontClose(ps->dpy, tt->font);
if(tt->draw)
XftDrawDestroy(tt->draw);
if(tt->color.pixel != None)
- XftColorFree(tt->mainwin->dpy,
+ XftColorFree(ps->dpy,
tt->mainwin->visual,
tt->mainwin->colormap,
&tt->color);
if(tt->background.pixel != None)
- XftColorFree(tt->mainwin->dpy,
+ XftColorFree(ps->dpy,
tt->mainwin->visual,
tt->mainwin->colormap,
&tt->background);
if(tt->border.pixel != None)
- XftColorFree(tt->mainwin->dpy,
+ XftColorFree(ps->dpy,
tt->mainwin->visual,
tt->mainwin->colormap,
&tt->border);
if(tt->shadow.pixel != None)
- XftColorFree(tt->mainwin->dpy,
+ XftColorFree(ps->dpy,
tt->mainwin->visual,
tt->mainwin->colormap,
&tt->shadow);
if(tt->window != None)
- XDestroyWindow(tt->mainwin->dpy, tt->window);
+ XDestroyWindow(ps->dpy, tt->window);
free(tt);
}
@@ -79,7 +81,7 @@ tooltip_create(MainWin *mw)
.colormap = mw->colormap,
};
- tt->window = XCreateWindow(mw->dpy, mw->root,
+ tt->window = XCreateWindow(ps->dpy, ps->root,
0, 0, 1, 1, 0,
mw->depth, InputOutput, mw->visual,
CWBorderPixel|CWBackPixel|CWOverrideRedirect|CWEventMask|CWColormap,
@@ -94,7 +96,7 @@ tooltip_create(MainWin *mw)
wm_wid_set_info(ps, tt->window, "tooltip", _NET_WM_WINDOW_TYPE_TOOLTIP);
tmp = ps->o.tooltip_border;
- if(! XftColorAllocName(mw->dpy, mw->visual, mw->colormap, tmp, &tt->border))
+ if(! XftColorAllocName(mw->ps->dpy, mw->visual, mw->colormap, tmp, &tt->border))
{
fprintf(stderr, "WARNING: Invalid color '%s'.\n", tmp);
tooltip_destroy(tt);
@@ -102,7 +104,7 @@ tooltip_create(MainWin *mw)
}
tmp = ps->o.tooltip_background;
- if(! XftColorAllocName(mw->dpy, mw->visual, mw->colormap, tmp, &tt->background))
+ if(! XftColorAllocName(mw->ps->dpy, mw->visual, mw->colormap, tmp, &tt->background))
{
fprintf(stderr, "WARNING: Invalid color '%s'.\n", tmp);
tooltip_destroy(tt);
@@ -114,7 +116,7 @@ tooltip_create(MainWin *mw)
tt->border.color.alpha = tmp_l;
tmp = ps->o.tooltip_text;
- if(! XftColorAllocName(mw->dpy, mw->visual, mw->colormap, tmp, &tt->color))
+ if(! XftColorAllocName(mw->ps->dpy, mw->visual, mw->colormap, tmp, &tt->color))
{
fprintf(stderr, "WARNING: Couldn't allocate color '%s'.\n", tmp);
tooltip_destroy(tt);
@@ -124,7 +126,7 @@ tooltip_create(MainWin *mw)
tmp = ps->o.tooltip_textShadow;
if(strcasecmp(tmp, "none") != 0)
{
- if(! XftColorAllocName(mw->dpy, mw->visual, mw->colormap, tmp, &tt->shadow))
+ if(! XftColorAllocName(mw->ps->dpy, mw->visual, mw->colormap, tmp, &tt->shadow))
{
fprintf(stderr, "WARNING: Couldn't allocate color '%s'.\n", tmp);
tooltip_destroy(tt);
@@ -132,7 +134,7 @@ tooltip_create(MainWin *mw)
}
}
- tt->draw = XftDrawCreate(mw->dpy, tt->window, mw->visual, mw->colormap);
+ tt->draw = XftDrawCreate(mw->ps->dpy, tt->window, mw->visual, mw->colormap);
if(! tt->draw)
{
fprintf(stderr, "WARNING: Couldn't create Xft draw surface.\n");
@@ -140,7 +142,7 @@ tooltip_create(MainWin *mw)
return 0;
}
- tt->font = XftFontOpenName(mw->dpy, mw->screen, ps->o.tooltip_font);
+ tt->font = XftFontOpenName(mw->ps->dpy, ps->screen, ps->o.tooltip_font);
if(! tt->font)
{
fprintf(stderr, "WARNING: Couldn't open Xft font.\n");
@@ -156,13 +158,15 @@ tooltip_create(MainWin *mw)
void
tooltip_map(Tooltip *tt, int x, int y, const FcChar8 *text, int len)
{
- XUnmapWindow(tt->mainwin->dpy, tt->window);
+ session_t * const ps = tt->mainwin->ps;
+
+ XUnmapWindow(ps->dpy, tt->window);
- XftTextExtentsUtf8(tt->mainwin->dpy, tt->font, text, len, &tt->extents);
+ XftTextExtentsUtf8(ps->dpy, tt->font, text, len, &tt->extents);
tt->width = tt->extents.width + 8;
tt->height = tt->font_height + 5 + (tt->shadow.pixel ? 2 : 0);
- XResizeWindow(tt->mainwin->dpy, tt->window, tt->width, tt->height);
+ XResizeWindow(ps->dpy, tt->window, tt->width, tt->height);
tooltip_move(tt, x, y);
if(tt->text)
@@ -173,8 +177,8 @@ tooltip_map(Tooltip *tt, int x, int y, const FcChar8 *text, int len)
tt->text_len = len;
- XMapWindow(tt->mainwin->dpy, tt->window);
- XRaiseWindow(tt->mainwin->dpy, tt->window);
+ XMapWindow(ps->dpy, tt->window);
+ XRaiseWindow(ps->dpy, tt->window);
}
void
@@ -188,13 +192,13 @@ tooltip_move(Tooltip *tt, int x, int y)
y = tt->mainwin->height + tt->mainwin->y - tt->extents.height - 8;
y = MAX(0, y);
- XMoveWindow(tt->mainwin->dpy, tt->window, x, y);
+ XMoveWindow(tt->mainwin->ps->dpy, tt->window, x, y);
}
void
tooltip_unmap(Tooltip *tt)
{
- XUnmapWindow(tt->mainwin->dpy, tt->window);
+ XUnmapWindow(tt->mainwin->ps->dpy, tt->window);
if(tt->text)
free(tt->text);
tt->text = 0;
diff --git a/src/wm.c b/src/wm.c
index 2490784..9f7e641 100644
--- a/src/wm.c
+++ b/src/wm.c
@@ -24,18 +24,27 @@ Atom
_XROOTPMAP_ID,
ESETROOT_PMAP_ID,
+ // ICCWM atoms
+ WM_PROTOCOLS,
+ WM_DELETE_WINDOW,
+
// Window type atoms
_NET_WM_WINDOW_TYPE_DESKTOP,
_NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_WINDOW_TYPE_NORMAL,
- _NET_WM_WINDOW_TYPE_TOOLTIP;
-
+ _NET_WM_WINDOW_TYPE_TOOLTIP,
+
+ // EWMH atoms
+ _NET_CLOSE_WINDOW,
+ _NET_WM_STATE,
+ _NET_WM_STATE_SHADED;
+
static Atom
/* Generic atoms */
XA_WM_STATE,
WM_CLIENT_LEADER,
XA_UTF8_STRING,
-
+
/* NetWM atoms */
_NET_SUPPORTING_WM_CHECK,
_NET_SUPPORTED,
@@ -44,12 +53,10 @@ static Atom
_NET_CLIENT_LIST_STACKING,
_NET_CURRENT_DESKTOP,
_NET_WM_DESKTOP,
- _NET_WM_STATE,
_NET_WM_STATE_HIDDEN,
_NET_WM_STATE_SKIP_TASKBAR,
_NET_WM_STATE_SKIP_PAGER,
_NET_WM_STATE_FULLSCREEN,
- _NET_WM_STATE_SHADED,
_NET_WM_STATE_ABOVE,
_NET_WM_STATE_STICKY,
_NET_WM_WINDOW_TYPE,
@@ -115,6 +122,9 @@ wm_get_atoms(session_t *ps) {
T_GETATOM(_XROOTPMAP_ID);
T_GETATOM(ESETROOT_PMAP_ID);
+ T_GETATOM(WM_PROTOCOLS),
+ T_GETATOM(WM_DELETE_WINDOW),
+
T_GETATOM(_NET_SUPPORTING_WM_CHECK);
T_GETATOM(_NET_SUPPORTED);
T_GETATOM(_NET_NUMBER_OF_DESKTOPS);
@@ -137,6 +147,8 @@ wm_get_atoms(session_t *ps) {
T_GETATOM(_NET_WM_WINDOW_TYPE_TOOLTIP);
T_GETATOM(_NET_WM_VISIBLE_NAME);
T_GETATOM(_NET_WM_NAME);
+ T_GETATOM(_NET_CLOSE_WINDOW);
+ T_GETATOM(_NET_WM_STATE_SHADED);
T_GETATOM(_WIN_SUPPORTING_WM_CHECK);
T_GETATOM(_WIN_WORKSPACE);
@@ -397,7 +409,7 @@ wm_get_window_title(session_t *ps, Window wid, int *length_return) {
if (ret && length_return)
*length_return = strlen(ret);
- return ret;
+ return (FcChar8 *) ret;
}
Window
@@ -653,7 +665,7 @@ wm_wid_get_prop_rstr(session_t *ps, Window wid, Atom prop) {
if (Success == XGetWindowProperty(ps->dpy, wid, prop, 0, BUF_LEN,
False, AnyPropertyType, &type_ret, &fmt_ret, &nitems,
&bytes_after_ret, &data) && nitems && 8 == fmt_ret)
- ret = mstrdup(data);
+ ret = mstrdup((char *) data);
sxfree(data);
return ret;
}
@@ -728,3 +740,53 @@ wm_wid_set_info(session_t *ps, Window wid, const char *name,
PropModeReplace, (unsigned char *) &val, 1);
}
}
+
+/**
+ * @brief Send a X client messsage.
+ */
+void
+wm_send_clientmsg(session_t *ps, Window twid, Window wid, Atom msg_type,
+ int fmt, long event_mask, int len, const unsigned char *data) {
+ assert(twid);
+ assert(8 == fmt || 16 == fmt || 32 == fmt);
+ assert(len * fmt <= 20 * 8);
+ XClientMessageEvent ev = {
+ .type = ClientMessage,
+ .window = wid,
+ .message_type = msg_type,
+ .format = fmt,
+ };
+ int seglen = 0;
+ switch (fmt) {
+ case 32: seglen = sizeof(long); break;
+ case 16: seglen = sizeof(short); break;
+ case 8: seglen = sizeof(char); break;
+ }
+ memcpy(ev.data.l, data, seglen * len);
+ XSendEvent(ps->dpy, twid, False, event_mask, (XEvent *) &ev);
+}
+
+/**
+ * @brief Find out the WM frame of a client window by querying X.
+ *
+ * @param ps current session
+ * @param wid window ID
+ * @return window ID of the frame window
+ */
+static Window
+wm_find_frame(session_t *ps, Window wid) {
+ // We traverse through its ancestors to find out the frame
+ for (Window cwid = wid; cwid && cwid != ps->root; ) {
+ Window rroot = None;
+ Window *children = NULL;
+ unsigned nchildren = 0;
+ wid = cwid;
+ if (!XQueryTree(ps->dpy, cwid, &rroot, &cwid, &children,
+ &nchildren))
+ cwid = 0;
+ sxfree(children);
+ }
+
+ return wid;
+}
+
diff --git a/src/wm.h b/src/wm.h
index becf1e5..8bc3aac 100644
--- a/src/wm.h
+++ b/src/wm.h
@@ -25,11 +25,20 @@ extern Atom
_XROOTPMAP_ID,
ESETROOT_PMAP_ID,
+ // ICCWM atoms
+ WM_PROTOCOLS,
+ WM_DELETE_WINDOW,
+
// Window type atoms
_NET_WM_WINDOW_TYPE_DESKTOP,
_NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_WINDOW_TYPE_NORMAL,
- _NET_WM_WINDOW_TYPE_TOOLTIP;
+ _NET_WM_WINDOW_TYPE_TOOLTIP,
+
+ // EWMH atoms
+ _NET_CLOSE_WINDOW,
+ _NET_WM_STATE,
+ _NET_WM_STATE_SHADED;
void wm_get_atoms(session_t *ps);
char wm_check(Display *dpy);
@@ -49,5 +58,43 @@ char *wm_wid_get_prop_rstr(session_t *ps, Window wid, Atom prop);
char *wm_wid_get_prop_utf8(session_t *ps, Window wid, Atom prop);
void wm_wid_set_info(session_t *ps, Window wid, const char *name,
Atom window_type);
+void wm_send_clientmsg(session_t *ps, Window twid, Window wid, Atom msg_type,
+ int fmt, long event_mask, int len, const unsigned char *data);
+
+static inline void
+wm_send_clientmsg_iccwm(session_t *ps, Window wid, Atom msg_type,
+ int len, const long *data) {
+ wm_send_clientmsg(ps, wid, wid, msg_type, 32, NoEventMask, len,
+ (const unsigned char *) data);
+}
+
+static inline void
+wm_close_window_iccwm(session_t *ps, Window wid) {
+ long data[] = { WM_DELETE_WINDOW, CurrentTime };
+ wm_send_clientmsg_iccwm(ps, wid, WM_PROTOCOLS,
+ sizeof(data) / sizeof(data[0]), data);
+}
+
+static inline void
+wm_send_clientmsg_ewmh_root(session_t *ps, Window wid, Atom msg_type,
+ int len, const long *data) {
+ wm_send_clientmsg(ps, ps->root, wid, msg_type, 32,
+ SubstructureNotifyMask | SubstructureRedirectMask, len,
+ (const unsigned char *) data);
+}
+
+static inline void
+wm_close_window_ewmh(session_t *ps, Window wid) {
+ long data[] = { CurrentTime, 2 };
+ wm_send_clientmsg_ewmh_root(ps, wid, _NET_CLOSE_WINDOW,
+ sizeof(data) / sizeof(data[0]), data);
+}
+
+static inline void
+wm_shade_window_ewmh(session_t *ps, Window wid) {
+ long data[] = { 2, _NET_WM_STATE_SHADED };
+ wm_send_clientmsg_ewmh_root(ps, wid, _NET_WM_STATE,
+ sizeof(data) / sizeof(data[0]), data);
+}
#endif /* SKIPPY_WM_H */
diff --git a/win b/win
new file mode 100644
index 0000000..e69de29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment