X-Git-Url: https://git.sur5r.net/?p=i3%2Fi3;a=blobdiff_plain;f=src%2Fx.c;h=267372f93bace95ce5e53ebee6e4d2a208034a9a;hp=ee5ed2ce794fa9ca397c99d6ec3295720d87cb99;hb=HEAD;hpb=a7e8c4dd466741d02873a81766192198dad6d570 diff --git a/src/x.c b/src/x.c index ee5ed2ce..267372f9 100644 --- a/src/x.c +++ b/src/x.c @@ -42,7 +42,7 @@ typedef struct con_state { bool child_mapped; bool is_hidden; - /** The con for which this state is. */ + /* The con for which this state is. */ Con *con; /* For reparenting, we have a flag (need_reparent) and the X ID of the old @@ -99,6 +99,27 @@ static con_state *state_for_frame(xcb_window_t window) { return NULL; } +/* + * Changes the atoms on the root window and the windows themselves to properly + * reflect the current focus for ewmh compliance. + * + */ +static void change_ewmh_focus(xcb_window_t new_focus, xcb_window_t old_focus) { + if (new_focus == old_focus) { + return; + } + + ewmh_update_active_window(new_focus); + + if (new_focus != XCB_WINDOW_NONE) { + ewmh_update_focused(new_focus, true); + } + + if (old_focus != XCB_WINDOW_NONE) { + ewmh_update_focused(old_focus, false); + } +} + /* * Initializes the X11 part for the given container. Called exactly once for * every container from con_new(). @@ -127,7 +148,7 @@ void x_con_init(Con *con) { /* We explicitly set a background color and border color (even though we * don’t even have a border) because the X11 server requires us to when * using 32 bit color depths, see - * http://stackoverflow.com/questions/3645632 */ + * https://stackoverflow.com/questions/3645632 */ mask |= XCB_CW_BACK_PIXEL; values[0] = root_screen->black_pixel; @@ -232,11 +253,7 @@ void x_move_win(Con *src, Con *dest) { } } -/* - * Kills the window decoration associated with the given container. - * - */ -void x_con_kill(Con *con) { +static void _x_con_kill(Con *con) { con_state *state; if (con->colormap != XCB_NONE) { @@ -245,7 +262,6 @@ void x_con_kill(Con *con) { draw_util_surface_free(conn, &(con->frame)); draw_util_surface_free(conn, &(con->frame_buffer)); - xcb_destroy_window(conn, con->frame.id); xcb_free_pixmap(conn, con->frame_buffer.id); state = state_for_frame(con->frame.id); CIRCLEQ_REMOVE(&state_head, state, state); @@ -258,6 +274,24 @@ void x_con_kill(Con *con) { focused_id = last_focused = XCB_NONE; } +/* + * Kills the window decoration associated with the given container. + * + */ +void x_con_kill(Con *con) { + _x_con_kill(con); + xcb_destroy_window(conn, con->frame.id); +} + +/* + * Completely reinitializes the container's frame, without destroying the old window. + * + */ +void x_con_reframe(Con *con) { + _x_con_kill(con); + x_con_init(con); +} + /* * Returns true if the client supports the given protocol atom (like WM_DELETE_WINDOW) * @@ -474,14 +508,12 @@ void x_draw_decoration(Con *con) { /* 3: draw a rectangle in border color around the client */ if (p->border_style != BS_NONE && p->con_is_leaf) { /* We might hide some borders adjacent to the screen-edge */ - adjacent_t borders_to_hide = ADJ_NONE; - borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders; - + adjacent_t borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders; Rect br = con_border_style_rect(con); /* These rectangles represent the border around the child window * (left, bottom and right part). We don’t just fill the whole - * rectangle because some childs are not freely resizable and we want + * rectangle because some children are not freely resizable and we want * their background color to "shine through". */ if (!(borders_to_hide & ADJ_LEFT_SCREEN_EDGE)) { draw_util_rectangle(&(con->frame_buffer), p->color->child_border, 0, 0, br.x, r->height); @@ -547,31 +579,8 @@ void x_draw_decoration(Con *con) { /* 6: draw the title */ int text_offset_y = (con->deco_rect.height - config.font.height) / 2; - struct Window *win = con->window; - if (win == NULL) { - i3String *title; - if (con->title_format == NULL) { - char *_title; - char *tree = con_get_tree_representation(con); - sasprintf(&_title, "i3: %s", tree); - free(tree); - - title = i3string_from_utf8(_title); - FREE(_title); - } else { - title = con_parse_title_format(con); - } - - draw_util_text(title, &(parent->frame_buffer), - p->color->text, p->color->background, - con->deco_rect.x + logical_px(2), - con->deco_rect.y + text_offset_y, - con->deco_rect.width - 2 * logical_px(2)); - I3STRING_FREE(title); - - goto after_title; - } - + const int title_padding = logical_px(2); + const int deco_width = (int)con->deco_rect.width; int mark_width = 0; if (config.show_marks && !TAILQ_EMPTY(&(con->marks_head))) { char *formatted_mark = sstrdup(""); @@ -593,33 +602,75 @@ void x_draw_decoration(Con *con) { i3String *mark = i3string_from_utf8(formatted_mark); mark_width = predict_text_width(mark); + int mark_offset_x = (config.title_align == ALIGN_RIGHT) + ? title_padding + : deco_width - mark_width - title_padding; + draw_util_text(mark, &(parent->frame_buffer), p->color->text, p->color->background, - con->deco_rect.x + con->deco_rect.width - mark_width - logical_px(2), + con->deco_rect.x + mark_offset_x, con->deco_rect.y + text_offset_y, mark_width); - I3STRING_FREE(mark); + + mark_width += title_padding; } FREE(formatted_mark); } - i3String *title = con->title_format == NULL ? win->name : con_parse_title_format(con); + i3String *title = NULL; + struct Window *win = con->window; + if (win == NULL) { + if (con->title_format == NULL) { + char *_title; + char *tree = con_get_tree_representation(con); + sasprintf(&_title, "i3: %s", tree); + free(tree); + + title = i3string_from_utf8(_title); + FREE(_title); + } else { + title = con_parse_title_format(con); + } + } else { + title = con->title_format == NULL ? win->name : con_parse_title_format(con); + } if (title == NULL) { goto copy_pixmaps; } + int title_offset_x; + switch (config.title_align) { + case ALIGN_LEFT: + /* (pad)[text ](pad)[mark + its pad) */ + title_offset_x = title_padding; + break; + case ALIGN_CENTER: + /* (pad)[ text ](pad)[mark + its pad) + * To center the text inside its allocated space, the surface + * between the brackets, we use the formula + * (surface_width - predict_text_width) / 2 + * where surface_width = deco_width - 2 * pad - mark_width + * so, offset = pad + (surface_width - predict_text_width) / 2 = + * = … = (deco_width - mark_width - predict_text_width) / 2 */ + title_offset_x = max(title_padding, (deco_width - mark_width - predict_text_width(title)) / 2); + break; + case ALIGN_RIGHT: + /* [mark + its pad](pad)[ text](pad) */ + title_offset_x = max(title_padding + mark_width, deco_width - title_padding - predict_text_width(title)); + break; + } + draw_util_text(title, &(parent->frame_buffer), p->color->text, p->color->background, - con->deco_rect.x + logical_px(2), + con->deco_rect.x + title_offset_x, con->deco_rect.y + text_offset_y, - con->deco_rect.width - mark_width - 2 * logical_px(2)); + deco_width - mark_width - 2 * title_padding); - if (con->title_format != NULL) { + if (win == NULL || con->title_format != NULL) { I3STRING_FREE(title); } -after_title: x_draw_decoration_after_title(con, p); copy_pixmaps: draw_util_copy_surface(&(con->frame_buffer), &(con->frame), 0, 0, 0, 0, con->rect.width, con->rect.height); @@ -766,11 +817,8 @@ void x_push_node(Con *con) { * background and only afterwards change the window size. This reduces * flickering. */ - /* As the pixmap only depends on the size and not on the position, it - * is enough to check if width/height have changed. Also, we don’t - * create a pixmap at all when the window is actually not visible - * (height == 0) or when it is not needed. */ - bool has_rect_changed = (state->rect.width != rect.width || state->rect.height != rect.height); + bool has_rect_changed = (state->rect.x != rect.x || state->rect.y != rect.y || + state->rect.width != rect.width || state->rect.height != rect.height); /* Check if the container has an unneeded pixmap left over from * previously having a border or titlebar. */ @@ -1120,7 +1168,7 @@ void x_push_changes(Con *con) { to_focus, focused, focused->name); send_take_focus(to_focus, last_timestamp); - ewmh_update_active_window((con_has_managed_window(focused) ? focused->window->id : XCB_WINDOW_NONE)); + change_ewmh_focus((con_has_managed_window(focused) ? focused->window->id : XCB_WINDOW_NONE), last_focused); if (to_focus != last_focused && is_con_attached(focused)) ipc_send_window_event("focus", focused); @@ -1139,7 +1187,7 @@ void x_push_changes(Con *con) { xcb_change_window_attributes(conn, focused->window->id, XCB_CW_EVENT_MASK, values); } - ewmh_update_active_window((con_has_managed_window(focused) ? focused->window->id : XCB_WINDOW_NONE)); + change_ewmh_focus((con_has_managed_window(focused) ? focused->window->id : XCB_WINDOW_NONE), last_focused); if (to_focus != XCB_NONE && to_focus != last_focused && focused->window != NULL && is_con_attached(focused)) ipc_send_window_event("focus", focused); @@ -1154,7 +1202,8 @@ void x_push_changes(Con *con) { * root window in order to avoid an X11 fallback mechanism causing a ghosting effect (see #1378). */ DLOG("Still no window focused, better set focus to the EWMH support window (%d)\n", ewmh_window); xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, ewmh_window, last_timestamp); - ewmh_update_active_window(XCB_WINDOW_NONE); + change_ewmh_focus(XCB_WINDOW_NONE, last_focused); + focused_id = ewmh_window; } @@ -1226,10 +1275,14 @@ void x_set_name(Con *con, const char *name) { * Set up the I3_SHMLOG_PATH atom. * */ -void update_shmlog_atom() { - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, - A_I3_SHMLOG_PATH, A_UTF8_STRING, 8, - strlen(shmlogname), shmlogname); +void update_shmlog_atom(void) { + if (*shmlogname == '\0') { + xcb_delete_property(conn, root, A_I3_SHMLOG_PATH); + } else { + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, + A_I3_SHMLOG_PATH, A_UTF8_STRING, 8, + strlen(shmlogname), shmlogname); + } } /*