swim.git
mon.c
/* swim - window manager
* Copyright (C) 2024 ArcNyxx
* see LICENCE file for licensing information */
#include <stdint.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#include <xcb/render.h>
#include <xcb/xcb_renderutil.h>
#include <xcb/xinerama.h>
#include "mon.h"
#include "swim.h"
#include "tile.h"
#include "util.h"
static mon_t *mkmon(xcb_connection_t *c, xcb_screen_t *scr,
xcb_render_pictformat_t fmt, uint16_t x, uint16_t y,
uint16_t w, uint16_t h);
static void mvmon(xcb_connection_t *c, mon_t *mon, uint16_t x, uint16_t y,
uint16_t w, uint16_t h);
static void rmmon(xcb_connection_t *c, mon_t **mp, mon_t *mons);
static mon_t *
mkmon(xcb_connection_t *c, xcb_screen_t *scr, xcb_render_pictformat_t fmt,
uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
mon_t *mon = srealloc(NULL, sizeof(mon_t));
*mon = (mon_t){ .x = x, .y = y, .w = w, .h = h, .tags = 1, .mfact = 50,
.nmaster = 1, .show = true, .gap = true, .top = true,
.win = ID(c), .pic = ID(c) };
#define CWM1 XCB_CW_OVERRIDE_REDIRECT | XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK
#define ARR1 (uint32_t []){ true, XCB_BACK_PIXMAP_PARENT_RELATIVE, \
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS }
xcb_create_window(c, XCB_COPY_FROM_PARENT, mon->win, scr->root,
x, y + !mon->top * (h - H), w, H, 0,
XCB_WINDOW_CLASS_COPY_FROM_PARENT,
XCB_COPY_FROM_PARENT, CWM1, ARR1);
xcb_change_property(c, XCB_PROP_MODE_REPLACE, mon->win,
XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8,
10, "swim\0swim");
xcb_render_create_picture(c, mon->pic, mon->win, fmt, 0, NULL);
xcb_map_window(c, mon->win);
return mon;
}
static void
rmmon(xcb_connection_t *c, mon_t **mp, mon_t *mons)
{
mon_t *mon = *mp; *mp = mon->next;
cli_t **cli;
for (cli = &mon->cli; *cli != NULL; cli = &(*cli)->next)
(*cli)->mon = mons;
*cli = mons->cli; mons->cli = mon->cli;
tile(mons);
xcb_render_free_picture(c, mon->pic);
xcb_destroy_window(c, mon->win);
free(mon);
}
static void
mvmon(xcb_connection_t *c, mon_t *mon, uint16_t x, uint16_t y,
uint16_t w, uint16_t h)
{
mon->x = x, mon->y = y, mon->w = w, mon->h = h;
for (cli_t *cli = mon->cli; cli != NULL; cli = cli->next)
if (cli->fsc)
#define CWM2 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | \
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT
#define ARR2 (uint32_t []){ x, y, w, h }
xcb_configure_window(c, cli->win, CWM2, ARR2);
tile(mon);
#define ARR3 (uint32_t []){ x, mon->show ? y + !mon->top * (h - H) : -H, w, H }
xcb_configure_window(c, mon->win, CWM2, ARR3);
}
void
chmon(xcb_connection_t *c, xcb_screen_t *scr, xcb_render_pictformat_t fmt,
mon_t **mp)
{
xcb_xinerama_is_active_reply_t *act = xcb_xinerama_is_active_reply(c,
xcb_xinerama_is_active(c), NULL);
if (!act->state)
die("swim: xinerama inactive");
free(act);
xcb_xinerama_query_screens_reply_t *dat =
xcb_xinerama_query_screens_reply(c,
xcb_xinerama_query_screens_unchecked(c), NULL);
xcb_xinerama_screen_info_iterator_t iter =
xcb_xinerama_query_screens_screen_info_iterator(dat);
if (iter.rem == 0)
die("swim: no monitors available");
mon_t *mons = *mp;
for (int new = 0; iter.rem > 0; xcb_xinerama_screen_info_next(&iter)) {
const uint16_t x = iter.data->x_org, y = iter.data->y_org,
w = iter.data->width, h = iter.data->height;
mon_t *mon = mons; int j = 0;
for (; j < new && mon != NULL; ++j, mon = mon->next)
if (mon->x != x || mon->y != y || mon->w != w ||
mon->h != h)
break;
if (j == new || mon == NULL) {
if (*mp != NULL)
mvmon(c, *mp, x, y, w, h);
else
*mp = mkmon(c, scr, fmt, x, y, w, h);
++new, mp = &(*mp)->next;
}
}
while (*mp != NULL)
rmmon(c, mp, mons);
free(dat);
}