Created
May 9, 2013 14:22
-
-
Save richardgv/5547743 to your computer and use it in GitHub Desktop.
richardgv/skippy-xd #2: Custom window actions and bindings, work in progress
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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