Focus changes (up/down) implemented
This commit is contained in:
parent
2d37bbb31d
commit
4de3a5059b
2
Makefile
2
Makefile
@ -1,2 +1,2 @@
|
||||
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
34
data.h
@ -4,14 +4,22 @@
|
||||
*/
|
||||
#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
|
||||
*
|
||||
*/
|
||||
typedef struct Cell {
|
||||
struct Cell {
|
||||
int row;
|
||||
int column;
|
||||
} Cell;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
typedef struct Font {
|
||||
struct Font {
|
||||
char *name;
|
||||
int height;
|
||||
} Font;
|
||||
};
|
||||
|
||||
/*
|
||||
* A client is X11-speak for a window.
|
||||
*
|
||||
*/
|
||||
typedef struct Client {
|
||||
struct Client {
|
||||
/* TODO: this is NOT final */
|
||||
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 */
|
||||
|
||||
/* Backpointer. A client is inside a container */
|
||||
Container *container;
|
||||
|
||||
|
||||
/* XCB contexts */
|
||||
xcb_gcontext_t titlegc;
|
||||
@ -40,14 +51,17 @@ typedef struct Client {
|
||||
xcb_window_t child;
|
||||
|
||||
/* The following entry provides the necessary list pointers to use Client with LIST_* macros */
|
||||
LIST_ENTRY(Client) clients;
|
||||
} Client;
|
||||
CIRCLEQ_ENTRY(Client) clients;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
int row;
|
||||
int col;
|
||||
@ -56,5 +70,5 @@ typedef struct Container {
|
||||
int height;
|
||||
/* Ensure MODE_DEFAULT maps to 0 because we use calloc for initialization later */
|
||||
enum { MODE_DEFAULT = 0, MODE_STACK = 1 } mode;
|
||||
LIST_HEAD(client_head, Client) clients;
|
||||
} Container;
|
||||
CIRCLEQ_HEAD(client_head, Client) clients;
|
||||
};
|
||||
|
167
mainx.c
167
mainx.c
@ -6,6 +6,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
@ -30,9 +31,6 @@ table_t *byChild = 0;
|
||||
table_t *byParent = 0;
|
||||
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. */
|
||||
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) {
|
||||
Client *client;
|
||||
int values[4];
|
||||
int mask = XCB_CONFIG_WINDOW_X |
|
||||
uint32_t values[4];
|
||||
uint32_t mask = XCB_CONFIG_WINDOW_X |
|
||||
XCB_CONFIG_WINDOW_Y |
|
||||
XCB_CONFIG_WINDOW_WIDTH |
|
||||
XCB_CONFIG_WINDOW_HEIGHT;
|
||||
@ -357,12 +355,12 @@ void render_container(xcb_connection_t *connection, Container *container) {
|
||||
|
||||
if (container->mode == MODE_DEFAULT) {
|
||||
int num_clients = 0;
|
||||
LIST_FOREACH(client, &(container->clients), clients)
|
||||
CIRCLEQ_FOREACH(client, &(container->clients), clients)
|
||||
num_clients++;
|
||||
printf("got %d clients in this default container.\n", num_clients);
|
||||
|
||||
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
|
||||
* needs to be changed to "percentage of the screen" by
|
||||
* 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]->height = height / num_rows;
|
||||
|
||||
|
||||
/* Render it */
|
||||
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);
|
||||
if (new == NULL) {
|
||||
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 values[3];
|
||||
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 */
|
||||
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->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 */
|
||||
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);
|
||||
|
||||
xcb_flush(conn);
|
||||
}
|
||||
|
||||
static bool focus_window_in_container(xcb_connection_t *connection, Container *container,
|
||||
direction_t direction) {
|
||||
/* If this container is empty, we’re 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 don’t have anything to select, we’re 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) {
|
||||
/* Let’s 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)
|
||||
@ -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 :-)
|
||||
*
|
||||
*/
|
||||
static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_generic_event_t *e) {
|
||||
xcb_key_press_event_t *event = (xcb_key_press_event_t*)e;
|
||||
|
||||
static int handle_key_press(void *ignored, xcb_connection_t *conn, xcb_key_press_event_t *event) {
|
||||
|
||||
/* FIXME: We need to translate the keypress + state into a string (like, ä)
|
||||
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("i'm in state %d\n", event->state);
|
||||
|
||||
if (event->detail == 28) {
|
||||
/* 't' */
|
||||
/* 30 = u
|
||||
* 57 = n
|
||||
* 27 = r
|
||||
* 28 = t
|
||||
* 40 = d
|
||||
*
|
||||
* …uhm, I should probably say that I’ve remapped my keys in hardware :)
|
||||
*/
|
||||
direction_t direction;
|
||||
if (event->detail == 30) {
|
||||
/* 'u' */
|
||||
pid_t pid;
|
||||
if ((pid = vfork()) == 0) {
|
||||
/* 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[1] = NULL;
|
||||
execve("/usr/bin/xterm", argv, env);
|
||||
/* not reached */
|
||||
}
|
||||
} else if (event->detail == 38) {
|
||||
//xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, myc.window, XCB_CURRENT_TIME);
|
||||
return 1;
|
||||
} 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;
|
||||
}
|
||||
|
||||
/* Update container */
|
||||
client->container->currently_focused = client;
|
||||
|
||||
/* 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_flush(conn);
|
||||
@ -655,10 +690,6 @@ static int handle_enter_notify(void *ignored, xcb_connection_t *conn, xcb_enter_
|
||||
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)
|
||||
{
|
||||
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 (cols = 0; cols < 10; cols++)
|
||||
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) {
|
||||
printf("removing from container\n");
|
||||
LIST_REMOVE(con_client, clients);
|
||||
CIRCLEQ_REMOVE(&(table[cols][rows]->clients), con_client, clients);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -719,7 +750,7 @@ printf("exposeevent\n");
|
||||
Client *client = table_get(byParent, e->window);
|
||||
if(!client || e->count != 0)
|
||||
return 1;
|
||||
redrawWindow(c, client);
|
||||
decorate_window(c, client);
|
||||
return 1;
|
||||
}
|
||||
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() {
|
||||
LIST_INIT(&all_clients);
|
||||
int i, j;
|
||||
for (i = 0; i < 10; i++)
|
||||
for (j = 0; j < 10; j++)
|
||||
@ -765,6 +795,7 @@ int main() {
|
||||
*
|
||||
*/
|
||||
table[0][0] = calloc(sizeof(Container), 1);
|
||||
CIRCLEQ_INIT(&(table[0][0]->clients));
|
||||
|
||||
xcb_connection_t *c;
|
||||
xcb_event_handlers_t evenths;
|
||||
@ -802,16 +833,17 @@ myfont.height = reply->font_ascent + reply->font_descent;
|
||||
for(i = 2; i < 128; ++i)
|
||||
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)
|
||||
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
|
||||
* contents (= Bars) */
|
||||
* contents (= top/bottom bar, titlebars for each window) */
|
||||
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 */
|
||||
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' */
|
||||
//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, 46, 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, 0, 27, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
|
||||
xcb_grab_key(c, 0, root, 0, 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;
|
||||
if ((pid = vfork()) == 0) {
|
||||
/* Child */
|
||||
|
Loading…
Reference in New Issue
Block a user