Bugfix: Change the event mask to ignore enter notifies when rendering the layout and changing workspaces

This commit is contained in:
Michael Stapelberg 2009-03-11 00:20:56 +01:00
parent 408b2bdb39
commit 38c8541807
8 changed files with 127 additions and 78 deletions

View File

@ -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 redecorate_window(xcb_connection_t *conn, Client *client);
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);
#endif

View File

@ -20,6 +20,10 @@
CIRCLEQ_NEXT(elm, field) : NULL)
#define CIRCLEQ_PREV_OR_NULL(head, elm, field) (CIRCLEQ_PREV(elm, field) != CIRCLEQ_END(head) ? \
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,
delete the preceding comma */
#define LOG(fmt, ...) slog("%s:%s:%d - " fmt, __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__)

View File

@ -22,6 +22,21 @@
#define XCB_CURSOR_SB_H_DOUBLE_ARROW 108
#define XCB_CURSOR_SB_V_DOUBLE_ARROW 116
/* The event masks are defined here because we dont 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,
_NET_SUPPORTING_WM_CHECK,
_NET_WM_NAME,

View File

@ -417,10 +417,11 @@ static void show_workspace(xcb_connection_t *conn, int workspace) {
/* TODO: does grabbing the server actually bring us any (speed)advantages? */
//xcb_grab_server(conn);
ignore_enter_notify_forall(conn, c_ws, true);
/* Unmap all clients of the current workspace */
int unmapped_clients = 0;
for (int cols = 0; cols < c_ws->cols; cols++)
for (int rows = 0; rows < c_ws->rows; rows++)
FOR_TABLE(c_ws)
CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) {
xcb_unmap_window(conn, client->frame);
unmapped_clients++;
@ -436,14 +437,17 @@ static void show_workspace(xcb_connection_t *conn, int workspace) {
if (stack_win->container->workspace == c_ws)
xcb_unmap_window(conn, stack_win->window);
ignore_enter_notify_forall(conn, c_ws, false);
c_ws = &workspaces[workspace-1];
current_row = c_ws->current_row;
current_col = c_ws->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 */
for (int cols = 0; cols < c_ws->cols; cols++)
for (int rows = 0; rows < c_ws->rows; rows++)
FOR_TABLE(c_ws)
CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients)
xcb_map_window(conn, client->frame);
@ -452,6 +456,8 @@ static void show_workspace(xcb_connection_t *conn, int workspace) {
if (stack_win->container->workspace == c_ws)
xcb_map_window(conn, stack_win->window);
ignore_enter_notify_forall(conn, c_ws, false);
/* Restore focus on the new workspace */
if (CUR_CELL->currently_focused != NULL)
set_focus(conn, CUR_CELL->currently_focused);

View File

@ -464,6 +464,34 @@ static void render_internal_bar(xcb_connection_t *conn, Workspace *r_ws, int wid
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 didnt 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) {
i3Screen *screen;
i3Font *font = load_font(conn, config.font);
@ -496,9 +524,11 @@ void render_layout(xcb_connection_t *conn) {
xoffset[rows] = r_ws->rect.x;
dump_table(conn, r_ws);
ignore_enter_notify_forall(conn, r_ws, true);
/* Go through the whole table and render whats necessary */
for (int cols = 0; cols < r_ws->cols; cols++)
for (int rows = 0; rows < r_ws->rows; rows++) {
FOR_TABLE(r_ws) {
Container *container = r_ws->table[cols][rows];
int single_width, single_height;
LOG("\n");
@ -532,6 +562,8 @@ void render_layout(xcb_connection_t *conn) {
LOG("==========\n");
}
ignore_enter_notify_forall(conn, r_ws, false);
render_bars(conn, r_ws, width, &height);
render_internal_bar(conn, r_ws, width, font->height + 6);
}

View File

@ -131,9 +131,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
/* We are interested in property changes */
mask = XCB_CW_EVENT_MASK;
values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_ENTER_WINDOW;
values[0] = CHILD_EVENT_MASK;
xcb_change_window_attributes(conn, child, mask, values);
/* 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… */
mask |= XCB_CW_EVENT_MASK;
values[1] = 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_ENTER_WINDOW | /* …user moves cursor inside our window */
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; /* …the application tries to resize itself */
values[1] = FRAME_EVENT_MASK;
LOG("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);

View File

@ -170,8 +170,7 @@ static void move_rows_from(xcb_connection_t *conn, Workspace *workspace, int row
void dump_table(xcb_connection_t *conn, Workspace *workspace) {
LOG("dump_table()\n");
for (int cols = 0; cols < workspace->cols; cols++) {
for (int rows = 0; rows < workspace->rows; rows++) {
FOR_TABLE(workspace) {
Container *con = workspace->table[cols][rows];
LOG("----\n");
LOG("at col=%d, row=%d\n", cols, rows);
@ -182,7 +181,6 @@ void dump_table(xcb_connection_t *conn, Workspace *workspace) {
}
LOG("----\n");
}
}
LOG("done\n");
}
@ -258,8 +256,7 @@ void cleanup_table(xcb_connection_t *conn, Workspace *workspace) {
void fix_colrowspan(xcb_connection_t *conn, Workspace *workspace) {
LOG("Fixing col/rowspan\n");
for (int cols = 0; cols < workspace->cols; cols++)
for (int rows = 0; rows < workspace->rows; rows++) {
FOR_TABLE(workspace) {
Container *con = workspace->table[cols][rows];
if (con->colspan > 1) {
LOG("gots one with colspan %d\n", con->colspan);

View File

@ -371,8 +371,8 @@ void toggle_fullscreen(xcb_connection_t *conn, Client *client) {
/* Because the coordinates of the window havent changed, it would not be
re-configured if we dont set the following flag */
client->force_reconfigure = true;
/* We left fullscreen mode, redraw the container */
render_container(conn, client->container);
/* We left fullscreen mode, redraw the whole layout to ensure enternotify events are disabled */
render_layout(conn);
}
xcb_flush(conn);