Bugfix: Change the event mask to ignore enter notifies when rendering the layout and changing workspaces
This commit is contained in:
parent
408b2bdb39
commit
38c8541807
|
@ -17,6 +17,7 @@ Rect get_unoccupied_space(Workspace *workspace);
|
||||||
void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t drawable, xcb_gcontext_t gc, int offset);
|
void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t drawable, xcb_gcontext_t gc, int offset);
|
||||||
void redecorate_window(xcb_connection_t *conn, Client *client);
|
void redecorate_window(xcb_connection_t *conn, Client *client);
|
||||||
void render_container(xcb_connection_t *conn, Container *container);
|
void render_container(xcb_connection_t *conn, Container *container);
|
||||||
|
void ignore_enter_notify_forall(xcb_connection_t *conn, Workspace *workspace, bool ignore_enter_notify);
|
||||||
void render_layout(xcb_connection_t *conn);
|
void render_layout(xcb_connection_t *conn);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
CIRCLEQ_NEXT(elm, field) : NULL)
|
CIRCLEQ_NEXT(elm, field) : NULL)
|
||||||
#define CIRCLEQ_PREV_OR_NULL(head, elm, field) (CIRCLEQ_PREV(elm, field) != CIRCLEQ_END(head) ? \
|
#define CIRCLEQ_PREV_OR_NULL(head, elm, field) (CIRCLEQ_PREV(elm, field) != CIRCLEQ_END(head) ? \
|
||||||
CIRCLEQ_PREV(elm, field) : NULL)
|
CIRCLEQ_PREV(elm, field) : NULL)
|
||||||
|
#define FOR_TABLE(workspace) \
|
||||||
|
for (int cols = 0; cols < workspace->cols; cols++) \
|
||||||
|
for (int rows = 0; rows < workspace->rows; rows++)
|
||||||
|
|
||||||
/* ##__VA_ARGS__ means: leave out __VA_ARGS__ completely if it is empty, that is,
|
/* ##__VA_ARGS__ means: leave out __VA_ARGS__ completely if it is empty, that is,
|
||||||
delete the preceding comma */
|
delete the preceding comma */
|
||||||
#define LOG(fmt, ...) slog("%s:%s:%d - " fmt, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
#define LOG(fmt, ...) slog("%s:%s:%d - " fmt, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)
|
||||||
|
|
|
@ -22,6 +22,21 @@
|
||||||
#define XCB_CURSOR_SB_H_DOUBLE_ARROW 108
|
#define XCB_CURSOR_SB_H_DOUBLE_ARROW 108
|
||||||
#define XCB_CURSOR_SB_V_DOUBLE_ARROW 116
|
#define XCB_CURSOR_SB_V_DOUBLE_ARROW 116
|
||||||
|
|
||||||
|
/* The event masks are defined here because we don’t only set them once but we need to set slight
|
||||||
|
variations of them (without XCB_EVENT_MASK_ENTER_WINDOW while rendering the layout) */
|
||||||
|
/* The XCB_CW_EVENT_MASK for the child (= real window) */
|
||||||
|
#define CHILD_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE | \
|
||||||
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY | \
|
||||||
|
XCB_EVENT_MASK_ENTER_WINDOW)
|
||||||
|
|
||||||
|
/* The XCB_CW_EVENT_MASK for its frame */
|
||||||
|
#define FRAME_EVENT_MASK (XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed/released */ \
|
||||||
|
XCB_EVENT_MASK_BUTTON_RELEASE | \
|
||||||
|
XCB_EVENT_MASK_EXPOSURE | /* …our window needs to be redrawn */ \
|
||||||
|
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | /* …user moves cursor inside our window */ \
|
||||||
|
XCB_EVENT_MASK_ENTER_WINDOW) /* …the application tries to resize itself */
|
||||||
|
|
||||||
|
|
||||||
enum { _NET_SUPPORTED = 0,
|
enum { _NET_SUPPORTED = 0,
|
||||||
_NET_SUPPORTING_WM_CHECK,
|
_NET_SUPPORTING_WM_CHECK,
|
||||||
_NET_WM_NAME,
|
_NET_WM_NAME,
|
||||||
|
|
|
@ -417,14 +417,15 @@ static void show_workspace(xcb_connection_t *conn, int workspace) {
|
||||||
/* TODO: does grabbing the server actually bring us any (speed)advantages? */
|
/* TODO: does grabbing the server actually bring us any (speed)advantages? */
|
||||||
//xcb_grab_server(conn);
|
//xcb_grab_server(conn);
|
||||||
|
|
||||||
|
ignore_enter_notify_forall(conn, c_ws, true);
|
||||||
|
|
||||||
/* Unmap all clients of the current workspace */
|
/* Unmap all clients of the current workspace */
|
||||||
int unmapped_clients = 0;
|
int unmapped_clients = 0;
|
||||||
for (int cols = 0; cols < c_ws->cols; cols++)
|
FOR_TABLE(c_ws)
|
||||||
for (int rows = 0; rows < c_ws->rows; rows++)
|
CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) {
|
||||||
CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) {
|
xcb_unmap_window(conn, client->frame);
|
||||||
xcb_unmap_window(conn, client->frame);
|
unmapped_clients++;
|
||||||
unmapped_clients++;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* If we did not unmap any clients, the workspace is empty and we can destroy it */
|
/* If we did not unmap any clients, the workspace is empty and we can destroy it */
|
||||||
if (unmapped_clients == 0)
|
if (unmapped_clients == 0)
|
||||||
|
@ -436,22 +437,27 @@ static void show_workspace(xcb_connection_t *conn, int workspace) {
|
||||||
if (stack_win->container->workspace == c_ws)
|
if (stack_win->container->workspace == c_ws)
|
||||||
xcb_unmap_window(conn, stack_win->window);
|
xcb_unmap_window(conn, stack_win->window);
|
||||||
|
|
||||||
|
ignore_enter_notify_forall(conn, c_ws, false);
|
||||||
|
|
||||||
c_ws = &workspaces[workspace-1];
|
c_ws = &workspaces[workspace-1];
|
||||||
current_row = c_ws->current_row;
|
current_row = c_ws->current_row;
|
||||||
current_col = c_ws->current_col;
|
current_col = c_ws->current_col;
|
||||||
LOG("new current row = %d, current col = %d\n", current_row, current_col);
|
LOG("new current row = %d, current col = %d\n", current_row, current_col);
|
||||||
|
|
||||||
|
ignore_enter_notify_forall(conn, c_ws, true);
|
||||||
|
|
||||||
/* Map all clients on the new workspace */
|
/* Map all clients on the new workspace */
|
||||||
for (int cols = 0; cols < c_ws->cols; cols++)
|
FOR_TABLE(c_ws)
|
||||||
for (int rows = 0; rows < c_ws->rows; rows++)
|
CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients)
|
||||||
CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients)
|
xcb_map_window(conn, client->frame);
|
||||||
xcb_map_window(conn, client->frame);
|
|
||||||
|
|
||||||
/* Map all stack windows, if any */
|
/* Map all stack windows, if any */
|
||||||
SLIST_FOREACH(stack_win, &stack_wins, stack_windows)
|
SLIST_FOREACH(stack_win, &stack_wins, stack_windows)
|
||||||
if (stack_win->container->workspace == c_ws)
|
if (stack_win->container->workspace == c_ws)
|
||||||
xcb_map_window(conn, stack_win->window);
|
xcb_map_window(conn, stack_win->window);
|
||||||
|
|
||||||
|
ignore_enter_notify_forall(conn, c_ws, false);
|
||||||
|
|
||||||
/* Restore focus on the new workspace */
|
/* Restore focus on the new workspace */
|
||||||
if (CUR_CELL->currently_focused != NULL)
|
if (CUR_CELL->currently_focused != NULL)
|
||||||
set_focus(conn, CUR_CELL->currently_focused);
|
set_focus(conn, CUR_CELL->currently_focused);
|
||||||
|
|
92
src/layout.c
92
src/layout.c
|
@ -464,6 +464,34 @@ static void render_internal_bar(xcb_connection_t *conn, Workspace *r_ws, int wid
|
||||||
LOG("done rendering internal\n");
|
LOG("done rendering internal\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modifies the event mask of all clients on the given workspace to either ignore or to handle
|
||||||
|
* enter notifies. It is handy to ignore notifies because they will be sent when a window is mapped
|
||||||
|
* under the cursor, thus when the user didn’t enter the window actively at all.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void ignore_enter_notify_forall(xcb_connection_t *conn, Workspace *workspace, bool ignore_enter_notify) {
|
||||||
|
Client *client;
|
||||||
|
uint32_t values[1];
|
||||||
|
|
||||||
|
LOG("Ignore enter_notify = %d\n", ignore_enter_notify);
|
||||||
|
|
||||||
|
FOR_TABLE(workspace)
|
||||||
|
CIRCLEQ_FOREACH(client, &(workspace->table[cols][rows]->clients), clients) {
|
||||||
|
/* Change event mask for the decorations */
|
||||||
|
values[0] = FRAME_EVENT_MASK;
|
||||||
|
if (ignore_enter_notify)
|
||||||
|
values[0] &= ~(XCB_EVENT_MASK_ENTER_WINDOW);
|
||||||
|
xcb_change_window_attributes(conn, client->frame, XCB_CW_EVENT_MASK, values);
|
||||||
|
|
||||||
|
/* Change event mask for the child itself */
|
||||||
|
values[0] = CHILD_EVENT_MASK;
|
||||||
|
if (ignore_enter_notify)
|
||||||
|
values[0] &= ~(XCB_EVENT_MASK_ENTER_WINDOW);
|
||||||
|
xcb_change_window_attributes(conn, client->child, XCB_CW_EVENT_MASK, values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void render_layout(xcb_connection_t *conn) {
|
void render_layout(xcb_connection_t *conn) {
|
||||||
i3Screen *screen;
|
i3Screen *screen;
|
||||||
i3Font *font = load_font(conn, config.font);
|
i3Font *font = load_font(conn, config.font);
|
||||||
|
@ -496,41 +524,45 @@ void render_layout(xcb_connection_t *conn) {
|
||||||
xoffset[rows] = r_ws->rect.x;
|
xoffset[rows] = r_ws->rect.x;
|
||||||
|
|
||||||
dump_table(conn, r_ws);
|
dump_table(conn, r_ws);
|
||||||
|
|
||||||
|
ignore_enter_notify_forall(conn, r_ws, true);
|
||||||
|
|
||||||
/* Go through the whole table and render what’s necessary */
|
/* Go through the whole table and render what’s necessary */
|
||||||
for (int cols = 0; cols < r_ws->cols; cols++)
|
FOR_TABLE(r_ws) {
|
||||||
for (int rows = 0; rows < r_ws->rows; rows++) {
|
Container *container = r_ws->table[cols][rows];
|
||||||
Container *container = r_ws->table[cols][rows];
|
int single_width, single_height;
|
||||||
int single_width, single_height;
|
LOG("\n");
|
||||||
LOG("\n");
|
LOG("========\n");
|
||||||
LOG("========\n");
|
LOG("container has %d colspan, %d rowspan\n",
|
||||||
LOG("container has %d colspan, %d rowspan\n",
|
container->colspan, container->rowspan);
|
||||||
container->colspan, container->rowspan);
|
LOG("container at %d, %d\n", xoffset[rows], yoffset[cols]);
|
||||||
LOG("container at %d, %d\n", xoffset[rows], yoffset[cols]);
|
/* Update position of the container */
|
||||||
/* Update position of the container */
|
container->row = rows;
|
||||||
container->row = rows;
|
container->col = cols;
|
||||||
container->col = cols;
|
container->x = xoffset[rows];
|
||||||
container->x = xoffset[rows];
|
container->y = yoffset[cols];
|
||||||
container->y = yoffset[cols];
|
|
||||||
|
|
||||||
if (container->width_factor == 0)
|
if (container->width_factor == 0)
|
||||||
container->width = (width / r_ws->cols);
|
container->width = (width / r_ws->cols);
|
||||||
else container->width = get_unoccupied_x(r_ws, rows) * container->width_factor;
|
else container->width = get_unoccupied_x(r_ws, rows) * container->width_factor;
|
||||||
single_width = container->width;
|
single_width = container->width;
|
||||||
container->width *= container->colspan;
|
container->width *= container->colspan;
|
||||||
|
|
||||||
if (container->height_factor == 0)
|
if (container->height_factor == 0)
|
||||||
container->height = (height / r_ws->rows);
|
container->height = (height / r_ws->rows);
|
||||||
else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor;
|
else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor;
|
||||||
single_height = container->height;
|
single_height = container->height;
|
||||||
container->height *= container->rowspan;
|
container->height *= container->rowspan;
|
||||||
|
|
||||||
/* Render the container if it is not empty */
|
/* Render the container if it is not empty */
|
||||||
render_container(conn, container);
|
render_container(conn, container);
|
||||||
|
|
||||||
xoffset[rows] += single_width;
|
xoffset[rows] += single_width;
|
||||||
yoffset[cols] += single_height;
|
yoffset[cols] += single_height;
|
||||||
LOG("==========\n");
|
LOG("==========\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ignore_enter_notify_forall(conn, r_ws, false);
|
||||||
|
|
||||||
render_bars(conn, r_ws, width, &height);
|
render_bars(conn, r_ws, width, &height);
|
||||||
render_internal_bar(conn, r_ws, width, font->height + 6);
|
render_internal_bar(conn, r_ws, width, font->height + 6);
|
||||||
|
|
10
src/mainx.c
10
src/mainx.c
|
@ -131,9 +131,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
|
|
||||||
/* We are interested in property changes */
|
/* We are interested in property changes */
|
||||||
mask = XCB_CW_EVENT_MASK;
|
mask = XCB_CW_EVENT_MASK;
|
||||||
values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
|
values[0] = CHILD_EVENT_MASK;
|
||||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
|
||||||
XCB_EVENT_MASK_ENTER_WINDOW;
|
|
||||||
xcb_change_window_attributes(conn, child, mask, values);
|
xcb_change_window_attributes(conn, child, mask, values);
|
||||||
|
|
||||||
/* Map the window first to avoid flickering */
|
/* Map the window first to avoid flickering */
|
||||||
|
@ -171,11 +169,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
|
|
||||||
/* We want to know when… */
|
/* We want to know when… */
|
||||||
mask |= XCB_CW_EVENT_MASK;
|
mask |= XCB_CW_EVENT_MASK;
|
||||||
values[1] = XCB_EVENT_MASK_BUTTON_PRESS | /* …mouse is pressed/released */
|
values[1] = FRAME_EVENT_MASK;
|
||||||
XCB_EVENT_MASK_BUTTON_RELEASE |
|
|
||||||
XCB_EVENT_MASK_EXPOSURE | /* …our window needs to be redrawn */
|
|
||||||
XCB_EVENT_MASK_ENTER_WINDOW | /* …user moves cursor inside our window */
|
|
||||||
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; /* …the application tries to resize itself */
|
|
||||||
|
|
||||||
LOG("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
|
LOG("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
|
||||||
|
|
||||||
|
|
53
src/table.c
53
src/table.c
|
@ -170,18 +170,16 @@ static void move_rows_from(xcb_connection_t *conn, Workspace *workspace, int row
|
||||||
|
|
||||||
void dump_table(xcb_connection_t *conn, Workspace *workspace) {
|
void dump_table(xcb_connection_t *conn, Workspace *workspace) {
|
||||||
LOG("dump_table()\n");
|
LOG("dump_table()\n");
|
||||||
for (int cols = 0; cols < workspace->cols; cols++) {
|
FOR_TABLE(workspace) {
|
||||||
for (int rows = 0; rows < workspace->rows; rows++) {
|
Container *con = workspace->table[cols][rows];
|
||||||
Container *con = workspace->table[cols][rows];
|
LOG("----\n");
|
||||||
LOG("----\n");
|
LOG("at col=%d, row=%d\n", cols, rows);
|
||||||
LOG("at col=%d, row=%d\n", cols, rows);
|
LOG("currently_focused = %p\n", con->currently_focused);
|
||||||
LOG("currently_focused = %p\n", con->currently_focused);
|
Client *loop;
|
||||||
Client *loop;
|
CIRCLEQ_FOREACH(loop, &(con->clients), clients) {
|
||||||
CIRCLEQ_FOREACH(loop, &(con->clients), clients) {
|
LOG("got client %08x / %s\n", loop->child, loop->name);
|
||||||
LOG("got client %08x / %s\n", loop->child, loop->name);
|
|
||||||
}
|
|
||||||
LOG("----\n");
|
|
||||||
}
|
}
|
||||||
|
LOG("----\n");
|
||||||
}
|
}
|
||||||
LOG("done\n");
|
LOG("done\n");
|
||||||
}
|
}
|
||||||
|
@ -258,22 +256,21 @@ void cleanup_table(xcb_connection_t *conn, Workspace *workspace) {
|
||||||
void fix_colrowspan(xcb_connection_t *conn, Workspace *workspace) {
|
void fix_colrowspan(xcb_connection_t *conn, Workspace *workspace) {
|
||||||
LOG("Fixing col/rowspan\n");
|
LOG("Fixing col/rowspan\n");
|
||||||
|
|
||||||
for (int cols = 0; cols < workspace->cols; cols++)
|
FOR_TABLE(workspace) {
|
||||||
for (int rows = 0; rows < workspace->rows; rows++) {
|
Container *con = workspace->table[cols][rows];
|
||||||
Container *con = workspace->table[cols][rows];
|
if (con->colspan > 1) {
|
||||||
if (con->colspan > 1) {
|
LOG("gots one with colspan %d\n", con->colspan);
|
||||||
LOG("gots one with colspan %d\n", con->colspan);
|
while (con->colspan > 1 &&
|
||||||
while (con->colspan > 1 &&
|
workspace->table[cols + (con->colspan - 1)][rows]->currently_focused != NULL)
|
||||||
workspace->table[cols + (con->colspan - 1)][rows]->currently_focused != NULL)
|
con->colspan--;
|
||||||
con->colspan--;
|
LOG("fixed it to %d\n", con->colspan);
|
||||||
LOG("fixed it to %d\n", con->colspan);
|
|
||||||
}
|
|
||||||
if (con->rowspan > 1) {
|
|
||||||
LOG("gots one with rowspan %d\n", con->rowspan);
|
|
||||||
while (con->rowspan > 1 &&
|
|
||||||
workspace->table[cols][rows + (con->rowspan - 1)]->currently_focused != NULL)
|
|
||||||
con->rowspan--;
|
|
||||||
LOG("fixed it to %d\n", con->rowspan);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (con->rowspan > 1) {
|
||||||
|
LOG("gots one with rowspan %d\n", con->rowspan);
|
||||||
|
while (con->rowspan > 1 &&
|
||||||
|
workspace->table[cols][rows + (con->rowspan - 1)]->currently_focused != NULL)
|
||||||
|
con->rowspan--;
|
||||||
|
LOG("fixed it to %d\n", con->rowspan);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,8 +371,8 @@ void toggle_fullscreen(xcb_connection_t *conn, Client *client) {
|
||||||
/* Because the coordinates of the window haven’t changed, it would not be
|
/* Because the coordinates of the window haven’t changed, it would not be
|
||||||
re-configured if we don’t set the following flag */
|
re-configured if we don’t set the following flag */
|
||||||
client->force_reconfigure = true;
|
client->force_reconfigure = true;
|
||||||
/* We left fullscreen mode, redraw the container */
|
/* We left fullscreen mode, redraw the whole layout to ensure enternotify events are disabled */
|
||||||
render_container(conn, client->container);
|
render_layout(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
Loading…
Reference in New Issue