]> git.sur5r.net Git - i3/i3/blob - src/util.c
Implement Xinerama (workspaces have a specific screen)
[i3/i3] / src / util.c
1 /*
2  * vim:ts=8:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  *
6  * (c) 2009 Michael Stapelberg and contributors
7  *
8  * See file LICENSE for license information.
9  *
10  */
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <sys/wait.h>
16
17 #include "i3.h"
18 #include "data.h"
19 #include "table.h"
20 #include "layout.h"
21
22 int min(int a, int b) {
23         return (a < b ? a : b);
24 }
25
26 int max(int a, int b) {
27         return (a > b ? a : b);
28 }
29
30 /*
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 :-).
35  *
36  * The shell is determined by looking for the SHELL environment variable. If it
37  * does not exist, /bin/sh is used.
38  *
39  */
40 void start_application(const char *command) {
41         if (fork() == 0) {
42                 /* Child process */
43                 if (fork() == 0) {
44                         /* Stores the path of the shell */
45                         static const char *shell = NULL;
46
47                         if (shell == NULL)
48                                 if ((shell = getenv("SHELL")) == NULL)
49                                         shell = "/bin/sh";
50
51                         /* This is the child */
52                         execl(shell, shell, "-c", command, NULL);
53                         /* not reached */
54                 }
55                 exit(0);
56         }
57         wait(0);
58 }
59
60 /*
61  * Checks a generic cookie for errors and quits with the given message if there
62  * was an error.
63  *
64  */
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);
67         if (error != NULL) {
68                 fprintf(stderr, "ERROR: %s : %d\n", err_message , error->error_code);
69                 xcb_disconnect(connection);
70                 exit(-1);
71         }
72 }
73
74 /*
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)
78  *
79  */
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;
86
87         /* Update container */
88         Client *old_client = client->container->currently_focused;
89         client->container->currently_focused = client;
90
91         current_col = client->container->col;
92         current_row = client->container->row;
93
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);
101         xcb_flush(conn);
102 }
103
104 /*
105  * Warps the pointer into the given client (in the middle of it, to be specific), therefore
106  * selecting it
107  *
108  */
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);
113 }
114
115 /*
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.
119  *
120  */
121 void toggle_fullscreen(xcb_connection_t *conn, Client *client) {
122         Workspace *workspace = client->container->workspace;
123
124         workspace->fullscreen_client = (client->fullscreen ? NULL : client);
125
126         client->fullscreen = !client->fullscreen;
127
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,
136                                       workspace->rect.y,
137                                       workspace->rect.width,
138                                       workspace->rect.height};
139
140                 printf("child itself will be at %dx%d with size %dx%d\n",
141                                 values[0], values[1], values[2], values[3]);
142
143                 /* Raise the window */
144                 xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, client->frame);
145
146                 xcb_configure_window(conn, client->frame, mask, values);
147                 xcb_configure_window(conn, client->child, mask, values);
148
149                 xcb_flush(conn);
150         } else {
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 */
156                 render_layout(conn);
157         }
158 }