ryudo/client.c

438 lines
8.5 KiB
C
Raw Normal View History

2019-12-02 18:23:00 +00:00
/* Copyright (c) 1994-1996 David Hogan, see README for licence details */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xrandr.h>
#include "config.h"
2019-12-02 18:23:00 +00:00
#include "dat.h"
#include "fns.h"
2021-02-26 18:01:22 +00:00
Client* clients;
Client* current;
2019-12-02 18:23:00 +00:00
2021-02-26 19:50:23 +00:00
void setactive(Client* c, int on) {
2021-02-26 18:01:22 +00:00
/* dbg("setactive client %x %d", c->window, c->on); */
2021-02-26 19:50:23 +00:00
if (c->parent == c->screen->root)
return;
2021-02-26 18:01:22 +00:00
if (on) {
XUngrabButton(dpy, AnyButton, AnyModifier, c->parent);
XSetInputFocus(dpy, c->window, RevertToPointerRoot, timestamp());
if (c->proto & Ptakefocus)
sendcmessage(c->window, wm_protocols, wm_take_focus, 0, 1);
cmapfocus(c);
} else {
if (c->proto & Plosefocus)
sendcmessage(c->window, wm_protocols, wm_lose_focus, 0, 1);
XGrabButton(
dpy,
AnyButton,
AnyModifier,
c->parent,
False,
ButtonMask,
GrabModeAsync,
GrabModeSync,
None,
None);
}
draw_border(c, on);
2019-12-02 18:23:00 +00:00
}
2021-02-26 19:50:23 +00:00
void draw_border(Client* c, int active) {
2021-02-26 18:01:22 +00:00
unsigned long pixel;
if (active) {
if (c->hold)
pixel = c->screen->activeholdborder;
else
pixel = c->screen->activeborder;
} else {
if (c->hold)
pixel = c->screen->inactiveholdborder;
else
pixel = c->screen->inactiveborder;
}
if (debug)
fprintf(
stderr,
"draw_border %p pixel %ld active %d hold %d\n",
(void*)c,
pixel,
active,
c->hold);
XSetWindowBackground(dpy, c->parent, pixel);
XClearWindow(dpy, c->parent);
2019-12-02 18:23:00 +00:00
}
2021-02-26 19:50:23 +00:00
void active(Client* c) {
2021-02-26 18:01:22 +00:00
Client* cc;
2019-12-02 18:23:00 +00:00
2021-02-26 18:01:22 +00:00
if (c == 0) {
fprintf(stderr, "ryudo: active(c==0)\n");
return;
}
if (c == current) {
draw_border(c, 1);
2021-02-26 19:50:23 +00:00
return;
}
#ifdef AUTOSTICK
2021-02-26 19:50:23 +00:00
if (isautostick(c))
return;
#endif
2021-02-26 18:01:22 +00:00
if (current) {
setactive(current, 0);
2021-02-26 19:50:23 +00:00
if (current->screen != c->screen)
cmapnofocus(current->screen);
2021-02-26 18:01:22 +00:00
}
setactive(c, 1);
for (cc = clients; cc; cc = cc->next)
2021-02-26 19:50:23 +00:00
if (cc->revert == c)
cc->revert = c->revert;
2021-02-26 18:01:22 +00:00
c->revert = current;
2021-02-26 19:50:23 +00:00
while (c->revert && !normal(c->revert))
c->revert = c->revert->revert;
2021-02-26 18:01:22 +00:00
current = c;
#ifdef DEBUG
2021-02-26 19:50:23 +00:00
if (debug)
dump_revert();
2019-12-02 18:23:00 +00:00
#endif
}
2021-02-26 19:50:23 +00:00
void nofocus(void) {
2021-02-26 18:01:22 +00:00
static Window w = 0;
int mask;
XSetWindowAttributes attr;
Client* c;
if (current) {
setactive(current, 0);
for (c = current->revert; c; c = c->revert)
if (normal(c)) {
active(c);
return;
}
cmapnofocus(current->screen);
/* if no candidates to revert to, fall through */
}
current = 0;
if (w == 0) {
mask = CWOverrideRedirect /*|CWColormap*/;
attr.override_redirect = 1;
/* attr.colormap = screens[0].def_cmap;*/
w = XCreateWindow(
dpy,
screens[0].root,
0,
0,
1,
1,
0,
0 /*screens[0].depth*/,
InputOnly,
screens[0].vis,
mask,
&attr);
XMapWindow(dpy, w);
}
XSetInputFocus(dpy, w, RevertToPointerRoot, timestamp());
2019-12-02 18:23:00 +00:00
}
2021-02-26 19:50:23 +00:00
void top(Client* c) {
2021-02-26 18:01:22 +00:00
Client **l, *cc;
l = &clients;
for (cc = *l; cc; cc = *l) {
if (cc == c) {
*l = c->next;
c->next = clients;
clients = c;
return;
}
l = &cc->next;
}
fprintf(stderr, "ryudo: %p not on client list in top()\n", (void*)c);
2019-12-02 18:23:00 +00:00
}
2021-02-26 19:50:23 +00:00
Client* getclient(Window w, int create) {
2021-02-26 18:01:22 +00:00
Client* c;
2021-02-26 19:50:23 +00:00
if (w == 0 || getscreen(w))
return 0;
2021-02-26 18:01:22 +00:00
for (c = clients; c; c = c->next)
2021-02-26 19:50:23 +00:00
if (c->window == w || c->parent == w)
return c;
2021-02-26 18:01:22 +00:00
2021-02-26 19:50:23 +00:00
if (!create)
return 0;
2021-02-26 18:01:22 +00:00
c = (Client*)malloc(sizeof(Client));
memset(c, 0, sizeof(Client));
c->window = w;
/* c->parent will be set by the caller */
c->parent = None;
c->reparenting = 0;
c->state = WithdrawnState;
c->init = 0;
c->cmap = None;
c->label = c->class = 0;
c->revert = 0;
c->is9term = 0;
c->hold = 0;
c->ncmapwins = 0;
c->cmapwins = 0;
c->wmcmaps = 0;
c->next = clients;
c->virt = virt;
clients = c;
return c;
2019-12-02 18:23:00 +00:00
}
2021-02-26 19:50:23 +00:00
void rmclient(Client* c) {
2021-02-26 18:01:22 +00:00
Client* cc;
for (cc = current; cc && cc->revert; cc = cc->revert)
2021-02-26 19:50:23 +00:00
if (cc->revert == c)
cc->revert = cc->revert->revert;
2021-02-26 18:01:22 +00:00
2021-02-26 19:50:23 +00:00
if (c == clients)
clients = c->next;
2021-02-26 18:01:22 +00:00
for (cc = clients; cc && cc->next; cc = cc->next)
2021-02-26 19:50:23 +00:00
if (cc->next == c)
cc->next = cc->next->next;
2021-02-26 18:01:22 +00:00
2021-02-26 19:50:23 +00:00
if (hidden(c))
unhidec(c, 0);
2021-02-26 18:01:22 +00:00
if (current == c) {
current = 0;
setactive(c, 0);
}
2021-02-26 19:50:23 +00:00
if (c->parent != c->screen->root)
XDestroyWindow(dpy, c->parent);
2021-02-26 18:01:22 +00:00
c->parent = c->window = None; /* paranoia */
2021-02-26 18:01:22 +00:00
if (c->ncmapwins != 0) {
XFree((char*)c->cmapwins);
free((char*)c->wmcmaps);
}
2021-02-26 19:50:23 +00:00
if (c->iconname != 0)
XFree((char*)c->iconname);
if (c->name != 0)
XFree((char*)c->name);
if (c->instance != 0)
XFree((char*)c->instance);
if (c->class != 0)
XFree((char*)c->class);
2021-02-26 18:01:22 +00:00
memset(c, 0, sizeof(Client)); /* paranoia */
free(c);
2019-12-02 18:23:00 +00:00
}
2021-02-26 18:01:22 +00:00
#ifdef DEBUG
2021-02-26 19:50:23 +00:00
void dump_revert(void) {
2021-02-26 18:01:22 +00:00
Client* c;
int i;
i = 0;
for (c = current; c; c = c->revert) {
fprintf(
2021-02-26 19:50:23 +00:00
stderr,
"%s(%x:%d)",
c->label ? c->label : "?",
(int)c->window,
c->state);
if (i++ > 100)
break;
if (c->revert)
fprintf(stderr, " -> ");
2021-02-26 18:01:22 +00:00
}
2021-02-26 19:50:23 +00:00
if (current == 0)
fprintf(stderr, "empty");
2021-02-26 18:01:22 +00:00
fprintf(stderr, "\n");
2019-12-02 18:23:00 +00:00
}
2021-02-26 19:50:23 +00:00
void dump_clients(void) {
2021-02-26 18:01:22 +00:00
Client* c;
for (c = clients; c; c = c->next)
fprintf(
stderr,
"w 0x%x parent 0x%x @ (%d, %d)\n",
(int)c->window,
(int)c->parent,
c->x,
c->y);
2019-12-02 18:23:00 +00:00
}
#endif
void shuffleonmonitor(int m) {
2021-02-26 18:01:22 +00:00
Client **l, *c;
XRRMonitorInfo monitor;
if (clients == 0 || clients->next == 0)
return;
c = 0;
/*for(c=clients; c->next; c=c->next) */
/* ; */
for (l = &clients; (*l)->next; l = &(*l)->next)
#ifdef AUTOSTICK
if ((*l)->state == 1 && !isautostick(*l) && getmonitorbyclient(*l) == m)
c = *l;
#else
if ((*l)->state == 1 && getmonitorbyclient(*l) == m)
c = *l;
#endif
if (c == 0)
return;
XMapRaised(dpy, c->parent);
top(c);
active(c);
if (zoom) {
monitor = monitorinfo[getmonitorbyclient(c)];
quickreshape(c, monitor.x, monitor.y, monitor.width, monitor.height, 1);
}
}
void shuffle(int up) {
Client **l, *c;
XRRMonitorInfo monitor;
2021-02-26 18:01:22 +00:00
2021-02-26 19:50:23 +00:00
if (clients == 0 || clients->next == 0)
return;
2021-02-26 18:01:22 +00:00
if (!up) {
c = 0;
/*for(c=clients; c->next; c=c->next) */
/* ; */
for (l = &clients; (*l)->next; l = &(*l)->next)
#ifdef AUTOSTICK
if (
(*l)->state == 1 && !isautostick(*l) &&
(!current || getmonitorbyclient(*l) == getmonitorbyclient(current)))
2021-02-26 19:50:23 +00:00
c = *l;
#else
if (
(*l)->state == 1 &&
(!current || getmonitorbyclient(*l) == getmonitorbyclient(current)))
2021-02-26 19:50:23 +00:00
c = *l;
#endif
2021-02-26 19:50:23 +00:00
if (c == 0)
return;
2021-02-26 18:01:22 +00:00
XMapRaised(dpy, c->parent);
top(c);
active(c);
if (zoom) {
monitor = monitorinfo[getmonitorbyclient(c)];
quickreshape(c, monitor.x, monitor.y, monitor.width, monitor.height, 1);
}
2021-02-26 18:01:22 +00:00
} else {
c = clients;
for (l = &clients; *l; l = &(*l)->next)
;
clients = c->next;
*l = c;
c->next = 0;
XLowerWindow(dpy, c->window);
}
/* XMapRaised(dpy, clients->parent); */
/* top(clients); */
/* active(clients); */
2019-12-02 18:23:00 +00:00
}
#ifdef AUTOSTICK
2021-02-26 19:50:23 +00:00
int isautostick(Client* c) {
2021-02-26 18:01:22 +00:00
static char* autostick[] = AUTOSTICK;
char** a = autostick;
while (*a) {
2021-02-26 19:50:23 +00:00
if (c && c->class && strstr(c->class, *a)) {
return 1;
}
++a;
}
return 0;
}
#endif
#ifdef ALWAYSDRAW
int shouldalwaysdraw(Client* c) {
static char* alwaysdraw[] = ALWAYSDRAW;
char** a = alwaysdraw;
while (*a) {
if (c && c->class && strstr(c->class, *a)) {
return 1;
}
++a;
}
return 0;
}
#endif
int isterminalwindow(Client* c) {
static char* termnames[] = TERMINALS;
char** t = termnames;
while (*t) {
if (c && c->class && strstr(c->class, *t)) {
return 1;
}
++t;
}
return 0;
}
#if defined(OPACITY) && defined(TRANSPARENTLIST)
int istransparent(Client* c) {
static char* transnames[] = TRANSPARENTLIST;
char** t = transnames;
while (*t) {
if (c && c->class && strstr(c->class, *t)) {
return 1;
}
++t;
}
return 0;
}
#endif
void ensureactive() {
if (!current)
shuffle(0);
}
void ensureactiveonmonitor(int monitor) {
if (!current)
shuffleonmonitor(monitor);
}
Window getrevert(Client* c) {
int m;
Client* cc;
if (!c) {
return 0;
}
if (c->trans) {
return c->trans;
} else {
m = getmonitorbyclient(c);
for (cc = c->revert; cc && cc->revert; cc = cc->revert) {
if (getmonitorbyclient(cc) == m) {
return cc->window;
}
}
}
return 0;
}