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>
|
2022-02-27 17:18:17 +00:00
|
|
|
#include <X11/extensions/Xrandr.h>
|
2021-02-26 22:18:39 +00:00
|
|
|
#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;
|
|
|
|
}
|
2022-03-01 06:40:32 +00:00
|
|
|
if (c == current) {
|
|
|
|
draw_border(c, 1);
|
2021-02-26 19:50:23 +00:00
|
|
|
return;
|
2022-03-01 06:40:32 +00:00
|
|
|
}
|
2021-02-21 23:13:58 +00:00
|
|
|
#ifdef AUTOSTICK
|
2021-02-26 19:50:23 +00:00
|
|
|
if (isautostick(c))
|
|
|
|
return;
|
2021-02-21 23:13:58 +00:00
|
|
|
#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;
|
2022-03-09 06:18:48 +00:00
|
|
|
/*Client* c;
|
2021-02-26 18:01:22 +00:00
|
|
|
if (current) {
|
|
|
|
setactive(current, 0);
|
|
|
|
for (c = current->revert; c; c = c->revert)
|
|
|
|
if (normal(c)) {
|
|
|
|
active(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cmapnofocus(current->screen);
|
|
|
|
}
|
2022-03-09 06:18:48 +00:00
|
|
|
current = 0;*/
|
2021-02-26 18:01:22 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-03-01 06:40:32 +00:00
|
|
|
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
|
|
|
|
2022-03-01 06:40:32 +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 */
|
2022-03-01 06:40:32 +00:00
|
|
|
|
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
|
|
|
|
|
2022-03-01 06:40:32 +00:00
|
|
|
void shuffleonmonitor(int m) {
|
2021-02-26 18:01:22 +00:00
|
|
|
Client **l, *c;
|
2022-03-01 06:40:32 +00:00
|
|
|
XRRMonitorInfo monitor;
|
2021-03-06 04:55:13 +00:00
|
|
|
|
2022-03-01 06:40:32 +00:00
|
|
|
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)
|
2021-02-21 23:13:58 +00:00
|
|
|
#ifdef AUTOSTICK
|
2022-03-01 06:40:32 +00:00
|
|
|
if (
|
|
|
|
(*l)->state == 1 && !isautostick(*l) &&
|
|
|
|
(!current || getmonitorbyclient(*l) == getmonitorbyclient(current)))
|
2021-02-26 19:50:23 +00:00
|
|
|
c = *l;
|
2021-02-21 23:13:58 +00:00
|
|
|
#else
|
2022-03-01 06:40:32 +00:00
|
|
|
if (
|
|
|
|
(*l)->state == 1 &&
|
|
|
|
(!current || getmonitorbyclient(*l) == getmonitorbyclient(current)))
|
2021-02-26 19:50:23 +00:00
|
|
|
c = *l;
|
2021-02-21 23:13:58 +00:00
|
|
|
#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);
|
2021-02-21 23:13:58 +00:00
|
|
|
active(c);
|
2021-03-06 04:55:13 +00:00
|
|
|
if (zoom) {
|
2022-03-01 06:40:32 +00:00
|
|
|
monitor = monitorinfo[getmonitorbyclient(c)];
|
|
|
|
quickreshape(c, monitor.x, monitor.y, monitor.width, monitor.height, 1);
|
2021-03-06 04:55:13 +00:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2021-02-21 23:13:58 +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;
|
|
|
|
}
|
2021-02-21 23:13:58 +00:00
|
|
|
++a;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
2021-03-09 05:35:05 +00:00
|
|
|
|
2021-11-16 22:16:28 +00:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
2021-11-17 04:25:43 +00:00
|
|
|
#if defined(OPACITY) && defined(TRANSPARENTLIST)
|
2021-11-16 22:16:28 +00:00
|
|
|
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;
|
|
|
|
}
|
2021-11-17 04:25:43 +00:00
|
|
|
#endif
|
2021-11-16 22:16:28 +00:00
|
|
|
|
2021-03-09 05:35:05 +00:00
|
|
|
void ensureactive() {
|
|
|
|
if (!current)
|
|
|
|
shuffle(0);
|
|
|
|
}
|
2022-03-01 06:40:32 +00:00
|
|
|
|
|
|
|
void ensureactiveonmonitor(int monitor) {
|
|
|
|
if (!current)
|
|
|
|
shuffleonmonitor(monitor);
|
2022-03-05 06:57:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2022-03-06 21:55:33 +00:00
|
|
|
#ifdef AUTOSTICK
|
|
|
|
if (getmonitorbyclient(cc) == m && normal(cc) && !isautostick(cc)) {
|
|
|
|
#else
|
|
|
|
if (getmonitorbyclient(cc) == m && normal(cc)) {
|
|
|
|
#endif
|
2022-03-05 06:57:25 +00:00
|
|
|
return cc->window;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2022-03-06 21:55:33 +00:00
|
|
|
}
|