diff options
Diffstat (limited to 'client.c')
-rw-r--r-- | client.c | 935 |
1 files changed, 935 insertions, 0 deletions
diff --git a/client.c b/client.c new file mode 100644 index 0000000..961be7c --- /dev/null +++ b/client.c @@ -0,0 +1,935 @@ +/* + * calmwm - the calm window manager + * + * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org> + * All rights reserved. + * + * $Id: client.c,v 1.1.1.1 2007/04/27 17:58:48 bernd Exp $ + */ + +#include "headers.h" +#include "calmwm.h" + +static struct client_ctx *client__cycle(struct client_ctx *cc, + struct client_ctx *(*iter)(struct client_ctx *)); +int _inwindowbounds(struct client_ctx *, int, int); + +static char emptystring[] = ""; + +struct client_ctx *_curcc = NULL; + +void +client_setup(void) +{ + TAILQ_INIT(&G_clientq); +} + +struct client_ctx * +client_find(Window win) +{ + struct client_ctx *cc; + + TAILQ_FOREACH(cc, &G_clientq, entry) + if (cc->pwin == win || cc->win == win) + return (cc); + + return (NULL); +} + +struct client_ctx * +client_new(Window win, struct screen_ctx *sc, int mapped) +{ + struct client_ctx *cc; + long tmp; + XSetWindowAttributes pxattr; + XWindowAttributes wattr; + int x, y, height, width, state; + XWMHints *wmhints; + + if (win == None) + return (NULL); + + XCALLOC(cc, struct client_ctx); + + XGrabServer(G_dpy); + + cc->state = mapped ? NormalState : IconicState; + cc->sc = sc; + cc->win = win; + cc->size= XAllocSizeHints(); + if (cc->size->width_inc == 0) + cc->size->width_inc = 1; + if (cc->size->height_inc == 0) + cc->size->height_inc = 1; + + TAILQ_INIT(&cc->nameq); + client_setname(cc); + + /* + * conf_client() needs at least cc->win and cc->name + */ + conf_client(cc); + + XGetWMNormalHints(G_dpy, cc->win, cc->size, &tmp); + XGetWindowAttributes(G_dpy, cc->win, &wattr); + + if (cc->size->flags & PBaseSize) { + cc->geom.min_dx = cc->size->base_width; + cc->geom.min_dy = cc->size->base_height; + } else if (cc->size->flags & PMinSize) { + cc->geom.min_dx = cc->size->min_width; + cc->geom.min_dy = cc->size->min_height; + } + + /* Saved pointer position */ + cc->ptr.x = -1; + cc->ptr.y = -1; + + client_gravitate(cc, 1); + + cc->geom.x = wattr.x; + cc->geom.y = wattr.y; + cc->geom.width = wattr.width; + cc->geom.height = wattr.height; + cc->geom.height = wattr.height; + cc->cmap = wattr.colormap; + + if (wattr.map_state != IsViewable) { + client_placecalc(cc); + if ((wmhints = XGetWMHints(G_dpy, cc->win)) != NULL) { + if (wmhints->flags & StateHint) + xu_setstate(cc, wmhints->initial_state); + + XFree(wmhints); + } + } + + if (xu_getstate(cc, &state) < 0) + state = NormalState; + + XSelectInput(G_dpy, cc->win, + ColormapChangeMask|EnterWindowMask|PropertyChangeMask|KeyReleaseMask); + + x = cc->geom.x - cc->bwidth; + y = cc->geom.y - cc->bwidth; + + width = cc->geom.width; + height = cc->geom.height; + if (cc->bwidth > 1) { + width += (cc->bwidth)*2; + height += (cc->bwidth)*2; + } + + pxattr.override_redirect = True; + pxattr.background_pixel = sc->bgcolor.pixel; + pxattr.event_mask = + ChildMask|ButtonPressMask|ButtonReleaseMask| + ExposureMask|EnterWindowMask; +/* pxattr.border_pixel = sc->blackpix; */ +/* pxattr.background_pixel = sc->whitepix; */ + + +/* cc->pwin = XCreateSimpleWindow(G_dpy, sc->rootwin, */ +/* x, y, width, height, 1, sc->blackpix, sc->whitepix); */ + + cc->pwin = XCreateWindow(G_dpy, sc->rootwin, x, y, + width, height, 0, /* XXX */ + DefaultDepth(G_dpy, sc->which), CopyFromParent, + DefaultVisual(G_dpy, sc->which), + CWOverrideRedirect | CWBackPixel | CWEventMask, &pxattr); + + if (G_doshape) { + XRectangle *r; + int n, tmp; + + XShapeSelectInput(G_dpy, cc->win, ShapeNotifyMask); + + r = XShapeGetRectangles(G_dpy, cc->win, ShapeBounding, &n, &tmp); + if (n > 1) + XShapeCombineShape(G_dpy, cc->pwin, ShapeBounding, + 0, 0, /* XXX border */ + cc->win, ShapeBounding, ShapeSet); + XFree(r); + } + + cc->active = 0; + client_draw_border(cc); + + XAddToSaveSet(G_dpy, cc->win); + XSetWindowBorderWidth(G_dpy, cc->win, 0); + XReparentWindow(G_dpy, cc->win, cc->pwin, cc->bwidth, cc->bwidth); + + /* Notify client of its configuration. */ + xev_reconfig(cc); + + XMapRaised(G_dpy, cc->pwin); + XMapWindow(G_dpy, cc->win); + xu_setstate(cc, cc->state); + + XSync(G_dpy, False); + XUngrabServer(G_dpy); + + TAILQ_INSERT_TAIL(&sc->mruq, cc, mru_entry); + TAILQ_INSERT_TAIL(&G_clientq, cc, entry); + + client_gethints(cc); + client_update(cc); + + if (mapped) { + if (G_conf.flags & CONF_STICKY_GROUPS) + group_sticky(cc); + else + group_autogroup(cc); + } + + return (cc); +} + +int +client_delete(struct client_ctx *cc, int sendevent, int ignorewindow) +{ + struct screen_ctx *sc = CCTOSC(cc); + struct winname *wn; + + if (cc->state == IconicState && !sendevent) + return (1); + + group_client_delete(cc); + XGrabServer(G_dpy); + + xu_setstate(cc, WithdrawnState); + XRemoveFromSaveSet(G_dpy, cc->win); + + if (!ignorewindow) { + client_gravitate(cc, 0); + XSetWindowBorderWidth(G_dpy, cc->win, 1); /* XXX */ + XReparentWindow(G_dpy, cc->win, + sc->rootwin, cc->geom.x, cc->geom.y); + } + if (cc->pwin) + XDestroyWindow(G_dpy, cc->pwin); + + XSync(G_dpy, False); + XUngrabServer(G_dpy); + + TAILQ_REMOVE(&sc->mruq, cc, mru_entry); + TAILQ_REMOVE(&G_clientq, cc, entry); + + if (_curcc == cc) + _curcc = NULL; + + if (sc->cycle_client == cc) + sc->cycle_client = NULL; + + XFree(cc->size); + + while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) { + TAILQ_REMOVE(&cc->nameq, wn, entry); + if (wn->name != emptystring) + XFree(wn->name); + xfree(wn); + } + + client_freehints(cc); + + xfree(cc); + + return (0); +} + +void +client_leave(struct client_ctx *cc) +{ + struct screen_ctx *sc; + + if (cc == NULL) + cc = _curcc; + if (cc == NULL) + return; + sc = CCTOSC(cc); + + xu_btn_ungrab(sc->rootwin, AnyModifier, Button1); +} + +void +client_nocurrent(void) +{ + if (_curcc != NULL) + client_setactive(_curcc, 0); + + _curcc = NULL; +} + +void +client_setactive(struct client_ctx *cc, int fg) +{ + struct screen_ctx* sc; + + if (cc == NULL) + cc = _curcc; + if (cc == NULL) + return; + + sc = CCTOSC(cc); + + if (fg) { + XInstallColormap(G_dpy, cc->cmap); + XSetInputFocus(G_dpy, cc->win, + RevertToPointerRoot, CurrentTime); + xu_btn_grab(cc->pwin, Mod1Mask, AnyButton); + xu_btn_grab(cc->pwin, ControlMask|Mod1Mask, Button1); + /* + * If we're in the middle of alt-tabbing, don't change + * the order please. + */ + if (!sc->altpersist) + client_mtf(cc); + } else + client_leave(cc); + + if (fg && _curcc != cc) { + client_setactive(NULL, 0); + _curcc = cc; + } + + cc->active = fg; + client_draw_border(cc); +} + +struct client_ctx * +client_current(void) +{ + return (_curcc); +} + +void +client_gravitate(struct client_ctx *cc, int yes) +{ + int dx = 0, dy = 0, mult = yes ? 1 : -1; + int gravity = (cc->size->flags & PWinGravity) ? + cc->size->win_gravity : NorthWestGravity; + + switch (gravity) { + case NorthWestGravity: + case SouthWestGravity: + case NorthEastGravity: + case StaticGravity: + dx = cc->bwidth; + case NorthGravity: + dy = cc->bwidth; + break; + } + + cc->geom.x += mult*dx; + cc->geom.y += mult*dy; +} + +void +client_maximize(struct client_ctx *cc) +{ + if (cc->flags & CLIENT_MAXIMIZED) { + cc->flags &= ~CLIENT_MAXIMIZED; + cc->geom = cc->savegeom; + } else { + XWindowAttributes rootwin_geom; + struct screen_ctx *sc = CCTOSC(cc); + + XGetWindowAttributes(G_dpy, sc->rootwin, &rootwin_geom); + cc->savegeom = cc->geom; + cc->geom.x = 0; + cc->geom.y = 0; + cc->geom.height = rootwin_geom.height; + cc->geom.width = rootwin_geom.width; + cc->flags |= CLIENT_MAXIMIZED; + } + + client_resize(cc); +} + +void +client_push_geometry(struct client_ctx *cc) +{ + cc->savegeom = cc->geom; +} + +void +client_restore_geometry(struct client_ctx *cc) +{ + cc->geom = cc->savegeom; + client_resize(cc); +} + +void +client_resize(struct client_ctx *cc) +{ + XMoveResizeWindow(G_dpy, cc->pwin, cc->geom.x - cc->bwidth, + cc->geom.y - cc->bwidth, cc->geom.width + cc->bwidth*2, + cc->geom.height + cc->bwidth*2); + XMoveResizeWindow(G_dpy, cc->win, cc->bwidth, cc->bwidth, + cc->geom.width, cc->geom.height); + xev_reconfig(cc); + client_draw_border(cc); +} + +void +client_move(struct client_ctx *cc) +{ + XMoveWindow(G_dpy, cc->pwin, + cc->geom.x - cc->bwidth, cc->geom.y - cc->bwidth); + xev_reconfig(cc); +} + +void +client_lower(struct client_ctx *cc) +{ + XLowerWindow(G_dpy, cc->pwin); +} + +void +client_raise(struct client_ctx *cc) +{ + XRaiseWindow(G_dpy, cc->pwin); + client_draw_border(cc); +} + +void +client_warp(struct client_ctx *cc) +{ + client_raise(cc); + xu_ptr_setpos(cc->pwin, 0, 0); +} + +void +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; + } + + client_raise(cc); + xu_ptr_setpos(cc->pwin, x, y); +} + +void +client_ptrsave(struct client_ctx *cc) +{ + int x, y; + + xu_ptr_getpos(cc->pwin, &x, &y); + if (_inwindowbounds(cc, x, y)) { + cc->ptr.x = x; + cc->ptr.y = y; + } +} + +void +client_hide(struct client_ctx *cc) +{ + /* XXX - add wm_state stuff */ + XUnmapWindow(G_dpy, cc->pwin); + XUnmapWindow(G_dpy, cc->win); + + cc->active = 0; + cc->flags |= CLIENT_HIDDEN; + xu_setstate(cc, IconicState); + + if (cc == _curcc) + _curcc = NULL; +} + +void +client_unhide(struct client_ctx *cc) +{ + XMapWindow(G_dpy, cc->win); + XMapRaised(G_dpy, cc->pwin); + + cc->flags &= ~CLIENT_HIDDEN; + xu_setstate(cc, NormalState); +} + +void +client_draw_border(struct client_ctx *cc) +{ + struct screen_ctx *sc = CCTOSC(cc); + + if (cc->active) { + XSetWindowBackground(G_dpy, cc->pwin, client_bg_pixel(cc)); + XClearWindow(G_dpy, cc->pwin); + + if (!cc->highlight && cc->bwidth > 1) + XDrawRectangle(G_dpy, cc->pwin, sc->gc, 1, 1, + cc->geom.width + cc->bwidth, + cc->geom.height + cc->bwidth); + } else { + XSetWindowBackgroundPixmap(G_dpy, cc->pwin, + client_bg_pixmap(cc)); + if (cc->bwidth > 1) + XSetWindowBackgroundPixmap(G_dpy, + cc->pwin, client_bg_pixmap(cc)); + + XClearWindow(G_dpy, cc->pwin); + } +} + +u_long +client_bg_pixel(struct client_ctx *cc) +{ + struct screen_ctx *sc = CCTOSC(cc); + u_long pixl; + + switch (cc->highlight) { + case CLIENT_HIGHLIGHT_BLUE: + pixl = sc->bluepixl; + break; + case CLIENT_HIGHLIGHT_RED: + pixl = sc->redpixl; + break; + default: + pixl = sc->blackpixl; + break; + } + + return (pixl); +} + +Pixmap +client_bg_pixmap(struct client_ctx *cc) +{ + struct screen_ctx *sc = CCTOSC(cc); + Pixmap pix; + + switch (cc->highlight) { + case CLIENT_HIGHLIGHT_BLUE: + pix = sc->blue; + break; + case CLIENT_HIGHLIGHT_RED: + pix = sc->red; + break; + default: + pix = sc->gray; + break; + } + + return (pix); +} + +void +client_update(struct client_ctx *cc) +{ + Atom *p, wm_delete, wm_protocols, wm_take_focus; + int i; + long n; + + /* XXX cache these. */ + wm_delete = XInternAtom(G_dpy, "WM_DELETE_WINDOW", False); + wm_protocols = XInternAtom(G_dpy, "WM_PROTOCOLS", False); + wm_take_focus = XInternAtom(G_dpy, "WM_TAKE_FOCUS", False); + + if ((n = xu_getprop(cc, wm_protocols, + XA_ATOM, 20L, (u_char **)&p)) <= 0) + return; + + for (i = 0; i < n; i++) + if (p[i] == wm_delete) + cc->xproto |= CLIENT_PROTO_DELETE; + else if (p[i] == wm_take_focus) + cc->xproto |= CLIENT_PROTO_TAKEFOCUS; + + XFree(p); +} + +void +client_send_delete(struct client_ctx *cc) +{ + Atom wm_delete, wm_protocols; + + /* XXX - cache */ + wm_delete = XInternAtom(G_dpy, "WM_DELETE_WINDOW", False); + wm_protocols = XInternAtom(G_dpy, "WM_PROTOCOLS", False); + + if (cc->xproto & CLIENT_PROTO_DELETE) + xu_sendmsg(cc, wm_protocols, wm_delete); + else + XKillClient(G_dpy, cc->win); +} + +void +client_setname(struct client_ctx *cc) +{ + char *newname; + struct winname *wn; + + XFetchName(G_dpy, cc->win, &newname); + if (newname == NULL) + newname = emptystring; + + TAILQ_FOREACH(wn, &cc->nameq, entry) + if (strcmp(wn->name, newname) == 0) { + /* Move to the last since we got a hit. */ + TAILQ_REMOVE(&cc->nameq, wn, entry); + TAILQ_INSERT_TAIL(&cc->nameq, wn, entry); + goto match; + } + + XMALLOC(wn, struct winname); + wn->name = newname; + TAILQ_INSERT_TAIL(&cc->nameq, wn, entry); + cc->nameqlen++; + +match: + cc->name = wn->name; + + /* Now, do some garbage collection. */ + if (cc->nameqlen > CLIENT_MAXNAMEQLEN) { + wn = TAILQ_FIRST(&cc->nameq); + assert(wn != NULL); + TAILQ_REMOVE(&cc->nameq, wn, entry); + if (wn->name != emptystring) + XFree(wn->name); + xfree(wn); + cc->nameqlen--; + } + + return; +} + +/* + * TODO: seems to have some issues still on the first invocation + * (globally the first) + */ + +struct client_ctx * +client_cyclenext(struct client_ctx *cc, int reverse) +{ + struct screen_ctx *sc = CCTOSC(cc); + struct client_ctx *(*iter)(struct client_ctx *) = + reverse ? &client_mruprev : &client_mrunext; + + /* TODO: maybe this should just be a CIRCLEQ. */ + + /* if altheld; then reset the iterator to the beginning */ + if (!sc->altpersist || sc->cycle_client == NULL) + sc->cycle_client = TAILQ_FIRST(&sc->mruq); + + if (sc->cycle_client == NULL) + return (NULL); + + /* + * INVARIANT: as long as sc->cycle_client != NULL here, we + * won't exit with sc->cycle_client == NULL + */ + + if ((sc->cycle_client = client__cycle(cc, iter)) == NULL) + sc->cycle_client = cc; + + /* Do the actual warp. */ + client_ptrsave(cc); + client_ptrwarp(sc->cycle_client); + sc->altpersist = 1; /* This is reset when alt is let go... */ + + /* Draw window. */ + client_cycleinfo(sc->cycle_client); + + return (sc->cycle_client); +} + +/* + * XXX - have to have proper exposure handling here. we will probably + * have to do this by registering with the event loop a function to + * redraw, then match that on windows. + */ + +void +client_cycleinfo(struct client_ctx *cc) +{ + int w, h, nlines, i, n, oneh, curn = -1, x, y, diff; + struct client_ctx *ccc, *list[3]; + struct screen_ctx *sc = CCTOSC(cc); + struct fontdesc *font = DefaultFont; + + memset(list, 0, sizeof(list)); + + nlines = 0; + TAILQ_FOREACH(ccc, &sc->mruq, mru_entry) + nlines++; + nlines = MIN(nlines, 3); + + oneh = font_ascent(font) + font_descent(font) + 1; + h = nlines*oneh; + + list[1] = cc; + + if (nlines > 1) + list[2] = client__cycle(cc, &client_mrunext); + if (nlines > 2) + list[0] = client__cycle(cc, &client_mruprev); + + w = 0; + for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) { + if ((ccc = list[i]) == NULL) + continue; + w = MAX(w, font_width(font, ccc->name, strlen(ccc->name))); + } + + w += 4; + + /* try to fit. */ + + if ((x = cc->ptr.x) < 0 || (y = cc->ptr.y) < 0) { + x = cc->geom.width / 2; + y = cc->geom.height / 2; + } + + if ((diff = cc->geom.width - (x + w)) < 0) + x += diff; + + if ((diff = cc->geom.height - (y + h)) < 0) + y += diff; + + XReparentWindow(G_dpy, sc->infowin, cc->win, 0, 0); + XMoveResizeWindow(G_dpy, sc->infowin, x, y, w, h); + XMapRaised(G_dpy, sc->infowin); + XClearWindow(G_dpy, sc->infowin); + + for (i = 0, n = 0; i < sizeof(list)/sizeof(list[0]); i++) { + if ((ccc = list[i]) == NULL) + continue; + font_draw(font, ccc->name, strlen(ccc->name), sc->infowin, + 2, n*oneh + font_ascent(font) + 1); + if (i == 1) + curn = n; + n++; + } + + assert(curn != -1); + + /* Highlight the current entry. */ + XFillRectangle(G_dpy, sc->infowin, sc->hlgc, 0, curn*oneh, w, oneh); +} + +struct client_ctx * +client_mrunext(struct client_ctx *cc) +{ + struct screen_ctx *sc = CCTOSC(cc); + struct client_ctx *ccc; + + return ((ccc = TAILQ_NEXT(cc, mru_entry)) != NULL ? + ccc : TAILQ_FIRST(&sc->mruq)); +} + +struct client_ctx * +client_mruprev(struct client_ctx *cc) +{ + struct screen_ctx *sc = CCTOSC(cc); + struct client_ctx *ccc; + + return ((ccc = TAILQ_PREV(cc, cycle_entry_q, mru_entry)) != NULL ? + ccc : TAILQ_LAST(&sc->mruq, cycle_entry_q)); +} + +static struct client_ctx * +client__cycle(struct client_ctx *cc, + struct client_ctx *(*iter)(struct client_ctx *)) +{ + struct client_ctx *save = cc; + + do { + if (!((cc = (*iter)(cc))->flags & CLIENT_HIDDEN)) + break; + } while (cc != save); + + return cc != save ? cc : NULL; +} + +void +client_altrelease() +{ + struct client_ctx *cc = _curcc; + struct screen_ctx *sc; + + if (cc == NULL) + return; + sc = CCTOSC(cc); + + XUnmapWindow(G_dpy, sc->infowin); + XReparentWindow(G_dpy, sc->infowin, sc->rootwin, 0, 0); +} + +void +client_placecalc(struct client_ctx *cc) +{ + struct screen_ctx *sc = CCTOSC(cc); + int yslack, xslack; + int x, y, height, width, ymax, xmax, mousex, mousey; + + y = cc->geom.y; + x = cc->geom.x; + + height = cc->geom.height; + width = cc->geom.width; + + ymax = DisplayHeight(G_dpy, sc->which) - cc->bwidth; + xmax = DisplayWidth(G_dpy, sc->which) - cc->bwidth; + + yslack = ymax - cc->geom.height; + xslack = xmax - cc->geom.width; + + xu_ptr_getpos(sc->rootwin, &mousex, &mousey); + + mousex = MAX(mousex, cc->bwidth) - cc->geom.width/2; + mousey = MAX(mousey, cc->bwidth) - cc->geom.height/2; + + mousex = MAX(mousex, (int)cc->bwidth); + mousey = MAX(mousey, (int)cc->bwidth); + + if (cc->size->flags & USPosition) { + x = cc->size->x; + if (x <= 0 || x >= xmax) + x = cc->bwidth; + y = cc->size->y; + if (y <= 0 || y >= ymax) + y = cc->bwidth; + } else { + if (yslack < 0) { + y = cc->bwidth; + height = ymax; + } else { + if (y == 0 || y > yslack) + y = MIN(mousey, yslack); + height = cc->geom.height; + } + + if (xslack < 0) { + x = cc->bwidth; + width = xmax; + } else { + if (x == 0 || x > xslack) + x = MIN(mousex, xslack); + width = cc->geom.width; + } + } + + cc->geom.y = y; + cc->geom.x = x; + + cc->geom.height = height; + cc->geom.width = width; +} + +void +client_vertmaximize(struct client_ctx *cc) +{ + if (cc->flags & CLIENT_MAXIMIZED) { + cc->flags &= ~CLIENT_MAXIMIZED; + cc->geom = cc->savegeom; + } else { + struct screen_ctx *sc = CCTOSC(cc); + int display_height = DisplayHeight(G_dpy, sc->which) - + cc->bwidth*2; + + cc->savegeom = cc->geom; + cc->geom.y = cc->bwidth; + if (cc->geom.min_dx == 0) + cc->geom.height = display_height; + else + cc->geom.height = display_height - + (display_height % cc->geom.min_dx); + cc->flags |= CLIENT_MAXIMIZED; + } + + client_resize(cc); +} + +void +client_map(struct client_ctx *cc) +{ + /* mtf? */ + client_ptrwarp(cc); +} + +void +client_mtf(struct client_ctx *cc) +{ + struct screen_ctx *sc; + + if (cc == NULL) + cc = _curcc; + if (cc == NULL) + return; + + sc = CCTOSC(cc); + + /* Move to front. */ + TAILQ_REMOVE(&sc->mruq, cc, mru_entry); + TAILQ_INSERT_HEAD(&sc->mruq, cc, mru_entry); +} + +void +client_gethints(struct client_ctx *cc) +{ + XClassHint xch; + int argc; + char **argv; + Atom mha; + struct mwm_hints *mwmh; + + if (XGetClassHint(G_dpy, cc->win, &xch)) { + if (xch.res_name != NULL) + cc->app_name = xch.res_name; + if (xch.res_class != NULL) + cc->app_class = xch.res_class; + } + + mha = XInternAtom(G_dpy, "_MOTIF_WM_HINTS", False); + if (xu_getprop(cc, mha, mha, PROP_MWM_HINTS_ELEMENTS, + (u_char **)&mwmh) == MWM_NUMHINTS) + if (mwmh->flags & MWM_HINTS_DECORATIONS && + !(mwmh->decorations & MWM_DECOR_ALL) && + !(mwmh->decorations & MWM_DECOR_BORDER)) + cc->bwidth = 0; + if (XGetCommand(G_dpy, cc->win, &argv, &argc)) { +#define MAX_ARGLEN 512 +#define ARG_SEP_ " " + int len = MAX_ARGLEN; + int i, o; + char *buf; + + buf = xmalloc(len); + buf[0] = '\0'; + + for (o = 0, i = 0; o < len && i < argc; i++) { + if (argv[i] == NULL) + break; + strlcat(buf, argv[i], len); + o += strlen(buf); + strlcat(buf, ARG_SEP_, len); + o += strlen(ARG_SEP_); + } + + if (strlen(buf) > 0) + cc->app_cliarg = buf; + + XFreeStringList(argv); + } +} + +void +client_freehints(struct client_ctx *cc) +{ + if (cc->app_name != NULL) + XFree(cc->app_name); + if (cc->app_class != NULL) + XFree(cc->app_class); + if (cc->app_cliarg != NULL) + xfree(cc->app_cliarg); +} + +int +_inwindowbounds(struct client_ctx *cc, int x, int y) +{ + return (x < cc->geom.width && x >= 0 && + y < cc->geom.height && y >= 0); +} |