277 lines
5.2 KiB
C
277 lines
5.2 KiB
C
#include "wm.h"
|
|
#include <X11/X.h>
|
|
#include <X11/Xlib.h>
|
|
#include <X11/extensions/Xinerama.h>
|
|
|
|
Monitor wm_monitor_open(Display *d, XineramaScreenInfo info)
|
|
{
|
|
Monitor m = {
|
|
.display = d,
|
|
.info = info
|
|
};
|
|
|
|
return m;
|
|
}
|
|
|
|
void wm_monitors_open_all(Display *d)
|
|
{
|
|
int count;
|
|
|
|
XineramaScreenInfo *xsi = XineramaQueryScreens(d, &count);
|
|
if (!xsi) {
|
|
printf("wm: Could not open display. Exiting.\n");
|
|
exit(1);
|
|
}
|
|
|
|
wm_monitors = malloc(count * sizeof(Monitor));
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
*(wm_monitors + i) = wm_monitor_open(d, *(xsi + i));
|
|
//cfg
|
|
wm_monitors[i].wscount = 9;
|
|
wm_monitors[i].wss = malloc(wm_smon->wscount*sizeof(int));
|
|
wm_monitors[i].selws = wm_monitors[i].wss[0];
|
|
for (int j = 0; j < wm_monitors[i].wscount; j++)
|
|
wm_monitors[i].wss[i] = j;
|
|
|
|
wm_monitors[i].clients = NULL;
|
|
}
|
|
|
|
wm_smon = &wm_monitors[0];
|
|
wm_smon->clients = &wm_root;
|
|
}
|
|
|
|
Display* wm_connect_display()
|
|
{
|
|
Display *d;
|
|
if (!(d = XOpenDisplay(NULL)))
|
|
{
|
|
printf("wm: Could not open display. Exiting.\n");
|
|
exit(1);
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
static int wm_xerror_handler(Display *displau, XErrorEvent *e)
|
|
{
|
|
if (e->error_code == BadAccess) {
|
|
wm_other_wm = true;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wm_other_wm_handler(Display *displau, XErrorEvent *e)
|
|
{
|
|
printf("wm: Error occured. %d\n", e->error_code);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void wm_create_handler(XCreateWindowEvent e)
|
|
{
|
|
Client *nc = malloc(sizeof(Client));
|
|
Client *c;
|
|
|
|
nc->wn = e.window;
|
|
nc->m = wm_smon;
|
|
nc->ws = nc->m->selws;
|
|
nc->hidden = true;
|
|
|
|
if (wm_smon->clients == NULL) {
|
|
wm_smon->clients = nc;
|
|
nc->prev = NULL;
|
|
} else {
|
|
LAST_WINDOW(c, wm_smon)
|
|
|
|
c->next = nc;
|
|
nc->prev = c;
|
|
nc->next = NULL;
|
|
}
|
|
}
|
|
|
|
// TODO
|
|
void wm_destroy_handler(XDestroyWindowEvent e)
|
|
{
|
|
Client *c;
|
|
|
|
// TODO: make function for linked list management
|
|
for (c = wm_smon->clients; c; c = c->next) {
|
|
if (e.window == c->wn) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
free(c);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void wm_reparent_handler(XReparentEvent e)
|
|
{
|
|
|
|
}
|
|
|
|
// TODO
|
|
void wm_configure_handler(XConfigureRequestEvent e)
|
|
{
|
|
Client *c;
|
|
XWindowChanges ch;
|
|
int cc_sws = 0;
|
|
|
|
for (c = wm_smon->clients; c; c = c->next) {
|
|
if (c->ws == wm_smon->selws) {
|
|
cc_sws++;
|
|
}
|
|
}
|
|
|
|
FIND_WINDOW(c, wm_smon, e.window)
|
|
|
|
// dynamic
|
|
if (cc_sws == 0) {
|
|
c->x = 0;
|
|
c->y = 0;
|
|
c->w = wm_smon->info.width;
|
|
c->h = wm_smon->info.height;
|
|
}
|
|
else {
|
|
// TODO
|
|
// c.x = m.h / cc_sws;
|
|
|
|
}
|
|
|
|
XConfigureWindow(wm_display, c->wn, e.value_mask, &ch);
|
|
}
|
|
|
|
void wm_map_handler(XMapRequestEvent e)
|
|
{
|
|
Client *c;
|
|
|
|
XMapWindow(wm_display, e.window);
|
|
|
|
FIND_WINDOW(c, wm_smon, e.window)
|
|
c->hidden = false;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
void wm_create_client(Window w)
|
|
{
|
|
|
|
}
|
|
|
|
void wm_client_hide(Client *c)
|
|
{
|
|
if (c->hidden)
|
|
return;
|
|
|
|
c->hidden = true;
|
|
XUnmapWindow(wm_display, c->wn);
|
|
}
|
|
|
|
void wm_client_show(Client *c)
|
|
{
|
|
|
|
if (!c->hidden)
|
|
return;
|
|
|
|
c->hidden = false;
|
|
XMapWindow(wm_display, c->wn);
|
|
}
|
|
|
|
void wm_switch_ws(int ws)
|
|
{
|
|
if (ws > wm_smon->wscount)
|
|
return;
|
|
|
|
Client *c;
|
|
|
|
for (c = wm_smon->clients; c; c = c->next) {
|
|
if (c->ws == wm_smon->selws) {
|
|
wm_client_hide(c);
|
|
}
|
|
}
|
|
|
|
wm_smon->selws = ws;
|
|
|
|
for (c = wm_smon->clients; c; c = c->next) {
|
|
if (c->ws == wm_smon->selws) {
|
|
wm_client_show(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
void wm_mainloop()
|
|
{
|
|
while (1) {
|
|
XEvent e;
|
|
XNextEvent(wm_display, &e);
|
|
|
|
switch (e.type) {
|
|
case CreateNotify:
|
|
wm_create_handler(e.xcreatewindow);
|
|
break;
|
|
case DestroyNotify:
|
|
wm_destroy_handler(e.xdestroywindow);
|
|
break;
|
|
case ReparentNotify:
|
|
wm_reparent_handler(e.xreparent);
|
|
break;
|
|
case ConfigureRequest:
|
|
wm_configure_handler(e.xconfigurerequest);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void wm_init()
|
|
{
|
|
Display *d = wm_connect_display();
|
|
wm_display = d;
|
|
wm_monitors_open_all(d);
|
|
|
|
wm_root.wn = DefaultRootWindow(d);
|
|
wm_last_client = &wm_root;
|
|
|
|
XSetErrorHandler(&wm_other_wm_handler);
|
|
|
|
XSelectInput(d, wm_root.wn, SubstructureRedirectMask |
|
|
SubstructureNotifyMask);
|
|
|
|
XSync(d, false);
|
|
|
|
if (wm_other_wm) {
|
|
printf("wm: Detected other window manager. Exiting.\n");
|
|
exit(1);
|
|
}
|
|
|
|
XSetErrorHandler(&wm_xerror_handler);
|
|
|
|
wm_mainloop();
|
|
}
|