#include <unistd.h>
#include <stdbool.h>
#include <assert.h>
+#include <limits.h>
#include <xcb/xcb.h>
#include "debug.h"
#include "handlers.h"
#include "util.h"
+#include "xcb.h"
+#include "xinerama.h"
#define TERMINAL "/usr/pkg/bin/urxvt"
Display *xkbdpy;
-TAILQ_HEAD(bindings_head, Binding) bindings;
+TAILQ_HEAD(bindings_head, Binding) bindings = TAILQ_HEAD_INITIALIZER(bindings);
xcb_event_handlers_t evenths;
-/* hm, xcb_wm wants us to implement this. */
-table_t *byChild = 0;
-table_t *byParent = 0;
xcb_window_t root_win;
+xcb_atom_t atoms[6];
+
char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso8859-1";
int num_screens = 0;
new = calloc(sizeof(Client), 1);
/* We initialize x and y with the invalid coordinates -1 so that they will
get updated at the next render_layout() at any case */
- new->x = -1;
- new->y = -1;
+ new->rect.x = -1;
+ new->rect.y = -1;
}
uint32_t mask = 0;
uint32_t values[3];
new->frame = xcb_generate_id(conn);
new->child = child;
- new->width = width;
- new->height = height;
+ new->rect.width = width;
+ new->rect.height = height;
/* Don’t generate events for our new window, it should *not* be managed */
mask |= XCB_CW_OVERRIDE_REDIRECT;
i3Font *font = load_font(conn, pattern);
+ height = min(height, c_ws->rect.y + c_ws->rect.height);
+ width = min(width, c_ws->rect.x + c_ws->rect.width);
+
/* Yo dawg, I heard you like windows, so I create a window around your window… */
- xcb_create_window(conn,
+ xcb_void_cookie_t cookie = xcb_create_window_checked(conn,
depth,
new->frame,
root,
height + 2 + 2 + font->height, /* 2 px border plus font’s height */
0, /* border_width = 0, we draw our own borders */
XCB_WINDOW_CLASS_INPUT_OUTPUT,
- visual,
+ XCB_WINDOW_CLASS_COPY_FROM_PARENT,
mask,
values);
+ printf("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
+ check_error(conn, cookie, "Could not create frame");
xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
/* Map the window on the screen (= make it visible) */
table_put(byChild, child, new);
/* Moves the original window into the new frame we've created for it */
- xcb_reparent_window(conn, child, new->frame, 0, font->height);
+ new->awaiting_useless_unmap = true;
+ cookie = xcb_reparent_window_checked(conn, child, new->frame, 0, font->height);
+ check_error(conn, cookie, "Could not reparent window");
/* We are interested in property changes */
mask = XCB_CW_EVENT_MASK;
values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
- XCB_EVENT_MASK_ENTER_WINDOW |
- XCB_EVENT_MASK_BUTTON_PRESS;
- xcb_change_window_attributes(conn, child, mask, values);
+ XCB_EVENT_MASK_ENTER_WINDOW;
+ cookie = xcb_change_window_attributes_checked(conn, child, mask, values);
+ check_error(conn, cookie, "Could not change window attributes");
/* We need to grab the mouse buttons for click to focus */
xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
/* Focus the new window */
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_NONE, new->child, XCB_CURRENT_TIME);
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
render_layout(conn);
}
free(rep);
}
-static void initialize_xinerama(xcb_connection_t *conn) {
- xcb_xinerama_query_screens_reply_t *reply;
- xcb_xinerama_screen_info_t *screen_info;
- int screen;
-
- if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) {
- printf("Xinerama extension not found, disabling.\n");
- return;
- }
-
- if (!xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL)->state) {
- printf("Xinerama is not active (in your X-Server), disabling.\n");
- return;
- }
-
-
- reply = xcb_xinerama_query_screens_reply(conn, xcb_xinerama_query_screens_unchecked(conn), NULL);
- /* TODO: error check */
- screen_info = xcb_xinerama_query_screens_screen_info(reply);
-
- num_screens = xcb_xinerama_query_screens_screen_info_length(reply);
-
- /* Just go through each workspace and associate as many screens as we can. */
- for (screen = 0; screen < num_screens; screen++) {
- workspaces[screen].x = screen_info[screen].x_org;
- workspaces[screen].y = screen_info[screen].y_org;
- workspaces[screen].width = screen_info[screen].width;
- workspaces[screen].height = screen_info[screen].height;
- workspaces[screen].screen_num = screen;
-
- printf("found Xinerama screen: %d x %d at %d x %d\n",
- screen_info[screen].width, screen_info[screen].height,
- screen_info[screen].x_org, screen_info[screen].y_org);
- }
-
- free(screen_info);
-}
-
int main(int argc, char *argv[], char *env[]) {
int i, screens;
xcb_connection_t *c;
byChild = alloc_table();
byParent = alloc_table();
- TAILQ_INIT(&bindings);
-
c = xcb_connect(NULL, &screens);
/* TODO: this has to be more beautiful somewhen */
xcb_property_handlers_init(&prophs, &evenths);
xcb_event_set_map_notify_handler(&evenths, handle_map_notify_event, &prophs);
+ xcb_event_set_client_message_handler(&evenths, handle_client_message, 0);
+
xcb_watch_wm_name(&prophs, 128, handle_windowname_change, 0);
root = xcb_aux_get_screen(c, screens)->root;
root_win = root;
uint32_t mask = XCB_CW_EVENT_MASK;
- uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE };
+ uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_ENTER_WINDOW};
xcb_change_window_attributes(c, root, mask, values);
+ /* Setup NetWM atoms */
+ /* TODO: needs cleanup, needs more xcb (asynchronous), needs more error checking */
+#define GET_ATOM(name) { \
+ xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, xcb_intern_atom(c, 0, strlen(#name), #name), NULL); \
+ if (!reply) { \
+ printf("Could not get atom " #name "\n"); \
+ exit(-1); \
+ } \
+ atoms[name] = reply->atom; \
+ free(reply); \
+}
+
+ GET_ATOM(_NET_SUPPORTED);
+ GET_ATOM(_NET_WM_STATE_FULLSCREEN);
+ GET_ATOM(_NET_SUPPORTING_WM_CHECK);
+ GET_ATOM(_NET_WM_NAME);
+ GET_ATOM(UTF8_STRING);
+ GET_ATOM(_NET_WM_STATE);
+
+ check_error(c, xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED], ATOM, 32, 5, atoms), "Could not set _NET_SUPPORTED");
+
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTING_WM_CHECK], WINDOW, 32, 1, &root);
+
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_WM_NAME] , atoms[UTF8_STRING], 8, strlen("i3"), "i3");
+
#define BIND(key, modifier, cmd) { \
Binding *new = malloc(sizeof(Binding)); \
new->keycode = key; \
BIND(30, 0, "exec /usr/pkg/bin/urxvt");
+ BIND(41, BIND_MOD_1, "f");
+
BIND(44, BIND_MOD_1, "h");
BIND(45, BIND_MOD_1, "j");
BIND(46, BIND_MOD_1, "k");
manage_existing_windows(c, &prophs, root);
+ /* Get pointer position to see on which screen we’re starting */
+ xcb_query_pointer_cookie_t pointer_cookie = xcb_query_pointer(c, root);
+ xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(c, pointer_cookie, NULL);
+ if (reply == NULL) {
+ printf("Could not get pointer position\n");
+ return 1;
+ }
+
+ i3Screen *screen = get_screen_containing(reply->root_x, reply->root_y);
+ if (screen == NULL) {
+ printf("ERROR: No such screen\n");
+ return 0;
+ }
+ if (screen->current_workspace != 0) {
+ printf("Ok, I need to go to the other workspace\n");
+ c_ws = &workspaces[screen->current_workspace];
+ }
+
xcb_event_wait_for_event_loop(&evenths);
/* not reached */