#include "all.h"
#include <time.h>
+#include <float.h>
#include <sys/time.h>
#include <xcb/randr.h>
#include <X11/XKBlib.h>
}
/* see if the user entered the window on a certain window decoration */
- int layout = (enter_child ? con->parent->layout : con->layout);
+ layout_t layout = (enter_child ? con->parent->layout : con->layout);
if (layout == L_DEFAULT) {
Con *child;
TAILQ_FOREACH(child, &(con->nodes_head), nodes)
if (fullscreen != con && con_is_floating(con) && con_is_leaf(con)) {
/* find the height for the decorations */
- int deco_height = config.font.height + 5;
+ int deco_height = con->deco_rect.height;
/* we actually need to apply the size/position changes to the *parent*
* container */
Rect bsr = con_border_style_rect(con);
}
Con *floatingcon = con->parent;
+ if (strcmp(con_get_workspace(floatingcon)->name, "__i3_scratch") == 0) {
+ DLOG("This is a scratchpad container, ignoring ConfigureRequest\n");
+ return;
+ }
+
Rect newrect = floatingcon->rect;
if (event->value_mask & XCB_CONFIG_WINDOW_X) {
static void handle_screen_change(xcb_generic_event_t *e) {
DLOG("RandR screen change\n");
+ /* The geometry of the root window is used for “fullscreen global” and
+ * changes when new outputs are added. */
+ xcb_get_geometry_cookie_t cookie = xcb_get_geometry(conn, root);
+ xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(conn, cookie, NULL);
+ if (reply == NULL) {
+ ELOG("Could not get geometry of the root window, exiting\n");
+ exit(1);
+ }
+ DLOG("root geometry reply: (%d, %d) %d x %d\n", reply->x, reply->y, reply->width, reply->height);
+
+ croot->rect.width = reply->width;
+ croot->rect.height = reply->height;
+
randr_query_outputs();
scratchpad_fix_resolution();
LOG("ClientMessage for window 0x%08x\n", event->window);
if (event->type == A__NET_WM_STATE) {
- if (event->format != 32 || event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN) {
- DLOG("atom in clientmessage is %d, fullscreen is %d\n",
- event->data.data32[1], A__NET_WM_STATE_FULLSCREEN);
- DLOG("not about fullscreen atom\n");
+ if (event->format != 32 ||
+ (event->data.data32[1] != A__NET_WM_STATE_FULLSCREEN &&
+ event->data.data32[1] != A__NET_WM_STATE_DEMANDS_ATTENTION)) {
+ DLOG("Unknown atom in clientmessage of type %d\n", event->data.data32[1]);
return;
}
return;
}
- /* Check if the fullscreen state should be toggled */
- if ((con->fullscreen_mode != CF_NONE &&
- (event->data.data32[0] == _NET_WM_STATE_REMOVE ||
- event->data.data32[0] == _NET_WM_STATE_TOGGLE)) ||
- (con->fullscreen_mode == CF_NONE &&
- (event->data.data32[0] == _NET_WM_STATE_ADD ||
- event->data.data32[0] == _NET_WM_STATE_TOGGLE))) {
- DLOG("toggling fullscreen\n");
- con_toggle_fullscreen(con, CF_OUTPUT);
+ if (event->data.data32[1] == A__NET_WM_STATE_FULLSCREEN) {
+ /* Check if the fullscreen state should be toggled */
+ if ((con->fullscreen_mode != CF_NONE &&
+ (event->data.data32[0] == _NET_WM_STATE_REMOVE ||
+ event->data.data32[0] == _NET_WM_STATE_TOGGLE)) ||
+ (con->fullscreen_mode == CF_NONE &&
+ (event->data.data32[0] == _NET_WM_STATE_ADD ||
+ event->data.data32[0] == _NET_WM_STATE_TOGGLE))) {
+ DLOG("toggling fullscreen\n");
+ con_toggle_fullscreen(con, CF_OUTPUT);
+ }
+ } else if (event->data.data32[1] == A__NET_WM_STATE_DEMANDS_ATTENTION) {
+ /* Check if the urgent flag must be set or not */
+ if (event->data.data32[0] == _NET_WM_STATE_ADD)
+ con_set_urgency(con, true);
+ else if (event->data.data32[0] == _NET_WM_STATE_REMOVE)
+ con_set_urgency(con, false);
+ else if (event->data.data32[0] == _NET_WM_STATE_TOGGLE)
+ con_set_urgency(con, !con->urgent);
}
tree_render();
return;
}
+ if (con_is_internal(ws)) {
+ DLOG("Workspace is internal, ignoring _NET_ACTIVE_WINDOW\n");
+ return;
+ }
+
if (ws != con_get_workspace(focused))
workspace_show(ws);
xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char*)ev);
xcb_flush(conn);
free(reply);
+ } else if (event->type == A__NET_REQUEST_FRAME_EXTENTS) {
+ /*
+ * A client can request an estimate for the frame size which the window
+ * manager will put around it before actually mapping its window. Java
+ * does this (as of openjdk-7).
+ *
+ * Note that the calculation below is not entirely accurate — once you
+ * set a different border type, it’s off. We _could_ request all the
+ * window properties (which have to be set up at this point according
+ * to EWMH), but that seems rather elaborate. The standard explicitly
+ * says the application must cope with an estimate that is not entirely
+ * accurate.
+ */
+ DLOG("_NET_REQUEST_FRAME_EXTENTS for window 0x%08x\n", event->window);
+
+ /* The reply data: approximate frame size */
+ Rect r = {
+ config.default_border_width, /* left */
+ config.default_border_width, /* right */
+ config.font.height + 5, /* top */
+ config.default_border_width /* bottom */
+ };
+ xcb_change_property(
+ conn,
+ XCB_PROP_MODE_REPLACE,
+ event->window,
+ A__NET_FRAME_EXTENTS,
+ XCB_ATOM_CARDINAL, 32, 4,
+ &r);
+ xcb_flush(conn);
} else {
DLOG("unhandled clientmessage\n");
return;
goto render_and_return;
/* Check if we need to set proportional_* variables using the correct ratio */
+ double aspect_ratio = 0.0;
if ((width / height) < min_aspect) {
- if (con->proportional_width != width ||
- con->proportional_height != (width / min_aspect)) {
- con->proportional_width = width;
- con->proportional_height = width / min_aspect;
- changed = true;
- }
+ aspect_ratio = min_aspect;
} else if ((width / height) > max_aspect) {
- if (con->proportional_width != width ||
- con->proportional_height != (width / max_aspect)) {
- con->proportional_width = width;
- con->proportional_height = width / max_aspect;
- changed = true;
- }
+ aspect_ratio = max_aspect;
} else goto render_and_return;
+ if (fabs(con->aspect_ratio - aspect_ratio) > DBL_EPSILON) {
+ con->aspect_ratio = aspect_ratio;
+ changed = true;
+ }
+
render_and_return:
if (changed)
tree_render();
return false;
}
- xcb_icccm_wm_hints_t hints;
-
+ bool urgency_hint;
if (reply == NULL)
- if (!(reply = xcb_get_property_reply(conn, xcb_icccm_get_wm_hints(conn, window), NULL)))
- return false;
-
- if (!xcb_icccm_get_wm_hints_from_reply(&hints, reply))
- return false;
-
- if (!con->urgent && focused == con) {
- DLOG("Ignoring urgency flag for current client\n");
- con->window->urgent.tv_sec = 0;
- con->window->urgent.tv_usec = 0;
- goto end;
- }
-
- /* Update the flag on the client directly */
- bool hint_urgent = (xcb_icccm_wm_hints_get_urgency(&hints) != 0);
-
- if (con->urgency_timer == NULL) {
- con->urgent = hint_urgent;
- } else
- DLOG("Discarding urgency WM_HINT because timer is running\n");
-
- //CLIENT_LOG(con);
- if (con->window) {
- if (con->urgent) {
- gettimeofday(&con->window->urgent, NULL);
- } else {
- con->window->urgent.tv_sec = 0;
- con->window->urgent.tv_usec = 0;
- }
- }
-
- con_update_parents_urgency(con);
-
- LOG("Urgency flag changed to %d\n", con->urgent);
-
- Con *ws;
- /* Set the urgency flag on the workspace, if a workspace could be found
- * (for dock clients, that is not the case). */
- if ((ws = con_get_workspace(con)) != NULL)
- workspace_update_urgent_flag(ws);
-
+ reply = xcb_get_property_reply(conn, xcb_icccm_get_wm_hints(conn, window), NULL);
+ window_update_hints(con->window, reply, &urgency_hint);
+ con_set_urgency(con, urgency_hint);
tree_render();
-end:
- if (con->window)
- window_update_hints(con->window, reply);
- else free(reply);
return true;
}
struct property_handler_t *handler = NULL;
xcb_get_property_reply_t *propr = NULL;
- for (int c = 0; c < sizeof(property_handlers) / sizeof(struct property_handler_t); c++) {
+ for (size_t c = 0; c < sizeof(property_handlers) / sizeof(struct property_handler_t); c++) {
if (property_handlers[c].atom != atom)
continue;
/* Client message are sent to the root window. The only interesting
* client message for us is _NET_WM_STATE, we honour
- * _NET_WM_STATE_FULLSCREEN */
+ * _NET_WM_STATE_FULLSCREEN and _NET_WM_STATE_DEMANDS_ATTENTION */
case XCB_CLIENT_MESSAGE:
handle_client_message((xcb_client_message_event_t*)event);
break;