412 lines
11 KiB
C
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;
|
|
}
|