]> git.corax.cc Git - mwm/commitdiff
monitor: Use double-buffering to draw the status bar
authorMatthias Kruk <m@m10k.eu>
Mon, 21 Jun 2021 21:55:18 +0000 (06:55 +0900)
committerMatthias Kruk <m@m10k.eu>
Mon, 21 Jun 2021 21:55:18 +0000 (06:55 +0900)
The status bar sometimes flickers when it is redrawn because the
displayed bar is redrawn directly, without getting buffered.
This commit adds an intermediary buffer that is used to render the
status bar before its contents are copied into its window.

monitor.c
mwm.c
mwm.h

index 0d61c3d161dfd31caf1ceeb78531ae531ff28f48..a9ff2bc1cac27d81c682fb042c14c93d31ae0a70 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -13,8 +13,8 @@
 #include "layout.h"
 
 #define STATUSBAR_HEIGHT 32
-#define INDICATOR_HEIGHT 32
-#define INDICATOR_PADDING 8
+#define INDICATOR_HEIGHT 64
+#define INDICATOR_PADDING 16
 
 #define HINDICATOR 0
 #define VINDICATOR 1
@@ -30,6 +30,8 @@ struct indicator {
 struct monitor {
        int id;
        Window statusbar;
+       Drawable draw_buffer;
+
        GC gfx_context;
        XftDraw *xft_context;
 
@@ -233,7 +235,8 @@ int monitor_new(struct mwm *mwm, int id, int x, int y, int w, int h,
 
        mon->statusbar = mwm_create_window(mwm, x, y, w, STATUSBAR_HEIGHT);
        mon->gfx_context = mwm_create_gc(mwm);
-       mon->xft_context = mwm_create_xft_context(mwm, (Drawable)mon->statusbar);
+       mon->draw_buffer = mwm_create_pixmap(mwm, 0, w, STATUSBAR_HEIGHT);
+       mon->xft_context = mwm_create_xft_context(mwm, mon->draw_buffer);
        XMapRaised(mwm_get_display(mwm), mon->statusbar);
 
        _indicator_update_geometry(mon);
@@ -302,6 +305,9 @@ int monitor_set_geometry(struct monitor *monitor, struct geom *geom)
        XMoveResizeWindow(mwm_get_display(monitor->mwm), monitor->statusbar,
                          monitor->geom.x, monitor->geom.y,
                          monitor->geom.w, STATUSBAR_HEIGHT);
+       mwm_free_pixmap(monitor->mwm, monitor->draw_buffer);
+       monitor->draw_buffer = mwm_create_pixmap(monitor->mwm, 0, monitor->geom.w, STATUSBAR_HEIGHT);
+       XftDrawChange(monitor->xft_context, monitor->draw_buffer);
 
        return(0);
 }
@@ -478,7 +484,7 @@ static int _draw_workspace_button(struct mwm *mwm, struct workspace *workspace,
        XSetForeground(dwdata->display, dwdata->monitor->gfx_context,
                       mwm_get_color(mwm, dwdata->palette, color));
 
-       XFillRectangle(dwdata->display, dwdata->monitor->statusbar,
+       XFillRectangle(dwdata->display, dwdata->monitor->draw_buffer,
                       dwdata->monitor->gfx_context, x, 0,
                       button_width, STATUSBAR_HEIGHT);
 
@@ -489,7 +495,7 @@ static int _draw_workspace_button(struct mwm *mwm, struct workspace *workspace,
        if(workspace_get_focused_client(workspace)) {
                XSetForeground(dwdata->display, dwdata->monitor->gfx_context,
                               mwm_get_color(mwm, dwdata->palette, MWM_COLOR_CLIENT_INDICATOR));
-               XFillRectangle(dwdata->display, dwdata->monitor->statusbar,
+               XFillRectangle(dwdata->display, dwdata->monitor->draw_buffer,
                               dwdata->monitor->gfx_context, x + 2, 2, button_width - 4, 2);
        }
 
@@ -503,7 +509,6 @@ static int _redraw_statusbar(struct monitor *monitor)
        struct _draw_workspace_data dwdata;
        struct monitor *focused_monitor;
        Display *display;
-       Window root;
        int status_x;
        int status_width;
        int workspace_button_width;
@@ -514,17 +519,9 @@ static int _redraw_statusbar(struct monitor *monitor)
        }
 
        display = mwm_get_display(monitor->mwm);
-       root = mwm_get_root_window(monitor->mwm);
        focused_monitor = mwm_get_focused_monitor(monitor->mwm);
        status[0] = 0;
 
-       /* start with background from root */
-       XCopyArea(display, root, monitor->statusbar,
-                 monitor->gfx_context,
-                 monitor->geom.x, monitor->geom.y,
-                 monitor->geom.w, STATUSBAR_HEIGHT,
-                 0, 0);
-
        /* draw the workspace buttons */
        dwdata.monitor = monitor;
        dwdata.display = display;
@@ -552,21 +549,26 @@ static int _redraw_statusbar(struct monitor *monitor)
        if(status_x < workspace_button_width) {
                status_x = workspace_button_width;
                status_width = monitor->geom.w - status_x;
+       } else if(status_x > workspace_button_width) {
+               XSetForeground(display, monitor->gfx_context,
+                              mwm_get_color(monitor->mwm, dwdata.palette, MWM_COLOR_FOCUSED));
+               XFillRectangle(display, monitor->draw_buffer,
+                              monitor->gfx_context, workspace_button_width, 0,
+                              status_x - workspace_button_width, STATUSBAR_HEIGHT);
        }
 
-       XSetForeground(display, monitor->gfx_context,
-                      mwm_get_color(monitor->mwm, dwdata.palette, MWM_COLOR_FOCUSED));
-       XDrawRectangle(display, monitor->statusbar,
-                      monitor->gfx_context, status_x, 0,
-                      status_width, STATUSBAR_HEIGHT - 1);
        XSetForeground(display, monitor->gfx_context,
                       mwm_get_color(monitor->mwm, dwdata.palette, MWM_COLOR_BACKGROUND));
-       XFillRectangle(display, monitor->statusbar,
-                      monitor->gfx_context, status_x + 1, 0,
-                      status_width - 1, STATUSBAR_HEIGHT - 1);
+       XFillRectangle(display, monitor->draw_buffer,
+                      monitor->gfx_context, status_x, 0,
+                      status_width, STATUSBAR_HEIGHT);
+
        mwm_render_text(monitor->mwm, monitor->xft_context, dwdata.palette, status,
                        status_x + dwdata.text_padding, dwdata.text_padding);
 
+       XCopyArea(display, monitor->draw_buffer, monitor->statusbar, monitor->gfx_context,
+                 0, 0, monitor->geom.w, STATUSBAR_HEIGHT, 0, 0);
+
        return(0);
 }
 
diff --git a/mwm.c b/mwm.c
index 4601a41fcf579ae79be9c5867f59e018df9c1b4c..d839071653502882350711336930b47407561be5 100644 (file)
--- a/mwm.c
+++ b/mwm.c
@@ -1528,6 +1528,18 @@ XftDraw* mwm_create_xft_context(struct mwm *mwm, Drawable drawable)
                             DefaultColormap(mwm->display, mwm->screen)));
 }
 
+Drawable mwm_create_pixmap(struct mwm *mwm, Window window, const int width, const int height)
+{
+       return(XCreatePixmap(mwm->display, window ? window : mwm->root, width, height,
+                            DefaultDepth(mwm->display, mwm->screen)));
+}
+
+void mwm_free_pixmap(struct mwm *mwm, Drawable drawable)
+{
+       XFreePixmap(mwm->display, drawable);
+       return;
+}
+
 int mwm_get_font_height(struct mwm *mwm)
 {
        return(mwm->font.height);
diff --git a/mwm.h b/mwm.h
index 306fa2e796e82c7c9e95109b598ead224949b605..50472e1b584c66dcb85b239f2d4026df25bfea92 100644 (file)
--- a/mwm.h
+++ b/mwm.h
@@ -65,7 +65,8 @@ int mwm_foreach_workspace(struct mwm *mwm,
 Window mwm_create_window(struct mwm *mwm, const int x, const int y, const int w, const int h);
 GC mwm_create_gc(struct mwm *mwm);
 XftDraw* mwm_create_xft_context(struct mwm *mwm, Drawable drawable);
-
+Drawable mwm_create_pixmap(struct mwm *mwm, Window window, const int width, const int height);
+void mwm_free_pixmap(struct mwm *mwm, Drawable drawable);
 int mwm_render_text(struct mwm *mwm, XftDraw *drawable,
                    mwm_palette_t palette, const char *text,
                    const int x, const int y);