4 * i3 - an improved dynamic tiling window manager
6 * (c) 2009 Michael Stapelberg and contributors
8 * See file LICENSE for license information.
22 int min(int a, int b) {
23 return (a < b ? a : b);
26 int max(int a, int b) {
27 return (a > b ? a : b);
31 * Starts the given application by passing it through a shell. We use double fork
32 * to avoid zombie processes. As the started application’s parent exits (immediately),
33 * the application is reparented to init (process-id 1), which correctly handles
34 * childs, so we don’t have to do it :-).
36 * The shell is determined by looking for the SHELL environment variable. If it
37 * does not exist, /bin/sh is used.
40 void start_application(const char *command) {
44 /* Stores the path of the shell */
45 static const char *shell = NULL;
48 if ((shell = getenv("SHELL")) == NULL)
51 /* This is the child */
52 execl(shell, shell, "-c", command, NULL);
61 * Checks a generic cookie for errors and quits with the given message if there
65 void check_error(xcb_connection_t *connection, xcb_void_cookie_t cookie, char *err_message) {
66 xcb_generic_error_t *error = xcb_request_check(connection, cookie);
68 fprintf(stderr, "ERROR: %s : %d\n", err_message , error->error_code);
69 xcb_disconnect(connection);
75 * Sets the given client as focused by updating the data structures correctly,
76 * updating the X input focus and finally re-decorating both windows (to signalize
77 * the user the new focus situation)
80 void set_focus(xcb_connection_t *conn, Client *client) {
81 /* TODO: check if the focus needs to be changed at all */
82 /* Store current_row/current_col */
83 c_ws->current_row = current_row;
84 c_ws->current_col = current_col;
85 c_ws = client->container->workspace;
87 /* Update container */
88 Client *old_client = client->container->currently_focused;
89 client->container->currently_focused = client;
91 current_col = client->container->col;
92 current_row = client->container->row;
94 /* Set focus to the entered window, and flush xcb buffer immediately */
95 xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, client->child, XCB_CURRENT_TIME);
96 //xcb_warp_pointer(conn, XCB_NONE, client->child, 0, 0, 0, 0, 10, 10);
97 /* Update last/current client’s titlebar */
98 if (old_client != NULL)
99 decorate_window(conn, old_client);
100 decorate_window(conn, client);
105 * Warps the pointer into the given client (in the middle of it, to be specific), therefore
109 void warp_pointer_into(xcb_connection_t *connection, Client *client) {
110 int mid_x = client->rect.width / 2,
111 mid_y = client->rect.height / 2;
112 xcb_warp_pointer(connection, XCB_NONE, client->child, 0, 0, 0, 0, mid_x, mid_y);
116 * Toggles fullscreen mode for the given client. It updates the data structures and
117 * reconfigures (= resizes/moves) the client and its frame to the full size of the
118 * screen. When leaving fullscreen, re-rendering the layout is forced.
121 void toggle_fullscreen(xcb_connection_t *conn, Client *client) {
122 Workspace *workspace = client->container->workspace;
124 workspace->fullscreen_client = (client->fullscreen ? NULL : client);
126 client->fullscreen = !client->fullscreen;
128 if (client->fullscreen) {
129 printf("Entering fullscreen mode...\n");
130 /* We just entered fullscreen mode, let’s configure the window */
131 uint32_t mask = XCB_CONFIG_WINDOW_X |
132 XCB_CONFIG_WINDOW_Y |
133 XCB_CONFIG_WINDOW_WIDTH |
134 XCB_CONFIG_WINDOW_HEIGHT;
135 uint32_t values[4] = {workspace->rect.x,
137 workspace->rect.width,
138 workspace->rect.height};
140 printf("child itself will be at %dx%d with size %dx%d\n",
141 values[0], values[1], values[2], values[3]);
143 /* Raise the window */
144 xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, client->frame);
146 xcb_configure_window(conn, client->frame, mask, values);
147 xcb_configure_window(conn, client->child, mask, values);
151 printf("left fullscreen\n");
152 /* Because the coordinates of the window haven’t changed, it would not be
153 re-configured if we don’t set the following flag */
154 client->force_reconfigure = true;
155 /* We left fullscreen mode, redraw the layout */