ryudo/client.c
2021-03-07 01:32:13 -05:00

330 lines
6.5 KiB
C

/* 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 "config.h"
#include "dat.h"
#include "fns.h"
Client* clients;
Client* current;
void setactive(Client* c, int on) {
/* dbg("setactive client %x %d", c->window, c->on); */
if (c->parent == c->screen->root)
return;
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);
}
void draw_border(Client* c, int active) {
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);
}
void active(Client* c) {
Client* cc;
if (c == 0) {
fprintf(stderr, "ryudo: active(c==0)\n");
return;
}
if (c == current)
return;
#ifdef AUTOSTICK
if (isautostick(c))
return;
#endif
if (current) {
setactive(current, 0);
if (current->screen != c->screen)
cmapnofocus(current->screen);
}
setactive(c, 1);
for (cc = clients; cc; cc = cc->next)
if (cc->revert == c)
cc->revert = c->revert;
c->revert = current;
while (c->revert && !normal(c->revert))
c->revert = c->revert->revert;
current = c;
#ifdef DEBUG
if (debug)
dump_revert();
#endif
}
void nofocus(void) {
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());
}
void top(Client* c) {
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, "rio: %p not on client list in top()\n", (void*)c);
}
Client* getclient(Window w, int create) {
Client* c;
if (w == 0 || getscreen(w))
return 0;
for (c = clients; c; c = c->next)
if (c->window == w || c->parent == w)
return c;
if (!create)
return 0;
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;
}
void rmclient(Client* c) {
Client* cc;
for (cc = current; cc && cc->revert; cc = cc->revert)
if (cc->revert == c)
cc->revert = cc->revert->revert;
if (c == clients)
clients = c->next;
for (cc = clients; cc && cc->next; cc = cc->next)
if (cc->next == c)
cc->next = cc->next->next;
if (hidden(c))
unhidec(c, 0);
if (c->parent != c->screen->root)
XDestroyWindow(dpy, c->parent);
c->parent = c->window = None; /* paranoia */
if (current == c) {
current = c->revert;
if (current == 0)
nofocus();
else {
if (current->screen != c->screen)
cmapnofocus(c->screen);
setactive(current, 1);
}
}
if (c->ncmapwins != 0) {
XFree((char*)c->cmapwins);
free((char*)c->wmcmaps);
}
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);
memset(c, 0, sizeof(Client)); /* paranoia */
free(c);
}
#ifdef DEBUG
void dump_revert(void) {
Client* c;
int i;
i = 0;
for (c = current; c; c = c->revert) {
fprintf(
stderr,
"%s(%x:%d)",
c->label ? c->label : "?",
(int)c->window,
c->state);
if (i++ > 100)
break;
if (c->revert)
fprintf(stderr, " -> ");
}
if (current == 0)
fprintf(stderr, "empty");
fprintf(stderr, "\n");
}
void dump_clients(void) {
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);
}
#endif
void shuffle(int up) {
Client **l, *c;
static XWindowAttributes ra;
XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &ra);
if (clients == 0 || clients->next == 0)
return;
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))
c = *l;
#else
if ((*l)->state == 1)
c = *l;
#endif
if (c == 0)
return;
XMapRaised(dpy, c->parent);
top(c);
active(c);
} 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); */
}
#ifdef AUTOSTICK
int isautostick(Client* c) {
static char* autostick[] = AUTOSTICK;
char** a = autostick;
while (*a) {
if (c && c->class && strstr(c->class, *a)) {
return 1;
}
++a;
}
return 0;
}
#endif