wm/client.c
2022-09-19 14:02:58 +02:00

412 lines
11 KiB
C

/*
The GPLv3 License (GPLv3)
Copyright (c) 2022 Akos Horvath
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "client.h"
// TODO
XWindowChanges wm_client_to_xwchanges(Client c)
{
XWindowChanges ch;
ch.x = c.x;
ch.y = c.y;
ch.width = c.w;
ch.height = c.h;
// ch.border_width = 0;
// ch.stack_mode = Above;
return ch;
}
Client* wm_client_find(Wm *wm, Window w)
{
Client *c;
for (c = wm->smon->clients; c; c = c->next) {
if (c->window == w)
return c;
}
return NULL;
}
Client* wm_client_create(Wm *wm, Window w)
{
Client *t;
XTextProperty xtp;
int strln;
XGetWMName(wm->display, w, &xtp);
Client *c = malloc(sizeof(Client));
c->window = w;
c->m = wm->smon;
c->ws = wm->smon->selws;
c->hidden = true;
c->is_floating = false;
if (xtp.value) {
strln = strlen((char*)xtp.value);
DEBUG_PRINT("%s allocating %d bytes for c->name\n", __func__, strln)
c->name = malloc(strln+1);
strcpy(c->name, (char*)xtp.value);
}
if (wm->smon->clients == NULL) {
wm->smon->clients = c;
c->prev = NULL;
} else {
t = wm_get_last_client(wm, *c->m);
//c = &root;
t->next = c;
c->prev = t;
c->next = NULL;
}
XSelectInput(wm->display, c->window, FocusChangeMask | EnterWindowMask |
PointerMotionMask);
wm_client_set_atom(wm, c, "_NET_WM_DESKTOP", (unsigned char*)&c->ws, XA_CARDINAL, 1);
return c;
}
void wm_client_hide(Wm *wm, Client *c)
{
RETURN_IF_NULL(c);
if (c->hidden)
return;
c->hidden = true;
XUnmapWindow(wm->display, c->window);
}
void wm_client_show(Wm *wm, Client *c)
{
RETURN_IF_NULL(c);
if (!c->hidden)
return;
c->hidden = false;
XMapWindow(wm->display, c->window);
}
void wm_client_focus(Wm *wm, Client *c)
{
RETURN_IF_NULL(c);
XSetInputFocus(wm->display, c->window, RevertToPointerRoot, CurrentTime);
wm_client_set_atom(wm, c, "_NET_ACTIVE_WINDOW", (unsigned char*) &c->window,
XA_WINDOW, 1);
// XChangeProperty(wm->display, root.window,
// XInternAtom(wm->display, "_NET_ACTIVE_WINDOW", False),
// 33, 32, PropModeReplace, (unsigned char *) &c->window, 1);
wm_monitor_clients_border(wm, c->m);
}
void wm_client_focus_dir(Wm *wm, Client *c, int dir)
{
RETURN_IF_NULL(c);
switch (dir) {
case UP:
wm_client_focus(wm, wm_client_get_dir_rel_c(c, dir));
break;
case DOWN:
wm_client_focus(wm, wm_client_get_dir_rel_c(c, dir));
break;
case LEFT:
wm_client_focus(wm, wm_client_get_dir_rel_c(c, dir));
break;
case RIGHT:
wm_client_focus(wm, wm_client_get_dir_rel_c(c, dir));
break;
default:
fprintf(stderr, "wm: %s invalid direction: %d\n", __func__, dir);
return;
}
}
void wm_client_free(Wm *wm, Client *c)
{
RETURN_IF_NULL(c);
if (c == wm->smon->clients) {
if (c->next)
wm->smon->clients = c->next;
else
wm->smon->clients = NULL;
} else {
if (!c->next)
c->prev->next = NULL;
else {
c->prev->next = c->next;
c->next->prev = c->prev;
}
}
}
void wm_client_kill(Wm *wm, Client *c)
{
RETURN_IF_NULL(c);
Monitor *m;
m = c->m;
XDestroyWindow(wm->display, c->window);
wm_client_free(wm, c);
wm_layout(wm, m);
}
void wm_client_set_atom(Wm *wm, Client *c, const char* name, const unsigned char *data,
Atom type, int nelements)
{
RETURN_IF_NULL(c);
RETURN_IF_NULL(name);
RETURN_IF_NULL(data);
XChangeProperty(wm->display, c->window, XInternAtom(wm->display, name, False),
type, 32, PropModeReplace, data, nelements);
}
// probably not working
Atom wm_client_get_atom(Wm *wm, Client *c, const char *name, unsigned char **atom_ret,
unsigned long *nitems_ret)
{
if (!c)
return -1;
if (!name)
return -1;
if (!atom_ret)
return -1;
if (!nitems_ret)
return -1;
Atom type_ret;
int format_ret;
unsigned long bytes_remain_ret;
int ret;
ret = XGetWindowProperty(wm->display, c->window,
XInternAtom(wm->display, name, False), 0, (~0L), False,
AnyPropertyType, &type_ret,
&format_ret, nitems_ret, &bytes_remain_ret, atom_ret);
if (ret != Success || (nitems_ret == 0 && type_ret == 0)) {
fprintf(stderr, "wm: XGetWindowProperty failed\n");
return -1;
}
DEBUG_PRINT("XGetWindowProperty return values, window %d:\n", (int)c->window);
DEBUG_PRINT("actual type return: %d\n", (int)type_ret);
DEBUG_PRINT("actual format return: %d\n", format_ret)
DEBUG_PRINT("actual number of items return: %ld\n", *nitems_ret)
DEBUG_PRINT("bytes remaining: %ld\n", *nitems_ret)
for (int i = 0; i < *nitems_ret; i++) {
printf("property return str: %s\n",
XGetAtomName(wm->display, ((Atom*)*atom_ret)[i]));
}
return type_ret;
}
Client* wm_client_get_dir_rel_c(Client *c, int dir)
{
DEBUG_PRINT("%s\n", __func__)
if (!c)
return NULL;
Client *r;
int x, y, dx, dy;
switch (dir) {
case UP:
x = c->x + c->w/2;
y = c->y;
dx = 0;
dy = -1;
break;
case DOWN:
x = c->x + c->w/2;
y = c->y + c->h;
dx = 0;
dy = 1;
break;
case LEFT:
x = c->x;
y = c->y + c->h/2;
dx = -1;
dy = 0;
break;
case RIGHT:
x = c->x + c->w;
y = c->y + c->h/3;
dx = 1;
dy = 0;
break;
default:
fprintf(stderr, "wm: %s invalid direction: %d\n", __func__, dir);
return NULL;
}
x+=dx*5;
y+=dy*5;
do {
x+=dx*2;
y+=dy*2;
for (r = c->m->clients; r; r = r->next) {
if ((x > r->x && x < r->x+r->w) && (y > r->y && y < r->y+r->h)) {
DEBUG_PRINT("%s ", __func__)
DEBUG_PRINT("found window %d in direction ", (int)c->window)
DEBUG_PRINT("%d\n", dir)
return r;
}
}
// TODO: bar
} while((x > 0 && x < c->m->info.width) &&
(y > 0 && y < c->m->info.height));
return r;
}
Client* wm_client_get_focused(Wm *wm)
{
Client *c;
for (c = wm->smon->clients; c; c = c->next) {
if (wm_client_is_focused(wm, c))
return c;
}
return NULL;
}
void wm_client_border(Wm *wm, Client *c)
{
RETURN_IF_NULL(c);
DEBUG_PRINT("border col: %s\nfocused border col: %s\n",
wm->cfg_border_col, wm->cfg_focused_border_col);
XVisualInfo vinfo;
XColor color;
XColor fcolor;
Colormap cmap;
XMatchVisualInfo(wm->display, DefaultScreen(wm->display), 32,
TrueColor, &vinfo);
cmap = XCreateColormap(wm->display, c->window, vinfo.visual, AllocNone);
XParseColor(wm->display, cmap, wm->cfg_focused_border_col, &fcolor);
XParseColor(wm->display, cmap, wm->cfg_border_col, &color);
XAllocColor(wm->display, cmap, &fcolor);
XAllocColor(wm->display, cmap, &color);
// DEBUG_PRINT("wm_client_border c: 0x%x\n", c)
if (c) {
// DEBUG_PRINT("wm_client_border window: %d\n", c->window)
}
XSetWindowBorderWidth(wm->display, c->window, wm->cfg_border_width);
// DEBUG_PRINT("drawing border for: %d\n", c->window);
if (wm_client_is_focused(wm, c)) {
DEBUG_PRINT("drawing focused border for: %d\n", (int)c->window);
XSetWindowBorder(wm->display, c->window, fcolor.pixel);
}
else
XSetWindowBorder(wm->display, c->window, color.pixel);
}
// FIXME probably unused
// void wm_client_border_focused(Client *c)
// {
// RETURN_IF_NULL(c);
// // if (!wm_client_is_focused(c))
// // return;
// XVisualInfo vinfo;
// XColor fcolor;
// Colormap cmap;
//
// XMatchVisualInfo(wm->display, DefaultScreen(wm->display), 32,
// TrueColor, &vinfo);
//
// cmap = XCreateColormap(wm->display, c->window, vinfo.visual, AllocNone);
// XParseColor(wm->display, cmap, wm->cfg_focused_border_col, &fcolor);
// XAllocColor(wm->display, cmap, &fcolor);
//
// XSetWindowBorderWidth(wm->display, c->window, wm->cfg_border_width);
//
// DEBUG_PRINT("drawing border for focused window: %d\n", (int)c->window);
// XSetWindowBorder(wm->display, c->window, fcolor.pixel);
// }
void wm_monitor_clients_border(Wm *wm, Monitor *m)
{
DEBUG_PRINT("%s\n", __func__)
RETURN_IF_NULL(m);
Client *c;
for (c = wm->smon->clients; c; c = c->next) {
if (c->window != wm->root.window) {
DEBUG_PRINT("monitor border c: %p\n", c)
DEBUG_PRINT("monitor border c window: %ld\n", c->window)
wm_client_border(wm, c);
}
}
}
bool wm_client_is_focused(Wm *wm, Client *c)
{
if (c == NULL)
return false;
int prop;
// prop = XGetWindowProperty(wm->display, c->window,
// XInternAtom(wm->display, "_NET_ACTIVE_WINDOW", False), 0, 1, False,
// XInternAtom(wm->display, "_NET_ACTIVE_WINDOW", False), XA_WINDOW,
// XA_WINDOW, unsigned long *, unsigned long *, unsigned char **)
// XChangeProperty(wm->display, root.window,
// XInternAtom(wm->display, "_NET_ACTIVE_WINDOW", False),
// 33, 32, PropModeReplace, (unsigned char *) &c->window, 1);
Client *c1;
Window w;
int r;
XGetInputFocus(wm->display, &w, &r);
//DEBUG_PRINT("is_focused focused window: %d\n", w)
if (w == c->window) {
// DEBUG_PRINT("IS_FOCUSED returning true for client: 0x%x", c)
// DEBUG_PRINT("window: %d\n", c->window)
return true;
}
// DEBUG_PRINT("IS_FOCUSED returning false for client: 0x%x", c)
// DEBUG_PRINT("window: %d\n", c->window)
return false;
}