+
+void
+debug_toggle(struct binding *b, struct swm_region *r, union arg *s)
+{
+ struct ws_win *win;
+ int num_screens, i, j;
+
+ /* Suppress warnings. */
+ (void)b;
+ (void)r;
+ (void)s;
+
+ DNPRINTF(SWM_D_MISC, "debug_toggle\n");
+
+ debug_enabled = !debug_enabled;
+
+ num_screens = get_screen_count();
+ for (i = 0; i < num_screens; i++)
+ for (j = 0; j < workspace_limit; j++)
+ TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
+ debug_refresh(win);
+
+ xcb_flush(conn);
+}
+
+void
+debug_refresh(struct ws_win *win)
+{
+ struct ws_win *w;
+ XftDraw *draw;
+ XGlyphInfo info;
+ GC l_draw;
+ XGCValues l_gcv;
+ XRectangle l_ibox, l_lbox;
+ xcb_rectangle_t rect;
+ size_t len;
+ uint32_t wc[4], mask, width, height, gcv[1];
+ int widx, sidx;
+ char *s;
+ xcb_screen_t *screen;
+
+ if (debug_enabled) {
+ /* Create debug window if it doesn't exist. */
+ if (win->debug == XCB_WINDOW_NONE) {
+ if ((screen = get_screen(win->s->idx)) == NULL)
+ errx(1, "ERROR: can't get screen %d.",
+ win->s->idx);
+
+ win->debug = xcb_generate_id(conn);
+ wc[0] = win->s->c[SWM_S_COLOR_BAR].pixel;
+ wc[1] = win->s->c[SWM_S_COLOR_BAR_BORDER].pixel;
+ wc[2] = screen->default_colormap;
+
+ xcb_create_window(conn, screen->root_depth, win->debug,
+ win->frame, 0, 0, 10, 10, 1,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual,
+ XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL |
+ XCB_CW_COLORMAP, wc);
+
+ xcb_map_window(conn, win->debug);
+ }
+
+ /* Determine workspace window list index. */
+ widx = 0;
+ TAILQ_FOREACH(w, &win->ws->winlist, entry) {
+ ++widx;
+ if (w == win)
+ break;
+ }
+
+ /* Determine stacking index (top down). */
+ sidx = 0;
+ TAILQ_FOREACH(w, &win->ws->stack, stack_entry) {
+ ++sidx;
+ if (w == win)
+ break;
+ }
+
+ if (asprintf(&s, "%#x f:%#x wl:%d s:%d im:%s", win->id,
+ win->frame, widx, sidx, get_win_input_model(win)) == -1)
+ return;
+
+ len = strlen(s);
+
+ /* Update window to an appropriate dimension. */
+ if (bar_font_legacy) {
+ XmbTextExtents(bar_fs, s, len, &l_ibox, &l_lbox);
+ width = l_lbox.width + 4;
+ height = bar_fs_extents->max_logical_extent.height + 4;
+ } else {
+ XftTextExtentsUtf8(display, bar_font, (FcChar8 *)s, len,
+ &info);
+ width = info.width + 4;
+ height = bar_font->height + 4;
+ }
+
+ mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
+ XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
+ if (win->bordered)
+ wc[0] = wc[1] = border_width;
+ else
+ wc[0] = wc[1] = 0;
+
+ wc[2] = width;
+ wc[3] = height;
+
+ xcb_configure_window(conn, win->debug, mask, wc);
+
+ /* Draw a filled rectangle to 'clear' window. */
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+
+ gcv[0] = win->s->c[SWM_S_COLOR_BAR].pixel;
+ xcb_change_gc(conn, win->s->bar_gc, XCB_GC_FOREGROUND, gcv);
+ xcb_poly_fill_rectangle(conn, win->debug, win->s->bar_gc, 1,
+ &rect);
+
+ /* Draw text. */
+ if (bar_font_legacy) {
+ l_gcv.graphics_exposures = 0;
+ l_draw = XCreateGC(display, win->debug, 0, &l_gcv);
+
+ XSetForeground(display, l_draw,
+ win->s->c[SWM_S_COLOR_BAR_FONT].pixel);
+
+ DRAWSTRING(display, win->debug, bar_fs, l_draw, 2,
+ (bar_fs_extents->max_logical_extent.height -
+ l_lbox.height) / 2 - l_lbox.y, s, len);
+
+ XFreeGC(display, l_draw);
+ } else {
+ draw = XftDrawCreate(display, win->debug,
+ DefaultVisual(display, win->s->idx),
+ DefaultColormap(display, win->s->idx));
+
+ XftDrawStringUtf8(draw, &bar_font_color, bar_font, 2,
+ (bar_height + bar_font->height) / 2 -
+ bar_font->descent, (FcChar8 *)s, len);
+
+ XftDrawDestroy(draw);
+ }
+
+ free(s);
+ } else if (win->debug != XCB_WINDOW_NONE) {
+ xcb_destroy_window(conn, win->debug);
+ win->debug = XCB_WINDOW_NONE;
+ }
+}