free(label);
}
+/*
+ * Pushes the client’s x and y coordinates to X11
+ *
+ */
+static void reposition_client(xcb_connection_t *connection, Client *client) {
+ printf("frame needs to be pushed to %dx%d\n", client->rect.x, client->rect.y);
+ /* Note: We can use a pointer to client->x like an array of uint32_ts
+ because it is followed by client->y by definition */
+ xcb_configure_window(connection, client->frame,
+ XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, &(client->rect.x));
+}
+
+/*
+ * Pushes the client’s width/height to X11 and resizes the child window
+ *
+ */
+static void resize_client(xcb_connection_t *connection, Client *client) {
+ i3Font *font = load_font(connection, pattern);
+
+ printf("resizing client to %d x %d\n", client->rect.width, client->rect.height);
+ xcb_configure_window(connection, client->frame,
+ XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
+ &(client->rect.width));
+
+ /* Adjust the position of the child inside its frame.
+ * The coordinates of the child are relative to its frame, we
+ * add a border of 2 pixel to each value */
+ uint32_t mask = XCB_CONFIG_WINDOW_X |
+ XCB_CONFIG_WINDOW_Y |
+ XCB_CONFIG_WINDOW_WIDTH |
+ XCB_CONFIG_WINDOW_HEIGHT;
+ Rect rect;
+ if (client->titlebar_position == TITLEBAR_OFF) {
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = client->rect.width;
+ rect.height = client->rect.height;
+ } else {
+ rect.x = 2;
+ rect.y = font->height + 2 + 2;
+ rect.width = client->rect.width - (2 + 2);
+ rect.height = client->rect.height - ((font->height + 2 + 2) + 2);
+ }
+
+ printf("child will be at %dx%d with size %dx%d\n", rect.x, rect.y, rect.width, rect.height);
+
+ xcb_configure_window(connection, client->child, mask, &(rect.x));
+}
+
static void render_container(xcb_connection_t *connection, Container *container) {
Client *client;
- i3Font *font = load_font(connection, pattern);
if (container->mode == MODE_DEFAULT) {
int num_clients = 0;
CIRCLEQ_FOREACH(client, &(container->clients), clients)
- num_clients++;
+ if (!client->dock)
+ num_clients++;
printf("got %d clients in this default container.\n", num_clients);
int current_client = 0;
CIRCLEQ_FOREACH(client, &(container->clients), clients) {
+ /* TODO: currently, clients are assigned to the current container.
+ Therefore, we need to skip them here. Does anything harmful happen
+ if clients *do not* have a container. Is this the more desired
+ situation? Let’s find out… */
+ if (client->dock)
+ continue;
/* TODO: at the moment, every column/row is screen / num_cols. This
* needs to be changed to "percentage of the screen" by
* default and adjustable by the user if necessary.
(client->rect.x != (client->rect.x = container->x)) |
(client->rect.y != (client->rect.y = container->y +
(container->height / num_clients) * current_client))) {
- printf("frame needs to be pushed to %dx%d\n", client->rect.x, client->rect.y);
- /* Note: We can use a pointer to client->x like an array of uint32_ts
- because it is followed by client->y by definition */
- xcb_configure_window(connection, client->frame,
- XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, &(client->rect.x));
+ reposition_client(connection, client);
}
/* TODO: vertical default layout */
if (client->force_reconfigure |
(client->rect.width != (client->rect.width = container->width)) |
(client->rect.height != (client->rect.height = container->height / num_clients))) {
- printf("resizing client to %d x %d\n", client->rect.width, client->rect.height);
- xcb_configure_window(connection, client->frame,
- XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
- &(client->rect.width));
-
- /* Adjust the position of the child inside its frame.
- * The coordinates of the child are relative to its frame, we
- * add a border of 2 pixel to each value */
- uint32_t mask = XCB_CONFIG_WINDOW_X |
- XCB_CONFIG_WINDOW_Y |
- XCB_CONFIG_WINDOW_WIDTH |
- XCB_CONFIG_WINDOW_HEIGHT;
- uint32_t values[4] = {2, /* x */
- font->height + 2 + 2, /* y */
- client->rect.width - (2 + 2), /* width */
- client->rect.height - ((font->height + 2 + 2) + 2)}; /* height */
-
- printf("child will be at %dx%d with size %dx%d\n",
- values[0], values[1], values[2], values[3]);
-
- xcb_configure_window(connection, client->child, mask, values);
+ resize_client(connection, client);
}
if (client->force_reconfigure)
}
}
+static void render_bars(xcb_connection_t *connection, Workspace *r_ws, int width, int height) {
+ Client *client;
+ SLIST_FOREACH(client, &(r_ws->dock_clients), dock_clients) {
+ if (client->force_reconfigure |
+ (client->rect.x != (client->rect.x = 0)) |
+ (client->rect.y != (client->rect.y = height)))
+ reposition_client(connection, client);
+
+ if (client->force_reconfigure |
+ (client->rect.width != (client->rect.width = width)) |
+ (client->rect.height != (client->rect.height = client->desired_height)))
+ resize_client(connection, client);
+
+ client->force_reconfigure = false;
+ height += client->desired_height;
+ }
+}
+
void render_layout(xcb_connection_t *connection) {
i3Screen *screen;
if (r_ws->fullscreen_client != NULL)
/* This is easy: A client has entered fullscreen mode, so we don’t render at all */
continue;
+
int width = r_ws->rect.width;
int height = r_ws->rect.height;
int x = r_ws->rect.x;
int y = r_ws->rect.y;
+ Client *client;
+ SLIST_FOREACH(client, &(r_ws->dock_clients), dock_clients) {
+ printf("got dock client: %p\n", client);
+ printf("it wants to be this height: %d\n", client->desired_height);
+ height -= client->desired_height;
+ }
+
printf("got %d rows and %d cols\n", r_ws->rows, r_ws->cols);
printf("each of them therefore is %d px width and %d px height\n",
width / r_ws->cols, height / r_ws->rows);
x += container->width;
}
+
+ render_bars(connection, r_ws, width, height);
}
xcb_flush(connection);
xcb_event_handlers_t evenths;
xcb_window_t root_win;
-xcb_atom_t atoms[6];
+xcb_atom_t atoms[9];
char *pattern = "-misc-fixed-medium-r-normal--13-120-75-75-C-70-iso8859-1";
xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
int16_t x, int16_t y, uint16_t width, uint16_t height) {
+ xcb_get_property_cookie_t wm_type_cookie, strut_cookie;
+
+ /* Place requests for propertys ASAP */
+ wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
+ strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
+
Client *new = table_get(byChild, child);
if (new == NULL) {
/* TODO: When does this happen for existing clients? Is that a bug? */
/* Focus the new window */
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
+ /* Get _NET_WM_WINDOW_TYPE (to see if it’s a dock) */
+ xcb_atom_t *atom;
+ xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
+ if (preply != NULL && preply->value_len > 0 && (atom = xcb_get_property_value(preply))) {
+ for (int i = 0; i < xcb_get_property_value_length(preply); i++)
+ if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
+ printf("Window is a dock.\n");
+ new->dock = true;
+ new->titlebar_position = TITLEBAR_OFF;
+ new->force_reconfigure = true;
+ SLIST_INSERT_HEAD(&(new->container->workspace->dock_clients), new, dock_clients);
+ }
+ }
+
+ /* Get _NET_WM_STRUT_PARTIAL to determine the client’s requested height */
+ uint32_t *strut;
+ preply = xcb_get_property_reply(conn, strut_cookie, NULL);
+ if (preply != NULL && preply->value_len > 0 && (strut = xcb_get_property_value(preply))) {
+ /* We only use a subset of the provided values, namely the reserved space at the top/bottom
+ of the screen. This is because the only possibility for bars is at to be at the top/bottom
+ with maximum horizontal size.
+ TODO: bars at the top */
+ new->desired_height = strut[3];
+ printf("the client wants to be %d pixels height\n", new->desired_height);
+ }
+
render_layout(conn);
}
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);
+ GET_ATOM(_NET_WM_WINDOW_TYPE);
+ GET_ATOM(_NET_WM_DESKTOP);
+ GET_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
+ GET_ATOM(_NET_WM_STRUT_PARTIAL);
+ GET_ATOM(UTF8_STRING);
+
+ xcb_property_set_handler(&prophs, atoms[_NET_WM_WINDOW_TYPE], UINT_MAX, window_type_handler, NULL);
+ /* TODO: In order to comply with EWMH, we have to watch _NET_WM_STRUT_PARTIAL */
- 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");
+ check_error(c, xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTED], ATOM, 32, 7, atoms), "Could not set _NET_SUPPORTED");
xcb_change_property(c, XCB_PROP_MODE_REPLACE, root, atoms[_NET_SUPPORTING_WM_CHECK], WINDOW, 32, 1, &root);