2007-04-27 21:58:48 +04:00
|
|
|
/*
|
|
|
|
* calmwm - the calm window manager
|
|
|
|
*
|
|
|
|
* Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
|
2008-01-11 19:06:44 +03:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
2007-04-27 21:58:48 +04:00
|
|
|
*
|
2011-05-11 17:53:51 +04:00
|
|
|
* $OpenBSD$
|
2007-04-27 21:58:48 +04:00
|
|
|
*/
|
|
|
|
|
2009-12-15 07:10:42 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/queue.h>
|
|
|
|
|
2009-12-15 06:34:34 +03:00
|
|
|
#include <assert.h>
|
2009-12-15 07:10:42 +03:00
|
|
|
#include <err.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
2009-12-15 06:34:34 +03:00
|
|
|
|
2007-04-27 21:58:48 +04:00
|
|
|
#include "calmwm.h"
|
|
|
|
|
2009-06-26 16:21:58 +04:00
|
|
|
static struct client_ctx *client_mrunext(struct client_ctx *);
|
|
|
|
static struct client_ctx *client_mruprev(struct client_ctx *);
|
2009-12-08 01:21:59 +03:00
|
|
|
static void client_none(struct screen_ctx *);
|
2009-06-26 16:21:58 +04:00
|
|
|
static void client_placecalc(struct client_ctx *);
|
|
|
|
static void client_update(struct client_ctx *);
|
|
|
|
static void client_gethints(struct client_ctx *);
|
|
|
|
static void client_freehints(struct client_ctx *);
|
|
|
|
static int client_inbound(struct client_ctx *, int, int);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2008-04-16 00:24:41 +04:00
|
|
|
static char emptystring[] = "";
|
|
|
|
struct client_ctx *_curcc = NULL;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
struct client_ctx *
|
|
|
|
client_find(Window win)
|
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
struct client_ctx *cc;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2007-05-28 22:34:27 +04:00
|
|
|
TAILQ_FOREACH(cc, &Clientq, entry)
|
2009-01-16 18:24:14 +03:00
|
|
|
if (cc->win == win)
|
2007-04-27 21:58:48 +04:00
|
|
|
return (cc);
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct client_ctx *
|
|
|
|
client_new(Window win, struct screen_ctx *sc, int mapped)
|
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
struct client_ctx *cc;
|
|
|
|
XWindowAttributes wattr;
|
|
|
|
XWMHints *wmhints;
|
2009-01-16 18:24:14 +03:00
|
|
|
int state;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
if (win == None)
|
|
|
|
return (NULL);
|
|
|
|
|
2009-06-20 04:22:39 +04:00
|
|
|
cc = xcalloc(1, sizeof(*cc));
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2007-05-28 22:34:27 +04:00
|
|
|
XGrabServer(X_Dpy);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
cc->state = mapped ? NormalState : IconicState;
|
|
|
|
cc->sc = sc;
|
|
|
|
cc->win = win;
|
2008-04-16 00:24:41 +04:00
|
|
|
cc->size = XAllocSizeHints();
|
2009-05-30 04:30:17 +04:00
|
|
|
|
2009-08-25 03:49:04 +04:00
|
|
|
client_getsizehints(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2009-05-30 04:30:17 +04:00
|
|
|
TAILQ_INIT(&cc->nameq);
|
|
|
|
client_setname(cc);
|
|
|
|
|
|
|
|
conf_client(cc);
|
|
|
|
|
2007-04-27 21:58:48 +04:00
|
|
|
/* Saved pointer position */
|
|
|
|
cc->ptr.x = -1;
|
|
|
|
cc->ptr.y = -1;
|
|
|
|
|
2009-05-30 04:30:17 +04:00
|
|
|
XGetWindowAttributes(X_Dpy, cc->win, &wattr);
|
2007-04-27 21:58:48 +04:00
|
|
|
cc->geom.x = wattr.x;
|
|
|
|
cc->geom.y = wattr.y;
|
|
|
|
cc->geom.width = wattr.width;
|
|
|
|
cc->geom.height = wattr.height;
|
|
|
|
cc->cmap = wattr.colormap;
|
|
|
|
|
|
|
|
if (wattr.map_state != IsViewable) {
|
|
|
|
client_placecalc(cc);
|
2007-05-28 22:34:27 +04:00
|
|
|
if ((wmhints = XGetWMHints(X_Dpy, cc->win)) != NULL) {
|
2007-04-27 21:58:48 +04:00
|
|
|
if (wmhints->flags & StateHint)
|
|
|
|
xu_setstate(cc, wmhints->initial_state);
|
2009-01-22 22:01:56 +03:00
|
|
|
|
2007-04-27 21:58:48 +04:00
|
|
|
XFree(wmhints);
|
|
|
|
}
|
2009-01-16 18:24:14 +03:00
|
|
|
client_move(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
2009-01-16 18:24:14 +03:00
|
|
|
client_draw_border(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
if (xu_getstate(cc, &state) < 0)
|
|
|
|
state = NormalState;
|
|
|
|
|
2008-05-16 01:56:21 +04:00
|
|
|
XSelectInput(X_Dpy, cc->win, ColormapChangeMask | EnterWindowMask |
|
|
|
|
PropertyChangeMask | KeyReleaseMask);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2007-05-28 22:34:27 +04:00
|
|
|
XAddToSaveSet(X_Dpy, cc->win);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2011-09-13 12:41:57 +04:00
|
|
|
client_transient(cc);
|
|
|
|
|
2007-04-27 21:58:48 +04:00
|
|
|
/* Notify client of its configuration. */
|
2011-03-22 13:49:46 +03:00
|
|
|
xu_configure(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2009-06-20 04:55:41 +04:00
|
|
|
(state == IconicState) ? client_hide(cc) : client_unhide(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
xu_setstate(cc, cc->state);
|
|
|
|
|
2007-05-28 22:34:27 +04:00
|
|
|
XSync(X_Dpy, False);
|
|
|
|
XUngrabServer(X_Dpy);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&sc->mruq, cc, mru_entry);
|
2007-05-28 22:34:27 +04:00
|
|
|
TAILQ_INSERT_TAIL(&Clientq, cc, entry);
|
2012-07-03 17:49:03 +04:00
|
|
|
|
|
|
|
xu_ewmh_net_client_list(sc);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
client_gethints(cc);
|
|
|
|
client_update(cc);
|
2008-04-16 00:24:41 +04:00
|
|
|
|
2008-05-16 01:56:21 +04:00
|
|
|
if (mapped)
|
2008-03-22 18:09:45 +03:00
|
|
|
group_autogroup(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
return (cc);
|
|
|
|
}
|
|
|
|
|
2011-06-24 09:40:09 +04:00
|
|
|
void
|
2009-01-17 21:41:50 +03:00
|
|
|
client_delete(struct client_ctx *cc)
|
2007-04-27 21:58:48 +04:00
|
|
|
{
|
2009-08-27 05:38:08 +04:00
|
|
|
struct screen_ctx *sc = cc->sc;
|
2008-07-11 18:21:28 +04:00
|
|
|
struct winname *wn;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
group_client_delete(cc);
|
|
|
|
|
2008-07-11 18:21:28 +04:00
|
|
|
XGrabServer(X_Dpy);
|
2007-04-27 21:58:48 +04:00
|
|
|
xu_setstate(cc, WithdrawnState);
|
2007-05-28 22:34:27 +04:00
|
|
|
XRemoveFromSaveSet(X_Dpy, cc->win);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2007-05-28 22:34:27 +04:00
|
|
|
XSync(X_Dpy, False);
|
|
|
|
XUngrabServer(X_Dpy);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
TAILQ_REMOVE(&sc->mruq, cc, mru_entry);
|
2007-05-28 22:34:27 +04:00
|
|
|
TAILQ_REMOVE(&Clientq, cc, entry);
|
2012-07-03 17:49:03 +04:00
|
|
|
|
|
|
|
xu_ewmh_net_client_list(sc);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
if (_curcc == cc)
|
2009-12-08 01:21:59 +03:00
|
|
|
client_none(sc);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
XFree(cc->size);
|
|
|
|
|
|
|
|
while ((wn = TAILQ_FIRST(&cc->nameq)) != NULL) {
|
|
|
|
TAILQ_REMOVE(&cc->nameq, wn, entry);
|
|
|
|
if (wn->name != emptystring)
|
2010-05-23 02:10:31 +04:00
|
|
|
xfree(wn->name);
|
2007-04-27 21:58:48 +04:00
|
|
|
xfree(wn);
|
|
|
|
}
|
|
|
|
|
|
|
|
client_freehints(cc);
|
|
|
|
xfree(cc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_leave(struct client_ctx *cc)
|
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
struct screen_ctx *sc;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
if (cc == NULL)
|
|
|
|
cc = _curcc;
|
|
|
|
if (cc == NULL)
|
|
|
|
return;
|
|
|
|
|
2009-08-27 05:38:08 +04:00
|
|
|
sc = cc->sc;
|
2007-04-27 21:58:48 +04:00
|
|
|
xu_btn_ungrab(sc->rootwin, AnyModifier, Button1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_setactive(struct client_ctx *cc, int fg)
|
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
struct screen_ctx *sc;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
if (cc == NULL)
|
|
|
|
cc = _curcc;
|
|
|
|
if (cc == NULL)
|
|
|
|
return;
|
|
|
|
|
2009-08-27 05:38:08 +04:00
|
|
|
sc = cc->sc;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
if (fg) {
|
2007-05-28 22:34:27 +04:00
|
|
|
XInstallColormap(X_Dpy, cc->cmap);
|
|
|
|
XSetInputFocus(X_Dpy, cc->win,
|
2007-04-27 21:58:48 +04:00
|
|
|
RevertToPointerRoot, CurrentTime);
|
2008-06-26 02:37:29 +04:00
|
|
|
conf_grab_mouse(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
/*
|
|
|
|
* If we're in the middle of alt-tabbing, don't change
|
|
|
|
* the order please.
|
|
|
|
*/
|
2012-05-13 19:17:13 +04:00
|
|
|
if (!sc->cycling)
|
2007-04-27 21:58:48 +04:00
|
|
|
client_mtf(cc);
|
|
|
|
} else
|
|
|
|
client_leave(cc);
|
|
|
|
|
|
|
|
if (fg && _curcc != cc) {
|
|
|
|
client_setactive(NULL, 0);
|
|
|
|
_curcc = cc;
|
2012-07-03 17:49:03 +04:00
|
|
|
xu_ewmh_net_active_window(sc, cc->win);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
cc->active = fg;
|
|
|
|
client_draw_border(cc);
|
|
|
|
}
|
|
|
|
|
2009-12-08 01:21:59 +03:00
|
|
|
/*
|
|
|
|
* set when there is no active client
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
client_none(struct screen_ctx *sc)
|
|
|
|
{
|
|
|
|
Window none = None;
|
|
|
|
|
2012-07-03 17:49:03 +04:00
|
|
|
xu_ewmh_net_active_window(sc, none);
|
|
|
|
|
2009-12-08 01:21:59 +03:00
|
|
|
_curcc = NULL;
|
|
|
|
}
|
|
|
|
|
2007-04-27 21:58:48 +04:00
|
|
|
struct client_ctx *
|
|
|
|
client_current(void)
|
|
|
|
{
|
|
|
|
return (_curcc);
|
|
|
|
}
|
|
|
|
|
2011-05-07 21:15:37 +04:00
|
|
|
void
|
|
|
|
client_freeze(struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
if (cc->flags & CLIENT_FREEZE)
|
|
|
|
cc->flags &= ~CLIENT_FREEZE;
|
|
|
|
else
|
|
|
|
cc->flags |= CLIENT_FREEZE;
|
|
|
|
}
|
|
|
|
|
2007-04-27 21:58:48 +04:00
|
|
|
void
|
|
|
|
client_maximize(struct client_ctx *cc)
|
|
|
|
{
|
2009-08-27 05:38:08 +04:00
|
|
|
struct screen_ctx *sc = cc->sc;
|
2008-09-30 03:16:46 +04:00
|
|
|
int xmax = sc->xmax, ymax = sc->ymax;
|
|
|
|
int x_org = 0, y_org = 0;
|
2008-07-16 02:06:48 +04:00
|
|
|
|
2011-05-07 21:15:37 +04:00
|
|
|
if (cc->flags & CLIENT_FREEZE)
|
|
|
|
return;
|
|
|
|
|
2011-09-04 20:59:31 +04:00
|
|
|
if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_MAXIMIZED) {
|
|
|
|
cc->flags &= ~CLIENT_MAXIMIZED;
|
2007-04-27 21:58:48 +04:00
|
|
|
cc->geom = cc->savegeom;
|
2011-06-24 10:01:47 +04:00
|
|
|
cc->bwidth = Conf.bwidth;
|
2011-09-04 20:59:31 +04:00
|
|
|
goto resize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((cc->flags & CLIENT_VMAXIMIZED) == 0) {
|
|
|
|
cc->savegeom.height = cc->geom.height;
|
|
|
|
cc->savegeom.y = cc->geom.y;
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
2011-09-04 20:59:31 +04:00
|
|
|
if ((cc->flags & CLIENT_HMAXIMIZED) == 0) {
|
|
|
|
cc->savegeom.width = cc->geom.width;
|
|
|
|
cc->savegeom.x = cc->geom.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HasXinerama) {
|
|
|
|
XineramaScreenInfo *xine;
|
2011-09-05 11:37:55 +04:00
|
|
|
/*
|
|
|
|
* pick screen that the middle of the window is on.
|
|
|
|
* that's probably more fair than if just the origin of
|
|
|
|
* a window is poking over a boundary
|
2011-09-04 20:59:31 +04:00
|
|
|
*/
|
|
|
|
xine = screen_find_xinerama(sc,
|
|
|
|
cc->geom.x + cc->geom.width / 2,
|
|
|
|
cc->geom.y + cc->geom.height / 2);
|
|
|
|
if (xine == NULL)
|
|
|
|
goto calc;
|
|
|
|
x_org = xine->x_org;
|
|
|
|
y_org = xine->y_org;
|
|
|
|
xmax = xine->width;
|
|
|
|
ymax = xine->height;
|
|
|
|
}
|
|
|
|
calc:
|
|
|
|
cc->geom.x = x_org + sc->gap.left;
|
|
|
|
cc->geom.y = y_org + sc->gap.top;
|
|
|
|
cc->geom.height = ymax - (sc->gap.top + sc->gap.bottom);
|
|
|
|
cc->geom.width = xmax - (sc->gap.left + sc->gap.right);
|
|
|
|
cc->bwidth = 0;
|
|
|
|
cc->flags |= CLIENT_MAXIMIZED;
|
|
|
|
|
|
|
|
resize:
|
2007-04-27 21:58:48 +04:00
|
|
|
client_resize(cc);
|
|
|
|
}
|
|
|
|
|
2008-07-16 02:12:09 +04:00
|
|
|
void
|
|
|
|
client_vertmaximize(struct client_ctx *cc)
|
|
|
|
{
|
2009-08-27 05:38:08 +04:00
|
|
|
struct screen_ctx *sc = cc->sc;
|
2008-09-30 03:16:46 +04:00
|
|
|
int y_org = 0, ymax = sc->ymax;
|
2008-07-16 02:12:09 +04:00
|
|
|
|
2011-05-07 21:15:37 +04:00
|
|
|
if (cc->flags & CLIENT_FREEZE)
|
|
|
|
return;
|
|
|
|
|
2008-07-16 02:12:09 +04:00
|
|
|
if (cc->flags & CLIENT_VMAXIMIZED) {
|
2011-06-24 10:01:47 +04:00
|
|
|
cc->geom.y = cc->savegeom.y;
|
|
|
|
cc->geom.height = cc->savegeom.height;
|
|
|
|
cc->bwidth = Conf.bwidth;
|
2011-09-04 20:59:31 +04:00
|
|
|
if (cc->flags & CLIENT_HMAXIMIZED)
|
|
|
|
cc->geom.width -= cc->bwidth * 2;
|
2011-06-24 10:01:47 +04:00
|
|
|
cc->flags &= ~CLIENT_VMAXIMIZED;
|
2011-09-04 20:59:31 +04:00
|
|
|
goto resize;
|
2008-07-16 02:12:09 +04:00
|
|
|
}
|
|
|
|
|
2011-09-04 20:59:31 +04:00
|
|
|
cc->savegeom.y = cc->geom.y;
|
|
|
|
cc->savegeom.height = cc->geom.height;
|
|
|
|
|
|
|
|
/* if this will make us fully maximized then remove boundary */
|
|
|
|
if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_HMAXIMIZED) {
|
|
|
|
cc->geom.width += Conf.bwidth * 2;
|
|
|
|
cc->bwidth = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HasXinerama) {
|
|
|
|
XineramaScreenInfo *xine;
|
|
|
|
xine = screen_find_xinerama(sc,
|
|
|
|
cc->geom.x + cc->geom.width / 2,
|
|
|
|
cc->geom.y + cc->geom.height / 2);
|
|
|
|
if (xine == NULL)
|
|
|
|
goto calc;
|
|
|
|
y_org = xine->y_org;
|
|
|
|
ymax = xine->height;
|
|
|
|
}
|
|
|
|
calc:
|
|
|
|
cc->geom.y = y_org + sc->gap.top;
|
|
|
|
cc->geom.height = ymax - (cc->bwidth * 2) - (sc->gap.top +
|
|
|
|
sc->gap.bottom);
|
|
|
|
cc->flags |= CLIENT_VMAXIMIZED;
|
|
|
|
|
|
|
|
resize:
|
2008-07-16 02:12:09 +04:00
|
|
|
client_resize(cc);
|
|
|
|
}
|
|
|
|
|
2009-08-25 03:54:41 +04:00
|
|
|
void
|
|
|
|
client_horizmaximize(struct client_ctx *cc)
|
|
|
|
{
|
2009-08-27 05:38:08 +04:00
|
|
|
struct screen_ctx *sc = cc->sc;
|
2009-08-25 03:54:41 +04:00
|
|
|
int x_org = 0, xmax = sc->xmax;
|
|
|
|
|
2011-05-07 21:15:37 +04:00
|
|
|
if (cc->flags & CLIENT_FREEZE)
|
|
|
|
return;
|
|
|
|
|
2009-08-25 03:54:41 +04:00
|
|
|
if (cc->flags & CLIENT_HMAXIMIZED) {
|
2011-06-24 10:01:47 +04:00
|
|
|
cc->geom.x = cc->savegeom.x;
|
|
|
|
cc->geom.width = cc->savegeom.width;
|
|
|
|
cc->bwidth = Conf.bwidth;
|
2011-09-04 20:59:31 +04:00
|
|
|
if (cc->flags & CLIENT_VMAXIMIZED)
|
|
|
|
cc->geom.height -= cc->bwidth * 2;
|
2011-06-24 10:01:47 +04:00
|
|
|
cc->flags &= ~CLIENT_HMAXIMIZED;
|
2011-09-04 20:59:31 +04:00
|
|
|
goto resize;
|
2012-05-13 19:15:54 +04:00
|
|
|
}
|
2011-09-04 20:59:31 +04:00
|
|
|
|
|
|
|
cc->savegeom.x = cc->geom.x;
|
|
|
|
cc->savegeom.width = cc->geom.width;
|
|
|
|
|
2011-09-05 11:37:55 +04:00
|
|
|
/* if this will make us fully maximized then remove boundary */
|
2011-09-04 20:59:31 +04:00
|
|
|
if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_VMAXIMIZED) {
|
|
|
|
cc->geom.height += cc->bwidth * 2;
|
|
|
|
cc->bwidth = 0;
|
2009-08-25 03:54:41 +04:00
|
|
|
}
|
|
|
|
|
2011-09-04 20:59:31 +04:00
|
|
|
if (HasXinerama) {
|
|
|
|
XineramaScreenInfo *xine;
|
|
|
|
xine = screen_find_xinerama(sc,
|
|
|
|
cc->geom.x + cc->geom.width / 2,
|
|
|
|
cc->geom.y + cc->geom.height / 2);
|
|
|
|
if (xine == NULL)
|
|
|
|
goto calc;
|
|
|
|
x_org = xine->x_org;
|
|
|
|
xmax = xine->width;
|
|
|
|
}
|
|
|
|
calc:
|
|
|
|
cc->geom.x = x_org + sc->gap.left;
|
|
|
|
cc->geom.width = xmax - (cc->bwidth * 2) - (sc->gap.left +
|
|
|
|
sc->gap.right);
|
|
|
|
cc->flags |= CLIENT_HMAXIMIZED;
|
|
|
|
|
|
|
|
resize:
|
2009-08-25 03:54:41 +04:00
|
|
|
client_resize(cc);
|
|
|
|
}
|
|
|
|
|
2007-04-27 21:58:48 +04:00
|
|
|
void
|
|
|
|
client_resize(struct client_ctx *cc)
|
|
|
|
{
|
2009-09-25 19:57:49 +04:00
|
|
|
client_draw_border(cc);
|
|
|
|
|
2009-01-22 22:01:56 +03:00
|
|
|
XMoveResizeWindow(X_Dpy, cc->win, cc->geom.x,
|
|
|
|
cc->geom.y, cc->geom.width, cc->geom.height);
|
2011-03-22 13:49:46 +03:00
|
|
|
xu_configure(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_move(struct client_ctx *cc)
|
|
|
|
{
|
2009-01-22 22:01:56 +03:00
|
|
|
XMoveWindow(X_Dpy, cc->win, cc->geom.x, cc->geom.y);
|
2011-03-22 13:49:46 +03:00
|
|
|
xu_configure(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_lower(struct client_ctx *cc)
|
|
|
|
{
|
2009-01-16 18:24:14 +03:00
|
|
|
XLowerWindow(X_Dpy, cc->win);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_raise(struct client_ctx *cc)
|
|
|
|
{
|
2009-01-16 18:24:14 +03:00
|
|
|
XRaiseWindow(X_Dpy, cc->win);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_ptrwarp(struct client_ctx *cc)
|
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
int x = cc->ptr.x, y = cc->ptr.y;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
if (x == -1 || y == -1) {
|
|
|
|
x = cc->geom.width / 2;
|
|
|
|
y = cc->geom.height / 2;
|
|
|
|
}
|
|
|
|
|
2009-06-20 04:55:41 +04:00
|
|
|
(cc->state == IconicState) ? client_unhide(cc) : client_raise(cc);
|
2009-01-16 18:24:14 +03:00
|
|
|
xu_ptr_setpos(cc->win, x, y);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_ptrsave(struct client_ctx *cc)
|
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
int x, y;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2009-01-16 18:24:14 +03:00
|
|
|
xu_ptr_getpos(cc->win, &x, &y);
|
2009-05-18 04:23:35 +04:00
|
|
|
if (client_inbound(cc, x, y)) {
|
2007-04-27 21:58:48 +04:00
|
|
|
cc->ptr.x = x;
|
|
|
|
cc->ptr.y = y;
|
2011-02-13 23:09:57 +03:00
|
|
|
} else {
|
|
|
|
cc->ptr.x = -1;
|
|
|
|
cc->ptr.y = -1;
|
2008-04-16 00:24:41 +04:00
|
|
|
}
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_hide(struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
/* XXX - add wm_state stuff */
|
2009-01-16 18:24:14 +03:00
|
|
|
XUnmapWindow(X_Dpy, cc->win);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
cc->active = 0;
|
|
|
|
cc->flags |= CLIENT_HIDDEN;
|
|
|
|
xu_setstate(cc, IconicState);
|
|
|
|
|
|
|
|
if (cc == _curcc)
|
2009-12-08 01:21:59 +03:00
|
|
|
client_none(cc->sc);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_unhide(struct client_ctx *cc)
|
|
|
|
{
|
2009-01-16 18:24:14 +03:00
|
|
|
XMapRaised(X_Dpy, cc->win);
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2008-05-19 16:56:58 +04:00
|
|
|
cc->highlight = 0;
|
2007-04-27 21:58:48 +04:00
|
|
|
cc->flags &= ~CLIENT_HIDDEN;
|
|
|
|
xu_setstate(cc, NormalState);
|
2009-05-17 20:51:43 +04:00
|
|
|
client_draw_border(cc);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_draw_border(struct client_ctx *cc)
|
|
|
|
{
|
2009-08-27 05:38:08 +04:00
|
|
|
struct screen_ctx *sc = cc->sc;
|
2009-05-18 03:40:57 +04:00
|
|
|
unsigned long pixel;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2009-01-16 18:24:14 +03:00
|
|
|
if (cc->active)
|
|
|
|
switch (cc->highlight) {
|
2009-05-18 03:40:57 +04:00
|
|
|
case CLIENT_HIGHLIGHT_GROUP:
|
|
|
|
pixel = sc->color[CWM_COLOR_BORDER_GROUP].pixel;
|
2009-01-16 18:24:14 +03:00
|
|
|
break;
|
2009-05-18 03:40:57 +04:00
|
|
|
case CLIENT_HIGHLIGHT_UNGROUP:
|
|
|
|
pixel = sc->color[CWM_COLOR_BORDER_UNGROUP].pixel;
|
2009-01-16 18:24:14 +03:00
|
|
|
break;
|
|
|
|
default:
|
2011-07-14 15:39:53 +04:00
|
|
|
pixel = sc->color[CWM_COLOR_BORDER_ACTIVE].pixel;
|
2009-01-16 18:24:14 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
2009-05-18 03:40:57 +04:00
|
|
|
pixel = sc->color[CWM_COLOR_BORDER_INACTIVE].pixel;
|
2009-01-22 22:01:56 +03:00
|
|
|
|
2009-01-16 18:24:14 +03:00
|
|
|
XSetWindowBorderWidth(X_Dpy, cc->win, cc->bwidth);
|
2009-05-18 03:40:57 +04:00
|
|
|
XSetWindowBorder(X_Dpy, cc->win, pixel);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
2009-06-26 16:21:58 +04:00
|
|
|
static void
|
2007-04-27 21:58:48 +04:00
|
|
|
client_update(struct client_ctx *cc)
|
|
|
|
{
|
2009-11-28 20:52:12 +03:00
|
|
|
Atom *p;
|
2008-07-11 18:21:28 +04:00
|
|
|
int i;
|
|
|
|
long n;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2012-07-04 22:00:13 +04:00
|
|
|
if ((n = xu_getprop(cc->win, cwmh[WM_PROTOCOLS].atom,
|
2007-04-27 21:58:48 +04:00
|
|
|
XA_ATOM, 20L, (u_char **)&p)) <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
2012-07-03 17:49:03 +04:00
|
|
|
if (p[i] == cwmh[WM_DELETE_WINDOW].atom)
|
2007-04-27 21:58:48 +04:00
|
|
|
cc->xproto |= CLIENT_PROTO_DELETE;
|
2012-07-03 17:49:03 +04:00
|
|
|
else if (p[i] == cwmh[WM_TAKE_FOCUS].atom)
|
2007-04-27 21:58:48 +04:00
|
|
|
cc->xproto |= CLIENT_PROTO_TAKEFOCUS;
|
|
|
|
|
|
|
|
XFree(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_send_delete(struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
if (cc->xproto & CLIENT_PROTO_DELETE)
|
2012-07-03 17:49:03 +04:00
|
|
|
xu_sendmsg(cc->win,
|
|
|
|
cwmh[WM_PROTOCOLS].atom, cwmh[WM_DELETE_WINDOW].atom);
|
2007-04-27 21:58:48 +04:00
|
|
|
else
|
2007-05-28 22:34:27 +04:00
|
|
|
XKillClient(X_Dpy, cc->win);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_setname(struct client_ctx *cc)
|
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
struct winname *wn;
|
|
|
|
char *newname;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2012-07-03 17:49:03 +04:00
|
|
|
if (!xu_getstrprop(cc->win, ewmh[_NET_WM_NAME].atom, &newname))
|
2011-06-24 09:40:09 +04:00
|
|
|
if (!xu_getstrprop(cc->win, XA_WM_NAME, &newname))
|
|
|
|
newname = emptystring;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-06-20 04:22:39 +04:00
|
|
|
wn = xmalloc(sizeof(*wn));
|
2007-04-27 21:58:48 +04:00
|
|
|
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)
|
2010-05-23 02:10:31 +04:00
|
|
|
xfree(wn->name);
|
2007-04-27 21:58:48 +04:00
|
|
|
xfree(wn);
|
|
|
|
cc->nameqlen--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-24 09:40:09 +04:00
|
|
|
void
|
2011-09-03 13:20:58 +04:00
|
|
|
client_cycle(struct screen_ctx *sc, int flags)
|
2007-04-27 21:58:48 +04:00
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
struct client_ctx *oldcc, *newcc;
|
2008-05-01 22:01:13 +04:00
|
|
|
int again = 1;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2008-07-11 18:21:28 +04:00
|
|
|
oldcc = client_current();
|
|
|
|
|
2008-05-01 22:01:13 +04:00
|
|
|
/* If no windows then you cant cycle */
|
|
|
|
if (TAILQ_EMPTY(&sc->mruq))
|
2011-06-24 09:40:09 +04:00
|
|
|
return;
|
2007-06-05 23:03:20 +04:00
|
|
|
|
2008-05-01 22:01:13 +04:00
|
|
|
if (oldcc == NULL)
|
2012-05-13 19:15:54 +04:00
|
|
|
oldcc = (flags & CWM_RCYCLE ?
|
|
|
|
TAILQ_LAST(&sc->mruq, cycle_entry_q) :
|
2008-05-01 22:01:13 +04:00
|
|
|
TAILQ_FIRST(&sc->mruq));
|
2007-06-05 23:03:20 +04:00
|
|
|
|
2008-05-01 22:01:13 +04:00
|
|
|
newcc = oldcc;
|
|
|
|
while (again) {
|
|
|
|
again = 0;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2011-09-03 13:20:58 +04:00
|
|
|
newcc = (flags & CWM_RCYCLE ? client_mruprev(newcc) :
|
2008-05-01 22:01:13 +04:00
|
|
|
client_mrunext(newcc));
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2008-06-30 21:52:37 +04:00
|
|
|
/* Only cycle visible and non-ignored windows. */
|
2011-09-03 13:20:58 +04:00
|
|
|
if ((newcc->flags & (CLIENT_HIDDEN|CLIENT_IGNORE))
|
|
|
|
|| ((flags & CWM_INGROUP) && (newcc->group != oldcc->group)))
|
2008-05-01 22:01:13 +04:00
|
|
|
again = 1;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2008-05-01 22:01:13 +04:00
|
|
|
/* Is oldcc the only non-hidden window? */
|
|
|
|
if (newcc == oldcc) {
|
|
|
|
if (again)
|
2011-06-24 09:40:09 +04:00
|
|
|
return; /* No windows visible. */
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2008-05-19 19:17:50 +04:00
|
|
|
break;
|
2008-05-01 22:01:13 +04:00
|
|
|
}
|
|
|
|
}
|
2008-05-19 19:17:50 +04:00
|
|
|
|
2012-05-13 19:17:13 +04:00
|
|
|
/* reset when cycling mod is released. XXX I hate this hack */
|
|
|
|
sc->cycling = 1;
|
2008-05-01 22:01:13 +04:00
|
|
|
client_ptrsave(oldcc);
|
|
|
|
client_ptrwarp(newcc);
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
|
2012-05-16 05:09:17 +04:00
|
|
|
void
|
|
|
|
client_cycle_leave(struct screen_ctx *sc, struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
sc->cycling = 0;
|
|
|
|
|
|
|
|
client_mtf(NULL);
|
|
|
|
if (cc) {
|
|
|
|
group_sticky_toggle_exit(cc);
|
|
|
|
XUngrabKeyboard(X_Dpy, CurrentTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-26 16:21:58 +04:00
|
|
|
static struct client_ctx *
|
2007-04-27 21:58:48 +04:00
|
|
|
client_mrunext(struct client_ctx *cc)
|
|
|
|
{
|
2009-08-27 05:38:08 +04:00
|
|
|
struct screen_ctx *sc = cc->sc;
|
2008-07-11 18:21:28 +04:00
|
|
|
struct client_ctx *ccc;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
return ((ccc = TAILQ_NEXT(cc, mru_entry)) != NULL ?
|
|
|
|
ccc : TAILQ_FIRST(&sc->mruq));
|
|
|
|
}
|
|
|
|
|
2009-06-26 16:21:58 +04:00
|
|
|
static struct client_ctx *
|
2007-04-27 21:58:48 +04:00
|
|
|
client_mruprev(struct client_ctx *cc)
|
|
|
|
{
|
2009-08-27 05:38:08 +04:00
|
|
|
struct screen_ctx *sc = cc->sc;
|
2008-07-11 18:21:28 +04:00
|
|
|
struct client_ctx *ccc;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
return ((ccc = TAILQ_PREV(cc, cycle_entry_q, mru_entry)) != NULL ?
|
|
|
|
ccc : TAILQ_LAST(&sc->mruq, cycle_entry_q));
|
|
|
|
}
|
|
|
|
|
2009-06-26 16:21:58 +04:00
|
|
|
static void
|
2007-04-27 21:58:48 +04:00
|
|
|
client_placecalc(struct client_ctx *cc)
|
|
|
|
{
|
2009-08-27 05:38:08 +04:00
|
|
|
struct screen_ctx *sc = cc->sc;
|
2009-01-22 22:01:56 +03:00
|
|
|
int xslack, yslack;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2010-02-02 22:28:46 +03:00
|
|
|
if (cc->size->flags & (USPosition|PPosition)) {
|
2008-09-30 03:16:46 +04:00
|
|
|
/*
|
|
|
|
* Ignore XINERAMA screens, just make sure it's somewhere
|
|
|
|
* in the virtual desktop. else it stops people putting xterms
|
|
|
|
* at startup in the screen the mouse doesn't start in *sigh*.
|
|
|
|
* XRandR bits mean that {x,y}max shouldn't be outside what's
|
|
|
|
* currently there.
|
|
|
|
*/
|
2009-01-22 22:01:56 +03:00
|
|
|
xslack = sc->xmax - cc->geom.width - cc->bwidth * 2;
|
|
|
|
yslack = sc->ymax - cc->geom.height - cc->bwidth * 2;
|
|
|
|
if (cc->size->x > 0)
|
|
|
|
cc->geom.x = MIN(cc->size->x, xslack);
|
|
|
|
if (cc->size->y > 0)
|
|
|
|
cc->geom.y = MIN(cc->size->y, yslack);
|
2007-04-27 21:58:48 +04:00
|
|
|
} else {
|
2008-09-30 03:16:46 +04:00
|
|
|
XineramaScreenInfo *info;
|
|
|
|
int xmouse, ymouse, xorig, yorig;
|
|
|
|
int xmax, ymax;
|
|
|
|
|
|
|
|
xu_ptr_getpos(sc->rootwin, &xmouse, &ymouse);
|
|
|
|
if (HasXinerama) {
|
2009-01-15 03:32:35 +03:00
|
|
|
info = screen_find_xinerama(sc, xmouse, ymouse);
|
2008-09-30 03:16:46 +04:00
|
|
|
if (info == NULL)
|
|
|
|
goto noxine;
|
|
|
|
xorig = info->x_org;
|
|
|
|
yorig = info->y_org;
|
|
|
|
xmax = xorig + info->width;
|
|
|
|
ymax = yorig + info->height;
|
|
|
|
} else {
|
|
|
|
noxine:
|
|
|
|
xorig = yorig = 0;
|
|
|
|
xmax = sc->xmax;
|
|
|
|
ymax = sc->ymax;
|
|
|
|
}
|
2009-01-22 22:01:56 +03:00
|
|
|
xmouse = MAX(xmouse, xorig) - cc->geom.width / 2;
|
|
|
|
ymouse = MAX(ymouse, yorig) - cc->geom.height / 2;
|
|
|
|
|
|
|
|
xmouse = MAX(xmouse, xorig);
|
|
|
|
ymouse = MAX(ymouse, yorig);
|
2008-09-30 03:16:46 +04:00
|
|
|
|
2009-01-22 22:01:56 +03:00
|
|
|
xslack = xmax - cc->geom.width - cc->bwidth * 2;
|
|
|
|
yslack = ymax - cc->geom.height - cc->bwidth * 2;
|
2008-09-30 03:16:46 +04:00
|
|
|
|
|
|
|
if (xslack >= xorig) {
|
2008-06-12 08:59:51 +04:00
|
|
|
cc->geom.x = MAX(MIN(xmouse, xslack),
|
2010-01-27 06:04:50 +03:00
|
|
|
xorig + sc->gap.left);
|
|
|
|
if (cc->geom.x > (xslack - sc->gap.right))
|
|
|
|
cc->geom.x -= sc->gap.right;
|
2007-04-27 21:58:48 +04:00
|
|
|
} else {
|
2010-01-27 06:04:50 +03:00
|
|
|
cc->geom.x = xorig + sc->gap.left;
|
|
|
|
cc->geom.width = xmax - sc->gap.left;
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
2008-09-30 03:16:46 +04:00
|
|
|
if (yslack >= yorig) {
|
2008-06-12 08:59:51 +04:00
|
|
|
cc->geom.y = MAX(MIN(ymouse, yslack),
|
2010-01-27 06:04:50 +03:00
|
|
|
yorig + sc->gap.top);
|
|
|
|
if (cc->geom.y > (yslack - sc->gap.bottom))
|
|
|
|
cc->geom.y -= sc->gap.bottom;
|
2007-04-27 21:58:48 +04:00
|
|
|
} else {
|
2010-01-27 06:04:50 +03:00
|
|
|
cc->geom.y = yorig + sc->gap.top;
|
|
|
|
cc->geom.height = ymax - sc->gap.top;
|
2007-04-27 21:58:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
client_mtf(struct client_ctx *cc)
|
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
struct screen_ctx *sc;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
if (cc == NULL)
|
|
|
|
cc = _curcc;
|
|
|
|
if (cc == NULL)
|
|
|
|
return;
|
|
|
|
|
2009-08-27 05:38:08 +04:00
|
|
|
sc = cc->sc;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
|
|
|
/* Move to front. */
|
|
|
|
TAILQ_REMOVE(&sc->mruq, cc, mru_entry);
|
|
|
|
TAILQ_INSERT_HEAD(&sc->mruq, cc, mru_entry);
|
|
|
|
}
|
|
|
|
|
2009-08-25 03:49:04 +04:00
|
|
|
void
|
|
|
|
client_getsizehints(struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
long tmp;
|
|
|
|
|
|
|
|
if (!XGetWMNormalHints(X_Dpy, cc->win, cc->size, &tmp))
|
|
|
|
cc->size->flags = PSize;
|
|
|
|
|
|
|
|
if (cc->size->flags & PBaseSize) {
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->hint.basew = cc->size->base_width;
|
|
|
|
cc->hint.baseh = cc->size->base_height;
|
2009-08-25 03:49:04 +04:00
|
|
|
} else if (cc->size->flags & PMinSize) {
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->hint.basew = cc->size->min_width;
|
|
|
|
cc->hint.baseh = cc->size->min_height;
|
2009-08-25 03:49:04 +04:00
|
|
|
}
|
|
|
|
if (cc->size->flags & PMinSize) {
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->hint.minw = cc->size->min_width;
|
|
|
|
cc->hint.minh = cc->size->min_height;
|
2009-08-25 03:49:04 +04:00
|
|
|
} else if (cc->size->flags & PBaseSize) {
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->hint.minw = cc->size->base_width;
|
|
|
|
cc->hint.minh = cc->size->base_height;
|
2009-08-25 03:49:04 +04:00
|
|
|
}
|
|
|
|
if (cc->size->flags & PMaxSize) {
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->hint.maxw = cc->size->max_width;
|
|
|
|
cc->hint.maxh = cc->size->max_height;
|
2009-08-25 03:49:04 +04:00
|
|
|
}
|
|
|
|
if (cc->size->flags & PResizeInc) {
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->hint.incw = cc->size->width_inc;
|
|
|
|
cc->hint.inch = cc->size->height_inc;
|
2009-08-25 03:49:04 +04:00
|
|
|
}
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->hint.incw = MAX(1, cc->hint.incw);
|
|
|
|
cc->hint.inch = MAX(1, cc->hint.inch);
|
2009-08-25 05:32:40 +04:00
|
|
|
|
2009-08-25 03:49:04 +04:00
|
|
|
if (cc->size->flags & PAspect) {
|
2009-11-28 20:52:12 +03:00
|
|
|
if (cc->size->min_aspect.x > 0)
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->hint.mina = (float)cc->size->min_aspect.y /
|
2009-08-25 03:49:04 +04:00
|
|
|
cc->size->min_aspect.x;
|
2009-11-28 20:52:12 +03:00
|
|
|
if (cc->size->max_aspect.y > 0)
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->hint.maxa = (float)cc->size->max_aspect.x /
|
2009-08-25 03:49:04 +04:00
|
|
|
cc->size->max_aspect.y;
|
|
|
|
}
|
|
|
|
}
|
2012-05-13 19:15:54 +04:00
|
|
|
|
2009-08-25 03:49:04 +04:00
|
|
|
void
|
|
|
|
client_applysizehints(struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
Bool baseismin;
|
|
|
|
|
2011-09-03 13:42:33 +04:00
|
|
|
baseismin = (cc->hint.basew == cc->hint.minw) &&
|
|
|
|
(cc->hint.baseh == cc->hint.minh);
|
2009-08-25 03:49:04 +04:00
|
|
|
|
|
|
|
/* temporarily remove base dimensions, ICCCM 4.1.2.3 */
|
|
|
|
if (!baseismin) {
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->geom.width -= cc->hint.basew;
|
|
|
|
cc->geom.height -= cc->hint.baseh;
|
2009-08-25 03:49:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* adjust for aspect limits */
|
2011-09-03 13:42:33 +04:00
|
|
|
if (cc->hint.mina > 0 && cc->hint.maxa > 0) {
|
|
|
|
if (cc->hint.maxa <
|
2009-08-25 03:49:04 +04:00
|
|
|
(float)cc->geom.width / cc->geom.height)
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->geom.width = cc->geom.height * cc->hint.maxa;
|
|
|
|
else if (cc->hint.mina <
|
2009-08-25 03:49:04 +04:00
|
|
|
(float)cc->geom.height / cc->geom.width)
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->geom.height = cc->geom.width * cc->hint.mina;
|
2009-08-25 03:49:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* remove base dimensions for increment */
|
|
|
|
if (baseismin) {
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->geom.width -= cc->hint.basew;
|
|
|
|
cc->geom.height -= cc->hint.baseh;
|
2009-08-25 03:49:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* adjust for increment value */
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->geom.width -= cc->geom.width % cc->hint.incw;
|
|
|
|
cc->geom.height -= cc->geom.height % cc->hint.inch;
|
2009-08-25 03:49:04 +04:00
|
|
|
|
|
|
|
/* restore base dimensions */
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->geom.width += cc->hint.basew;
|
|
|
|
cc->geom.height += cc->hint.baseh;
|
2009-08-25 03:49:04 +04:00
|
|
|
|
|
|
|
/* adjust for min width/height */
|
2011-09-03 13:42:33 +04:00
|
|
|
cc->geom.width = MAX(cc->geom.width, cc->hint.minw);
|
|
|
|
cc->geom.height = MAX(cc->geom.height, cc->hint.minh);
|
2009-08-25 03:49:04 +04:00
|
|
|
|
|
|
|
/* adjust for max width/height */
|
2011-09-03 13:42:33 +04:00
|
|
|
if (cc->hint.maxw)
|
|
|
|
cc->geom.width = MIN(cc->geom.width, cc->hint.maxw);
|
|
|
|
if (cc->hint.maxh)
|
|
|
|
cc->geom.height = MIN(cc->geom.height, cc->hint.maxh);
|
2009-08-25 03:49:04 +04:00
|
|
|
}
|
|
|
|
|
2009-06-26 16:21:58 +04:00
|
|
|
static void
|
2007-04-27 21:58:48 +04:00
|
|
|
client_gethints(struct client_ctx *cc)
|
|
|
|
{
|
2008-07-11 18:21:28 +04:00
|
|
|
XClassHint xch;
|
|
|
|
struct mwm_hints *mwmh;
|
2007-04-27 21:58:48 +04:00
|
|
|
|
2007-05-28 22:34:27 +04:00
|
|
|
if (XGetClassHint(X_Dpy, cc->win, &xch)) {
|
2007-04-27 21:58:48 +04:00
|
|
|
if (xch.res_name != NULL)
|
|
|
|
cc->app_name = xch.res_name;
|
|
|
|
if (xch.res_class != NULL)
|
|
|
|
cc->app_class = xch.res_class;
|
|
|
|
}
|
|
|
|
|
2012-07-03 17:49:03 +04:00
|
|
|
if (xu_getprop(cc->win, cwmh[_MOTIF_WM_HINTS].atom, _MOTIF_WM_HINTS,
|
2009-01-22 18:26:33 +03:00
|
|
|
PROP_MWM_HINTS_ELEMENTS, (u_char **)&mwmh) == MWM_NUMHINTS)
|
2007-04-27 21:58:48 +04:00
|
|
|
if (mwmh->flags & MWM_HINTS_DECORATIONS &&
|
|
|
|
!(mwmh->decorations & MWM_DECOR_ALL) &&
|
|
|
|
!(mwmh->decorations & MWM_DECOR_BORDER))
|
|
|
|
cc->bwidth = 0;
|
|
|
|
}
|
|
|
|
|
2009-06-26 16:21:58 +04:00
|
|
|
static void
|
2007-04-27 21:58:48 +04:00
|
|
|
client_freehints(struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
if (cc->app_name != NULL)
|
|
|
|
XFree(cc->app_name);
|
|
|
|
if (cc->app_class != NULL)
|
|
|
|
XFree(cc->app_class);
|
|
|
|
}
|
|
|
|
|
2011-09-13 12:41:57 +04:00
|
|
|
void
|
|
|
|
client_transient(struct client_ctx *cc)
|
|
|
|
{
|
|
|
|
struct client_ctx *tc;
|
|
|
|
Window trans;
|
|
|
|
|
|
|
|
if (XGetTransientForHint(X_Dpy, cc->win, &trans)) {
|
|
|
|
if ((tc = client_find(trans)) && tc->group) {
|
|
|
|
group_movetogroup(cc, tc->group->shortcut - 1);
|
|
|
|
if (tc->flags & CLIENT_IGNORE)
|
|
|
|
cc->flags |= CLIENT_IGNORE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-15 03:32:35 +03:00
|
|
|
static int
|
2009-05-18 04:23:35 +04:00
|
|
|
client_inbound(struct client_ctx *cc, int x, int y)
|
2007-04-27 21:58:48 +04:00
|
|
|
{
|
|
|
|
return (x < cc->geom.width && x >= 0 &&
|
|
|
|
y < cc->geom.height && y >= 0);
|
|
|
|
}
|
2011-06-24 10:06:24 +04:00
|
|
|
|
|
|
|
int
|
|
|
|
client_snapcalc(int n, int dn, int nmax, int bwidth, int snapdist)
|
|
|
|
{
|
|
|
|
int n0, n1, s0, s1;
|
|
|
|
|
|
|
|
s0 = s1 = 0;
|
|
|
|
n0 = n;
|
|
|
|
n1 = n + dn + (bwidth * 2);
|
|
|
|
|
|
|
|
if (abs(n0) <= snapdist)
|
|
|
|
s0 = -n0;
|
|
|
|
|
|
|
|
if (nmax - snapdist <= n1 && n1 <= nmax + snapdist)
|
|
|
|
s1 = nmax - n1;
|
|
|
|
|
|
|
|
/* possible to snap in both directions */
|
|
|
|
if (s0 != 0 && s1 != 0)
|
|
|
|
if (abs(s0) < abs(s1))
|
2012-05-13 19:15:54 +04:00
|
|
|
return (s0);
|
2011-06-24 10:06:24 +04:00
|
|
|
else
|
2012-05-13 19:15:54 +04:00
|
|
|
return (s1);
|
2011-06-24 10:06:24 +04:00
|
|
|
else if (s0 != 0)
|
2012-05-13 19:15:54 +04:00
|
|
|
return (s0);
|
2011-06-24 10:06:24 +04:00
|
|
|
else if (s1 != 0)
|
2012-05-13 19:15:54 +04:00
|
|
|
return (s1);
|
2011-06-24 10:06:24 +04:00
|
|
|
else
|
2012-05-13 19:15:54 +04:00
|
|
|
return (0);
|
2011-06-24 10:06:24 +04:00
|
|
|
}
|