Focus changes (up/down) implemented

This commit is contained in:
Michael Stapelberg 2009-02-08 02:39:56 +01:00
parent 2d37bbb31d
commit 4de3a5059b
3 changed files with 118 additions and 85 deletions

View File

@ -1,2 +1,2 @@
all: all:
gcc -Wall -g -I/usr/include/xcb -o mainx mainx.c -lxcb-wm gcc -Wall -gdwarf-2 -g3 -I/usr/include/xcb -o mainx mainx.c -lxcb-wm

34
data.h
View File

@ -4,14 +4,22 @@
*/ */
#include "queue.h" #include "queue.h"
/* Forward definitions */
typedef struct Cell Cell;
typedef struct Font Font;
typedef struct Container Container;
typedef struct Client Client;
typedef enum { D_LEFT, D_RIGHT, D_UP, D_DOWN } direction_t;
/* /*
* Defines a position in the table * Defines a position in the table
* *
*/ */
typedef struct Cell { struct Cell {
int row; int row;
int column; int column;
} Cell; };
/* /*
* We need to save the height of a font because it is required for each drawing of * We need to save the height of a font because it is required for each drawing of
@ -19,20 +27,23 @@ typedef struct Cell {
* Font-entry will be filled for later use. * Font-entry will be filled for later use.
* *
*/ */
typedef struct Font { struct Font {
char *name; char *name;
int height; int height;
} Font; };
/* /*
* A client is X11-speak for a window. * A client is X11-speak for a window.
* *
*/ */
typedef struct Client { struct Client {
/* TODO: this is NOT final */ /* TODO: this is NOT final */
Cell old_position; /* if you set a client to floating and set it back to managed, Cell old_position; /* if you set a client to floating and set it back to managed,
it does remember its old position and *tries* to get back there */ it does remember its old position and *tries* to get back there */
/* Backpointer. A client is inside a container */
Container *container;
/* XCB contexts */ /* XCB contexts */
xcb_gcontext_t titlegc; xcb_gcontext_t titlegc;
@ -40,14 +51,17 @@ typedef struct Client {
xcb_window_t child; xcb_window_t child;
/* The following entry provides the necessary list pointers to use Client with LIST_* macros */ /* The following entry provides the necessary list pointers to use Client with LIST_* macros */
LIST_ENTRY(Client) clients; CIRCLEQ_ENTRY(Client) clients;
} Client; };
/* /*
* 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.
* *
*/ */
typedef struct Container { struct Container {
/* Those are speaking for themselves: */
Client *currently_focused;
/* Position of the container inside our table */ /* Position of the container inside our table */
int row; int row;
int col; int col;
@ -56,5 +70,5 @@ typedef struct Container {
int height; int height;
/* Ensure MODE_DEFAULT maps to 0 because we use calloc for initialization later */ /* Ensure MODE_DEFAULT maps to 0 because we use calloc for initialization later */
enum { MODE_DEFAULT = 0, MODE_STACK = 1 } mode; enum { MODE_DEFAULT = 0, MODE_STACK = 1 } mode;
LIST_HEAD(client_head, Client) clients; CIRCLEQ_HEAD(client_head, Client) clients;
} Container; };

167
mainx.c
View File

@ -6,6 +6,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <stdbool.h> #include <stdbool.h>
#include <assert.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
@ -30,9 +31,6 @@ table_t *byChild = 0;
table_t *byParent = 0; table_t *byParent = 0;
xcb_window_t root_win; xcb_window_t root_win;
/* We have a list of Clients, called all_clients */
LIST_HEAD(all_clients_head, Client) all_clients;
/* _the_ table. Stores all clients. */ /* _the_ table. Stores all clients. */
Container *table[10][10]; Container *table[10][10];
@ -348,8 +346,8 @@ void decorate_window(xcb_connection_t *conn, Client *client) {
void render_container(xcb_connection_t *connection, Container *container) { void render_container(xcb_connection_t *connection, Container *container) {
Client *client; Client *client;
int values[4]; uint32_t values[4];
int mask = XCB_CONFIG_WINDOW_X | uint32_t mask = XCB_CONFIG_WINDOW_X |
XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_Y |
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_WIDTH |
XCB_CONFIG_WINDOW_HEIGHT; XCB_CONFIG_WINDOW_HEIGHT;
@ -357,12 +355,12 @@ void render_container(xcb_connection_t *connection, Container *container) {
if (container->mode == MODE_DEFAULT) { if (container->mode == MODE_DEFAULT) {
int num_clients = 0; int num_clients = 0;
LIST_FOREACH(client, &(container->clients), clients) CIRCLEQ_FOREACH(client, &(container->clients), clients)
num_clients++; 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; int current_client = 0;
LIST_FOREACH(client, &(container->clients), clients) { CIRCLEQ_FOREACH(client, &(container->clients), clients) {
/* TODO: at the moment, every column/row is 200px. This /* TODO: at the moment, every column/row is 200px. This
* needs to be changed to "percentage of the screen" by * needs to be changed to "percentage of the screen" by
* default and adjustable by the user if necessary. * default and adjustable by the user if necessary.
@ -430,7 +428,6 @@ void render_layout(xcb_connection_t *conn) {
table[cols][rows]->width = width / num_cols; table[cols][rows]->width = width / num_cols;
table[cols][rows]->height = height / num_rows; table[cols][rows]->height = height / num_rows;
/* Render it */ /* Render it */
render_container(conn, table[cols][rows]); render_container(conn, table[cols][rows]);
} }
@ -448,18 +445,18 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
Client *new = table_get(byChild, child); Client *new = table_get(byChild, child);
if (new == NULL) { if (new == NULL) {
printf("oh, it's new\n"); printf("oh, it's new\n");
new = malloc(sizeof(Client)); new = calloc(sizeof(Client), 1);
} }
xcb_drawable_t drawable;
uint32_t mask = 0; uint32_t mask = 0;
uint32_t values[3]; uint32_t values[3];
xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
/* Insert into the list of all clients */
LIST_INSERT_HEAD(&all_clients, new, clients);
/* Insert into the currently active container */ /* Insert into the currently active container */
LIST_INSERT_HEAD(&(table[current_col][current_row]->clients), new, clients); CIRCLEQ_INSERT_TAIL(&(table[current_col][current_row]->clients), new, clients);
printf("currently_focused = %p\n", new);
table[current_col][current_row]->currently_focused = new;
new->container = table[current_col][current_row];
new->window = xcb_generate_id(conn); new->window = xcb_generate_id(conn);
new->child = child; new->child = child;
@ -520,35 +517,52 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
/* TODO: At the moment, new windows just get focus */ /* TODO: At the moment, new windows just get focus */
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->window, XCB_CURRENT_TIME); xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->window, XCB_CURRENT_TIME);
#if 0
xcb_intern_atom_cookie_t atom_cookie = xcb_intern_atom(conn, 0, strlen("_NET_ACTIVE_WINDOW"), "_NET_ACTIVE_WINDOW");
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, atom_cookie, NULL);
int atom = -1;
if (reply) {
atom = reply->atom;
printf("setting atom %d\n", atom);
free(reply);
}
printf("atom = %d\n", atom);
xcb_change_property(conn,
XCB_PROP_MODE_REPLACE,
root,
atom,
WINDOW,
32, /* format, see http://standards.freedesktop.org/wm-spec/1.3/ar01s03.html */
1, /* source indication? FIXME */
&myc.window);
#endif
render_layout(conn); render_layout(conn);
xcb_flush(conn); xcb_flush(conn);
} }
static bool focus_window_in_container(xcb_connection_t *connection, Container *container,
direction_t direction) {
/* If this container is empty, were done */
if (container->currently_focused == NULL)
return false;
Client *candidad;
if (direction == D_UP)
candidad = CIRCLEQ_PREV(container->currently_focused, clients);
else if (direction == D_DOWN)
candidad = CIRCLEQ_NEXT(container->currently_focused, clients);
/* If we dont have anything to select, were done */
if (candidad == CIRCLEQ_END(&(container->clients)))
return false;
/* Set focus if we could successfully move */
container->currently_focused = candidad;
xcb_set_input_focus(connection, XCB_INPUT_FOCUS_NONE, candidad->child, XCB_CURRENT_TIME);
xcb_flush(connection);
return true;
}
static void focus_window(xcb_connection_t *connection, direction_t direction) {
printf("focusing direction %d\n", direction);
/* TODO: for horizontal default layout, this has to be expanded to LEFT/RIGHT */
if (direction == D_UP || direction == D_DOWN) {
/* Lets see if we can perform up/down focus in the current container */
Container *container = table[current_col][current_row];
/* There always is a container. If not, current_col or current_row is wrong */
assert(container != NULL);
if (focus_window_in_container(connection, container, direction))
return;
} else {
printf("direction unhandled\n");
}
}
int format_event(xcb_generic_event_t *e) int format_event(xcb_generic_event_t *e)
@ -597,9 +611,7 @@ static int handleEvent(void *ignored, xcb_connection_t *c, xcb_generic_event_t *
* functions to get one more modifier while not losing AltGr :-) * functions to get one more modifier while not losing AltGr :-)
* *
*/ */
static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_generic_event_t *e) { static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) {
xcb_key_press_event_t *event = (xcb_key_press_event_t*)e;
/* FIXME: We need to translate the keypress + state into a string (like, ä) /* FIXME: We need to translate the keypress + state into a string (like, ä)
because they do not generate keysyms (use xev and see for yourself) */ because they do not generate keysyms (use xev and see for yourself) */
@ -608,8 +620,17 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_generic_e
printf("gots press %d\n", event->detail); printf("gots press %d\n", event->detail);
printf("i'm in state %d\n", event->state); printf("i'm in state %d\n", event->state);
if (event->detail == 28) { /* 30 = u
/* 't' */ * 57 = n
* 27 = r
* 28 = t
* 40 = d
*
* uhm, I should probably say that Ive remapped my keys in hardware :)
*/
direction_t direction;
if (event->detail == 30) {
/* 'u' */
pid_t pid; pid_t pid;
if ((pid = vfork()) == 0) { if ((pid = vfork()) == 0) {
/* Child */ /* Child */
@ -621,14 +642,25 @@ static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_generic_e
argv[0] = "/usr/bin/xterm"; argv[0] = "/usr/bin/xterm";
argv[1] = NULL; argv[1] = NULL;
execve("/usr/bin/xterm", argv, env); execve("/usr/bin/xterm", argv, env);
/* not reached */
} }
} else if (event->detail == 38) { return 1;
//xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, myc.window, XCB_CURRENT_TIME); } else if (event->detail == 57) {
direction = D_LEFT;
} else if (event->detail == 27) {
direction = D_DOWN;
} else if (event->detail == 28) {
direction = D_UP;
} else if (event->detail == 40) {
direction = D_RIGHT;
} }
//decorate_window(c, &myc); /* TODO: ctrl -> focus_container(conn, direction) */
focus_window(conn, direction);
/* TODO: shift -> move_current_window(conn, direction) */
/* TODO: shift + ctrl -> move_current_container(conn, direction) */
return format_event(e); return 1;
} }
/* /*
@ -648,6 +680,9 @@ static int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_
return 1; return 1;
} }
/* Update container */
client->container->currently_focused = client;
/* Set focus to the entered window, and flush xcb buffer immediately */ /* Set focus to the entered window, and flush xcb buffer immediately */
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME); xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME);
xcb_flush(conn); xcb_flush(conn);
@ -655,10 +690,6 @@ static int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_
return 1; return 1;
} }
static void redrawWindow(xcb_connection_t *c, Client *client) {
decorate_window(c, client);
}
int handle_map_notify_event(void *prophs, xcb_connection_t *c, xcb_map_notify_event_t *e) int handle_map_notify_event(void *prophs, xcb_connection_t *c, xcb_map_notify_event_t *e)
{ {
window_attributes_t wa = { TAG_VALUE }; window_attributes_t wa = { TAG_VALUE };
@ -689,10 +720,10 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *c, xcb_unmap_notify_
for (rows = 0; rows < 10; rows++) for (rows = 0; rows < 10; rows++)
for (cols = 0; cols < 10; cols++) for (cols = 0; cols < 10; cols++)
if (table[cols][rows] != NULL) if (table[cols][rows] != NULL)
LIST_FOREACH(con_client, &(table[cols][rows]->clients), clients) CIRCLEQ_FOREACH(con_client, &(table[cols][rows]->clients), clients)
if (con_client == client) { if (con_client == client) {
printf("removing from container\n"); printf("removing from container\n");
LIST_REMOVE(con_client, clients); CIRCLEQ_REMOVE(&(table[cols][rows]->clients), con_client, clients);
break; break;
} }
@ -719,7 +750,7 @@ printf("exposeevent\n");
Client *client = table_get(byParent, e->window); Client *client = table_get(byParent, e->window);
if(!client || e->count != 0) if(!client || e->count != 0)
return 1; return 1;
redrawWindow(c, client); decorate_window(c, client);
return 1; return 1;
} }
void manage_existing_windows(xcb_connection_t *c, xcb_property_handlers_t *prophs, xcb_window_t root) void manage_existing_windows(xcb_connection_t *c, xcb_property_handlers_t *prophs, xcb_window_t root)
@ -753,7 +784,6 @@ void manage_existing_windows(xcb_connection_t *c, xcb_property_handlers_t *proph
} }
int main() { int main() {
LIST_INIT(&all_clients);
int i, j; int i, j;
for (i = 0; i < 10; i++) for (i = 0; i < 10; i++)
for (j = 0; j < 10; j++) for (j = 0; j < 10; j++)
@ -765,6 +795,7 @@ int main() {
* *
*/ */
table[0][0] = calloc(sizeof(Container), 1); table[0][0] = calloc(sizeof(Container), 1);
CIRCLEQ_INIT(&(table[0][0]->clients));
xcb_connection_t *c; xcb_connection_t *c;
xcb_event_handlers_t evenths; xcb_event_handlers_t evenths;
@ -802,16 +833,17 @@ myfont.height = reply->font_ascent + reply->font_descent;
for(i = 2; i < 128; ++i) for(i = 2; i < 128; ++i)
xcb_event_set_handler(&evenths, i, handleEvent, 0); xcb_event_set_handler(&evenths, i, handleEvent, 0);
/* Key presses are pretty obvious, I think */
xcb_event_set_handler(&evenths, XCB_KEY_PRESS, handle_key_press, 0);
for(i = 0; i < 256; ++i) for(i = 0; i < 256; ++i)
xcb_event_set_error_handler(&evenths, i, (xcb_generic_error_handler_t) handleEvent, 0); xcb_event_set_error_handler(&evenths, i, (xcb_generic_error_handler_t) handleEvent, 0);
/* Expose = an Application should redraw itself. That is, we have to redraw our /* Expose = an Application should redraw itself. That is, we have to redraw our
* contents (= Bars) */ * contents (= top/bottom bar, titlebars for each window) */
xcb_event_set_expose_handler(&evenths, handleExposeEvent, 0); xcb_event_set_expose_handler(&evenths, handleExposeEvent, 0);
/* Key presses are pretty obvious, I think */
xcb_event_set_key_press_handler(&evenths, handle_key_press, 0);
/* Enter window = user moved his mouse over the window */ /* Enter window = user moved his mouse over the window */
xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, 0); xcb_event_set_enter_notify_handler(&evenths, handle_enter_notify, 0);
@ -830,27 +862,14 @@ myfont.height = reply->font_ascent + reply->font_descent;
/* Grab 'a' */ /* Grab 'a' */
//xcb_grab_key(c, 0, root, 0, 38, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); //xcb_grab_key(c, 0, root, 0, 38, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
xcb_grab_key(c, 0, root, 0, 30, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
xcb_grab_key(c, 0, root, 0, 57, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
xcb_grab_key(c, 0, root, 0, 28, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); xcb_grab_key(c, 0, root, 0, 28, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
xcb_grab_key(c, 0, root, 0, 27, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
xcb_grab_key(c, 0, root, 0, 46, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); xcb_grab_key(c, 0, root, 0, 40, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
#if 0
if (xcb_grab_pointer_reply(c, xcb_grab_pointer_unchecked(c, 0, root,
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_ENTER_WINDOW |
XCB_EVENT_MASK_LEAVE_WINDOW |
XCB_EVENT_MASK_POINTER_MOTION,
XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC,
XCB_NONE, XCB_NONE,
XCB_CURRENT_TIME), NULL))
printf("could not grab pointer\n");
#endif
//xcb_grab_key(c, 0, root, XCB_BUTTON_MASK_ANY, 40, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); //xcb_grab_key(c, 0, root, XCB_BUTTON_MASK_ANY, 40, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
/* 't' */
pid_t pid; pid_t pid;
if ((pid = vfork()) == 0) { if ((pid = vfork()) == 0) {
/* Child */ /* Child */