wmii/cmd/wm/page.c

327 lines
8.4 KiB
C
Raw Normal View History

2005-11-18 18:54:58 +03:00
/*
2006-01-20 17:20:24 +03:00
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
2005-11-18 18:54:58 +03:00
* See LICENSE file for license details.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
2005-12-27 23:13:50 +03:00
#include <X11/Xatom.h>
2005-11-18 18:54:58 +03:00
#include "wm.h"
2005-12-21 18:18:11 +03:00
static void handle_after_write_page(IXPServer * s, File * file);
2005-11-18 18:54:58 +03:00
2006-01-26 20:29:49 +03:00
static void select_client(void *obj, char *arg);
2006-01-12 18:06:50 +03:00
static void toggle_layout(void *obj, char *arg);
static void xexec(void *obj, char *arg);
2006-01-26 20:29:49 +03:00
static void swap_client(void *obj, char *arg);
static void xnew_column(void *obj, char *arg);
2005-12-12 19:04:40 +03:00
/* action table for /?/ namespace */
2005-12-05 01:45:59 +03:00
Action page_acttbl[] = {
2006-01-12 18:06:50 +03:00
{"toggle", toggle_layout},
{"exec", xexec},
2006-01-26 20:29:49 +03:00
{"swap", swap_client},
{"newcol", xnew_column},
{"select", select_client},
2005-12-21 18:18:11 +03:00
{0, 0}
2005-11-18 18:54:58 +03:00
};
2006-01-26 14:39:20 +03:00
void
attach_page_to_array(Page *p, Page **array, size_t *size)
{
size_t i;
if(!array) {
*size = 2;
array = cext_emallocz(sizeof(Page *) * (*size));
}
for(i = 0; (i < (*size)) && array[i]; i++);
if(i >= (*size)) {
Page **tmp = array;
(*size) *= 2;
array = cext_emallocz(sizeof(Page *) * (*size));
for(i = 0; tmp[i]; i++)
array[i] = tmp[i];
free(tmp);
}
array[i] = p;
}
void
detach_page_from_array(Page *p, Page **array)
{
size_t i;
for(i = 0; array[i] != p; i++);
for(; array[i + 1]; i++)
array[i] = array[i + 1];
array[i] = nil;
}
2005-12-21 18:18:11 +03:00
Page *
alloc_page()
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
Page *p, *new = cext_emallocz(sizeof(Page));
char buf[MAX_BUF], buf2[16];
2006-01-26 16:16:04 +03:00
static int id = 1;
size_t np;
2005-12-21 18:18:11 +03:00
2006-01-26 16:16:04 +03:00
snprintf(buf2, sizeof(buf2), "%d", id);
snprintf(buf, sizeof(buf), "/%d", id);
2005-12-21 18:18:11 +03:00
new->file[P_PREFIX] = ixp_create(ixps, buf);
2006-01-26 16:16:04 +03:00
snprintf(buf, sizeof(buf), "/%d/name", id);
2005-12-21 18:18:11 +03:00
new->file[P_NAME] = wmii_create_ixpfile(ixps, buf, buf2);
2006-01-26 16:16:04 +03:00
snprintf(buf, sizeof(buf), "/%d/floating/", id);
new->file[P_FLOATING_PREFIX] = ixp_create(ixps, buf);
2006-01-26 17:24:34 +03:00
snprintf(buf, sizeof(buf), "/%d/column/", id);
new->file[P_COLUMN_PREFIX] = ixp_create(ixps, buf);
2006-01-26 16:16:04 +03:00
snprintf(buf, sizeof(buf), "/%d/sel/", id);
new->file[P_SEL_PREFIX] = ixp_create(ixps, buf);
new->file[P_SEL_PREFIX]->bind = 1; /* mount point */
snprintf(buf, sizeof(buf), "/%d/floating/sel", id);
new->file[P_SEL_FLOATING_CLIENT] = ixp_create(ixps, buf);
new->file[P_SEL_FLOATING_CLIENT]->bind = 1;
2006-01-26 17:24:34 +03:00
snprintf(buf, sizeof(buf), "/%d/column/sel", id);
new->file[P_SEL_COLUMN_CLIENT] = ixp_create(ixps, buf);
new->file[P_SEL_COLUMN_CLIENT]->bind = 1;
2006-01-26 16:16:04 +03:00
snprintf(buf, sizeof(buf), "/%d/ctl", id);
2005-12-21 18:18:11 +03:00
new->file[P_CTL] = ixp_create(ixps, buf);
new->file[P_CTL]->after_write = handle_after_write_page;
def[WM_SEL_PAGE]->content = new->file[P_PREFIX]->content;
invoke_wm_event(def[WM_EVENT_PAGE_UPDATE]);
2006-01-26 16:16:04 +03:00
id++;
2006-01-26 17:24:34 +03:00
p->rect_column = rect;
attach_page_to_array(p, page, &pagesz);
for(np = 0; (np < pagesz) && page[np]; np++);
2006-01-26 16:16:04 +03:00
focus_page(new);
XChangeProperty(dpy, root, net_atoms[NET_NUMBER_OF_DESKTOPS], XA_CARDINAL,
2006-01-26 16:16:04 +03:00
32, PropModeReplace, (unsigned char *) &np, 1);
2005-12-21 18:18:11 +03:00
return new;
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
void
2006-01-26 16:16:04 +03:00
destroy_page(Page *p)
{
2006-01-26 16:16:04 +03:00
unsigned int i;
size_t naqueue = 0;
2006-01-26 16:16:04 +03:00
for(i = 0; (i < aqueuesz) && aqueue[i]; i++)
if(aqueue[i] == p)
naqueue++;
for(i = 0; i < naqueue; i++)
detach_page_from_array(p, aqueue);
2006-01-26 17:24:34 +03:00
for(i = 0; (i < clientsz) && client[i]; i++)
if(client[i]->page == p)
detach_client(client[i], False);
2006-01-26 16:16:04 +03:00
2006-01-26 17:24:34 +03:00
for(i = 0; (i < pagesz) && page[i] && (p != page[i]); i++);
2006-01-26 16:16:04 +03:00
if(sel_page && (sel_page == i))
sel_page--;
2005-12-21 18:18:11 +03:00
def[WM_SEL_PAGE]->content = 0;
ixp_remove_file(ixps, p->file[P_PREFIX]);
2005-12-27 23:13:50 +03:00
free(p);
2006-01-26 17:24:34 +03:00
for(i = 0; (i < pagesz) && page[i]; i++);
XChangeProperty(dpy, root, net_atoms[NET_NUMBER_OF_DESKTOPS], XA_CARDINAL,
2006-01-26 16:16:04 +03:00
32, PropModeReplace, (unsigned char *) &i, 1);
/* determine what to focus and do that */
2006-01-26 17:24:34 +03:00
if(page[sel_page])
focus_page(page[sel_page]);
2006-01-22 22:19:45 +03:00
else {
invoke_wm_event(def[WM_EVENT_CLIENT_UPDATE]);
2006-01-22 22:19:45 +03:00
invoke_wm_event(def[WM_EVENT_PAGE_UPDATE]);
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
}
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
void
2006-01-26 16:16:04 +03:00
focus_page(Page *p)
{
2006-01-26 16:16:04 +03:00
unsigned int i, j;
2006-01-26 17:24:34 +03:00
Page *old = page ? page[sel_page] : nil;
2006-01-26 17:24:34 +03:00
if(!page)
2006-01-26 16:16:04 +03:00
return;
2006-01-26 17:24:34 +03:00
for(i = 0; (i < pagesz) && page[i]; i++);
2006-01-26 16:16:04 +03:00
if(i == sel_page)
return;
2006-01-26 16:16:04 +03:00
sel_page = i;
2006-01-26 17:24:34 +03:00
for(j = 0; (j < clientsz) && client[j]; j++) {
if(client[j]->page == old)
XMoveWindow(dpy, client[j]->frame.win, 2 * rect.width, 2 * rect.height);
else if(client[j]->page == p)
XMoveWindow(dpy, client[j]->frame.win,
client[j]->frame.rect.x, client[j]->frame.rect.y);
2006-01-26 16:16:04 +03:00
}
2005-12-21 18:18:11 +03:00
def[WM_SEL_PAGE]->content = p->file[P_PREFIX]->content;
2006-01-26 17:24:34 +03:00
if(p->is_column)
p->file[P_SEL_PREFIX]->content = p->file[P_COLUMN_PREFIX]->content;
2006-01-26 16:16:04 +03:00
else
p->file[P_SEL_PREFIX]->content = p->file[P_FLOATING_PREFIX]->content;
2005-12-21 18:18:11 +03:00
invoke_wm_event(def[WM_EVENT_PAGE_UPDATE]);
XChangeProperty(dpy, root, net_atoms[NET_CURRENT_DESKTOP], XA_CARDINAL,
2006-01-26 16:16:04 +03:00
32, PropModeReplace, (unsigned char *) &sel_page, 1);
}
2005-12-21 18:18:11 +03:00
XRectangle *
rectangles(unsigned int *num)
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
XRectangle *result = 0;
int i, j = 0;
Window d1, d2;
Window *wins;
XWindowAttributes wa;
XRectangle r;
if(XQueryTree(dpy, root, &d1, &d2, &wins, num)) {
result = cext_emallocz(*num * sizeof(XRectangle));
for(i = 0; i < *num; i++) {
if(!XGetWindowAttributes(dpy, wins[i], &wa))
continue;
if(wa.override_redirect && (wa.map_state == IsViewable)) {
r.x = wa.x;
r.y = wa.y;
r.width = wa.width;
r.height = wa.height;
result[j++] = r;
}
}
}
if(wins) {
XFree(wins);
}
*num = j;
return result;
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
static void
2006-01-26 16:16:04 +03:00
handle_after_write_page(IXPServer *s, File *file)
2005-11-18 18:54:58 +03:00
{
2006-01-26 16:16:04 +03:00
size_t i;
2006-01-26 17:24:34 +03:00
for(i = 0; (i < pagesz) && page[i]; i++) {
if(file == page[i]->file[P_CTL]) {
run_action(file, page[i], page_acttbl);
2006-01-26 16:16:04 +03:00
return;
2005-12-21 18:18:11 +03:00
}
}
2005-11-18 18:54:58 +03:00
}
static void
xexec(void *obj, char *arg)
{
2006-01-26 16:16:04 +03:00
attach_page_to_array(obj, aqueue, &aqueuesz);
wmii_spawn(dpy, arg);
}
2005-12-21 18:18:11 +03:00
static void
2006-01-12 18:06:50 +03:00
toggle_layout(void *obj, char *arg)
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
Page *p = obj;
2006-01-26 17:24:34 +03:00
p->is_column = !p->is_column;
if(p->is_column) {
Column *col = p->column[p->sel_column];
if(col && col->clientsz && col->client[col->sel])
focus_client(col->client[col->sel]);
2006-01-26 16:16:04 +03:00
}
else if(p->floating && p->floatingsz && p->floating[p->sel_float])
focus_client(p->floating[p->sel_float]);
}
2006-01-26 20:29:49 +03:00
static void
swap_client(void *obj, char *arg)
{
Page *p = obj;
Client *c = sel_client_of_page(p);
Column *west = nil, *east = nil, *col = c->column;
Client *north = nil, *south = nil;
size_t i;
if(!col || !arg)
return;
for(i = 0; (i < p->columnsz) && p->column[i] && (p->column[i] != col); i++);
west = i ? p->column[i - 1] : nil;
east = (i < p->columnsz) && p->column[i + 1] ? p->column[i + 1] : nil;
for(i = 0; (i < col->clientsz) && col->client[i] && (col->client[i] != c); i++);
north = i ? col->client[i - 1] : nil;
south = (i < col->clientsz) && col->client[i + 1] ? col->client[i + 1] : nil;
if(!strncmp(arg, "north", 6) && north) {
col->client[i] = col->client[i - 1];
col->client[i - 1] = c;
arrange_column(p, col);
} else if(!strncmp(arg, "south", 6) && south) {
col->client[i] = col->client[i + 1];
col->client[i + 1] = c;
arrange_column(p, col);
}
else if(!strncmp(arg, "west", 5) && west) {
col->client[i] = west->client[west->sel];
col->client[i]->column = col;
west->client[west->sel] = c;
west->client[west->sel]->column = west;
arrange_column(p, col);
arrange_column(p, west);
} else if(!strncmp(arg, "east", 5) && east) {
col->client[i] = west->client[west->sel];
col->client[i]->column = col;
east->client[east->sel] = c;
east->client[east->sel]->column = east;
arrange_column(p, col);
arrange_column(p, east);
}
focus_client(c);
}
static void
xnew_column(void *obj, char *arg)
{
new_column(obj);
}
static void
select_client(void *obj, char *arg)
{
Page *p = obj;
Client *c = sel_client_of_page(p);
size_t i;
if(!c || !arg)
return;
if(c->column)
select_column(c, arg);
else {
for(i = 0; (i < p->floatingsz) && p->floating[i] && (p->floating[i] != c); i++);
if(!strncmp(arg, "prev", 5)) {
if(!i)
for(i = 0; (i < p->floatingsz) && p->floating[i]; i++);
focus_client(p->floating[i - 1]);
} else if(!strncmp(arg, "next", 5)) {
if(p->floating[i + 1])
focus_client(p->floating[i + 1]);
else
focus_client(p->floating[0]);
}
else {
const char *errstr;
for(i = 0; (i < p->floatingsz) && p->floating[i]; i++);
i = cext_strtonum(arg, 0, i - 1, &errstr);
if(errstr)
return;
focus_client(p->floating[i]);
}
}
}