]> git.sur5r.net Git - i3/i3/blobdiff - src/mainx.c
Use c99
[i3/i3] / src / mainx.c
index a73ea6f93009a9c9749e17487f444d0bbd2d2e0e..d3ea967c8db04f41a1be66394a27bcbff5624a58 100644 (file)
@@ -17,6 +17,7 @@
 #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;
@@ -128,8 +130,8 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                 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];
@@ -143,8 +145,8 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
         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;
@@ -161,8 +163,11 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
         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,
@@ -172,9 +177,11 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                         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) */
@@ -189,15 +196,17 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         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,
@@ -206,7 +215,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                         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);
 }
@@ -240,44 +249,6 @@ void manage_existing_windows(xcb_connection_t *c, xcb_property_handlers_t *proph
         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;
@@ -293,8 +264,6 @@ int main(int argc, char *argv[], char *env[]) {
         byChild = alloc_table();
         byParent = alloc_table();
 
-        TAILQ_INIT(&bindings);
-
         c = xcb_connect(NULL, &screens);
 
         /* TODO: this has to be more beautiful somewhen */
@@ -343,15 +312,42 @@ int main(int argc, char *argv[], char *env[]) {
         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; \
@@ -365,6 +361,8 @@ int main(int argc, char *argv[], char *env[]) {
 
         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");
@@ -409,6 +407,24 @@ int main(int argc, char *argv[], char *env[]) {
 
         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 */