@@ 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;
}