Implement stacking
This commit is contained in:
parent
6e81d1c5e4
commit
0e3a378c39
1
TODO
1
TODO
|
@ -1,6 +1,5 @@
|
||||||
TODO list, in order of importance:
|
TODO list, in order of importance:
|
||||||
|
|
||||||
* freely resizable (e.g. using your mouse, for now) percentage of rows/cols
|
|
||||||
* document stuff!
|
* document stuff!
|
||||||
* more documentation!
|
* more documentation!
|
||||||
* debian package
|
* debian package
|
||||||
|
|
|
@ -164,6 +164,21 @@ struct Client {
|
||||||
SLIST_ENTRY(Client) dock_clients;
|
SLIST_ENTRY(Client) dock_clients;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Contains data for the windows needed to draw the titlebars on in stacking mode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct Stack_Window {
|
||||||
|
xcb_window_t window;
|
||||||
|
xcb_gcontext_t gc;
|
||||||
|
uint32_t width, height;
|
||||||
|
|
||||||
|
/* Backpointer to the container this stack window is in */
|
||||||
|
Container *container;
|
||||||
|
|
||||||
|
SLIST_ENTRY(Stack_Window) stack_windows;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A container is either in default or stacking mode. It sits inside the table.
|
* A container is either in default or stacking mode. It sits inside the table.
|
||||||
*
|
*
|
||||||
|
@ -186,6 +201,9 @@ struct Container {
|
||||||
float width_factor;
|
float width_factor;
|
||||||
float height_factor;
|
float height_factor;
|
||||||
|
|
||||||
|
/* When in stacking mode, we draw the titlebars of each client onto a separate window */
|
||||||
|
struct Stack_Window stack_win;
|
||||||
|
|
||||||
/* Backpointer to the workspace this container is in */
|
/* Backpointer to the workspace this container is in */
|
||||||
Workspace *workspace;
|
Workspace *workspace;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
extern Display *xkbdpy;
|
extern Display *xkbdpy;
|
||||||
extern TAILQ_HEAD(bindings_head, Binding) bindings;
|
extern TAILQ_HEAD(bindings_head, Binding) bindings;
|
||||||
|
extern SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins;
|
||||||
extern xcb_event_handlers_t evenths;
|
extern xcb_event_handlers_t evenths;
|
||||||
extern char *pattern;
|
extern char *pattern;
|
||||||
extern int num_screens;
|
extern int num_screens;
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
#define _LAYOUT_H
|
#define _LAYOUT_H
|
||||||
|
|
||||||
Rect get_unoccupied_space(Workspace *workspace);
|
Rect get_unoccupied_space(Workspace *workspace);
|
||||||
void decorate_window(xcb_connection_t *conn, Client *client);
|
void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t drawable, xcb_gcontext_t gc, int offset);
|
||||||
|
void render_container(xcb_connection_t *connection, Container *container);
|
||||||
void render_layout(xcb_connection_t *conn);
|
void render_layout(xcb_connection_t *conn);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,6 +30,7 @@ char *sstrdup(const char *str);
|
||||||
void start_application(const char *command);
|
void start_application(const char *command);
|
||||||
void check_error(xcb_connection_t *connection, xcb_void_cookie_t cookie, char *err_message);
|
void check_error(xcb_connection_t *connection, xcb_void_cookie_t cookie, char *err_message);
|
||||||
void set_focus(xcb_connection_t *conn, Client *client);
|
void set_focus(xcb_connection_t *conn, Client *client);
|
||||||
|
void switch_layout_mode(xcb_connection_t *conn, Container *container, int mode);
|
||||||
void warp_pointer_into(xcb_connection_t *connection, Client *client);
|
void warp_pointer_into(xcb_connection_t *connection, Client *client);
|
||||||
void toggle_fullscreen(xcb_connection_t *conn, Client *client);
|
void toggle_fullscreen(xcb_connection_t *conn, Client *client);
|
||||||
|
|
||||||
|
|
|
@ -29,5 +29,8 @@ enum { _NET_SUPPORTED = 0,
|
||||||
|
|
||||||
uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex);
|
uint32_t get_colorpixel(xcb_connection_t *conn, xcb_window_t window, char *hex);
|
||||||
xcb_window_t create_window(xcb_connection_t *conn, Rect r, uint16_t window_class, uint32_t mask, uint32_t *values);
|
xcb_window_t create_window(xcb_connection_t *conn, Rect r, uint16_t window_class, uint32_t mask, uint32_t *values);
|
||||||
|
void xcb_change_gc_single(xcb_connection_t *conn, xcb_gcontext_t gc, uint32_t mask, uint32_t value);
|
||||||
|
void xcb_draw_line(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc,
|
||||||
|
uint32_t colorpixel, uint32_t x, uint32_t y, uint32_t to_x, uint32_t to_y);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -343,6 +343,13 @@ void parse_command(xcb_connection_t *conn, const char *command) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is it just 's' for stacking or 'd' for default? */
|
||||||
|
if ((command[0] == 's' || command[0] == 'd') && (command[1] == '\0')) {
|
||||||
|
printf("Switching mode for current container\n");
|
||||||
|
switch_layout_mode(conn, CUR_CELL, (command[0] == 's' ? MODE_STACK : MODE_DEFAULT));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Is it a <with>? */
|
/* Is it a <with>? */
|
||||||
if (command[0] == 'w') {
|
if (command[0] == 'w') {
|
||||||
/* TODO: implement */
|
/* TODO: implement */
|
||||||
|
|
|
@ -89,7 +89,7 @@ int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event) {
|
int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_event_t *event) {
|
||||||
printf("enter_notify\n");
|
printf("enter_notify for %08x\n", event->event);
|
||||||
|
|
||||||
/* This was either a focus for a client’s parent (= titlebar)… */
|
/* This was either a focus for a client’s parent (= titlebar)… */
|
||||||
Client *client = table_get(byParent, event->event);
|
Client *client = table_get(byParent, event->event);
|
||||||
|
@ -110,6 +110,10 @@ int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_notify_
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When in stacking, enter notifications are ignored. Focus will be changed via keyboard only. */
|
||||||
|
if (client->container->mode == MODE_STACK)
|
||||||
|
return 1;
|
||||||
|
|
||||||
set_focus(conn, client);
|
set_focus(conn, client);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -354,7 +358,7 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
strncpy(client->name, xcb_get_property_value(prop), client->name_len);
|
strncpy(client->name, xcb_get_property_value(prop), client->name_len);
|
||||||
printf("rename to \"%.*s\".\n", client->name_len, client->name);
|
printf("rename to \"%.*s\".\n", client->name_len, client->name);
|
||||||
|
|
||||||
decorate_window(conn, client);
|
decorate_window(conn, client, client->frame, client->titlegc, 0);
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -365,11 +369,28 @@ int handle_windowname_change(void *data, xcb_connection_t *conn, uint8_t state,
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *e) {
|
int handle_expose_event(void *data, xcb_connection_t *conn, xcb_expose_event_t *e) {
|
||||||
Client *client = table_get(byParent, e->window);
|
printf("got expose_event\n");
|
||||||
if(!client || e->count != 0)
|
/* e->count is the number of minimum remaining expose events for this window, so we
|
||||||
|
skip all events but the last one */
|
||||||
|
if (e->count != 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
Client *client = table_get(byParent, e->window);
|
||||||
|
if (client == NULL) {
|
||||||
|
/* There was no client in the table, so this is probably an expose event for
|
||||||
|
one of our stack_windows. */
|
||||||
|
struct Stack_Window *stack_win;
|
||||||
|
SLIST_FOREACH(stack_win, &stack_wins, stack_windows)
|
||||||
|
if (stack_win->window == e->window) {
|
||||||
|
render_container(conn, stack_win->container);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
printf("handle_expose_event()\n");
|
printf("handle_expose_event()\n");
|
||||||
decorate_window(conn, client);
|
if (client->container->mode != MODE_STACK)
|
||||||
|
decorate_window(conn, client, client->frame, client->titlegc, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
109
src/layout.c
109
src/layout.c
|
@ -14,6 +14,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "i3.h"
|
#include "i3.h"
|
||||||
|
@ -81,9 +82,7 @@ int get_unoccupied_y(Workspace *workspace, int col) {
|
||||||
* (Re-)draws window decorations for a given Client
|
* (Re-)draws window decorations for a given Client
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void decorate_window(xcb_connection_t *conn, Client *client) {
|
void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t drawable, xcb_gcontext_t gc, int offset) {
|
||||||
uint32_t mask = 0;
|
|
||||||
uint32_t values[3];
|
|
||||||
i3Font *font = load_font(conn, pattern);
|
i3Font *font = load_font(conn, pattern);
|
||||||
uint32_t background_color,
|
uint32_t background_color,
|
||||||
text_color,
|
text_color,
|
||||||
|
@ -107,45 +106,31 @@ void decorate_window(xcb_connection_t *conn, Client *client) {
|
||||||
- Draw a rect around the whole client in background_color
|
- Draw a rect around the whole client in background_color
|
||||||
- Draw two lines in a lighter color
|
- Draw two lines in a lighter color
|
||||||
- Draw the window’s title
|
- Draw the window’s title
|
||||||
|
|
||||||
Note that xcb_image_text apparently adds 1xp border around the font? Can anyone confirm this?
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Draw a green rectangle around the window */
|
/* Draw a green rectangle around the window */
|
||||||
mask = XCB_GC_FOREGROUND;
|
xcb_change_gc_single(conn, gc, XCB_GC_FOREGROUND, background_color);
|
||||||
values[0] = background_color;
|
printf("drawing at offset %d\n", offset);
|
||||||
xcb_change_gc(conn, client->titlegc, mask, values);
|
|
||||||
|
|
||||||
xcb_rectangle_t rect = {0, 0, client->rect.width, client->rect.height};
|
xcb_rectangle_t rect = {0, offset, client->rect.width, offset + client->rect.height};
|
||||||
xcb_poly_fill_rectangle(conn, client->frame, client->titlegc, 1, &rect);
|
xcb_poly_fill_rectangle(conn, drawable, gc, 1, &rect);
|
||||||
|
|
||||||
/* Draw the lines */
|
/* Draw the lines */
|
||||||
/* TODO: this needs to be more beautiful somewhen. maybe stdarg + change_gc(gc, ...) ? */
|
xcb_draw_line(conn, drawable, gc, border_color, 2, offset, client->rect.width, offset);
|
||||||
#define DRAW_LINE(colorpixel, x, y, to_x, to_y) { \
|
xcb_draw_line(conn, drawable, gc, border_color, 2, offset + font->height + 3,
|
||||||
uint32_t draw_values[1]; \
|
2 + client->rect.width, offset + font->height + 3);
|
||||||
draw_values[0] = colorpixel; \
|
|
||||||
xcb_change_gc(conn, client->titlegc, XCB_GC_FOREGROUND, draw_values); \
|
|
||||||
xcb_point_t points[] = {{x, y}, {to_x, to_y}}; \
|
|
||||||
xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, client->frame, client->titlegc, 2, points); \
|
|
||||||
}
|
|
||||||
|
|
||||||
DRAW_LINE(border_color, 2, 0, client->rect.width, 0);
|
|
||||||
DRAW_LINE(border_color, 2, font->height + 3, 2 + client->rect.width, font->height + 3);
|
|
||||||
|
|
||||||
/* Draw the font */
|
/* Draw the font */
|
||||||
mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
|
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
|
||||||
|
uint32_t values[] = { text_color, background_color, font->id };
|
||||||
values[0] = text_color;
|
xcb_change_gc(conn, gc, mask, values);
|
||||||
values[1] = background_color;
|
|
||||||
values[2] = font->id;
|
|
||||||
|
|
||||||
xcb_change_gc(conn, client->titlegc, mask, values);
|
|
||||||
|
|
||||||
/* TODO: utf8? */
|
/* TODO: utf8? */
|
||||||
char *label;
|
char *label;
|
||||||
asprintf(&label, "(%08x) %.*s", client->frame, client->name_len, client->name);
|
asprintf(&label, "(%08x) %.*s", client->frame, client->name_len, client->name);
|
||||||
xcb_void_cookie_t text_cookie = xcb_image_text_8_checked(conn, strlen(label), client->frame,
|
printf("label is %s\n", label);
|
||||||
client->titlegc, 3 /* X */, font->height /* Y = baseline of font */, label);
|
xcb_void_cookie_t text_cookie = xcb_image_text_8_checked(conn, strlen(label), drawable,
|
||||||
|
gc, 3 /* X */, offset + font->height /* Y = baseline of font */, label);
|
||||||
check_error(conn, text_cookie, "Could not draw client's title");
|
check_error(conn, text_cookie, "Could not draw client's title");
|
||||||
free(label);
|
free(label);
|
||||||
}
|
}
|
||||||
|
@ -169,7 +154,7 @@ static void reposition_client(xcb_connection_t *connection, Client *client) {
|
||||||
static void resize_client(xcb_connection_t *connection, Client *client) {
|
static void resize_client(xcb_connection_t *connection, Client *client) {
|
||||||
i3Font *font = load_font(connection, pattern);
|
i3Font *font = load_font(connection, pattern);
|
||||||
|
|
||||||
printf("resizing client to %d x %d\n", client->rect.width, client->rect.height);
|
printf("resizing client \"%s\" to %d x %d\n", client->name, client->rect.width, client->rect.height);
|
||||||
xcb_configure_window(connection, client->frame,
|
xcb_configure_window(connection, client->frame,
|
||||||
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
||||||
&(client->rect.width));
|
&(client->rect.width));
|
||||||
|
@ -182,7 +167,8 @@ static void resize_client(xcb_connection_t *connection, Client *client) {
|
||||||
XCB_CONFIG_WINDOW_WIDTH |
|
XCB_CONFIG_WINDOW_WIDTH |
|
||||||
XCB_CONFIG_WINDOW_HEIGHT;
|
XCB_CONFIG_WINDOW_HEIGHT;
|
||||||
Rect rect;
|
Rect rect;
|
||||||
if (client->titlebar_position == TITLEBAR_OFF) {
|
if (client->titlebar_position == TITLEBAR_OFF ||
|
||||||
|
client->container->mode == MODE_STACK) {
|
||||||
rect.x = 0;
|
rect.x = 0;
|
||||||
rect.y = 0;
|
rect.y = 0;
|
||||||
rect.width = client->rect.width;
|
rect.width = client->rect.width;
|
||||||
|
@ -199,17 +185,23 @@ static void resize_client(xcb_connection_t *connection, Client *client) {
|
||||||
xcb_configure_window(connection, client->child, mask, &(rect.x));
|
xcb_configure_window(connection, client->child, mask, &(rect.x));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void render_container(xcb_connection_t *connection, Container *container) {
|
/*
|
||||||
|
* Renders the given container. Is called by render_layout() or individually (for example
|
||||||
|
* when focus changes in a stacking container)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void render_container(xcb_connection_t *connection, Container *container) {
|
||||||
Client *client;
|
Client *client;
|
||||||
|
int num_clients = 0, current_client = 0;
|
||||||
|
|
||||||
|
if (container->currently_focused == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CIRCLEQ_FOREACH(client, &(container->clients), clients)
|
||||||
|
num_clients++;
|
||||||
|
|
||||||
if (container->mode == MODE_DEFAULT) {
|
if (container->mode == MODE_DEFAULT) {
|
||||||
int num_clients = 0;
|
|
||||||
CIRCLEQ_FOREACH(client, &(container->clients), clients)
|
|
||||||
if (!client->dock)
|
|
||||||
num_clients++;
|
|
||||||
printf("got %d clients in this default container.\n", num_clients);
|
printf("got %d clients in this default container.\n", num_clients);
|
||||||
|
|
||||||
int current_client = 0;
|
|
||||||
CIRCLEQ_FOREACH(client, &(container->clients), clients) {
|
CIRCLEQ_FOREACH(client, &(container->clients), clients) {
|
||||||
/* Check if we changed client->x or client->y by updating it.
|
/* Check if we changed client->x or client->y by updating it.
|
||||||
* Note the bitwise OR instead of logical OR to force evaluation of both statements */
|
* Note the bitwise OR instead of logical OR to force evaluation of both statements */
|
||||||
|
@ -233,7 +225,42 @@ static void render_container(xcb_connection_t *connection, Container *container)
|
||||||
current_client++;
|
current_client++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* TODO: Implement stacking */
|
i3Font *font = load_font(connection, pattern);
|
||||||
|
int decoration_height = (font->height + 2 + 2);
|
||||||
|
struct Stack_Window *stack_win = &(container->stack_win);
|
||||||
|
|
||||||
|
/* Check if we need to reconfigure our stack title window */
|
||||||
|
if ((stack_win->width != (stack_win->width = container->width)) |
|
||||||
|
(stack_win->height != (stack_win->height = decoration_height * num_clients)))
|
||||||
|
xcb_configure_window(connection, stack_win->window,
|
||||||
|
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, &(stack_win->width));
|
||||||
|
|
||||||
|
/* All clients are repositioned */
|
||||||
|
CIRCLEQ_FOREACH(client, &(container->clients), clients) {
|
||||||
|
/* Check if we changed client->x or client->y by updating it.
|
||||||
|
* Note the bitwise OR instead of logical OR to force evaluation of both statements */
|
||||||
|
if (client->force_reconfigure |
|
||||||
|
(client->rect.x != (client->rect.x = container->x)) |
|
||||||
|
(client->rect.y != (client->rect.y = container->y + (decoration_height * num_clients))))
|
||||||
|
reposition_client(connection, client);
|
||||||
|
|
||||||
|
if (client->force_reconfigure |
|
||||||
|
(client->rect.width != (client->rect.width = container->width)) |
|
||||||
|
(client->rect.height !=
|
||||||
|
(client->rect.height = container->height - (decoration_height * num_clients))))
|
||||||
|
resize_client(connection, client);
|
||||||
|
|
||||||
|
client->force_reconfigure = false;
|
||||||
|
|
||||||
|
decorate_window(connection, client, stack_win->window, stack_win->gc,
|
||||||
|
current_client * decoration_height);
|
||||||
|
current_client++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Raise the focused window */
|
||||||
|
uint32_t values[] = { XCB_STACK_MODE_ABOVE };
|
||||||
|
xcb_configure_window(connection, container->currently_focused->frame,
|
||||||
|
XCB_CONFIG_WINDOW_STACK_MODE, values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +335,7 @@ void render_layout(xcb_connection_t *connection) {
|
||||||
else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor;
|
else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor;
|
||||||
container->height *= container->rowspan;
|
container->height *= container->rowspan;
|
||||||
|
|
||||||
/* Render it */
|
/* Render the container if it is not empty */
|
||||||
render_container(connection, container);
|
render_container(connection, container);
|
||||||
|
|
||||||
xoffset[rows] += container->width;
|
xoffset[rows] += container->width;
|
||||||
|
|
|
@ -47,12 +47,12 @@
|
||||||
Display *xkbdpy;
|
Display *xkbdpy;
|
||||||
|
|
||||||
TAILQ_HEAD(bindings_head, Binding) bindings = TAILQ_HEAD_INITIALIZER(bindings);
|
TAILQ_HEAD(bindings_head, Binding) bindings = TAILQ_HEAD_INITIALIZER(bindings);
|
||||||
|
SLIST_HEAD(stack_wins_head, Stack_Window) stack_wins = SLIST_HEAD_INITIALIZER(stack_wins);
|
||||||
xcb_event_handlers_t evenths;
|
xcb_event_handlers_t evenths;
|
||||||
|
|
||||||
xcb_window_t root_win;
|
xcb_window_t root_win;
|
||||||
xcb_atom_t atoms[9];
|
xcb_atom_t atoms[9];
|
||||||
|
|
||||||
|
|
||||||
char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso8859-1";
|
char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso8859-1";
|
||||||
int num_screens = 0;
|
int num_screens = 0;
|
||||||
|
|
||||||
|
@ -393,6 +393,9 @@ int main(int argc, char *argv[], char *env[]) {
|
||||||
|
|
||||||
BIND(41, BIND_MOD_1, "f");
|
BIND(41, BIND_MOD_1, "f");
|
||||||
|
|
||||||
|
BIND(43, BIND_MOD_1, "s");
|
||||||
|
BIND(26, BIND_MOD_1, "d");
|
||||||
|
|
||||||
BIND(44, BIND_MOD_1, "h");
|
BIND(44, BIND_MOD_1, "h");
|
||||||
BIND(45, BIND_MOD_1, "j");
|
BIND(45, BIND_MOD_1, "j");
|
||||||
BIND(46, BIND_MOD_1, "k");
|
BIND(46, BIND_MOD_1, "k");
|
||||||
|
|
68
src/util.c
68
src/util.c
|
@ -23,6 +23,7 @@
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "xcb.h"
|
||||||
|
|
||||||
int min(int a, int b) {
|
int min(int a, int b) {
|
||||||
return (a < b ? a : b);
|
return (a < b ? a : b);
|
||||||
|
@ -138,11 +139,74 @@ void set_focus(xcb_connection_t *conn, Client *client) {
|
||||||
//xcb_warp_pointer(conn, XCB_NONE, client->child, 0, 0, 0, 0, 10, 10);
|
//xcb_warp_pointer(conn, XCB_NONE, client->child, 0, 0, 0, 0, 10, 10);
|
||||||
/* Update last/current client’s titlebar */
|
/* Update last/current client’s titlebar */
|
||||||
if (old_client != NULL)
|
if (old_client != NULL)
|
||||||
decorate_window(conn, old_client);
|
decorate_window(conn, old_client, old_client->frame, old_client->titlegc, 0);
|
||||||
decorate_window(conn, client);
|
decorate_window(conn, client, client->frame, client->titlegc, 0);
|
||||||
|
|
||||||
|
/* If we’re in stacking mode, we render the container to update changes in the title
|
||||||
|
bars and to raise the focused client */
|
||||||
|
if (client->container->mode == MODE_STACK)
|
||||||
|
render_container(conn, client->container);
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switches the layout of the given container taking care of the necessary house-keeping
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void switch_layout_mode(xcb_connection_t *conn, Container *container, int mode) {
|
||||||
|
if (mode == MODE_STACK) {
|
||||||
|
/* When entering stacking mode, we need to open a window on which we can draw the
|
||||||
|
title bars of the clients */
|
||||||
|
Rect rect = {container->x, container->y, container->width, 15 /* TODO: exact */ };
|
||||||
|
|
||||||
|
/* Don’t generate events for our new window, it should *not* be managed */
|
||||||
|
uint32_t mask = 0;
|
||||||
|
uint32_t values[2];
|
||||||
|
|
||||||
|
mask |= XCB_CW_OVERRIDE_REDIRECT;
|
||||||
|
values[0] = 1;
|
||||||
|
|
||||||
|
/* We want to know when… */
|
||||||
|
mask |= XCB_CW_EVENT_MASK;
|
||||||
|
values[1] = XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed */
|
||||||
|
XCB_EVENT_MASK_EXPOSURE; /* …our window needs to be redrawn */
|
||||||
|
|
||||||
|
struct Stack_Window *stack_win = &(container->stack_win);
|
||||||
|
stack_win->window = create_window(conn, rect, XCB_WINDOW_CLASS_INPUT_OUTPUT, mask, values);
|
||||||
|
|
||||||
|
/* Generate a graphics context for the titlebar */
|
||||||
|
stack_win->gc = xcb_generate_id(conn);
|
||||||
|
xcb_create_gc(conn, stack_win->gc, stack_win->window, 0, 0);
|
||||||
|
|
||||||
|
stack_win->container = container;
|
||||||
|
|
||||||
|
SLIST_INSERT_HEAD(&stack_wins, stack_win, stack_windows);
|
||||||
|
} else {
|
||||||
|
if (container->mode == MODE_STACK) {
|
||||||
|
/* When going out of stacking mode, we need to close the window */
|
||||||
|
struct Stack_Window *stack_win = &(container->stack_win);
|
||||||
|
|
||||||
|
SLIST_REMOVE(&stack_wins, stack_win, Stack_Window, stack_windows);
|
||||||
|
|
||||||
|
xcb_free_gc(conn, stack_win->gc);
|
||||||
|
xcb_destroy_window(conn, stack_win->window);
|
||||||
|
|
||||||
|
stack_win->width = -1;
|
||||||
|
stack_win->height = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
container->mode = mode;
|
||||||
|
|
||||||
|
/* Force reconfiguration of each client */
|
||||||
|
Client *client;
|
||||||
|
|
||||||
|
CIRCLEQ_FOREACH(client, &(container->clients), clients)
|
||||||
|
client->force_reconfigure = true;
|
||||||
|
|
||||||
|
render_layout(conn);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Warps the pointer into the given client (in the middle of it, to be specific), therefore
|
* Warps the pointer into the given client (in the middle of it, to be specific), therefore
|
||||||
* selecting it
|
* selecting it
|
||||||
|
|
19
src/xcb.c
19
src/xcb.c
|
@ -82,3 +82,22 @@ xcb_window_t create_window(xcb_connection_t *conn, Rect dims, uint16_t window_cl
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changes a single value in the graphic context (so one doesn’t have to define an array of values)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void xcb_change_gc_single(xcb_connection_t *conn, xcb_gcontext_t gc, uint32_t mask, uint32_t value) {
|
||||||
|
xcb_change_gc(conn, gc, mask, &value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draws a line from x,y to to_x,to_y using the given color
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void xcb_draw_line(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc,
|
||||||
|
uint32_t colorpixel, uint32_t x, uint32_t y, uint32_t to_x, uint32_t to_y) {
|
||||||
|
xcb_change_gc_single(conn, gc, XCB_GC_FOREGROUND, colorpixel);
|
||||||
|
xcb_point_t points[] = {{x, y}, {to_x, to_y}};
|
||||||
|
xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, drawable, gc, 2, points);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue