~zenomat/wm

3622d0746a89a1bb31947a67df6c3916846084e2 — zenomat 9 months ago dd356bd main
this prob doesn't work, pushing for on the way coding
3 files changed, 129 insertions(+), 54 deletions(-)

M c-wm.c
M c-wm.h
M config.h
M c-wm.c => c-wm.c +108 -50
@@ 33,8 33,14 @@
 * 				- this is irrelevant, because we can't accidantaly unmap windows on display change
 * 		- [ ] move windows between monitors
 * 		- [ ] handle workspaces
 * 		- [ ] don't send keymap keypresses to window
 * 		- [x] don't send keymap keypresses to window
 * 		- [ ] support for floating windows, like popups (browser addons, signing key entry window)
 * 			- kinda works now, bit very wonky
 * 			- firefox doesn't send destory event
 * 			- [x] maybe introduce floating tag
 * 				- windows with that tag shoudln't influence window tiling
 * 		- [ ] support monocle layout
 * 		- [ ] exit c-wm
 */

xcb_connection_t* connection;


@@ 157,7 163,7 @@ int findWindowIndex(xcb_window_t window)
{
	WorkSpace* ws = &wm_state->outputs[wm_state->active_output_idx].workspace[wm_state->outputs[wm_state->active_output_idx].active_workspace_idx];
	for (int i = 0; i < ws->winnum; i++) {
		if (ws->windows[i] == window) {
		if (ws->windows[i].id == window) {
			return i;
		}
	}


@@ 200,17 206,22 @@ void addOutputToOutputs(Output output)
}

// adds the given window to the active workspace
void addWindowToWorkSpace(xcb_window_t window)
void addWindowToWorkSpace(Window window)
{
	WorkSpace* ws = &wm_state->outputs[wm_state->active_output_idx].workspace[wm_state->outputs[wm_state->active_output_idx].active_workspace_idx];
	int amount = ws->winnum + 1;
	if (ws->winnum <= 0) {
		int amount = 1;
	}
	// realloc the windows array to accomodate the new window
	xcb_window_t* new_windows_arr = realloc(ws->windows, (ws->winnum + 1) * sizeof(xcb_window_t));
	if (new_windows_arr) {
		ws->windows = new_windows_arr;
	} else {
	Window* new_windows_arr = realloc(ws->windows, amount * sizeof(Window));
	if (new_windows_arr == NULL) {
		fprintf(stderr, "ERROR: Reallocating window array failed: %s\n", strerror(errno));
		exit(errno);
	}

	ws->windows = new_windows_arr;

	// increment winnum, because we added a new window to the workspace
	ws->windows[ws->winnum] = window;
	ws->winnum++;


@@ 223,15 234,15 @@ void removeWindowFromWorkSpace(xcb_window_t window)
	bool found = false;
	int amount;
	// check how many elements we need to allocate memeory for
	if (ws->winnum == 0) {
		amount = 0;
	if (ws->winnum <= 0) {
		amount = 1;
	} else {
		amount = ws->winnum - 1;
	}
	// no realloc, because we don't want to copy the previous array
	xcb_window_t* new_windows_arr = calloc(amount, sizeof(xcb_window_t));
	Window* new_windows_arr = calloc(amount, sizeof(Window));
	if (new_windows_arr == NULL) {
		fprintf(stderr, "ERROR: Could not allocate memory for new array: %s\n", strerror(errno));
		fprintf(stderr, "ERROR: Could not allocate memory for new window array: %s\n", strerror(errno));
		exit(errno);
	}
	/*


@@ 240,7 251,7 @@ void removeWindowFromWorkSpace(xcb_window_t window)
	 * skip it, because we don't want it in the new array
	 */
	for (int i = 0; i < ws->winnum; i++) {
		if (ws->windows[i] == window) {
		if (ws->windows[i].id == window) {
			found = true;
			continue;
		} else {


@@ 250,7 261,9 @@ void removeWindowFromWorkSpace(xcb_window_t window)
		}
	}
	ws->windows = new_windows_arr;
	ws->winnum--;
	if (!(ws->winnum <= 0)) {
		ws->winnum--;
	}
}

/*


@@ 263,6 276,7 @@ void colorBorders()
{
	int active_output = wm_state->active_output_idx;
	int active_workspace = wm_state->outputs[active_output].active_workspace_idx;
	int active_window = wm_state->outputs[active_output].workspace[active_workspace].active_window_idx;
	uint32_t values[1];
	/*
	 * go through all monitors and all windows on the active workspace


@@ 271,12 285,12 @@ void colorBorders()
	 */
	for (int i = 0; i < wm_state->output_num; i++) {
		for (int j = 0; j < wm_state->outputs[i].workspace[active_workspace].winnum; j++) {
			if (i == wm_state->active_output_idx && wm_state->outputs[i].workspace[active_workspace].windows[j] == wm_state->outputs[i].workspace[active_workspace].active_window) {
			if (i == wm_state->active_output_idx && wm_state->outputs[i].workspace[active_workspace].windows[j].id == wm_state->outputs[i].workspace[active_workspace].windows[active_window].id) {
				values[0] = border_focused_color;
			} else {
				values[0] = border_unfocused_color;
			}
			xcb_change_window_attributes(connection, wm_state->outputs[i].workspace[active_workspace].windows[j], XCB_CW_BORDER_PIXEL, values);
			xcb_change_window_attributes(connection, wm_state->outputs[i].workspace[active_workspace].windows[j].id, XCB_CW_BORDER_PIXEL, values);
		}
	}
	xcb_flush(connection);


@@ 316,9 330,9 @@ void setFocusPrevDisplay()
void setFocus(xcb_window_t window)
{
	WorkSpace* ws = &wm_state->outputs[wm_state->active_output_idx].workspace[wm_state->outputs[wm_state->active_output_idx].active_workspace_idx];
	ws->active_window = window;
	ws->active_window_idx = findWindowIndex(window);
	// set input focus to the window, so it receives the keyboard input
	xcb_set_input_focus(connection, XCB_INPUT_FOCUS_POINTER_ROOT, ws->active_window, XCB_CURRENT_TIME);
	xcb_set_input_focus(connection, XCB_INPUT_FOCUS_POINTER_ROOT, ws->windows[ws->active_window_idx].id, XCB_CURRENT_TIME);
	/* recolor all borders, because we want our main window to have the active
	 * focus color.
	 * we can't just repaint the previous focused window, because we don't have


@@ 333,14 347,9 @@ void setFocusNext()
	WorkSpace* ws = &wm_state->outputs[wm_state->active_output_idx].workspace[wm_state->outputs[wm_state->active_output_idx].active_workspace_idx];
	// find the next window id
	// we wrap around on the end, using mod
	int active_window_idx = findWindowIndex(ws->active_window);
	if (active_window_idx < 0) {
		fprintf(stderr, "ERROR: could not find window index of next window\n");
		return;
	}
	int offset = (active_window_idx == ws->winnum - 1) ? ws->winnum : 0;
	int next_win_idx = mod(active_window_idx + 1, ws->winnum + 1) - offset;
	xcb_window_t next_win = ws->windows[next_win_idx];
	int offset = (ws->active_window_idx == ws->winnum - 1) ? ws->winnum : 0;
	int next_win_idx = mod(ws->active_window_idx + 1, ws->winnum + 1) - offset;
	xcb_window_t next_win = ws->windows[next_win_idx].id;
	setFocus(next_win);
}



@@ 350,14 359,9 @@ void setFocusPrev()
	WorkSpace* ws = &wm_state->outputs[wm_state->active_output_idx].workspace[wm_state->outputs[wm_state->active_output_idx].active_workspace_idx];
	// find the prev window id
	// we wrap around on the end, using mod
	int active_window_idx = findWindowIndex(ws->active_window);
	if (active_window_idx < 0) {
		fprintf(stderr, "ERROR: could not find window index of next window\n");
		return;
	}
	int offset = (active_window_idx == 0) ? 1 : 0;
	int prev_win_idx = mod(active_window_idx - 1, ws->winnum + 1) - offset;
	xcb_window_t prev_win = ws->windows[prev_win_idx];
	int offset = (ws->active_window_idx == 0) ? 1 : 0;
	int prev_win_idx = mod(ws->active_window_idx - 1, ws->winnum + 1) - offset;
	xcb_window_t prev_win = ws->windows[prev_win_idx].id;
	setFocus(prev_win);
}



@@ 389,7 393,7 @@ void spawn(char** prg)
void killActiveWindow()
{
	WorkSpace* ws = &wm_state->outputs[wm_state->active_output_idx].workspace[wm_state->outputs[wm_state->active_output_idx].active_workspace_idx];
	xcb_kill_client(connection, ws->active_window);
	xcb_kill_client(connection, ws->windows[ws->active_window_idx].id);
	xcb_flush(connection);
}



@@ 400,7 404,7 @@ void rotateToNext()
	WorkSpace* ws = &wm_state->outputs[wm_state->active_output_idx].workspace[wm_state->outputs[wm_state->active_output_idx].active_workspace_idx];
	// store the last window in tmp, so we can later assign that to the first one
	// (wrap around)
	int tmp = ws->windows[ws->winnum - 1];
	Window tmp = ws->windows[ws->winnum - 1];
	/*
	 * got through all windows and map the window to the previous,
	 * except the first window, because here we have to assign the last,


@@ 412,13 416,20 @@ void rotateToNext()
	updateDisplay();
}

void setFloating(xcb_window_t window)
{
	int idx = findWindowIndex(window);
	wm_state->outputs[wm_state->active_output_idx].workspace[wm_state->outputs[wm_state->active_output_idx].active_workspace_idx].windows[idx].state = floating;
	updateDisplay();
}

// rotates the window stack towards the beginning, wraps around
void rotateToPrev()
{
	WorkSpace* ws = &wm_state->outputs[wm_state->active_output_idx].workspace[wm_state->outputs[wm_state->active_output_idx].active_workspace_idx];
	// store the first window in tmp, so we can later assign that to the last one
	// (wrap around)
	int tmp = ws->windows[0];
	Window tmp = ws->windows[0];
	/*
	 * got through all windows and map the window to the next,
	 * except the last window, because here we have to assign the first,


@@ 448,6 459,21 @@ void updateDisplay()
	int height = 0;
	// in this loop all windows get remapped, if a new one is added
	for (int window_idx = 0; window_idx < winnum; window_idx++) {
		Window win = wm_state->outputs[active_output].workspace[active_workspace].windows[window_idx];
		// if the current window we want to tile is floating, ignore it
		if (win.state == floating) {
			uint32_t values[] = { win.x, win.y, win.width, win.height };
			uint16_t mask = 0;

			mask |= XCB_CONFIG_WINDOW_X;
			mask |= XCB_CONFIG_WINDOW_Y;
			mask |= XCB_CONFIG_WINDOW_WIDTH;
			mask |= XCB_CONFIG_WINDOW_HEIGHT;

			xcb_configure_window(connection, win.id, mask, values);
			continue;
		}

		// the master window
		if (window_idx == 0) {
			/*


@@ 478,8 504,7 @@ void updateDisplay()
				height -= gaps;
		}
#ifdef DEBUG
		uint32_t id = wm_state->outputs[active_output].workspace[active_workspace].windows[window_idx];
		printf(PDEBUG("mapping window(%u) at x=%d, y=%d, height=%d, width=%d"), id, x, y, height, width);
		printf(PDEBUG("mapping window(%u) at x=%d, y=%d, height=%d, width=%d"), win.id, x, y, height, width);
#endif
		uint32_t values[] = { x, y, width, height };
		uint16_t mask = 0;


@@ 489,7 514,7 @@ void updateDisplay()
		mask |= XCB_CONFIG_WINDOW_WIDTH;
		mask |= XCB_CONFIG_WINDOW_HEIGHT;

		xcb_configure_window(connection, wm_state->outputs[active_output].workspace[active_workspace].windows[window_idx], mask, values);
		xcb_configure_window(connection, win.id, mask, values);
	}
	xcb_flush(connection);
}


@@ 511,9 536,13 @@ void handleMapRequest(xcb_generic_event_t* event)
	xcb_configure_window(connection, map->window, XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
	xcb_flush(connection);

	Window win = {
		map->window,
		tiled,
	};
	// add the mapped window to the windows array,
	// so we can keep track of it
	addWindowToWorkSpace(map->window);
	addWindowToWorkSpace(win);

	// set focus to the window, because we want to focus the newest window
	setFocus(map->window);


@@ 532,9 561,10 @@ void handleWindowDestroy(xcb_generic_event_t* event)

	// if we kill the last window, set the focus to root, because there
	// will be no next window
	if (ws->winnum == 0 || ws->winnum == 1) {
	if (ws->winnum <= 1) {
		setFocus(screen->root);
	} else {
		printf("Setting focus to next, because winnum = %d\n", ws->winnum);
		setFocusNext();
	}



@@ 544,6 574,25 @@ void handleWindowDestroy(xcb_generic_event_t* event)
	updateDisplay();
}

void handleConfigureRequest(xcb_generic_event_t* event)
{
	xcb_configure_request_event_t* conf = (xcb_configure_request_event_t*)event;

	if (!findWindowIndex(conf->window)) {
		printf("Window not already found in windows, adding");
		Window win = {
			conf->window,
			floating,
		};
		addWindowToWorkSpace(win);
		updateDisplay();
		return;
	}
	printf("WIndow already in windows, doing nothing extra\n");
	// actuallt assign the values to the window
	setFloating(conf->window);
}

// handles the keypress event send by the X server
void handleKeyPress(xcb_generic_event_t* event)
{


@@ 571,15 620,18 @@ void handleEventLoop()
	while ((event = xcb_wait_for_event(connection))) {
		switch (event->response_type & ~0x80) {
		case XCB_MAP_REQUEST: {
			printf("Map request\n");
			handleMapRequest(event);
			break;
		}
		case XCB_DESTROY_NOTIFY: {
			printf("Destroy notify\n");
			handleWindowDestroy(event);
			break;
		}
		case XCB_CONFIGURE_REQUEST: {
			printf(PDEBUG("COnfigure request"));
			handleConfigureRequest(event);
			break;
		}
		case XCB_KEY_PRESS: {


@@ 589,7 641,7 @@ void handleEventLoop()
		default:
			/* Unknown event type, ignore it */
#ifdef DEBUG
			printf(PDEBUG("Unknown event: %i"), event->response_type);
			// printf(PDEBUG("Unknown event: %i"), event->response_type);
#endif
			break;
		}


@@ 598,6 650,15 @@ void handleEventLoop()
	}
}

void quit()
{
	xcb_disconnect(connection);

	// free the allocated windows array on the heap
	free(wm_state->outputs);
	free(wm_state);
}

void wm_setup()
{
	// all the events we want to get notifications about


@@ 637,11 698,11 @@ void wm_setup()
	// get all the outputs and put the information in our wm_state struct
	populateOutputs();

	// go through all the workspaces on all outputs and assing to memory
	// go through all the workspaces on all outputs and assing the memory
	for (int i = 0; i < wm_state->output_num; i++) {
		for (int j = 0; j < 9; j++) {
			wm_state->outputs[i].workspace[j].winnum = 0;
			xcb_window_t* windows = calloc(1, sizeof(xcb_window_t));
			Window* windows = calloc(1, sizeof(Window));
			if (windows == NULL) {
				fprintf(stderr, "ERROR: failed to allocate windows array: %s\n", strerror(errno));
				exit(errno);


@@ 649,6 710,9 @@ void wm_setup()
			wm_state->outputs[i].workspace[j].windows = windows;
		}
	}

	// register exit function
	atexit(quit);
}

int main()


@@ 669,11 733,5 @@ int main()

	handleEventLoop();

	xcb_disconnect(connection);

	// free the allocated windows array on the heap
	free(wm_state->outputs);
	free(wm_state);

	return 0;
}

M c-wm.h => c-wm.h +20 -4
@@ 1,6 1,20 @@
typedef enum State {
	floating = 0,
	tiled,
} State;

typedef struct Window {
	xcb_window_t id;
	State state;
	int16_t x;
	int16_t y;
	uint16_t width;
	uint16_t height;
} Window;

typedef struct WorkSpace {
	xcb_window_t* windows;
	xcb_window_t active_window;
	Window* windows;
	int active_window_idx;
	int winnum;
} WorkSpace;



@@ 28,13 42,13 @@ typedef struct Keymap {
} Keymap;

int mod(int, int);
int getWindowNum(); 
int getWindowNum();
void populateOutputs();
int findWindowIndex(xcb_window_t);
xcb_keysym_t xcb_get_keysym(xcb_keycode_t);
xcb_keycode_t* xcb_get_keycodes(xcb_keysym_t);
void addOutputToOutputs(Output);
void addWindowToTag(int, int, xcb_window_t);
void addWindowToTag(int, int, Window);
void removeWindowFromWindows(int, int, xcb_window_t);
void colorBorders();
void setActiveDisplay();


@@ 50,8 64,10 @@ void rotateToPrev();
void updateDisplay();
void handleMapRequest(xcb_generic_event_t*);
void handleWindowDestroy(xcb_generic_event_t*);
void handleConfigureRequest(xcb_generic_event_t*);
void handleKeyPress(xcb_generic_event_t*);
void handleEventLoop();
void quit();
void wm_setup();
int main();


M config.h => config.h +1 -0
@@ 16,4 16,5 @@ static Keymap keymap[] = {
	{ ALTKEY | SHIFTKEY,				Key_k,				rotateToNext,			NULL},
	{ ALTKEY,							Key_Comma,			setFocusPrevDisplay, 	NULL},
	{ ALTKEY,							Key_Period,			setFocusNextDisplay, 	NULL},
	{ ALTKEY | SHIFTKEY,				Key_q,				quit,					NULL},		
};