From b1cae3d367d5ad9186897f84f8645cc4848024e6 Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Sun, 18 Jun 2023 21:27:31 +0300 Subject: [PATCH 01/15] github: update codeql action's init, autobuild and analyze to v2 addresses this annotation: This version of the CodeQL Action was deprecated on January 18th, 2023, and is no longer updated or supported. For better performance, improved security, and new features, upgrade to v2. For more information, see https://github.blog/changelog/2023-01-18-code-scanning-codeql-action-v1-is-now-deprecated/ partially addresses this annotation: Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: actions/checkout@v2, github/codeql-action/init@v1, github/codeql-action/autobuild@v1, github/codeql-action/analyze@v1. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/. --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c9ebfa6..1471844 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,7 +31,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} @@ -41,7 +41,7 @@ jobs: # Autobuild - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From a5591b33a63ad5e86f659ebd47ba99e07a752184 Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Sun, 18 Jun 2023 21:33:16 +0300 Subject: [PATCH 02/15] github: update actions' checkout to v3 addresses this annotation: Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: actions/checkout@v2. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/. --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/coding-style-pr.yml | 2 +- .github/workflows/coding-style.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1471844..8329bce 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. diff --git a/.github/workflows/coding-style-pr.yml b/.github/workflows/coding-style-pr.yml index c667e3f..5de4c67 100644 --- a/.github/workflows/coding-style-pr.yml +++ b/.github/workflows/coding-style-pr.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: git fetch --depth=1 origin ${{ github.event.pull_request.base.sha }} - uses: yshui/git-clang-format-lint@v1.14 with: diff --git a/.github/workflows/coding-style.yml b/.github/workflows/coding-style.yml index d378113..49f5379 100644 --- a/.github/workflows/coding-style.yml +++ b/.github/workflows/coding-style.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 2 - uses: yshui/git-clang-format-lint@v1.14 From 4911cbc24a478d7150ad788f67e68faca7b792dc Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Sun, 18 Jun 2023 21:37:41 +0300 Subject: [PATCH 03/15] github: don't checkout the head of a pull request addresses this annotation: 1 issue was detected with this workflow: git checkout HEAD^2 is no longer necessary. Please remove this step as Code Scanning recommends analyzing the merge commit for best results. --- .github/workflows/codeql-analysis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8329bce..c0d5d0f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -19,15 +19,6 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL From 9295f7e4c7c54088a6b87bab628a0b6350fb14ba Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sat, 24 Jun 2023 02:49:20 +0100 Subject: [PATCH 04/15] core: don't check RLIMIT_RTPRIO FreeBSD doesn't have RLIMIT_RTPRIO. So instead we skip this check and just always try to set our priority to the lowest SCHED_RR priority available. Fixes #1082 Signed-off-by: Yuxuan Shui --- src/picom.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/picom.c b/src/picom.c index 8a58fe5..9ddb49d 100644 --- a/src/picom.c +++ b/src/picom.c @@ -2577,11 +2577,8 @@ err: return NULL; } void set_rr_scheduling(void) { - struct rlimit rlim; - if (getrlimit(RLIMIT_RTPRIO, &rlim) != 0) { - log_warn("Failed to get RLIMIT_RTPRIO, not setting real-time priority"); - return; - } + int priority = sched_get_priority_min(SCHED_RR); + int old_policy; int ret; struct sched_param param; @@ -2592,14 +2589,15 @@ void set_rr_scheduling(void) { return; } - param.sched_priority = (int)rlim.rlim_cur; - + param.sched_priority = priority; ret = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m); if (ret != 0) { - log_info("Failed to set scheduling priority to %lu", rlim.rlim_cur); + log_info("Failed to set real-time scheduling priority to %d. Consider " + "giving picom the CAP_SYS_NICE capability", + priority); return; } - log_info("Set scheduling priority to %lu", rlim.rlim_cur); + log_info("Set real-time scheduling priority to %d", priority); } /** From e0c14f63c6b2691c2cf8adb2a8e83944f6531833 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sat, 24 Jun 2023 02:59:04 +0100 Subject: [PATCH 05/15] core: don't use pthread functions Don't use pthread_{set,get}schedparam, which requires -lpthread. Use sched_setscheduler/sched_getparam instead, which is provided by libc. Signed-off-by: Yuxuan Shui --- src/picom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/picom.c b/src/picom.c index 9ddb49d..c07626b 100644 --- a/src/picom.c +++ b/src/picom.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -2579,18 +2580,17 @@ err: void set_rr_scheduling(void) { int priority = sched_get_priority_min(SCHED_RR); - int old_policy; int ret; struct sched_param param; - ret = pthread_getschedparam(pthread_self(), &old_policy, ¶m); + ret = sched_getparam(0, ¶m); if (ret != 0) { log_debug("Failed to get old scheduling priority"); return; } param.sched_priority = priority; - ret = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m); + ret = sched_setscheduler(0, SCHED_RR, ¶m); if (ret != 0) { log_info("Failed to set real-time scheduling priority to %d. Consider " "giving picom the CAP_SYS_NICE capability", From f8cdc81635a0405693beb7c802119acbbc426968 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 26 Jun 2023 13:25:53 +0100 Subject: [PATCH 06/15] core: add comment to set_rr_scheduling Signed-off-by: Yuxuan Shui --- src/picom.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/picom.c b/src/picom.c index c07626b..126922e 100644 --- a/src/picom.c +++ b/src/picom.c @@ -2577,6 +2577,14 @@ err: free(ps); return NULL; } + +/// Switch to real-time scheduling policy (SCHED_RR) if possible +/// +/// Make picom realtime to reduce latency, and make rendering times more predictable to +/// help pacing. +/// +/// This requires the user to set up permissions for the real-time scheduling. e.g. by +/// setting `ulimit -r`, or giving us the CAP_SYS_NICE capability. void set_rr_scheduling(void) { int priority = sched_get_priority_min(SCHED_RR); From d08b6092a3f59309e00467d567ee79582c53e5ca Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Mon, 26 Jun 2023 18:01:22 +0300 Subject: [PATCH 07/15] win: don't include GL/gl.h it seems unused and removing it addresses a fixme --- src/win.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/win.h b/src/win.h index fe73340..da46572 100644 --- a/src/win.h +++ b/src/win.h @@ -11,11 +11,6 @@ #include "uthash_extra.h" -// FIXME shouldn't need this -#ifdef CONFIG_OPENGL -#include -#endif - #include "c2.h" #include "compiler.h" #include "list.h" From 6496f753596e3779c15527947801eb40c9abd430 Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Wed, 25 Jan 2023 02:18:36 +0300 Subject: [PATCH 08/15] update contributors list it's (almost) automatically generated from the git log and the contributors' emails are (trivially) obfuscated --- CONTRIBUTORS | 164 +++++++++++++++++++++++++++------------------------ 1 file changed, 87 insertions(+), 77 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9512bf8..d4373ab 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,85 +1,95 @@ -Sorted in alphabetical order -Open an issue or pull request if you don't want your name listed here. +Sorted in alphabetical order. Feel free to open an issue or create a +pull request if you want to change or remove your mention. -Adam Jackson -adelin-b -Alexander Kapshuna -Antonin Décimo -Antonio Vivace -Avi-D-coder -Ben Friesen -Bernd Busse -Bert Gijsbers -bhagwan -Bodhi -Brottweiler -Carl Worth -Christopher Jeffrey -Corax26 -Dan Elkouby -Dana Jansens -Daniel Kwan -Dave Airlie +Adam Jackson +adelin-b +Alexander Kapshuna +Antonin Décimo +Antonio Vivace +Avi ד +Ben Friesen +Bernd Busse +Bert Gijsbers +bhagwan +Bodhi +Brottweiler +Carl Worth +Christopher Jeffrey +Corax26 +Dan Elkouby +Dana Jansens +Daniel Kwan +Dave Airlie David Schlachter dolio -Duncan -Dylan Araps -Einar Lielmanis -Eric Anholt +Duncan +Dylan Araps +Einar Lielmanis +Eric Anholt +Evgeniy Baskov Greg Flynn -Harish Rajagopal -hasufell -Ignacio Taranto +h7x4 +Harish Rajagopal +hasufell +i-c-u-p +Ignacio Taranto Istvan Petres -James Cloos -Jamey Sharp -Jan Beich -Jarrad -Javeed Shaikh -Jerónimo Navarro -jialeens -Johnny Pribyl -Keith Packard -Kevin Kelley -ktprograms -Lukas Schmelzeisen -mæp -Mark Tiefenbruck -Matthew Allum -Maxim Solovyov -Michael Reed -Michele Lambertucci -Namkhai Bourquin -Nate Hart -nia -notfoss -Omar Polo -orbea -@Paradigm0001 +Jake +James Cloos +Jamey Sharp +Jan Beich +Jarrad +Javeed Shaikh +Jerónimo Navarro +jialeens +Johnny Pribyl +Keith Packard +Kevin Kelley +ktprograms +Kurenshe Nurdaulet +Lukas Schmelzeisen +Mark Tiefenbruck +Matthew Allum +Maxim Solovyov +Michael Reed +Michele Lambertucci +mæp +Namkhai Bourquin +Nate Hart +nia +Nikolay Borodin +notfoss +Omar Polo +oofsauce +orbea +Paradigm0001 Patrick Collins -Peter Mattern -Phil Blundell -Que Quotion -Rafael Kitover -Richard Grenville -Rytis Karpuska -Samuel Hand -Scott Leggett -scrouthtv -Sebastien Waegeneire -Subhaditya Nath -Tasos Sahanidis -Thiago Kenji Okada -Tilman Sauerbeck -Tim van Dalen -Tomas Janousek -Tom Dörr +Peter Mattern +Phil Blundell +Que Quotion +Rafael Kitover +Richard Grenville +Rytis Karpuska +Samuel Hand +Scott Leggett +scrouthtv +Sebastien Waegeneire +Stefan Radziuk +Subhaditya Nath +Tasos Sahanidis +Thiago Kenji Okada +Tilman Sauerbeck +Tim Siegel +Tim van Dalen +tokyoneon78 +Tom Dörr +Tomas Janousek Toni Jarjour -Tuomas Kinnunen -Uli Schlachter -Walter Lapchynski -Will Dietz -XeCycle -Yuxuan Shui +Tuomas Kinnunen +Uli Schlachter +Walter Lapchynski +Will Dietz +XeCycle +Yuxuan Shui zilrich -ಠ_ಠ +ಠ_ಠ From d044e3e38663b16778695bb85732798770a361fa Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Wed, 28 Jun 2023 21:21:45 +0300 Subject: [PATCH 09/15] readme: simplify build instructions don't initialize submodules (we don't have any) and specify the source directory explicitly (assume that the current directory is the source one) --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5b358bb..f1f66b0 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,7 @@ To build the documents, you need `asciidoc` ### To build ```bash -$ git submodule update --init --recursive -$ meson setup --buildtype=release . build +$ meson setup --buildtype=release build $ ninja -C build ``` @@ -75,12 +74,12 @@ If you have libraries and/or headers installed at non-default location (e.g. und You can do that by setting the `CPPFLAGS` and `LDFLAGS` environment variables when running `meson`. Like this: ```bash -$ LDFLAGS="-L/path/to/libraries" CPPFLAGS="-I/path/to/headers" meson setup --buildtype=release . build +$ LDFLAGS="-L/path/to/libraries" CPPFLAGS="-I/path/to/headers" meson setup --buildtype=release build ``` As an example, on FreeBSD, you might have to run meson with: ```bash -$ LDFLAGS="-L/usr/local/lib" CPPFLAGS="-I/usr/local/include" meson setup --buildtype=release . build +$ LDFLAGS="-L/usr/local/lib" CPPFLAGS="-I/usr/local/include" meson setup --buildtype=release build $ ninja -C build ``` From d4f72828f76ecacedfc2dcd0fb489f661be72bc8 Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Wed, 28 Jun 2023 21:30:59 +0300 Subject: [PATCH 10/15] gitmodules: remove the .gitmodules file it's unused because we don't have any submodules --- .gitmodules | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29..0000000 From 4e6dddc76e7db7f6c98b3dcb2efce192bae4e17d Mon Sep 17 00:00:00 2001 From: Monsterovich Date: Fri, 30 Jun 2023 00:28:45 +0200 Subject: [PATCH 11/15] win: don't re-bind mask image when there is already one Co-authored-by: Yuxuan Shui --- src/win.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/win.c b/src/win.c index a97733d..1aa10fd 100644 --- a/src/win.c +++ b/src/win.c @@ -368,7 +368,10 @@ bool win_bind_shadow(struct backend_base *b, struct managed_win *w, struct color b->ops->shadow_from_mask == NULL) { w->shadow_image = b->ops->render_shadow(b, w->widthb, w->heightb, sctx, c); } else { - win_bind_mask(b, w); + if (!w->mask_image) { + // It's possible we already allocated a mask because of background blur + win_bind_mask(b, w); + } w->shadow_image = b->ops->shadow_from_mask(b, w->mask_image, sctx, c); } if (!w->shadow_image) { From 1307d9ec709c9fbbe99939d46ad04c57d5e4b501 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Thu, 29 Jun 2023 05:39:36 +0100 Subject: [PATCH 12/15] core: isolate X connection with error handling into a struct Part of the long running effort to reduce the prevalence of `session_t`. After this, functions that communicate with X can make use of the error handling machinary (set_ignore_cookie, set_cant_fail_cookie) without needing to take a `session_t` parameter. This commit converts everything to use the new struct `x_connection`, most of the conversions are mechanical. Signed-off-by: Yuxuan Shui --- src/backend/backend.c | 8 +- src/backend/backend.h | 3 +- src/backend/backend_common.c | 71 +++--- src/backend/backend_common.h | 12 +- src/backend/dummy/dummy.c | 7 +- src/backend/gl/egl.c | 13 +- src/backend/gl/glx.c | 99 ++++---- src/backend/gl/glx.h | 3 +- src/backend/xrender/xrender.c | 184 +++++++-------- src/c2.c | 116 ++++++---- src/common.h | 79 +------ src/dbus.c | 2 +- src/event.c | 62 ++--- src/opengl.c | 33 +-- src/picom.c | 425 ++++++++++++++-------------------- src/picom.h | 2 +- src/render.c | 394 +++++++++++++++++-------------- src/render.h | 2 - src/vsync.c | 20 +- src/win.c | 112 ++++----- src/win.h | 4 +- src/x.c | 230 +++++++++++------- src/x.h | 200 ++++++++++++---- 23 files changed, 1095 insertions(+), 986 deletions(-) diff --git a/src/backend/backend.c b/src/backend/backend.c index da1fa42..f094555 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -91,10 +91,10 @@ void paint_all_new(session_t *ps, struct managed_win *t) { return handle_device_reset(ps); } if (ps->o.xrender_sync_fence) { - if (ps->xsync_exists && !x_fence_sync(ps->c, ps->sync_fence)) { + if (ps->xsync_exists && !x_fence_sync(&ps->c, ps->sync_fence)) { log_error("x_fence_sync failed, xrender-sync-fence will be " "disabled from now on."); - xcb_sync_destroy_fence(ps->c, ps->sync_fence); + xcb_sync_destroy_fence(ps->c.c, ps->sync_fence); ps->sync_fence = XCB_NONE; ps->o.xrender_sync_fence = false; ps->xsync_exists = false; @@ -348,7 +348,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) { } if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 && - w->randr_monitor < ps->randr_nmonitors) { + w->randr_monitor < ps->monitors.count) { // There can be a window where number of monitors is // updated, but the monitor number attached to the window // have not. @@ -358,7 +358,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) { // bounds. pixman_region32_intersect( ®_shadow, ®_shadow, - &ps->randr_monitor_regs[w->randr_monitor]); + &ps->monitors.regions[w->randr_monitor]); } if (ps->o.transparent_clipping) { diff --git a/src/backend/backend.h b/src/backend/backend.h index 7cd64a0..3ed7a76 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -23,8 +23,7 @@ struct backend_operations; typedef struct backend_base { struct backend_operations *ops; - xcb_connection_t *c; - xcb_window_t root; + struct x_connection *c; struct ev_loop *loop; /// Whether the backend can accept new render request at the moment diff --git a/src/backend/backend_common.c b/src/backend/backend_common.c index ecdefa4..5b24c67 100644 --- a/src/backend/backend_common.c +++ b/src/backend/backend_common.c @@ -19,17 +19,18 @@ /** * Generate a 1x1 Picture of a particular color. */ -xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool argb, - double a, double r, double g, double b) { +xcb_render_picture_t +solid_picture(struct x_connection *c, bool argb, double a, double r, double g, double b) { xcb_pixmap_t pixmap; xcb_render_picture_t picture; xcb_render_create_picture_value_list_t pa; xcb_render_color_t col; xcb_rectangle_t rect; - pixmap = x_create_pixmap(c, argb ? 32 : 8, d, 1, 1); - if (!pixmap) + pixmap = x_create_pixmap(c, argb ? 32 : 8, 1, 1); + if (!pixmap) { return XCB_NONE; + } pa.repeat = 1; picture = x_create_picture_with_standard_and_pixmap( @@ -37,7 +38,7 @@ xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool a XCB_RENDER_CP_REPEAT, &pa); if (!picture) { - xcb_free_pixmap(c, pixmap); + xcb_free_pixmap(c->c, pixmap); return XCB_NONE; } @@ -51,14 +52,14 @@ xcb_render_picture_t solid_picture(xcb_connection_t *c, xcb_drawable_t d, bool a rect.width = 1; rect.height = 1; - xcb_render_fill_rectangles(c, XCB_RENDER_PICT_OP_SRC, picture, col, 1, &rect); - xcb_free_pixmap(c, pixmap); + xcb_render_fill_rectangles(c->c, XCB_RENDER_PICT_OP_SRC, picture, col, 1, &rect); + xcb_free_pixmap(c->c, pixmap); return picture; } -xcb_image_t * -make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, int height) { +xcb_image_t *make_shadow(struct x_connection *c, const conv *kernel, double opacity, + int width, int height) { /* * We classify shadows into 4 kinds of regions * r = shadow radius @@ -84,8 +85,9 @@ make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, assert(d % 2 == 1); assert(d > 0); - ximage = xcb_image_create_native(c, to_u16_checked(swidth), to_u16_checked(sheight), - XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL); + ximage = + xcb_image_create_native(c->c, to_u16_checked(swidth), to_u16_checked(sheight), + XCB_IMAGE_FORMAT_Z_PIXMAP, 8, 0, 0, NULL); if (!ximage) { log_error("failed to create an X image"); return 0; @@ -193,7 +195,7 @@ make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, /** * Generate shadow Picture for a window. */ -bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const int width, +bool build_shadow(struct x_connection *c, double opacity, const int width, const int height, const conv *kernel, xcb_render_picture_t shadow_pixel, xcb_pixmap_t *pixmap, xcb_render_picture_t *pict) { xcb_image_t *shadow_image = NULL; @@ -207,9 +209,9 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i return false; } - shadow_pixmap = x_create_pixmap(c, 8, d, shadow_image->width, shadow_image->height); + shadow_pixmap = x_create_pixmap(c, 8, shadow_image->width, shadow_image->height); shadow_pixmap_argb = - x_create_pixmap(c, 32, d, shadow_image->width, shadow_image->height); + x_create_pixmap(c, 32, shadow_image->width, shadow_image->height); if (!shadow_pixmap || !shadow_pixmap_argb) { log_error("Failed to create shadow pixmaps"); @@ -225,11 +227,11 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i } gc = x_new_id(c); - xcb_create_gc(c, gc, shadow_pixmap, 0, NULL); + xcb_create_gc(c->c, gc, shadow_pixmap, 0, NULL); // We need to make room for protocol metadata in the request. The metadata should // be 24 bytes plus padding, let's be generous and give it 1kb - auto maximum_image_size = xcb_get_maximum_request_length(c) * 4 - 1024; + auto maximum_image_size = xcb_get_maximum_request_length(c->c) * 4 - 1024; auto maximum_row = to_u16_checked(clamp(maximum_image_size / shadow_image->stride, 0, UINT16_MAX)); if (maximum_row <= 0) { @@ -248,23 +250,23 @@ bool build_shadow(xcb_connection_t *c, xcb_drawable_t d, double opacity, const i } uint32_t offset = row * shadow_image->stride / sizeof(*shadow_image->data); - xcb_put_image(c, (uint8_t)shadow_image->format, shadow_pixmap, gc, + xcb_put_image(c->c, (uint8_t)shadow_image->format, shadow_pixmap, gc, shadow_image->width, batch_height, 0, to_i16_checked(row), 0, shadow_image->depth, shadow_image->stride * batch_height, shadow_image->data + offset); } - xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, shadow_pixel, shadow_picture, + xcb_render_composite(c->c, XCB_RENDER_PICT_OP_SRC, shadow_pixel, shadow_picture, shadow_picture_argb, 0, 0, 0, 0, 0, 0, shadow_image->width, shadow_image->height); *pixmap = shadow_pixmap_argb; *pict = shadow_picture_argb; - xcb_free_gc(c, gc); + xcb_free_gc(c->c, gc); xcb_image_destroy(shadow_image); - xcb_free_pixmap(c, shadow_pixmap); - xcb_render_free_picture(c, shadow_picture); + xcb_free_pixmap(c->c, shadow_pixmap); + x_free_picture(c, shadow_picture); return true; @@ -273,19 +275,19 @@ shadow_picture_err: xcb_image_destroy(shadow_image); } if (shadow_pixmap) { - xcb_free_pixmap(c, shadow_pixmap); + xcb_free_pixmap(c->c, shadow_pixmap); } if (shadow_pixmap_argb) { - xcb_free_pixmap(c, shadow_pixmap_argb); + xcb_free_pixmap(c->c, shadow_pixmap_argb); } if (shadow_picture) { - xcb_render_free_picture(c, shadow_picture); + x_free_picture(c, shadow_picture); } if (shadow_picture_argb) { - xcb_render_free_picture(c, shadow_picture_argb); + x_free_picture(c, shadow_picture_argb); } if (gc) { - xcb_free_gc(c, gc); + xcb_free_gc(c->c, gc); } return false; @@ -294,22 +296,22 @@ shadow_picture_err: void *default_backend_render_shadow(backend_t *backend_data, int width, int height, struct backend_shadow_context *sctx, struct color color) { const conv *kernel = (void *)sctx; - xcb_render_picture_t shadow_pixel = solid_picture( - backend_data->c, backend_data->root, true, 1, color.red, color.green, color.blue); + xcb_render_picture_t shadow_pixel = + solid_picture(backend_data->c, true, 1, color.red, color.green, color.blue); xcb_pixmap_t shadow = XCB_NONE; xcb_render_picture_t pict = XCB_NONE; - if (!build_shadow(backend_data->c, backend_data->root, color.alpha, width, height, - kernel, shadow_pixel, &shadow, &pict)) { - xcb_render_free_picture(backend_data->c, shadow_pixel); + if (!build_shadow(backend_data->c, color.alpha, width, height, kernel, + shadow_pixel, &shadow, &pict)) { + x_free_picture(backend_data->c, shadow_pixel); return NULL; } auto visual = x_get_visual_for_standard(backend_data->c, XCB_PICT_STANDARD_ARGB_32); void *ret = backend_data->ops->bind_pixmap( backend_data, shadow, x_get_visual_info(backend_data->c, visual), true); - xcb_render_free_picture(backend_data->c, pict); - xcb_render_free_picture(backend_data->c, shadow_pixel); + x_free_picture(backend_data->c, pict); + x_free_picture(backend_data->c, shadow_pixel); return ret; } @@ -506,9 +508,8 @@ struct backend_image *default_new_backend_image(int w, int h) { } void init_backend_base(struct backend_base *base, session_t *ps) { - base->c = ps->c; + base->c = &ps->c; base->loop = ps->loop; - base->root = ps->root; base->busy = false; base->ops = NULL; } diff --git a/src/backend/backend_common.h b/src/backend/backend_common.h index c72a168..2e49cec 100644 --- a/src/backend/backend_common.h +++ b/src/backend/backend_common.h @@ -44,15 +44,15 @@ struct backend_image { int border_width; }; -bool build_shadow(xcb_connection_t *, xcb_drawable_t, double opacity, int width, - int height, const conv *kernel, xcb_render_picture_t shadow_pixel, +bool build_shadow(struct x_connection *, double opacity, int width, int height, + const conv *kernel, xcb_render_picture_t shadow_pixel, xcb_pixmap_t *pixmap, xcb_render_picture_t *pict); -xcb_render_picture_t solid_picture(xcb_connection_t *, xcb_drawable_t, bool argb, - double a, double r, double g, double b); +xcb_render_picture_t +solid_picture(struct x_connection *, bool argb, double a, double r, double g, double b); -xcb_image_t * -make_shadow(xcb_connection_t *c, const conv *kernel, double opacity, int width, int height); +xcb_image_t *make_shadow(struct x_connection *c, const conv *kernel, double opacity, + int width, int height); /// The default implementation of `is_win_transparent`, it simply looks at win::mode. So /// this is not suitable for backends that alter the content of windows diff --git a/src/backend/dummy/dummy.c b/src/backend/dummy/dummy.c index 5f5e122..4e3d713 100644 --- a/src/backend/dummy/dummy.c +++ b/src/backend/dummy/dummy.c @@ -30,9 +30,8 @@ struct dummy_data { struct backend_base *dummy_init(struct session *ps attr_unused) { auto ret = (struct backend_base *)ccalloc(1, struct dummy_data); - ret->c = ps->c; + ret->c = &ps->c; ret->loop = ps->loop; - ret->root = ps->root; ret->busy = false; return ret; } @@ -44,7 +43,7 @@ void dummy_deinit(struct backend_base *data) { HASH_DEL(dummy->images, img); free(img->refcount); if (img->owned) { - xcb_free_pixmap(data->c, img->pixmap); + xcb_free_pixmap(data->c->c, img->pixmap); } free(img); } @@ -118,7 +117,7 @@ void dummy_release_image(backend_t *base, void *image) { HASH_DEL(dummy->images, img); free(img->refcount); if (img->owned) { - xcb_free_pixmap(base->c, img->pixmap); + xcb_free_pixmap(base->c->c, img->pixmap); } free(img); } diff --git a/src/backend/gl/egl.c b/src/backend/gl/egl.c index 761eb63..a78c190 100644 --- a/src/backend/gl/egl.c +++ b/src/backend/gl/egl.c @@ -79,7 +79,7 @@ static void egl_release_image(backend_t *base, struct gl_texture *tex) { } if (p->owned) { - xcb_free_pixmap(base->c, p->pixmap); + xcb_free_pixmap(base->c->c, p->pixmap); p->pixmap = XCB_NONE; } @@ -154,10 +154,10 @@ static backend_t *egl_init(session_t *ps) { } gd = ccalloc(1, struct egl_data); - gd->display = eglGetPlatformDisplayProc(EGL_PLATFORM_X11_EXT, ps->dpy, + gd->display = eglGetPlatformDisplayProc(EGL_PLATFORM_X11_EXT, ps->c.dpy, (EGLAttrib[]){ EGL_PLATFORM_X11_SCREEN_EXT, - ps->scr, + ps->c.screen, EGL_NONE, }); if (gd->display == EGL_NO_DISPLAY) { @@ -190,7 +190,7 @@ static backend_t *egl_init(session_t *ps) { goto end; } - auto visual_info = x_get_visual_info(ps->c, ps->vis); + auto visual_info = x_get_visual_info(&ps->c, ps->c.screen_info->root_visual); EGLConfig config = NULL; int nconfigs = 1; // clang-format off @@ -280,7 +280,8 @@ egl_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b struct egl_data *gd = (void *)base; struct egl_pixmap *eglpixmap = NULL; - auto r = xcb_get_geometry_reply(base->c, xcb_get_geometry(base->c, pixmap), NULL); + auto r = + xcb_get_geometry_reply(base->c->c, xcb_get_geometry(base->c->c, pixmap), NULL); if (!r) { log_error("Invalid pixmap %#010x", pixmap); return NULL; @@ -335,7 +336,7 @@ err: free(eglpixmap); if (owned) { - xcb_free_pixmap(base->c, pixmap); + xcb_free_pixmap(base->c->c, pixmap); } free(wd); return NULL; diff --git a/src/backend/gl/glx.c b/src/backend/gl/glx.c index 80056c6..d30dc9f 100644 --- a/src/backend/gl/glx.c +++ b/src/backend/gl/glx.c @@ -42,8 +42,6 @@ struct _glx_pixmap { struct _glx_data { struct gl_data gl; - Display *display; - int screen; xcb_window_t target_win; GLXContext ctx; }; @@ -52,18 +50,18 @@ struct _glx_data { do { \ if (glXGetFBConfigAttrib(a, b, attr, c)) { \ log_info("Cannot get FBConfig attribute " #attr); \ - continue; \ + break; \ } \ } while (0) -struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvisual_info m) { +struct glx_fbconfig_info *glx_find_fbconfig(struct x_connection *c, struct xvisual_info m) { log_debug("Looking for FBConfig for RGBA%d%d%d%d, depth %d", m.red_size, m.blue_size, m.green_size, m.alpha_size, m.visual_depth); int ncfg; // clang-format off GLXFBConfig *cfg = - glXChooseFBConfig(dpy, screen, (int[]){ + glXChooseFBConfig(c->dpy, c->screen, (int[]){ GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, @@ -87,25 +85,26 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi GLXFBConfig ret; for (int i = 0; i < ncfg; i++) { int depthbuf, stencil, doublebuf, bufsize; - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BUFFER_SIZE, &bufsize); - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_DEPTH_SIZE, &depthbuf); - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_STENCIL_SIZE, &stencil); - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_DOUBLEBUFFER, &doublebuf); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BUFFER_SIZE, &bufsize); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_DEPTH_SIZE, &depthbuf); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_STENCIL_SIZE, &stencil); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_DOUBLEBUFFER, &doublebuf); if (depthbuf + stencil + bufsize * (doublebuf + 1) >= min_cost) { continue; } int red, green, blue; - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_RED_SIZE, &red); - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BLUE_SIZE, &blue); - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_GREEN_SIZE, &green); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_RED_SIZE, &red); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BLUE_SIZE, &blue); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_GREEN_SIZE, &green); if (red != m.red_size || green != m.green_size || blue != m.blue_size) { // Color size doesn't match, this cannot work continue; } int rgb, rgba; - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &rgb); - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &rgba); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &rgb); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, + &rgba); if (!rgb && !rgba) { log_info("FBConfig is neither RGBA nor RGB, we cannot " "handle this setup."); @@ -113,10 +112,9 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi } int visual; - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_VISUAL_ID, &visual); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_VISUAL_ID, &visual); if (m.visual_depth != -1 && - x_get_visual_depth(XGetXCBConnection(dpy), (xcb_visualid_t)visual) != - m.visual_depth) { + x_get_visual_depth(c, (xcb_visualid_t)visual) != m.visual_depth) { // FBConfig and the correspondent X Visual might not have the same // depth. (e.g. 32 bit FBConfig with a 24 bit Visual). This is // quite common, seen in both open source and proprietary drivers. @@ -129,9 +127,9 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi // All check passed, we are using this one. found = true; ret = cfg[i]; - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT, - &texture_tgts); - glXGetFBConfigAttribChecked(dpy, cfg[i], GLX_Y_INVERTED_EXT, &y_inverted); + glXGetFBConfigAttribChecked( + c->dpy, cfg[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT, &texture_tgts); + glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_Y_INVERTED_EXT, &y_inverted); // Prefer the texture format with matching alpha, with the other one as // fallback @@ -161,24 +159,22 @@ struct glx_fbconfig_info *glx_find_fbconfig(Display *dpy, int screen, struct xvi * Free a glx_texture_t. */ static void glx_release_image(backend_t *base, struct gl_texture *tex) { - struct _glx_data *gd = (void *)base; - struct _glx_pixmap *p = tex->user_data; // Release binding if (p->glpixmap && tex->texture) { glBindTexture(GL_TEXTURE_2D, tex->texture); - glXReleaseTexImageEXT(gd->display, p->glpixmap, GLX_FRONT_LEFT_EXT); + glXReleaseTexImageEXT(base->c->dpy, p->glpixmap, GLX_FRONT_LEFT_EXT); glBindTexture(GL_TEXTURE_2D, 0); } // Free GLX Pixmap if (p->glpixmap) { - glXDestroyPixmap(gd->display, p->glpixmap); + glXDestroyPixmap(base->c->dpy, p->glpixmap); p->glpixmap = 0; } if (p->owned) { - xcb_free_pixmap(base->c, p->pixmap); + xcb_free_pixmap(base->c->c, p->pixmap); p->pixmap = XCB_NONE; } @@ -196,8 +192,8 @@ void glx_deinit(backend_t *base) { // Destroy GLX context if (gd->ctx) { - glXMakeCurrent(gd->display, None, NULL); - glXDestroyContext(gd->display, gd->ctx); + glXMakeCurrent(base->c->dpy, None, NULL); + glXDestroyContext(base->c->dpy, gd->ctx); gd->ctx = 0; } @@ -233,12 +229,10 @@ static bool glx_set_swap_interval(int interval, Display *dpy, GLXDrawable drawab */ static backend_t *glx_init(session_t *ps) { bool success = false; - glxext_init(ps->dpy, ps->scr); + glxext_init(ps->c.dpy, ps->c.screen); auto gd = ccalloc(1, struct _glx_data); init_backend_base(&gd->gl.base, ps); - gd->display = ps->dpy; - gd->screen = ps->scr; gd->target_win = session_get_target_window(ps); XVisualInfo *pvis = NULL; @@ -251,8 +245,8 @@ static backend_t *glx_init(session_t *ps) { // Get XVisualInfo int nitems = 0; - XVisualInfo vreq = {.visualid = ps->vis}; - pvis = XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems); + XVisualInfo vreq = {.visualid = ps->c.screen_info->root_visual}; + pvis = XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems); if (!pvis) { log_error("Failed to acquire XVisualInfo for current visual."); goto end; @@ -260,22 +254,22 @@ static backend_t *glx_init(session_t *ps) { // Ensure the visual is double-buffered int value = 0; - if (glXGetConfig(ps->dpy, pvis, GLX_USE_GL, &value) || !value) { + if (glXGetConfig(ps->c.dpy, pvis, GLX_USE_GL, &value) || !value) { log_error("Root visual is not a GL visual."); goto end; } - if (glXGetConfig(ps->dpy, pvis, GLX_STENCIL_SIZE, &value) || !value) { + if (glXGetConfig(ps->c.dpy, pvis, GLX_STENCIL_SIZE, &value) || !value) { log_error("Root visual lacks stencil buffer."); goto end; } - if (glXGetConfig(ps->dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) { + if (glXGetConfig(ps->c.dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) { log_error("Root visual is not a double buffered GL visual."); goto end; } - if (glXGetConfig(ps->dpy, pvis, GLX_RGBA, &value) || !value) { + if (glXGetConfig(ps->c.dpy, pvis, GLX_RGBA, &value) || !value) { log_error("Root visual is a color index visual, not supported"); goto end; } @@ -293,11 +287,11 @@ static backend_t *glx_init(session_t *ps) { // Find a fbconfig with visualid matching the one from the target win, so we can // be sure that the fbconfig is compatible with our target window. int ncfgs; - GLXFBConfig *cfg = glXGetFBConfigs(gd->display, gd->screen, &ncfgs); + GLXFBConfig *cfg = glXGetFBConfigs(ps->c.dpy, ps->c.screen, &ncfgs); bool found = false; for (int i = 0; i < ncfgs; i++) { int visualid; - glXGetFBConfigAttribChecked(gd->display, cfg[i], GLX_VISUAL_ID, &visualid); + glXGetFBConfigAttribChecked(ps->c.dpy, cfg[i], GLX_VISUAL_ID, &visualid); if ((VisualID)visualid != pvis->visualid) { continue; } @@ -316,7 +310,7 @@ static backend_t *glx_init(session_t *ps) { attributes[7] = GLX_LOSE_CONTEXT_ON_RESET_ARB; } - gd->ctx = glXCreateContextAttribsARB(ps->dpy, cfg[i], 0, true, attributes); + gd->ctx = glXCreateContextAttribsARB(ps->c.dpy, cfg[i], 0, true, attributes); free(cfg); if (!gd->ctx) { @@ -334,7 +328,7 @@ static backend_t *glx_init(session_t *ps) { // Attach GLX context GLXDrawable tgt = gd->target_win; - if (!glXMakeCurrent(ps->dpy, tgt, gd->ctx)) { + if (!glXMakeCurrent(ps->c.dpy, tgt, gd->ctx)) { log_error("Failed to attach GLX context."); goto end; } @@ -348,11 +342,11 @@ static backend_t *glx_init(session_t *ps) { gd->gl.release_user_data = glx_release_image; if (ps->o.vsync) { - if (!glx_set_swap_interval(1, ps->dpy, tgt)) { + if (!glx_set_swap_interval(1, ps->c.dpy, tgt)) { log_error("Failed to enable vsync."); } } else { - glx_set_swap_interval(0, ps->dpy, tgt); + glx_set_swap_interval(0, ps->c.dpy, tgt); } success = true; @@ -372,7 +366,6 @@ end: static void * glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) { - struct _glx_data *gd = (void *)base; struct _glx_pixmap *glxpixmap = NULL; // Retrieve pixmap parameters, if they aren't provided if (fmt.visual_depth > OPENGL_MAX_DEPTH) { @@ -386,7 +379,8 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b return false; } - auto r = xcb_get_geometry_reply(base->c, xcb_get_geometry(base->c, pixmap), NULL); + auto r = + xcb_get_geometry_reply(base->c->c, xcb_get_geometry(base->c->c, pixmap), NULL); if (!r) { log_error("Invalid pixmap %#010x", pixmap); return NULL; @@ -400,7 +394,7 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b wd->inner = (struct backend_image_inner_base *)inner; free(r); - auto fbcfg = glx_find_fbconfig(gd->display, gd->screen, fmt); + auto fbcfg = glx_find_fbconfig(base->c, fmt); if (!fbcfg) { log_error("Couldn't find FBConfig with requested visual %x", fmt.visual); goto err; @@ -429,7 +423,7 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b glxpixmap = cmalloc(struct _glx_pixmap); glxpixmap->pixmap = pixmap; - glxpixmap->glpixmap = glXCreatePixmap(gd->display, fbcfg->cfg, pixmap, attrs); + glxpixmap->glpixmap = glXCreatePixmap(base->c->dpy, fbcfg->cfg, pixmap, attrs); glxpixmap->owned = owned; free(fbcfg); @@ -446,19 +440,19 @@ glx_bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, b inner->has_alpha = fmt.alpha_size != 0; wd->inner->refcount = 1; glBindTexture(GL_TEXTURE_2D, inner->texture); - glXBindTexImageEXT(gd->display, glxpixmap->glpixmap, GLX_FRONT_LEFT_EXT, NULL); + glXBindTexImageEXT(base->c->dpy, glxpixmap->glpixmap, GLX_FRONT_LEFT_EXT, NULL); glBindTexture(GL_TEXTURE_2D, 0); gl_check_err(); return wd; err: if (glxpixmap && glxpixmap->glpixmap) { - glXDestroyPixmap(gd->display, glxpixmap->glpixmap); + glXDestroyPixmap(base->c->dpy, glxpixmap->glpixmap); } free(glxpixmap); if (owned) { - xcb_free_pixmap(base->c, pixmap); + xcb_free_pixmap(base->c->c, pixmap); } free(wd); return NULL; @@ -467,7 +461,7 @@ err: static void glx_present(backend_t *base, const region_t *region attr_unused) { struct _glx_data *gd = (void *)base; gl_present(base, region); - glXSwapBuffers(gd->display, gd->target_win); + glXSwapBuffers(base->c->dpy, gd->target_win); } static int glx_buffer_age(backend_t *base) { @@ -477,15 +471,14 @@ static int glx_buffer_age(backend_t *base) { struct _glx_data *gd = (void *)base; unsigned int val; - glXQueryDrawable(gd->display, gd->target_win, GLX_BACK_BUFFER_AGE_EXT, &val); + glXQueryDrawable(base->c->dpy, gd->target_win, GLX_BACK_BUFFER_AGE_EXT, &val); return (int)val ?: -1; } static void glx_diagnostics(backend_t *base) { - struct _glx_data *gd = (void *)base; bool warn_software_rendering = false; const char *software_renderer_names[] = {"llvmpipe", "SWR", "softpipe"}; - auto glx_vendor = glXGetClientString(gd->display, GLX_VENDOR); + auto glx_vendor = glXGetClientString(base->c->dpy, GLX_VENDOR); printf("* Driver vendors:\n"); printf(" * GLX: %s\n", glx_vendor); printf(" * GL: %s\n", glGetString(GL_VENDOR)); diff --git a/src/backend/gl/glx.h b/src/backend/gl/glx.h index 44b4da0..ce8702a 100644 --- a/src/backend/gl/glx.h +++ b/src/backend/gl/glx.h @@ -41,8 +41,7 @@ struct glx_fbconfig_criteria { int visual_depth; }; -struct glx_fbconfig_info *glx_find_fbconfig(Display *, int screen, struct xvisual_info); - +struct glx_fbconfig_info *glx_find_fbconfig(struct x_connection *, struct xvisual_info); struct glxext_info { bool initialized; diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index 0041817..bb2acd4 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -28,7 +28,6 @@ typedef struct _xrender_data { backend_t base; /// If vsync is enabled and supported by the current system bool vsync; - xcb_visualid_t default_visual; /// Target window xcb_window_t target_win; /// Painting target, it is either the root or the overlay @@ -104,9 +103,9 @@ struct xrender_image { /// Make a picture of size width x height, which has a rounded rectangle of corner_radius /// rendered in it. struct xrender_rounded_rectangle_cache * -make_rounded_corner_cache(xcb_connection_t *c, xcb_render_picture_t src, - xcb_drawable_t root, int width, int height, int corner_radius) { - auto picture = x_create_picture_with_standard(c, root, width, height, +make_rounded_corner_cache(struct x_connection *c, xcb_render_picture_t src, int width, + int height, int corner_radius) { + auto picture = x_create_picture_with_standard(c, width, height, XCB_PICT_STANDARD_ARGB_32, 0, NULL); if (picture == XCB_NONE) { return NULL; @@ -160,7 +159,7 @@ make_rounded_corner_cache(xcb_connection_t *c, xcb_render_picture_t src, } #undef ADD_POINT - XCB_AWAIT_VOID(xcb_render_tri_strip, c, XCB_RENDER_PICT_OP_SRC, src, picture, + XCB_AWAIT_VOID(xcb_render_tri_strip, c->c, XCB_RENDER_PICT_OP_SRC, src, picture, x_get_pictfmt_for_standard(c, XCB_PICT_STANDARD_A_8), 0, 0, (uint32_t)point_count, points); free(points); @@ -182,30 +181,29 @@ static xcb_render_picture_t process_mask(struct _xrender_data *xd, struct xrende *allocated = true; x_clear_picture_clip_region(xd->base.c, inner->pict); auto ret = x_create_picture_with_visual( - xd->base.c, xd->base.root, inner->width, inner->height, inner->visual, - XCB_RENDER_CP_REPEAT, + xd->base.c, inner->width, inner->height, inner->visual, XCB_RENDER_CP_REPEAT, (xcb_render_create_picture_value_list_t[]){XCB_RENDER_REPEAT_PAD}); - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_SRC, inner->pict, XCB_NONE, + xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_SRC, inner->pict, XCB_NONE, ret, 0, 0, 0, 0, 0, 0, tmpw, tmph); // Remember: the mask has a 1-pixel border if (mask->base.corner_radius != 0) { if (mask->rounded_rectangle == NULL) { mask->rounded_rectangle = make_rounded_corner_cache( - xd->base.c, xd->white_pixel, xd->base.root, inner->width - 2, + xd->base.c, xd->white_pixel, inner->width - 2, inner->height - 2, (int)mask->base.corner_radius); } - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_IN_REVERSE, + xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_IN_REVERSE, mask->rounded_rectangle->p, XCB_NONE, ret, 0, 0, 0, 0, 1, 1, (uint16_t)(tmpw - 2), (uint16_t)(tmph - 2)); } if (mask->base.color_inverted) { - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_XOR, xd->white_pixel, + xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_XOR, xd->white_pixel, XCB_NONE, ret, 0, 0, 0, 0, 0, 0, tmpw, tmph); } if (alpha_pict != XCB_NONE) { - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_SRC, ret, alpha_pict, + xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_SRC, ret, alpha_pict, ret, 0, 0, 0, 0, 0, 0, to_u16_checked(inner->width), to_u16_checked(inner->height)); } @@ -246,43 +244,43 @@ compose_impl(struct _xrender_data *xd, struct xrender_image *xrimg, coord_t dst, pixman_region32_intersect(®, (region_t *)reg_paint, (region_t *)reg_visible); x_set_picture_clip_region(xd->base.c, result, 0, 0, ®); if (img->corner_radius != 0 && xrimg->rounded_rectangle == NULL) { - xrimg->rounded_rectangle = make_rounded_corner_cache( - xd->base.c, xd->white_pixel, xd->base.root, inner->width, - inner->height, (int)img->corner_radius); + xrimg->rounded_rectangle = + make_rounded_corner_cache(xd->base.c, xd->white_pixel, inner->width, + inner->height, (int)img->corner_radius); } if (((img->color_inverted || img->dim != 0) && has_alpha) || img->corner_radius != 0) { // Apply image properties using a temporary image, because the source // image is transparent. Otherwise the properties can be applied directly // on the target image. - auto tmp_pict = - x_create_picture_with_visual(xd->base.c, xd->base.root, inner->width, - inner->height, inner->visual, 0, NULL); + auto tmp_pict = x_create_picture_with_visual( + xd->base.c, inner->width, inner->height, inner->visual, 0, NULL); // Set clip region translated to source coordinate x_set_picture_clip_region(xd->base.c, tmp_pict, to_i16_checked(-dst.x), to_i16_checked(-dst.y), ®); // Copy source -> tmp - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_SRC, inner->pict, + xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_SRC, inner->pict, XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph); if (img->color_inverted) { if (inner->has_alpha) { auto tmp_pict2 = x_create_picture_with_visual( - xd->base.c, xd->base.root, tmpw, tmph, inner->visual, - 0, NULL); - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_SRC, + xd->base.c, tmpw, tmph, inner->visual, 0, NULL); + xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_SRC, tmp_pict, XCB_NONE, tmp_pict2, 0, 0, 0, 0, 0, 0, tmpw, tmph); - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_DIFFERENCE, + xcb_render_composite(xd->base.c->c, + XCB_RENDER_PICT_OP_DIFFERENCE, xd->white_pixel, XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph); xcb_render_composite( - xd->base.c, XCB_RENDER_PICT_OP_IN_REVERSE, tmp_pict2, + xd->base.c->c, XCB_RENDER_PICT_OP_IN_REVERSE, tmp_pict2, XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph); - xcb_render_free_picture(xd->base.c, tmp_pict2); + x_free_picture(xd->base.c, tmp_pict2); } else { - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_DIFFERENCE, + xcb_render_composite(xd->base.c->c, + XCB_RENDER_PICT_OP_DIFFERENCE, xd->white_pixel, XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph); } @@ -297,33 +295,34 @@ compose_impl(struct _xrender_data *xd, struct xrender_image *xrimg, coord_t dst, .height = tmph, }; - xcb_render_fill_rectangles(xd->base.c, XCB_RENDER_PICT_OP_OVER, + xcb_render_fill_rectangles(xd->base.c->c, XCB_RENDER_PICT_OP_OVER, tmp_pict, dim_color, 1, &rect); } if (img->corner_radius != 0 && xrimg->rounded_rectangle != NULL) { // Clip tmp_pict with a rounded rectangle - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_IN_REVERSE, + xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_IN_REVERSE, xrimg->rounded_rectangle->p, XCB_NONE, tmp_pict, 0, 0, 0, 0, 0, 0, tmpw, tmph); } - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_OVER, tmp_pict, + xcb_render_composite(xd->base.c->c, XCB_RENDER_PICT_OP_OVER, tmp_pict, mask_pict, result, 0, 0, mask_dst_x, mask_dst_y, to_i16_checked(dst.x), to_i16_checked(dst.y), tmpew, tmpeh); - xcb_render_free_picture(xd->base.c, tmp_pict); + xcb_render_free_picture(xd->base.c->c, tmp_pict); } else { uint8_t op = (has_alpha ? XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC); - xcb_render_composite(xd->base.c, op, inner->pict, mask_pict, result, 0, 0, - mask_dst_x, mask_dst_y, to_i16_checked(dst.x), + xcb_render_composite(xd->base.c->c, op, inner->pict, mask_pict, result, 0, + 0, mask_dst_x, mask_dst_y, to_i16_checked(dst.x), to_i16_checked(dst.y), tmpew, tmpeh); if (img->dim != 0 || img->color_inverted) { // Apply properties, if we reach here, then has_alpha == false assert(!has_alpha); if (img->color_inverted) { - xcb_render_composite(xd->base.c, XCB_RENDER_PICT_OP_DIFFERENCE, + xcb_render_composite(xd->base.c->c, + XCB_RENDER_PICT_OP_DIFFERENCE, xd->white_pixel, XCB_NONE, result, 0, 0, 0, 0, to_i16_checked(dst.x), to_i16_checked(dst.y), tmpew, tmpeh); @@ -338,13 +337,14 @@ compose_impl(struct _xrender_data *xd, struct xrender_image *xrimg, coord_t dst, .height = tmpeh, }; - xcb_render_fill_rectangles(xd->base.c, XCB_RENDER_PICT_OP_OVER, + xcb_render_fill_rectangles(xd->base.c->c, + XCB_RENDER_PICT_OP_OVER, result, dim_color, 1, &rect); } } } if (mask_allocated) { - xcb_render_free_picture(xd->base.c, mask_pict); + x_free_picture(xd->base.c, mask_pict); } pixman_region32_fini(®); } @@ -362,7 +362,7 @@ static void fill(backend_t *base, struct color c, const region_t *clip) { x_set_picture_clip_region(base->c, xd->back[2], 0, 0, clip); // color is in X fixed point representation xcb_render_fill_rectangles( - base->c, XCB_RENDER_PICT_OP_OVER, xd->back[2], + base->c->c, XCB_RENDER_PICT_OP_OVER, xd->back[2], (xcb_render_color_t){.red = (uint16_t)(c.red * 0xffff), .green = (uint16_t)(c.green * 0xffff), .blue = (uint16_t)(c.blue * 0xffff), @@ -382,7 +382,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask } struct _xrender_data *xd = (void *)backend_data; - xcb_connection_t *c = xd->base.c; + auto c = xd->base.c; region_t reg_op; pixman_region32_init(®_op); pixman_region32_intersect(®_op, (region_t *)reg_blur, (region_t *)reg_visible); @@ -405,10 +405,12 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT; const xcb_render_create_picture_value_list_t pic_attrs = {.repeat = XCB_RENDER_REPEAT_PAD}; xcb_render_picture_t tmp_picture[2] = { - x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized, height_resized, - xd->default_visual, pic_attrs_mask, &pic_attrs), - x_create_picture_with_visual(xd->base.c, xd->base.root, width_resized, height_resized, - xd->default_visual, pic_attrs_mask, &pic_attrs)}; + x_create_picture_with_visual(xd->base.c, width_resized, height_resized, + xd->base.c->screen_info->root_visual, + pic_attrs_mask, &pic_attrs), + x_create_picture_with_visual(xd->base.c, width_resized, height_resized, + xd->base.c->screen_info->root_visual, + pic_attrs_mask, &pic_attrs)}; if (!tmp_picture[0] || !tmp_picture[1]) { log_error("Failed to build intermediate Picture."); @@ -445,8 +447,8 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask // Copy from source picture to destination. The filter must // be applied on source picture, to get the nearby pixels outside the // window. - xcb_render_set_picture_filter(c, src_pict, to_u16_checked(strlen(filter)), - filter, + xcb_render_set_picture_filter(c->c, src_pict, + to_u16_checked(strlen(filter)), filter, to_u32_checked(bctx->x_blur_kernel[i]->size), bctx->x_blur_kernel[i]->kernel); @@ -454,21 +456,21 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask // First pass, back buffer -> tmp picture // (we do this even if this is also the last pass, because we // cannot do back buffer -> back buffer) - xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, + xcb_render_composite(c->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, dst_pict, to_i16_checked(extent_resized->x1), to_i16_checked(extent_resized->y1), 0, 0, 0, 0, width_resized, height_resized); } else if (i < bctx->x_blur_kernel_count - 1) { // This is not the last pass or the first pass, // tmp picture 1 -> tmp picture 2 - xcb_render_composite(c, XCB_RENDER_PICT_OP_SRC, src_pict, + xcb_render_composite(c->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, dst_pict, 0, 0, 0, 0, 0, 0, width_resized, height_resized); } else { x_set_picture_clip_region(c, xd->back[2], 0, 0, ®_op); // This is the last pass, and we are doing more than 1 pass xcb_render_composite( - c, XCB_RENDER_PICT_OP_OVER, src_pict, mask_pict, xd->back[2], + c->c, XCB_RENDER_PICT_OP_OVER, src_pict, mask_pict, xd->back[2], 0, 0, to_i16_checked(extent_resized->x1 - mask_dst.x + 1), to_i16_checked(extent_resized->y1 - mask_dst.y + 1), to_i16_checked(extent_resized->x1), @@ -477,7 +479,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask // reset filter xcb_render_set_picture_filter( - c, src_pict, to_u16_checked(strlen(filter0)), filter0, 0, NULL); + c->c, src_pict, to_u16_checked(strlen(filter0)), filter0, 0, NULL); src_pict = tmp_picture[current]; dst_pict = tmp_picture[!current]; @@ -488,15 +490,15 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask if (i == 1) { x_set_picture_clip_region(c, xd->back[2], 0, 0, ®_op); xcb_render_composite( - c, XCB_RENDER_PICT_OP_OVER, src_pict, mask_pict, xd->back[2], 0, 0, + c->c, XCB_RENDER_PICT_OP_OVER, src_pict, mask_pict, xd->back[2], 0, 0, to_i16_checked(extent_resized->x1 - mask_dst.x + 1), to_i16_checked(extent_resized->y1 - mask_dst.y + 1), to_i16_checked(extent_resized->x1), to_i16_checked(extent_resized->y1), width_resized, height_resized); } - xcb_render_free_picture(c, tmp_picture[0]); - xcb_render_free_picture(c, tmp_picture[1]); + x_free_picture(c, tmp_picture[0]); + x_free_picture(c, tmp_picture[1]); pixman_region32_fini(®_op); pixman_region32_fini(®_op_resized); return true; @@ -505,7 +507,7 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_, void *mask static void * bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) { xcb_generic_error_t *e; - auto r = xcb_get_geometry_reply(base->c, xcb_get_geometry(base->c, pixmap), &e); + auto r = xcb_get_geometry_reply(base->c->c, xcb_get_geometry(base->c->c, pixmap), &e); if (!r) { log_error("Invalid pixmap: %#010x", pixmap); x_print_error(e->full_sequence, e->major_code, e->minor_code, e->error_code); @@ -540,9 +542,9 @@ bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool return img; } static void release_image_inner(backend_t *base, struct _xrender_image_data_inner *inner) { - xcb_render_free_picture(base->c, inner->pict); + x_free_picture(base->c, inner->pict); if (inner->owned) { - xcb_free_pixmap(base->c, inner->pixmap); + xcb_free_pixmap(base->c->c, inner->pixmap); } free(inner); } @@ -556,7 +558,7 @@ release_rounded_corner_cache(backend_t *base, struct xrender_rounded_rectangle_c assert(cache->refcount > 0); cache->refcount--; if (cache->refcount == 0) { - xcb_render_free_picture(base->c, cache->p); + x_free_picture(base->c, cache->p); free(cache); } } @@ -575,22 +577,22 @@ static void release_image(backend_t *base, void *image) { static void deinit(backend_t *backend_data) { struct _xrender_data *xd = (void *)backend_data; for (int i = 0; i < 256; i++) { - xcb_render_free_picture(xd->base.c, xd->alpha_pict[i]); + x_free_picture(xd->base.c, xd->alpha_pict[i]); } - xcb_render_free_picture(xd->base.c, xd->target); + x_free_picture(xd->base.c, xd->target); for (int i = 0; i < 3; i++) { if (xd->back[i] != XCB_NONE) { - xcb_render_free_picture(xd->base.c, xd->back[i]); + x_free_picture(xd->base.c, xd->back[i]); } if (xd->back_pixmap[i] != XCB_NONE) { - xcb_free_pixmap(xd->base.c, xd->back_pixmap[i]); + xcb_free_pixmap(xd->base.c->c, xd->back_pixmap[i]); } } if (xd->present_event) { - xcb_unregister_for_special_event(xd->base.c, xd->present_event); + xcb_unregister_for_special_event(xd->base.c->c, xd->present_event); } - xcb_render_free_picture(xd->base.c, xd->white_pixel); - xcb_render_free_picture(xd->base.c, xd->black_pixel); + x_free_picture(xd->base.c, xd->white_pixel); + x_free_picture(xd->base.c, xd->black_pixel); free(xd); } @@ -609,7 +611,7 @@ static void present(backend_t *base, const region_t *region) { x_clear_picture_clip_region(base->c, xd->back[xd->curr_back]); // Update the back buffer first, then present - xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, xd->back[2], + xcb_render_composite(base->c->c, XCB_RENDER_PICT_OP_SRC, xd->back[2], XCB_NONE, xd->back[xd->curr_back], orig_x, orig_y, 0, 0, orig_x, orig_y, region_width, region_height); @@ -618,10 +620,10 @@ static void present(backend_t *base, const region_t *region) { // Make sure we got reply from PresentPixmap before waiting for events, // to avoid deadlock auto e = xcb_request_check( - base->c, xcb_present_pixmap_checked( - xd->base.c, xd->target_win, - xd->back_pixmap[xd->curr_back], 0, XCB_NONE, xregion, 0, - 0, XCB_NONE, XCB_NONE, XCB_NONE, 0, 0, 0, 0, 0, NULL)); + base->c->c, xcb_present_pixmap_checked( + xd->base.c->c, xd->target_win, + xd->back_pixmap[xd->curr_back], 0, XCB_NONE, xregion, 0, + 0, XCB_NONE, XCB_NONE, XCB_NONE, 0, 0, 0, 0, 0, NULL)); x_destroy_region(base->c, xregion); if (e) { log_error("Failed to present pixmap"); @@ -630,7 +632,7 @@ static void present(backend_t *base, const region_t *region) { } // TODO(yshui) don't block wait for present completion xcb_present_generic_event_t *pev = - (void *)xcb_wait_for_special_event(base->c, xd->present_event); + (void *)xcb_wait_for_special_event(base->c->c, xd->present_event); if (!pev) { // We don't know what happened, maybe X died // But reset buffer age, so in case we do recover, we will @@ -654,7 +656,7 @@ static void present(backend_t *base, const region_t *region) { free(pev); } else { // No vsync needed, draw into the target picture directly - xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, xd->back[2], + xcb_render_composite(base->c->c, XCB_RENDER_PICT_OP_SRC, xd->back[2], XCB_NONE, xd->target, orig_x, orig_y, 0, 0, orig_x, orig_y, region_width, region_height); } @@ -673,7 +675,7 @@ static int buffer_age(backend_t *backend_data) { static struct _xrender_image_data_inner * new_inner(backend_t *base, int w, int h, xcb_visualid_t visual, uint8_t depth) { auto new_inner = ccalloc(1, struct _xrender_image_data_inner); - new_inner->pixmap = x_create_pixmap(base->c, depth, base->root, w, h); + new_inner->pixmap = x_create_pixmap(base->c, depth, w, h); if (new_inner->pixmap == XCB_NONE) { log_error("Failed to create pixmap for copy"); free(new_inner); @@ -683,7 +685,7 @@ new_inner(backend_t *base, int w, int h, xcb_visualid_t visual, uint8_t depth) { base->c, visual, new_inner->pixmap, 0, NULL); if (new_inner->pict == XCB_NONE) { log_error("Failed to create picture for copy"); - xcb_free_pixmap(base->c, new_inner->pixmap); + xcb_free_pixmap(base->c->c, new_inner->pixmap); free(new_inner); return NULL; } @@ -705,12 +707,12 @@ static void *make_mask(backend_t *base, geometry_t size, const region_t *reg) { auto inner = new_inner(base, size.width + 2, size.height + 2, x_get_visual_for_standard(base->c, XCB_PICT_STANDARD_ARGB_32), 32); - xcb_render_change_picture(base->c, inner->pict, XCB_RENDER_CP_REPEAT, + xcb_render_change_picture(base->c->c, inner->pict, XCB_RENDER_CP_REPEAT, (uint32_t[]){XCB_RENDER_REPEAT_PAD}); const rect_t *extent = pixman_region32_extents((region_t *)reg); x_set_picture_clip_region(base->c, xd->back[2], 1, 1, reg); xcb_render_fill_rectangles( - base->c, XCB_RENDER_PICT_OP_SRC, inner->pict, + base->c->c, XCB_RENDER_PICT_OP_SRC, inner->pict, (xcb_render_color_t){.red = 0, .green = 0, .blue = 0, .alpha = 0xffff}, 1, (xcb_rectangle_t[]){{.x = to_i16_checked(extent->x1 + 1), .y = to_i16_checked(extent->y1 + 1), @@ -720,7 +722,7 @@ static void *make_mask(backend_t *base, geometry_t size, const region_t *reg) { // Paint the border transparent xcb_render_fill_rectangles( - base->c, XCB_RENDER_PICT_OP_SRC, inner->pict, + base->c->c, XCB_RENDER_PICT_OP_SRC, inner->pict, (xcb_render_color_t){.red = 0, .green = 0, .blue = 0, .alpha = 0}, 4, (xcb_rectangle_t[]){{.x = 0, .y = 0, .width = w16, .height = 1}, {.x = 0, .y = 0, .width = 1, .height = h16}, @@ -758,7 +760,7 @@ static bool decouple_image(backend_t *base, struct backend_image *img, const reg } x_set_picture_clip_region(base->c, inner->pict, 0, 0, reg); - xcb_render_composite(base->c, XCB_RENDER_PICT_OP_SRC, inner->pict, XCB_NONE, + xcb_render_composite(base->c->c, XCB_RENDER_PICT_OP_SRC, inner->pict, XCB_NONE, inner2->pict, 0, 0, 0, 0, 0, 0, to_u16_checked(inner->width), to_u16_checked(inner->height)); @@ -797,8 +799,8 @@ static bool image_op(backend_t *base, enum image_operations op, void *image, auto inner = (struct _xrender_image_data_inner *)img->inner; auto alpha_pict = xd->alpha_pict[(int)((1 - dargs[0]) * MAX_ALPHA)]; x_set_picture_clip_region(base->c, inner->pict, 0, 0, ®); - xcb_render_composite(base->c, XCB_RENDER_PICT_OP_OUT_REVERSE, alpha_pict, - XCB_NONE, inner->pict, 0, 0, 0, 0, 0, 0, + xcb_render_composite(base->c->c, XCB_RENDER_PICT_OP_OUT_REVERSE, + alpha_pict, XCB_NONE, inner->pict, 0, 0, 0, 0, 0, 0, to_u16_checked(inner->width), to_u16_checked(inner->height)); inner->has_alpha = true; @@ -877,24 +879,24 @@ static backend_t *backend_xrender_init(session_t *ps) { for (int i = 0; i <= MAX_ALPHA; ++i) { double o = (double)i / (double)MAX_ALPHA; - xd->alpha_pict[i] = solid_picture(ps->c, ps->root, false, o, 0, 0, 0); + xd->alpha_pict[i] = solid_picture(&ps->c, false, o, 0, 0, 0); assert(xd->alpha_pict[i] != XCB_NONE); } xd->target_width = ps->root_width; xd->target_height = ps->root_height; - xd->default_visual = ps->vis; - xd->black_pixel = solid_picture(ps->c, ps->root, true, 1, 0, 0, 0); - xd->white_pixel = solid_picture(ps->c, ps->root, true, 1, 1, 1, 1); + xd->black_pixel = solid_picture(&ps->c, true, 1, 0, 0, 0); + xd->white_pixel = solid_picture(&ps->c, true, 1, 1, 1, 1); xd->target_win = session_get_target_window(ps); xcb_render_create_picture_value_list_t pa = { .subwindowmode = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS, }; xd->target = x_create_picture_with_visual_and_pixmap( - ps->c, ps->vis, xd->target_win, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); + &ps->c, ps->c.screen_info->root_visual, xd->target_win, + XCB_RENDER_CP_SUBWINDOW_MODE, &pa); - auto pictfmt = x_get_pictform_for_visual(ps->c, ps->vis); + auto pictfmt = x_get_pictform_for_visual(&ps->c, ps->c.screen_info->root_visual); if (!pictfmt) { log_fatal("Default visual is invalid"); abort(); @@ -902,11 +904,11 @@ static backend_t *backend_xrender_init(session_t *ps) { xd->vsync = ps->o.vsync; if (ps->present_exists) { - auto eid = x_new_id(ps->c); + auto eid = x_new_id(&ps->c); auto e = - xcb_request_check(ps->c, xcb_present_select_input_checked( - ps->c, eid, xd->target_win, - XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY)); + xcb_request_check(ps->c.c, xcb_present_select_input_checked( + ps->c.c, eid, xd->target_win, + XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY)); if (e) { log_error("Cannot select present input, vsync will be disabled"); xd->vsync = false; @@ -914,7 +916,7 @@ static backend_t *backend_xrender_init(session_t *ps) { } xd->present_event = - xcb_register_for_special_xge(ps->c, &xcb_present_id, eid, NULL); + xcb_register_for_special_xge(ps->c.c, &xcb_present_id, eid, NULL); if (!xd->present_event) { log_error("Cannot register for special XGE, vsync will be " "disabled"); @@ -928,14 +930,14 @@ static backend_t *backend_xrender_init(session_t *ps) { // double buffering. int first_buffer_index = xd->vsync ? 0 : 2; for (int i = first_buffer_index; i < 3; i++) { - xd->back_pixmap[i] = x_create_pixmap(ps->c, pictfmt->depth, ps->root, - to_u16_checked(ps->root_width), - to_u16_checked(ps->root_height)); + xd->back_pixmap[i] = + x_create_pixmap(&ps->c, pictfmt->depth, to_u16_checked(ps->root_width), + to_u16_checked(ps->root_height)); const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT; const xcb_render_create_picture_value_list_t pic_attrs = { .repeat = XCB_RENDER_REPEAT_PAD}; xd->back[i] = x_create_picture_with_pictfmt_and_pixmap( - ps->c, pictfmt, xd->back_pixmap[i], pic_attrs_mask, &pic_attrs); + &ps->c, pictfmt, xd->back_pixmap[i], pic_attrs_mask, &pic_attrs); xd->buffer_age[i] = -1; if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) { log_error("Cannot create pixmap for rendering"); diff --git a/src/c2.c b/src/c2.c index f8af699..823d30e 100644 --- a/src/c2.c +++ b/src/c2.c @@ -336,17 +336,19 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p * Parse a condition string. */ c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data) { - if (!pattern) + if (!pattern) { return NULL; + } // Parse the pattern c2_ptr_t result = C2_PTR_INIT; int offset = -1; - if (strlen(pattern) >= 2 && ':' == pattern[1]) + if (strlen(pattern) >= 2 && ':' == pattern[1]) { offset = c2_parse_legacy(pattern, 0, &result); - else + } else { offset = c2_parse_grp(pattern, 0, &result, 0); + } if (offset < 0) { c2_freep(&result); @@ -395,11 +397,13 @@ c2_lptr_t *c2_parse(c2_lptr_t **pcondlst, const char *pattern, void *data) { */ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int level) { // Check for recursion levels - if (level > C2_MAX_LEVELS) + if (level > C2_MAX_LEVELS) { c2_error("Exceeded maximum recursion levels."); + } - if (!pattern) + if (!pattern) { return -1; + } // Expected end character const char endchar = (offset ? ')' : '\0'); @@ -428,17 +432,20 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int assert(elei <= 2); // Jump over spaces - if (isspace((unsigned char)pattern[offset])) + if (isspace((unsigned char)pattern[offset])) { continue; + } // Handle end of group - if (')' == pattern[offset]) + if (')' == pattern[offset]) { break; + } // Handle "!" if ('!' == pattern[offset]) { - if (!next_expected) + if (!next_expected) { c2_error("Unexpected \"!\"."); + } neg = !neg; continue; @@ -446,8 +453,9 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int // Handle AND and OR if ('&' == pattern[offset] || '|' == pattern[offset]) { - if (next_expected) + if (next_expected) { c2_error("Unexpected logical operator."); + } next_expected = true; if (!mstrncmp("&&", pattern + offset)) { @@ -456,15 +464,17 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int } else if (!mstrncmp("||", pattern + offset)) { ops[elei] = C2_B_OOR; ++offset; - } else + } else { c2_error("Illegal logical operator."); + } continue; } // Parsing an element - if (!next_expected) + if (!next_expected) { c2_error("Unexpected expression."); + } assert(!elei || ops[elei]); @@ -491,21 +501,25 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int // It's a subgroup if it starts with '(' if ('(' == pattern[offset]) { - if ((offset = c2_parse_grp(pattern, offset + 1, pele, level + 1)) < 0) + if ((offset = c2_parse_grp(pattern, offset + 1, pele, level + 1)) < 0) { goto fail; + } } // Otherwise it's a leaf else { - if ((offset = c2_parse_target(pattern, offset, pele)) < 0) + if ((offset = c2_parse_target(pattern, offset, pele)) < 0) { goto fail; + } assert(!pele->isbranch && !c2_ptr_isempty(*pele)); - if ((offset = c2_parse_op(pattern, offset, pele)) < 0) + if ((offset = c2_parse_op(pattern, offset, pele)) < 0) { goto fail; + } - if ((offset = c2_parse_pattern(pattern, offset, pele)) < 0) + if ((offset = c2_parse_pattern(pattern, offset, pele)) < 0) { goto fail; + } } // Decrement offset -- we will increment it in loop update --offset; @@ -513,10 +527,11 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int // Apply negation if (neg) { neg = false; - if (pele->isbranch) + if (pele->isbranch) { pele->b->neg = !pele->b->neg; - else + } else { pele->l->neg = !pele->l->neg; + } } next_expected = false; @@ -525,10 +540,12 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int } // Wrong end character? - if (pattern[offset] && !endchar) + if (pattern[offset] && !endchar) { c2_error("Expected end of string but found '%c'.", pattern[offset]); - if (!pattern[offset] && endchar) + } + if (!pattern[offset] && endchar) { c2_error("Expected '%c' but found end of string.", endchar); + } // Handle end of group if (!elei) { @@ -544,8 +561,9 @@ static int c2_parse_grp(const char *pattern, int offset, c2_ptr_t *presult, int *presult = eles[0]; - if (')' == pattern[offset]) + if (')' == pattern[offset]) { ++offset; + } return offset; @@ -778,11 +796,11 @@ static int c2_parse_op(const char *pattern, int offset, c2_ptr_t *presult) { // Parse operator while ('=' == pattern[offset] || '>' == pattern[offset] || '<' == pattern[offset]) { - if ('=' == pattern[offset] && C2_L_OGT == pleaf->op) + if ('=' == pattern[offset] && C2_L_OGT == pleaf->op) { pleaf->op = C2_L_OGTEQ; - else if ('=' == pattern[offset] && C2_L_OLT == pleaf->op) + } else if ('=' == pattern[offset] && C2_L_OLT == pleaf->op) { pleaf->op = C2_L_OLTEQ; - else if (pleaf->op) { + } else if (pleaf->op) { c2_error("Duplicate operator."); } else { switch (pattern[offset]) { @@ -797,9 +815,10 @@ static int c2_parse_op(const char *pattern, int offset, c2_ptr_t *presult) { } // Check for problems - if (C2_L_OEQ != pleaf->op && (pleaf->match || pleaf->match_ignorecase)) + if (C2_L_OEQ != pleaf->op && (pleaf->match || pleaf->match_ignorecase)) { c2_error("Exists/greater-than/less-than operators cannot have a " "qualifier."); + } return offset; @@ -891,9 +910,10 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult) char *pstr = NULL; long val = strtol( tstr, &pstr, ('o' == pattern[offset] ? 8 : 16)); - if (pstr != &tstr[2] || val <= 0) + if (pstr != &tstr[2] || val <= 0) { c2_error("Invalid octal/hex escape " "sequence."); + } *(ptptnstr++) = to_char_checked(val); offset += 2; break; @@ -904,8 +924,9 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult) *(ptptnstr++) = pattern[offset]; } } - if (!pattern[offset]) + if (!pattern[offset]) { c2_error("Premature end of pattern string."); + } ++offset; *ptptnstr = '\0'; pleaf->ptnstr = strdup(tptnstr); @@ -914,27 +935,32 @@ static int c2_parse_pattern(const char *pattern, int offset, c2_ptr_t *presult) C2H_SKIP_SPACES(); - if (!pleaf->ptntype) + if (!pleaf->ptntype) { c2_error("Invalid pattern type."); + } // Check if the type is correct if (!(((C2_L_TSTRING == pleaf->type || C2_L_TATOM == pleaf->type) && C2_L_PTSTRING == pleaf->ptntype) || ((C2_L_TCARDINAL == pleaf->type || C2_L_TWINDOW == pleaf->type || C2_L_TDRAWABLE == pleaf->type) && - C2_L_PTINT == pleaf->ptntype))) + C2_L_PTINT == pleaf->ptntype))) { c2_error("Pattern type incompatible with target type."); + } - if (C2_L_PTINT == pleaf->ptntype && pleaf->match) + if (C2_L_PTINT == pleaf->ptntype && pleaf->match) { c2_error("Integer/boolean pattern cannot have operator qualifiers."); + } - if (C2_L_PTINT == pleaf->ptntype && pleaf->match_ignorecase) + if (C2_L_PTINT == pleaf->ptntype && pleaf->match_ignorecase) { c2_error("Integer/boolean pattern cannot have flags."); + } if (C2_L_PTSTRING == pleaf->ptntype && (C2_L_OGT == pleaf->op || C2_L_OGTEQ == pleaf->op || C2_L_OLT == pleaf->op || - C2_L_OLTEQ == pleaf->op)) + C2_L_OLTEQ == pleaf->op)) { c2_error("String pattern cannot have an arithmetic operator."); + } return offset; @@ -1173,9 +1199,8 @@ c2_lptr_t *c2_free_lptr(c2_lptr_t *lp, c2_userdata_free f) { static const char *c2h_dump_str_tgt(const c2_l_t *pleaf) { if (pleaf->predef != C2_L_PUNDEFINED) { return C2_PREDEFS[pleaf->predef].name; - } else { - return pleaf->tgt; } + return pleaf->tgt; } /** @@ -1378,11 +1403,11 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w int word_count = 1; if (pleaf->index < 0) { // Get length of property in 32-bit multiples - auto prop_info = x_get_prop_info(ps->c, wid, pleaf->tgtatom); + auto prop_info = x_get_prop_info(&ps->c, wid, pleaf->tgtatom); word_count = to_int_checked((prop_info.length + 4 - 1) / 4); } winprop_t prop = x_get_prop_with_offset( - ps->c, wid, pleaf->tgtatom, idx, word_count, + &ps->c, wid, pleaf->tgtatom, idx, word_count, c2_get_atom_type(pleaf), pleaf->format); ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1)); @@ -1455,11 +1480,11 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w int word_count = 1; if (pleaf->index < 0) { // Get length of property in 32-bit multiples - auto prop_info = x_get_prop_info(ps->c, wid, pleaf->tgtatom); + auto prop_info = x_get_prop_info(&ps->c, wid, pleaf->tgtatom); word_count = to_int_checked((prop_info.length + 4 - 1) / 4); } winprop_t prop = x_get_prop_with_offset( - ps->c, wid, pleaf->tgtatom, idx, word_count, + &ps->c, wid, pleaf->tgtatom, idx, word_count, c2_get_atom_type(pleaf), pleaf->format); ntargets = (pleaf->index < 0 ? prop.nitems : min2(prop.nitems, 1)); @@ -1470,7 +1495,7 @@ static inline void c2_match_once_leaf(session_t *ps, const struct managed_win *w xcb_atom_t atom = (xcb_atom_t)winprop_get_int(prop, i); if (atom) { xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply( - ps->c, xcb_get_atom_name(ps->c, atom), NULL); + ps->c.c, xcb_get_atom_name(ps->c.c, atom), NULL); if (reply) { targets[i] = targets_free_inner[i] = strndup( xcb_get_atom_name_name(reply), @@ -1599,8 +1624,9 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p if (cond.isbranch) { const c2_b_t *pb = cond.b; - if (!pb) + if (!pb) { return false; + } error = false; @@ -1630,8 +1656,9 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p else { const c2_l_t *pleaf = cond.l; - if (!pleaf) + if (!pleaf) { return false; + } c2_match_once_leaf(ps, w, pleaf, &result, &error); @@ -1651,11 +1678,13 @@ static bool c2_match_once(session_t *ps, const struct managed_win *w, const c2_p } // Postprocess the result - if (error) + if (error) { result = false; + } - if (cond.isbranch ? cond.b->neg : cond.l->neg) + if (cond.isbranch ? cond.b->neg : cond.l->neg) { result = !result; + } return result; } @@ -1673,8 +1702,9 @@ bool c2_match(session_t *ps, const struct managed_win *w, const c2_lptr_t *condl // Then go through the whole linked list for (; condlst; condlst = condlst->next) { if (c2_match_once(ps, w, condlst->ptr)) { - if (pdata) + if (pdata) { *pdata = condlst->data; + } return true; } } diff --git a/src/common.h b/src/common.h index e183a1e..707d00e 100644 --- a/src/common.h +++ b/src/common.h @@ -84,18 +84,6 @@ struct glx_session; struct atom; struct conv; -enum pending_reply_action { - PENDING_REPLY_ACTION_IGNORE, - PENDING_REPLY_ACTION_ABORT, - PENDING_REPLY_ACTION_DEBUG_ABORT, -}; - -typedef struct pending_reply { - struct pending_reply *next; - unsigned long sequence; - enum pending_reply_action action; -} pending_reply_t; - #ifdef CONFIG_OPENGL #ifdef DEBUG_GLX_DEBUG_CONTEXT typedef GLXContext (*f_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config, @@ -183,28 +171,14 @@ typedef struct session { struct shader_info *shaders; // === Display related === + /// X connection + struct x_connection c; /// Whether the X server is grabbed by us bool server_grabbed; - /// Display in use. - Display *dpy; - /// Previous handler of X errors - XErrorHandler previous_xerror_handler; - /// Default screen. - int scr; - /// XCB connection. - xcb_connection_t *c; - /// Default visual. - xcb_visualid_t vis; - /// Default depth. - int depth; - /// Root window. - xcb_window_t root; - /// Height of root window. - int root_height; /// Width of root window. int root_width; - // Damage of root window. - // Damage root_damage; + /// Height of root window. + int root_height; /// X Composite overlay window. xcb_window_t overlay; /// The target window for debug mode @@ -289,11 +263,6 @@ typedef struct session { xcb_render_picture_t *alpha_picts; /// Time of last fading. In milliseconds. long long fade_time; - /// Head pointer of the error ignore linked list. - pending_reply_t *pending_reply_head; - /// Pointer to the next member of tail element of the error - /// ignore linked list. - pending_reply_t **pending_reply_tail; // Cached blur convolution kernels. struct x_convolution_kernel **blur_kerns_cache; /// If we should quit @@ -391,10 +360,8 @@ typedef struct session { int glx_event; /// Error base number for X GLX extension. int glx_error; - /// Number of X RandR monitors. - int randr_nmonitors; - /// X RandR monitor regions. - region_t *randr_monitor_regs; + /// Information about monitors. + struct x_monitors monitors; /// Whether X Sync extension exists. bool xsync_exists; /// Event base number for X Sync extension. @@ -492,7 +459,7 @@ static inline struct timespec get_time_timespec(void) { * Return the painting target window. */ static inline xcb_window_t get_tgt_window(session_t *ps) { - return ps->overlay != XCB_NONE ? ps->overlay : ps->root; + return ps->overlay != XCB_NONE ? ps->overlay : ps->c.screen_info->root; } /** @@ -502,35 +469,6 @@ static inline bool bkend_use_glx(session_t *ps) { return BKEND_GLX == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend; } -static void -set_reply_action(session_t *ps, uint32_t sequence, enum pending_reply_action action) { - auto i = cmalloc(pending_reply_t); - if (!i) { - abort(); - } - - i->sequence = sequence; - i->next = 0; - i->action = action; - *ps->pending_reply_tail = i; - ps->pending_reply_tail = &i->next; -} - -/** - * Ignore X errors caused by given X request. - */ -static inline void set_ignore_cookie(session_t *ps, xcb_void_cookie_t cookie) { - if (ps->o.show_all_xerrors) { - return; - } - - set_reply_action(ps, cookie.sequence, PENDING_REPLY_ACTION_IGNORE); -} - -static inline void set_cant_fail_cookie(session_t *ps, xcb_void_cookie_t cookie) { - set_reply_action(ps, cookie.sequence, PENDING_REPLY_ACTION_ABORT); -} - /** * Determine if a window has a specific property. * @@ -541,7 +479,8 @@ static inline void set_cant_fail_cookie(session_t *ps, xcb_void_cookie_t cookie) */ static inline bool wid_has_prop(const session_t *ps, xcb_window_t w, xcb_atom_t atom) { auto r = xcb_get_property_reply( - ps->c, xcb_get_property(ps->c, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0), NULL); + ps->c.c, + xcb_get_property(ps->c.c, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0), NULL); if (!r) { return false; } diff --git a/src/dbus.c b/src/dbus.c index baff2bc..ad98a0f 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -1165,7 +1165,7 @@ static bool cdbus_process_opts_get(session_t *ps, DBusMessage *msg) { // display if (!strcmp("display", target)) { - cdbus_reply_string(ps, msg, DisplayString(ps->dpy)); + cdbus_reply_string(ps, msg, DisplayString(ps->c.dpy)); return true; } diff --git a/src/event.c b/src/event.c index b140082..807cf4e 100644 --- a/src/event.c +++ b/src/event.c @@ -57,7 +57,7 @@ static inline const char *ev_window_name(session_t *ps, xcb_window_t wid) { char *name = ""; if (wid) { name = "(Failed to get title)"; - if (ps->root == wid) { + if (ps->c.screen_info->root == wid) { name = "(Root window)"; } else if (ps->overlay == wid) { name = "(Overlay)"; @@ -184,7 +184,7 @@ static inline void ev_focus_out(session_t *ps, xcb_focus_out_event_t *ev) { } static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) { - if (ev->parent == ps->root) { + if (ev->parent == ps->c.screen_info->root) { add_win_top(ps, ev->window); } } @@ -239,7 +239,7 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) { } // Recalculate which monitor this window is on - win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, mw); + win_update_monitor(&ps->monitors, mw); } // override_redirect flag cannot be changed after window creation, as far @@ -250,7 +250,7 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) { static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event_t *ev) { log_debug("{ send_event: %d, id: %#010x, above: %#010x, override_redirect: %d }", ev->event, ev->window, ev->above_sibling, ev->override_redirect); - if (ev->window == ps->root) { + if (ev->window == ps->c.screen_info->root) { set_root_flags(ps, ROOT_FLAGS_CONFIGURED); } else { configure_win(ps, ev); @@ -284,8 +284,8 @@ static inline void ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) { // in redirected state. if (ps->overlay && ev->window == ps->overlay && !ps->redirected) { log_debug("Overlay is mapped while we are not redirected"); - auto e = - xcb_request_check(ps->c, xcb_unmap_window_checked(ps->c, ps->overlay)); + auto e = xcb_request_check( + ps->c.c, xcb_unmap_window_checked(ps->c.c, ps->overlay)); if (e) { log_error("Failed to unmap the overlay window"); free(e); @@ -323,7 +323,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t ps->pending_updates = true; } - if (ev->parent == ps->root) { + if (ev->parent == ps->c.screen_info->root) { // X will generate reparent notifiy even if the parent didn't actually // change (i.e. reparent again to current parent). So we check if that's // the case @@ -351,7 +351,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t // Reset event mask in case something wrong happens xcb_change_window_attributes( - ps->c, ev->window, XCB_CW_EVENT_MASK, + ps->c.c, ev->window, XCB_CW_EVENT_MASK, (const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN)}); if (!wid_has_prop(ps, ev->window, ps->atoms->aWM_STATE)) { @@ -360,7 +360,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t "property change in case it gains one.", ev->window); xcb_change_window_attributes( - ps->c, ev->window, XCB_CW_EVENT_MASK, + ps->c.c, ev->window, XCB_CW_EVENT_MASK, (const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN) | XCB_EVENT_MASK_PROPERTY_CHANGE}); } else { @@ -373,9 +373,9 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t win_set_flags(w_real_top, WIN_FLAGS_CLIENT_STALE); ps->pending_updates = true; } else { - if (!w_real_top) + if (!w_real_top) { log_debug("parent %#010x not found", ev->parent); - else { + } else { // Window is not currently mapped, unmark its // client to trigger a client recheck when it is // mapped later. @@ -392,8 +392,9 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t static inline void ev_circulate_notify(session_t *ps, xcb_circulate_notify_event_t *ev) { auto w = find_win(ps, ev->window); - if (!w) + if (!w) { return; + } if (ev->place == PlaceOnTop) { restack_top(ps, w); @@ -410,7 +411,8 @@ static inline void expose_root(session_t *ps, const rect_t *rects, int nrects) { } static inline void ev_expose(session_t *ps, xcb_expose_event_t *ev) { - if (ev->window == ps->root || (ps->overlay && ev->window == ps->overlay)) { + if (ev->window == ps->c.screen_info->root || + (ps->overlay && ev->window == ps->overlay)) { int more = ev->count + 1; if (ps->n_expose == ps->size_expose) { if (ps->expose_rects) { @@ -439,8 +441,8 @@ static inline void ev_expose(session_t *ps, xcb_expose_event_t *ev) { static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t *ev) { if (unlikely(log_get_level_tls() <= LOG_LEVEL_TRACE)) { // Print out changed atom - xcb_get_atom_name_reply_t *reply = - xcb_get_atom_name_reply(ps->c, xcb_get_atom_name(ps->c, ev->atom), NULL); + xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply( + ps->c.c, xcb_get_atom_name(ps->c.c, ev->atom), NULL); const char *name = "?"; int name_len = 1; if (reply) { @@ -452,7 +454,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t free(reply); } - if (ps->root == ev->window) { + if (ps->c.screen_info->root == ev->window) { if (ps->o.use_ewmh_active_win && ps->atoms->a_NET_ACTIVE_WINDOW == ev->atom) { // to update focus ps->pending_updates = true; @@ -473,7 +475,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t // Check whether it could be a client window if (!find_toplevel(ps, ev->window)) { // Reset event mask anyway - xcb_change_window_attributes(ps->c, ev->window, XCB_CW_EVENT_MASK, + xcb_change_window_attributes(ps->c.c, ev->window, XCB_CW_EVENT_MASK, (const uint32_t[]){determine_evmask( ps, ev->window, WIN_EVMODE_UNKNOWN)}); @@ -586,12 +588,16 @@ static inline void repair_win(session_t *ps, struct managed_win *w) { if (!w->ever_damaged) { win_extents(w, &parts); - set_ignore_cookie( - ps, xcb_damage_subtract(ps->c, w->damage, XCB_NONE, XCB_NONE)); + if (!ps->o.show_all_xerrors) { + set_ignore_cookie(&ps->c, xcb_damage_subtract(ps->c.c, w->damage, + XCB_NONE, XCB_NONE)); + } } else { - set_ignore_cookie( - ps, xcb_damage_subtract(ps->c, w->damage, XCB_NONE, ps->damaged_region)); - x_fetch_region(ps->c, ps->damaged_region, &parts); + if (!ps->o.show_all_xerrors) { + set_ignore_cookie(&ps->c, xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE, + ps->damaged_region)); + } + x_fetch_region(&ps->c, ps->damaged_region, &parts); pixman_region32_translate(&parts, w->g.x + w->g.border_width, w->g.y + w->g.border_width); } @@ -667,7 +673,7 @@ ev_selection_clear(session_t *ps, xcb_selection_clear_event_t attr_unused *ev) { void ev_handle(session_t *ps, xcb_generic_event_t *ev) { if (XCB_EVENT_RESPONSE_TYPE(ev) != KeymapNotify) { - discard_pending(ps, ev->full_sequence); + x_discard_pending(&ps->c, ev->full_sequence); } xcb_window_t wid = ev_window(ps, ev); @@ -689,9 +695,9 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) { // https://bugs.freedesktop.org/show_bug.cgi?id=35945 // https://lists.freedesktop.org/archives/xcb/2011-November/007337.html auto response_type = XCB_EVENT_RESPONSE_TYPE(ev); - auto proc = XESetWireToEvent(ps->dpy, response_type, 0); + auto proc = XESetWireToEvent(ps->c.dpy, response_type, 0); if (proc) { - XESetWireToEvent(ps->dpy, response_type, proc); + XESetWireToEvent(ps->c.dpy, response_type, proc); XEvent dummy; // Stop Xlib from complaining about lost sequence numbers. @@ -701,8 +707,8 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) { // // We only need the low 16 bits uint16_t seq = ev->sequence; - ev->sequence = (uint16_t)(LastKnownRequestProcessed(ps->dpy) & 0xffff); - proc(ps->dpy, &dummy, (xEvent *)ev); + ev->sequence = (uint16_t)(LastKnownRequestProcessed(ps->c.dpy) & 0xffff); + proc(ps->c.dpy, &dummy, (xEvent *)ev); // Restore the sequence number ev->sequence = seq; } @@ -736,7 +742,7 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) { case SelectionClear: ev_selection_clear(ps, (xcb_selection_clear_event_t *)ev); break; - case 0: ev_xcb_error(ps, (xcb_generic_error_t *)ev); break; + case 0: x_handle_error(&ps->c, (xcb_generic_error_t *)ev); break; default: if (ps->shape_exists && ev->response_type == ps->shape_event) { ev_shape_notify(ps, (xcb_shape_notify_event_t *)ev); diff --git a/src/opengl.c b/src/opengl.c index 5d2d66c..6f4d047 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -39,7 +39,7 @@ static inline XVisualInfo *get_visualinfo_from_visual(session_t *ps, xcb_visuali XVisualInfo vreq = {.visualid = visual}; int nitems = 0; - return XGetVisualInfo(ps->dpy, VisualIDMask, &vreq, &nitems); + return XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems); } /** @@ -56,7 +56,7 @@ bool glx_init(session_t *ps, bool need_render) { } // Get XVisualInfo - pvis = get_visualinfo_from_visual(ps, ps->vis); + pvis = get_visualinfo_from_visual(ps, ps->c.screen_info->root_visual); if (!pvis) { log_error("Failed to acquire XVisualInfo for current visual."); goto glx_init_end; @@ -65,12 +65,13 @@ bool glx_init(session_t *ps, bool need_render) { // Ensure the visual is double-buffered if (need_render) { int value = 0; - if (Success != glXGetConfig(ps->dpy, pvis, GLX_USE_GL, &value) || !value) { + if (Success != glXGetConfig(ps->c.dpy, pvis, GLX_USE_GL, &value) || !value) { log_error("Root visual is not a GL visual."); goto glx_init_end; } - if (Success != glXGetConfig(ps->dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) { + if (Success != glXGetConfig(ps->c.dpy, pvis, GLX_DOUBLEBUFFER, &value) || + !value) { log_error("Root visual is not a double buffered GL visual."); goto glx_init_end; } @@ -112,7 +113,7 @@ bool glx_init(session_t *ps, bool need_render) { if (!psglx->context) { // Get GLX context #ifndef DEBUG_GLX_DEBUG_CONTEXT - psglx->context = glXCreateContext(ps->dpy, pvis, None, GL_TRUE); + psglx->context = glXCreateContext(ps->c.dpy, pvis, None, GL_TRUE); #else { GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis); @@ -134,7 +135,7 @@ bool glx_init(session_t *ps, bool need_render) { static const int attrib_list[] = { GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, None}; psglx->context = p_glXCreateContextAttribsARB( - ps->dpy, fbconfig, NULL, GL_TRUE, attrib_list); + ps->c.dpy, fbconfig, NULL, GL_TRUE, attrib_list); } #endif @@ -144,7 +145,7 @@ bool glx_init(session_t *ps, bool need_render) { } // Attach GLX context - if (!glXMakeCurrent(ps->dpy, get_tgt_window(ps), psglx->context)) { + if (!glXMakeCurrent(ps->c.dpy, get_tgt_window(ps), psglx->context)) { log_error("Failed to attach GLX context."); goto glx_init_end; } @@ -201,7 +202,7 @@ bool glx_init(session_t *ps, bool need_render) { // Clear screen glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // glXSwapBuffers(ps->dpy, get_tgt_window(ps)); + // glXSwapBuffers(ps->c.dpy, get_tgt_window(ps)); } success = true; @@ -266,8 +267,8 @@ void glx_destroy(session_t *ps) { // Destroy GLX context if (ps->psglx->context) { - glXMakeCurrent(ps->dpy, None, NULL); - glXDestroyContext(ps->dpy, ps->psglx->context); + glXMakeCurrent(ps->c.dpy, None, NULL); + glXDestroyContext(ps->c.dpy, ps->psglx->context); ps->psglx->context = NULL; } @@ -732,7 +733,7 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, // Retrieve pixmap parameters, if they aren't provided if (!width || !height) { auto r = xcb_get_geometry_reply( - ps->c, xcb_get_geometry(ps->c, pixmap), NULL); + ps->c.c, xcb_get_geometry(ps->c.c, pixmap), NULL); if (!r) { log_error("Failed to query info of pixmap %#010x.", pixmap); return false; @@ -773,7 +774,7 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, 0, }; - ptex->glpixmap = glXCreatePixmap(ps->dpy, fbcfg->cfg, pixmap, attrs); + ptex->glpixmap = glXCreatePixmap(ps->c.dpy, fbcfg->cfg, pixmap, attrs); ptex->pixmap = pixmap; ptex->target = (GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE); @@ -820,9 +821,9 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, // The specification requires rebinding whenever the content changes... // We can't follow this, too slow. if (need_release) - glXReleaseTexImageEXT(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); + glXReleaseTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); - glXBindTexImageEXT(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL); + glXBindTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL); // Cleanup glBindTexture(ptex->target, 0); @@ -840,13 +841,13 @@ void glx_release_pixmap(session_t *ps, glx_texture_t *ptex) { // Release binding if (ptex->glpixmap && ptex->texture) { glBindTexture(ptex->target, ptex->texture); - glXReleaseTexImageEXT(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); + glXReleaseTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT); glBindTexture(ptex->target, 0); } // Free GLX Pixmap if (ptex->glpixmap) { - glXDestroyPixmap(ps->dpy, ptex->glpixmap); + glXDestroyPixmap(ps->c.dpy, ptex->glpixmap); ptex->glpixmap = 0; } diff --git a/src/picom.c b/src/picom.c index 126922e..1567ab8 100644 --- a/src/picom.c +++ b/src/picom.c @@ -129,7 +129,7 @@ static inline bool dpms_screen_is_off(xcb_dpms_info_reply_t *info) { void check_dpms_status(EV_P attr_unused, ev_timer *w, int revents attr_unused) { auto ps = session_ptr(w, dpms_check_timer); - auto r = xcb_dpms_info_reply(ps->c, xcb_dpms_info(ps->c), NULL); + auto r = xcb_dpms_info_reply(ps->c.c, xcb_dpms_info(ps->c.c), NULL); if (!r) { log_fatal("Failed to query DPMS status."); abort(); @@ -149,7 +149,7 @@ void check_dpms_status(EV_P attr_unused, ev_timer *w, int revents attr_unused) { * XXX move to win.c */ static inline struct managed_win *find_win_all(session_t *ps, const xcb_window_t wid) { - if (!wid || PointerRoot == wid || wid == ps->root || wid == ps->overlay) { + if (!wid || PointerRoot == wid || wid == ps->c.screen_info->root || wid == ps->overlay) { return NULL; } @@ -352,8 +352,9 @@ void add_damage(session_t *ps, const region_t *damage) { */ static double fade_timeout(session_t *ps) { auto now = get_time_ms(); - if (ps->o.fade_delta + ps->fade_time < now) + if (ps->o.fade_delta + ps->fade_time < now) { return 0; + } auto diff = ps->o.fade_delta + ps->fade_time - now; @@ -406,47 +407,6 @@ static bool run_fade(session_t *ps, struct managed_win **_w, long long steps) { return true; } -// === Error handling === - -void discard_pending(session_t *ps, uint32_t sequence) { - while (ps->pending_reply_head) { - if (sequence > ps->pending_reply_head->sequence) { - auto next = ps->pending_reply_head->next; - free(ps->pending_reply_head); - ps->pending_reply_head = next; - if (!ps->pending_reply_head) { - ps->pending_reply_tail = &ps->pending_reply_head; - } - } else { - break; - } - } -} - -static void handle_error(session_t *ps, xcb_generic_error_t *ev) { - if (ps == NULL) { - // Do not ignore errors until the session has been initialized - return; - } - discard_pending(ps, ev->full_sequence); - if (ps->pending_reply_head && ps->pending_reply_head->sequence == ev->full_sequence) { - if (ps->pending_reply_head->action != PENDING_REPLY_ACTION_IGNORE) { - x_log_error(LOG_LEVEL_ERROR, ev->full_sequence, ev->major_code, - ev->minor_code, ev->error_code); - } - switch (ps->pending_reply_head->action) { - case PENDING_REPLY_ACTION_ABORT: - log_fatal("An unrecoverable X error occurred, aborting..."); - abort(); - case PENDING_REPLY_ACTION_DEBUG_ABORT: assert(false); break; - case PENDING_REPLY_ACTION_IGNORE: break; - } - return; - } - x_log_error(LOG_LEVEL_WARN, ev->full_sequence, ev->major_code, ev->minor_code, - ev->error_code); -} - // === Windows === /** @@ -482,8 +442,8 @@ uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) { */ void update_ewmh_active_win(session_t *ps) { // Search for the window - xcb_window_t wid = - wid_get_prop_window(ps->c, ps->root, ps->atoms->a_NET_ACTIVE_WINDOW); + xcb_window_t wid = wid_get_prop_window(&ps->c, ps->c.screen_info->root, + ps->atoms->a_NET_ACTIVE_WINDOW); auto w = find_win_all(ps, wid); // Mark the window focused. No need to unfocus the previous one. @@ -510,7 +470,7 @@ static void recheck_focus(session_t *ps) { // opacity on it xcb_window_t wid = XCB_NONE; xcb_get_input_focus_reply_t *reply = - xcb_get_input_focus_reply(ps->c, xcb_get_input_focus(ps->c), NULL); + xcb_get_input_focus_reply(ps->c.c, xcb_get_input_focus(ps->c.c), NULL); if (reply) { wid = reply->focus; @@ -719,7 +679,7 @@ err: /// Handle configure event of the root window static void configure_root(session_t *ps) { - auto r = XCB_AWAIT(xcb_get_geometry, ps->c, ps->root); + auto r = XCB_AWAIT(xcb_get_geometry, ps->c.c, ps->c.screen_info->root); if (!r) { log_fatal("Failed to fetch root geometry"); abort(); @@ -795,8 +755,8 @@ static void configure_root(session_t *ps) { static void handle_root_flags(session_t *ps) { if ((ps->root_flags & ROOT_FLAGS_SCREEN_CHANGE) != 0) { - if (ps->o.crop_shadow_to_monitor) { - x_update_randr_monitors(ps); + if (ps->o.crop_shadow_to_monitor && ps->randr_exists) { + x_update_monitors(&ps->c, &ps->monitors); } ps->root_flags &= ~(uint64_t)ROOT_FLAGS_SCREEN_CHANGE; } @@ -1096,10 +1056,11 @@ void root_damaged(session_t *ps) { ps->backend_data->ops->release_image(ps->backend_data, ps->root_image); ps->root_image = NULL; } - auto pixmap = x_get_root_back_pixmap(ps->c, ps->root, ps->atoms); + auto pixmap = x_get_root_back_pixmap(&ps->c, ps->atoms); if (pixmap != XCB_NONE) { ps->root_image = ps->backend_data->ops->bind_pixmap( - ps->backend_data, pixmap, x_get_visual_info(ps->c, ps->vis), false); + ps->backend_data, pixmap, + x_get_visual_info(&ps->c, ps->c.screen_info->root_visual), false); if (ps->root_image) { ps->backend_data->ops->set_image_property( ps->backend_data, IMAGE_PROPERTY_EFFECTIVE_SIZE, @@ -1114,27 +1075,6 @@ void root_damaged(session_t *ps) { force_repaint(ps); } -/** - * Xlib error handler function. - */ -static int xerror(Display attr_unused *dpy, XErrorEvent *ev) { - // Fake a xcb error, fill in just enough information - xcb_generic_error_t xcb_err; - xcb_err.full_sequence = (uint32_t)ev->serial; - xcb_err.major_code = ev->request_code; - xcb_err.minor_code = ev->minor_code; - xcb_err.error_code = ev->error_code; - handle_error(ps_g, &xcb_err); - return 0; -} - -/** - * XCB error handler function. - */ -void ev_xcb_error(session_t *ps, xcb_generic_error_t *err) { - handle_error(ps, err); -} - /** * Force a full-screen repaint. */ @@ -1169,10 +1109,11 @@ void opts_set_no_fading_openclose(session_t *ps, bool newval) { static int register_cm(session_t *ps) { assert(!ps->reg_win); - ps->reg_win = x_new_id(ps->c); + ps->reg_win = x_new_id(&ps->c); auto e = xcb_request_check( - ps->c, xcb_create_window_checked(ps->c, XCB_COPY_FROM_PARENT, ps->reg_win, ps->root, - 0, 0, 1, 1, 0, XCB_NONE, ps->vis, 0, NULL)); + ps->c.c, xcb_create_window_checked(ps->c.c, XCB_COPY_FROM_PARENT, ps->reg_win, + ps->c.screen_info->root, 0, 0, 1, 1, 0, XCB_NONE, + ps->c.screen_info->root_visual, 0, NULL)); if (e) { log_fatal("Failed to create window."); @@ -1191,10 +1132,10 @@ static int register_cm(session_t *ps) { // Set names and classes for (size_t i = 0; i < ARR_SIZE(prop_atoms); i++) { e = xcb_request_check( - ps->c, xcb_change_property_checked( - ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, prop_atoms[i], - prop_is_utf8[i] ? ps->atoms->aUTF8_STRING : XCB_ATOM_STRING, - 8, strlen("picom"), "picom")); + ps->c.c, xcb_change_property_checked( + ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win, prop_atoms[i], + prop_is_utf8[i] ? ps->atoms->aUTF8_STRING : XCB_ATOM_STRING, + 8, strlen("picom"), "picom")); if (e) { log_error_x_error(e, "Failed to set window property %d", prop_atoms[i]); @@ -1204,9 +1145,9 @@ static int register_cm(session_t *ps) { const char picom_class[] = "picom\0picom"; e = xcb_request_check( - ps->c, xcb_change_property_checked(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, - ps->atoms->aWM_CLASS, XCB_ATOM_STRING, 8, - ARR_SIZE(picom_class), picom_class)); + ps->c.c, xcb_change_property_checked(ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win, + ps->atoms->aWM_CLASS, XCB_ATOM_STRING, 8, + ARR_SIZE(picom_class), picom_class)); if (e) { log_error_x_error(e, "Failed to set the WM_CLASS property"); free(e); @@ -1220,10 +1161,10 @@ static int register_cm(session_t *ps) { if (gethostname(hostname, hostname_max) == 0) { e = xcb_request_check( - ps->c, xcb_change_property_checked( - ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, - ps->atoms->aWM_CLIENT_MACHINE, XCB_ATOM_STRING, 8, - (uint32_t)strlen(hostname), hostname)); + ps->c.c, xcb_change_property_checked( + ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win, + ps->atoms->aWM_CLIENT_MACHINE, XCB_ATOM_STRING, + 8, (uint32_t)strlen(hostname), hostname)); if (e) { log_error_x_error(e, "Failed to set the WM_CLIENT_MACHINE" " property"); @@ -1239,16 +1180,16 @@ static int register_cm(session_t *ps) { // Set _NET_WM_PID { auto pid = getpid(); - xcb_change_property(ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, + xcb_change_property(ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win, ps->atoms->a_NET_WM_PID, XCB_ATOM_CARDINAL, 32, 1, &pid); } // Set COMPTON_VERSION e = xcb_request_check( - ps->c, xcb_change_property_checked( - ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, - get_atom(ps->atoms, "COMPTON_VERSION"), XCB_ATOM_STRING, 8, - (uint32_t)strlen(PICOM_VERSION), PICOM_VERSION)); + ps->c.c, xcb_change_property_checked( + ps->c.c, XCB_PROP_MODE_REPLACE, ps->reg_win, + get_atom(ps->atoms, "COMPTON_VERSION"), XCB_ATOM_STRING, 8, + (uint32_t)strlen(PICOM_VERSION), PICOM_VERSION)); if (e) { log_error_x_error(e, "Failed to set COMPTON_VERSION."); free(e); @@ -1260,7 +1201,7 @@ static int register_cm(session_t *ps) { xcb_atom_t atom; char *buf = NULL; - if (asprintf(&buf, "%s%d", register_prop, ps->scr) < 0) { + if (asprintf(&buf, "%s%d", register_prop, ps->c.screen) < 0) { log_fatal("Failed to allocate memory"); return -1; } @@ -1268,7 +1209,7 @@ static int register_cm(session_t *ps) { free(buf); xcb_get_selection_owner_reply_t *reply = xcb_get_selection_owner_reply( - ps->c, xcb_get_selection_owner(ps->c, atom), NULL); + ps->c.c, xcb_get_selection_owner(ps->c.c, atom), NULL); if (reply && reply->owner != XCB_NONE) { // Another compositor already running @@ -1276,7 +1217,7 @@ static int register_cm(session_t *ps) { return 1; } free(reply); - xcb_set_selection_owner(ps->c, ps->reg_win, atom, 0); + xcb_set_selection_owner(ps->c.c, ps->reg_win, atom, 0); } return 0; @@ -1306,9 +1247,8 @@ static inline bool write_pid(session_t *ps) { * Initialize X composite overlay window. */ static bool init_overlay(session_t *ps) { - xcb_composite_get_overlay_window_reply_t *reply = - xcb_composite_get_overlay_window_reply( - ps->c, xcb_composite_get_overlay_window(ps->c, ps->root), NULL); + xcb_composite_get_overlay_window_reply_t *reply = xcb_composite_get_overlay_window_reply( + ps->c.c, xcb_composite_get_overlay_window(ps->c.c, ps->c.screen_info->root), NULL); if (reply) { ps->overlay = reply->overlay_win; free(reply); @@ -1318,13 +1258,13 @@ static bool init_overlay(session_t *ps) { if (ps->overlay != XCB_NONE) { // Set window region of the overlay window, code stolen from // compiz-0.8.8 - if (!XCB_AWAIT_VOID(xcb_shape_mask, ps->c, XCB_SHAPE_SO_SET, + if (!XCB_AWAIT_VOID(xcb_shape_mask, ps->c.c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, ps->overlay, 0, 0, 0)) { log_fatal("Failed to set the bounding shape of overlay, giving " "up."); return false; } - if (!XCB_AWAIT_VOID(xcb_shape_rectangles, ps->c, XCB_SHAPE_SO_SET, + if (!XCB_AWAIT_VOID(xcb_shape_rectangles, ps->c.c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, ps->overlay, 0, 0, 0, NULL)) { log_fatal("Failed to set the input shape of overlay, giving up."); @@ -1332,7 +1272,7 @@ static bool init_overlay(session_t *ps) { } // Listen to Expose events on the overlay - xcb_change_window_attributes(ps->c, ps->overlay, XCB_CW_EVENT_MASK, + xcb_change_window_attributes(ps->c.c, ps->overlay, XCB_CW_EVENT_MASK, (const uint32_t[]){XCB_EVENT_MASK_EXPOSURE}); // Retrieve DamageNotify on root window if we are painting on an @@ -1340,7 +1280,7 @@ static bool init_overlay(session_t *ps) { // root_damage = XDamageCreate(ps->dpy, root, XDamageReportNonEmpty); // Unmap the overlay, we will map it when needed in redirect_start - XCB_AWAIT_VOID(xcb_unmap_window, ps->c, ps->overlay); + XCB_AWAIT_VOID(xcb_unmap_window, ps->c.c, ps->overlay); } else { log_error("Cannot get X Composite overlay window. Falling " "back to painting on root window."); @@ -1351,27 +1291,29 @@ static bool init_overlay(session_t *ps) { } static bool init_debug_window(session_t *ps) { - xcb_colormap_t colormap = x_new_id(ps->c); - ps->debug_window = x_new_id(ps->c); + xcb_colormap_t colormap = x_new_id(&ps->c); + ps->debug_window = x_new_id(&ps->c); auto err = xcb_request_check( - ps->c, xcb_create_colormap_checked(ps->c, XCB_COLORMAP_ALLOC_NONE, colormap, - ps->root, ps->vis)); + ps->c.c, xcb_create_colormap_checked(ps->c.c, XCB_COLORMAP_ALLOC_NONE, + colormap, ps->c.screen_info->root, + ps->c.screen_info->root_visual)); if (err) { goto err_out; } err = xcb_request_check( - ps->c, xcb_create_window_checked(ps->c, (uint8_t)ps->depth, ps->debug_window, - ps->root, 0, 0, to_u16_checked(ps->root_width), - to_u16_checked(ps->root_height), 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, ps->vis, - XCB_CW_COLORMAP, (uint32_t[]){colormap, 0})); + ps->c.c, xcb_create_window_checked( + ps->c.c, (uint8_t)ps->c.screen_info->root_depth, + ps->debug_window, ps->c.screen_info->root, 0, 0, + to_u16_checked(ps->root_width), to_u16_checked(ps->root_height), + 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, ps->c.screen_info->root_visual, + XCB_CW_COLORMAP, (uint32_t[]){colormap, 0})); if (err) { goto err_out; } - err = xcb_request_check(ps->c, xcb_map_window_checked(ps->c, ps->debug_window)); + err = xcb_request_check(ps->c.c, xcb_map_window_checked(ps->c.c, ps->debug_window)); if (err) { goto err_out; } @@ -1386,7 +1328,7 @@ xcb_window_t session_get_target_window(session_t *ps) { if (ps->o.debug_mode) { return ps->debug_window; } - return ps->overlay != XCB_NONE ? ps->overlay : ps->root; + return ps->overlay != XCB_NONE ? ps->overlay : ps->c.screen_info->root; } uint8_t session_redirection_mode(session_t *ps) { @@ -1416,18 +1358,18 @@ static bool redirect_start(session_t *ps) { // Map overlay window. Done firstly according to this: // https://bugzilla.gnome.org/show_bug.cgi?id=597014 if (ps->overlay != XCB_NONE) { - xcb_map_window(ps->c, ps->overlay); + xcb_map_window(ps->c.c, ps->overlay); } - bool success = XCB_AWAIT_VOID(xcb_composite_redirect_subwindows, ps->c, ps->root, - session_redirection_mode(ps)); + bool success = XCB_AWAIT_VOID(xcb_composite_redirect_subwindows, ps->c.c, + ps->c.screen_info->root, session_redirection_mode(ps)); if (!success) { log_fatal("Another composite manager is already running " "(and does not handle _NET_WM_CM_Sn correctly)"); return false; } - x_sync(ps->c); + x_sync(&ps->c); if (!initialize_backend(ps)) { return false; @@ -1456,16 +1398,16 @@ static bool redirect_start(session_t *ps) { } if (ps->present_exists && ps->frame_pacing) { - ps->present_event_id = x_new_id(ps->c); + ps->present_event_id = x_new_id(&ps->c); auto select_input = xcb_present_select_input( - ps->c, ps->present_event_id, session_get_target_window(ps), + ps->c.c, ps->present_event_id, session_get_target_window(ps), XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY); - auto notify_msc = - xcb_present_notify_msc(ps->c, session_get_target_window(ps), 0, 0, 1, 0); - set_cant_fail_cookie(ps, select_input); - set_cant_fail_cookie(ps, notify_msc); + auto notify_msc = xcb_present_notify_msc( + ps->c.c, session_get_target_window(ps), 0, 0, 1, 0); + set_cant_fail_cookie(&ps->c, select_input); + set_cant_fail_cookie(&ps->c, notify_msc); ps->present_event = xcb_register_for_special_xge( - ps->c, &xcb_present_id, ps->present_event_id, NULL); + ps->c.c, &xcb_present_id, ps->present_event_id, NULL); // Initialize rendering and frame timing statistics, and frame pacing // states. @@ -1480,13 +1422,13 @@ static bool redirect_start(session_t *ps) { } // Must call XSync() here - x_sync(ps->c); + x_sync(&ps->c); ps->redirected = true; ps->first_frame = true; // Re-detect driver since we now have a backend - ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root); + ps->drivers = detect_driver(ps->c.c, ps->backend_data, ps->c.screen_info->root); apply_driver_workarounds(ps, ps->drivers); root_damaged(ps); @@ -1506,10 +1448,11 @@ static void unredirect(session_t *ps) { destroy_backend(ps); - xcb_composite_unredirect_subwindows(ps->c, ps->root, session_redirection_mode(ps)); + xcb_composite_unredirect_subwindows(ps->c.c, ps->c.screen_info->root, + session_redirection_mode(ps)); // Unmap overlay window if (ps->overlay != XCB_NONE) { - xcb_unmap_window(ps->c, ps->overlay); + xcb_unmap_window(ps->c.c, ps->overlay); } // Free the damage ring @@ -1521,15 +1464,15 @@ static void unredirect(session_t *ps) { ps->damage_ring = ps->damage = NULL; if (ps->present_event_id) { - xcb_present_select_input(ps->c, ps->present_event_id, + xcb_present_select_input(ps->c.c, ps->present_event_id, session_get_target_window(ps), 0); ps->present_event_id = XCB_NONE; - xcb_unregister_for_special_event(ps->c, ps->present_event); + xcb_unregister_for_special_event(ps->c.c, ps->present_event); ps->present_event = NULL; } // Must call XSync() here - x_sync(ps->c); + x_sync(&ps->c); ps->redirected = false; log_debug("Screen unredirected."); @@ -1553,9 +1496,9 @@ handle_present_complete_notify(session_t *ps, xcb_present_complete_notify_event_ next_msc = ps->last_msc + 1; event_is_invalid = true; } - auto cookie = xcb_present_notify_msc(ps->c, session_get_target_window(ps), - 0, next_msc, 0, 0); - set_cant_fail_cookie(ps, cookie); + auto cookie = xcb_present_notify_msc( + ps->c.c, session_get_target_window(ps), 0, next_msc, 0, 0); + set_cant_fail_cookie(&ps->c, cookie); } if (event_is_invalid) { return; @@ -1602,7 +1545,7 @@ static void handle_present_events(session_t *ps) { return; } xcb_present_generic_event_t *ev; - while ((ev = (void *)xcb_poll_for_special_event(ps->c, ps->present_event))) { + while ((ev = (void *)xcb_poll_for_special_event(ps->c.c, ps->present_event))) { if (ev->event != ps->present_event_id) { // This event doesn't have the right event context, it's not meant // for us. @@ -1623,7 +1566,7 @@ static void handle_queued_x_events(EV_P attr_unused, ev_prepare *w, int revents handle_present_events(ps); xcb_generic_event_t *ev; - while ((ev = xcb_poll_for_queued_event(ps->c))) { + while ((ev = xcb_poll_for_queued_event(ps->c.c))) { ev_handle(ps, ev); free(ev); }; @@ -1632,9 +1575,9 @@ static void handle_queued_x_events(EV_P attr_unused, ev_prepare *w, int revents // for an indefinite amount of time. // Use XFlush here too, we might still use some Xlib functions // because OpenGL. - XFlush(ps->dpy); - xcb_flush(ps->c); - int err = xcb_connection_has_error(ps->c); + XFlush(ps->c.dpy); + xcb_flush(ps->c.c); + int err = xcb_connection_has_error(ps->c.c); if (err) { log_fatal("X11 server connection broke (error %d)", err); exit(1); @@ -1692,7 +1635,7 @@ static void fade_timer_callback(EV_P attr_unused, ev_timer *w, int revents attr_ static void handle_pending_updates(EV_P_ struct session *ps) { if (ps->pending_updates) { log_debug("Delayed handling of events, entering critical section"); - auto e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c)); + auto e = xcb_request_check(ps->c.c, xcb_grab_server_checked(ps->c.c)); if (e) { log_fatal_x_error(e, "failed to grab x server"); free(e); @@ -1718,7 +1661,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) { { auto r = xcb_get_input_focus_reply( - ps->c, xcb_get_input_focus(ps->c), NULL); + ps->c.c, xcb_get_input_focus(ps->c.c), NULL); if (!ps->active_win || (r && r->focus != ps->active_win->base.id)) { recheck_focus(ps); } @@ -1728,7 +1671,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) { // Process window flags (stale images) refresh_images(ps); - e = xcb_request_check(ps->c, xcb_ungrab_server_checked(ps->c)); + e = xcb_request_check(ps->c.c, xcb_ungrab_server_checked(ps->c.c)); if (e) { log_fatal_x_error(e, "failed to ungrab x server"); free(e); @@ -1868,7 +1811,7 @@ static void draw_callback(EV_P_ ev_timer *w, int revents) { static void x_event_callback(EV_P attr_unused, ev_io *w, int revents attr_unused) { session_t *ps = (session_t *)w; - xcb_generic_event_t *ev = xcb_poll_for_event(ps->c); + xcb_generic_event_t *ev = xcb_poll_for_event(ps->c.c); if (ev) { ev_handle(ps, ev); free(ev); @@ -1966,12 +1909,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, const char *config_file, bool all_xerrors, bool fork) { static const session_t s_def = { .backend_data = NULL, - .dpy = NULL, - .scr = 0, - .c = NULL, - .vis = 0, - .depth = 0, - .root = XCB_NONE, .root_height = 0, .root_width = 0, // .root_damage = XCB_NONE, @@ -1987,8 +1924,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy, .redirected = false, .alpha_picts = NULL, .fade_time = 0L, - .pending_reply_head = NULL, - .pending_reply_tail = NULL, .quit = false, .expose_rects = NULL, @@ -2056,52 +1991,42 @@ static session_t *session_init(int argc, char **argv, Display *dpy, // TODO(yshui) investigate what's the best window size render_statistics_init(&ps->render_stats, 128); - ps->pending_reply_tail = &ps->pending_reply_head; - ps->o.show_all_xerrors = all_xerrors; // Use the same Display across reset, primarily for resource leak checking - ps->dpy = dpy; - ps->c = XGetXCBConnection(ps->dpy); + x_connection_init(&ps->c, dpy); + // We store width/height from screen_info instead using them directly because they + // can change, see configure_root(). + ps->root_width = ps->c.screen_info->width_in_pixels; + ps->root_height = ps->c.screen_info->height_in_pixels; const xcb_query_extension_reply_t *ext_info; - ps->previous_xerror_handler = XSetErrorHandler(xerror); - - ps->scr = DefaultScreen(ps->dpy); - - auto screen = x_screen_of_display(ps->c, ps->scr); - ps->vis = screen->root_visual; - ps->depth = screen->root_depth; - ps->root = screen->root; - ps->root_width = screen->width_in_pixels; - ps->root_height = screen->height_in_pixels; - // Start listening to events on root earlier to catch all possible // root geometry changes auto e = xcb_request_check( - ps->c, xcb_change_window_attributes_checked( - ps->c, ps->root, XCB_CW_EVENT_MASK, - (const uint32_t[]){XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | - XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_PROPERTY_CHANGE})); + ps->c.c, xcb_change_window_attributes_checked( + ps->c.c, ps->c.screen_info->root, XCB_CW_EVENT_MASK, + (const uint32_t[]){XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | + XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | + XCB_EVENT_MASK_PROPERTY_CHANGE})); if (e) { log_error_x_error(e, "Failed to setup root window event mask"); free(e); } - xcb_prefetch_extension_data(ps->c, &xcb_render_id); - xcb_prefetch_extension_data(ps->c, &xcb_composite_id); - xcb_prefetch_extension_data(ps->c, &xcb_damage_id); - xcb_prefetch_extension_data(ps->c, &xcb_shape_id); - xcb_prefetch_extension_data(ps->c, &xcb_xfixes_id); - xcb_prefetch_extension_data(ps->c, &xcb_randr_id); - xcb_prefetch_extension_data(ps->c, &xcb_present_id); - xcb_prefetch_extension_data(ps->c, &xcb_sync_id); - xcb_prefetch_extension_data(ps->c, &xcb_glx_id); - xcb_prefetch_extension_data(ps->c, &xcb_dpms_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_render_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_composite_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_damage_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_shape_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_xfixes_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_randr_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_present_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_sync_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_glx_id); + xcb_prefetch_extension_data(ps->c.c, &xcb_dpms_id); - ext_info = xcb_get_extension_data(ps->c, &xcb_render_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_render_id); if (!ext_info || !ext_info->present) { log_fatal("No render extension"); exit(1); @@ -2109,7 +2034,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, ps->render_event = ext_info->first_event; ps->render_error = ext_info->first_error; - ext_info = xcb_get_extension_data(ps->c, &xcb_composite_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_composite_id); if (!ext_info || !ext_info->present) { log_fatal("No composite extension"); exit(1); @@ -2120,8 +2045,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy, { xcb_composite_query_version_reply_t *reply = xcb_composite_query_version_reply( - ps->c, - xcb_composite_query_version(ps->c, XCB_COMPOSITE_MAJOR_VERSION, + ps->c.c, + xcb_composite_query_version(ps->c.c, XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MINOR_VERSION), NULL); @@ -2133,45 +2058,45 @@ static session_t *session_init(int argc, char **argv, Display *dpy, free(reply); } - ext_info = xcb_get_extension_data(ps->c, &xcb_damage_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_damage_id); if (!ext_info || !ext_info->present) { log_fatal("No damage extension"); exit(1); } ps->damage_event = ext_info->first_event; ps->damage_error = ext_info->first_error; - xcb_discard_reply(ps->c, xcb_damage_query_version(ps->c, XCB_DAMAGE_MAJOR_VERSION, - XCB_DAMAGE_MINOR_VERSION) - .sequence); + xcb_discard_reply(ps->c.c, xcb_damage_query_version(ps->c.c, XCB_DAMAGE_MAJOR_VERSION, + XCB_DAMAGE_MINOR_VERSION) + .sequence); - ext_info = xcb_get_extension_data(ps->c, &xcb_xfixes_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_xfixes_id); if (!ext_info || !ext_info->present) { log_fatal("No XFixes extension"); exit(1); } ps->xfixes_event = ext_info->first_event; ps->xfixes_error = ext_info->first_error; - xcb_discard_reply(ps->c, xcb_xfixes_query_version(ps->c, XCB_XFIXES_MAJOR_VERSION, - XCB_XFIXES_MINOR_VERSION) - .sequence); + xcb_discard_reply(ps->c.c, xcb_xfixes_query_version(ps->c.c, XCB_XFIXES_MAJOR_VERSION, + XCB_XFIXES_MINOR_VERSION) + .sequence); - ps->damaged_region = x_new_id(ps->c); - if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c, ps->damaged_region, 0, NULL)) { + ps->damaged_region = x_new_id(&ps->c); + if (!XCB_AWAIT_VOID(xcb_xfixes_create_region, ps->c.c, ps->damaged_region, 0, NULL)) { log_fatal("Failed to create a XFixes region"); goto err; } - ext_info = xcb_get_extension_data(ps->c, &xcb_glx_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_glx_id); if (ext_info && ext_info->present) { ps->glx_exists = true; ps->glx_error = ext_info->first_error; ps->glx_event = ext_info->first_event; } - ext_info = xcb_get_extension_data(ps->c, &xcb_dpms_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_dpms_id); ps->dpms_exists = ext_info && ext_info->present; if (ps->dpms_exists) { - auto r = xcb_dpms_info_reply(ps->c, xcb_dpms_info(ps->c), NULL); + auto r = xcb_dpms_info_reply(ps->c.c, xcb_dpms_info(ps->c.c), NULL); if (!r) { log_fatal("Failed to query DPMS info"); goto err; @@ -2226,7 +2151,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, "binary will not be installed in the future."); } - ps->atoms = init_atoms(ps->c); + ps->atoms = init_atoms(ps->c.c); ps->atoms_wintypes[WINTYPE_UNKNOWN] = 0; #define SET_WM_TYPE_ATOM(x) \ ps->atoms_wintypes[WINTYPE_##x] = ps->atoms->a_NET_WM_WINDOW_TYPE_##x @@ -2287,25 +2212,25 @@ static session_t *session_init(int argc, char **argv, Display *dpy, rebuild_shadow_exclude_reg(ps); // Query X Shape - ext_info = xcb_get_extension_data(ps->c, &xcb_shape_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_shape_id); if (ext_info && ext_info->present) { ps->shape_event = ext_info->first_event; ps->shape_error = ext_info->first_error; ps->shape_exists = true; } - ext_info = xcb_get_extension_data(ps->c, &xcb_randr_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_randr_id); if (ext_info && ext_info->present) { ps->randr_exists = true; ps->randr_event = ext_info->first_event; ps->randr_error = ext_info->first_error; } - ext_info = xcb_get_extension_data(ps->c, &xcb_present_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_present_id); if (ext_info && ext_info->present) { auto r = xcb_present_query_version_reply( - ps->c, - xcb_present_query_version(ps->c, XCB_PRESENT_MAJOR_VERSION, + ps->c.c, + xcb_present_query_version(ps->c.c, XCB_PRESENT_MAJOR_VERSION, XCB_PRESENT_MINOR_VERSION), NULL); if (r) { @@ -2315,14 +2240,14 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } // Query X Sync - ext_info = xcb_get_extension_data(ps->c, &xcb_sync_id); + ext_info = xcb_get_extension_data(ps->c.c, &xcb_sync_id); if (ext_info && ext_info->present) { ps->xsync_error = ext_info->first_error; ps->xsync_event = ext_info->first_event; // Need X Sync 3.1 for fences auto r = xcb_sync_initialize_reply( - ps->c, - xcb_sync_initialize(ps->c, XCB_SYNC_MAJOR_VERSION, XCB_SYNC_MINOR_VERSION), + ps->c.c, + xcb_sync_initialize(ps->c.c, XCB_SYNC_MAJOR_VERSION, XCB_SYNC_MINOR_VERSION), NULL); if (r && (r->major_version > 3 || (r->major_version == 3 && r->minor_version >= 1))) { @@ -2333,9 +2258,10 @@ static session_t *session_init(int argc, char **argv, Display *dpy, ps->sync_fence = XCB_NONE; if (ps->xsync_exists) { - ps->sync_fence = x_new_id(ps->c); - e = xcb_request_check(ps->c, xcb_sync_create_fence_checked( - ps->c, ps->root, ps->sync_fence, 0)); + ps->sync_fence = x_new_id(&ps->c); + e = xcb_request_check( + ps->c.c, xcb_sync_create_fence_checked( + ps->c.c, ps->c.screen_info->root, ps->sync_fence, 0)); if (e) { if (ps->o.xrender_sync_fence) { log_error_x_error(e, "Failed to create a XSync fence. " @@ -2412,7 +2338,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } } - ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root); + ps->drivers = detect_driver(ps->c.c, ps->backend_data, ps->c.screen_info->root); apply_driver_workarounds(ps, ps->drivers); // Initialize filters, must be preceded by OpenGL context creation @@ -2453,26 +2379,29 @@ static session_t *session_init(int argc, char **argv, Display *dpy, // Monitor screen changes if vsync_sw is enabled and we are using // an auto-detected refresh rate, or when X RandR features are enabled if (ps->randr_exists && ps->o.crop_shadow_to_monitor) { - xcb_randr_select_input(ps->c, ps->root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); + xcb_randr_select_input(ps->c.c, ps->c.screen_info->root, + XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); + x_update_monitors(&ps->c, &ps->monitors); } - x_update_randr_monitors(ps); - { xcb_render_create_picture_value_list_t pa = { .subwindowmode = IncludeInferiors, }; ps->root_picture = x_create_picture_with_visual_and_pixmap( - ps->c, ps->vis, ps->root, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); + &ps->c, ps->c.screen_info->root_visual, ps->c.screen_info->root, + XCB_RENDER_CP_SUBWINDOW_MODE, &pa); if (ps->overlay != XCB_NONE) { ps->tgt_picture = x_create_picture_with_visual_and_pixmap( - ps->c, ps->vis, ps->overlay, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); - } else + &ps->c, ps->c.screen_info->root_visual, ps->overlay, + XCB_RENDER_CP_SUBWINDOW_MODE, &pa); + } else { ps->tgt_picture = ps->root_picture; + } } - ev_io_init(&ps->xiow, x_event_callback, ConnectionNumber(ps->dpy), EV_READ); + ev_io_init(&ps->xiow, x_event_callback, ConnectionNumber(ps->c.dpy), EV_READ); ev_io_start(ps->loop, &ps->xiow); ev_init(&ps->unredir_timer, tmout_unredir_callback); ev_init(&ps->draw_timer, draw_callback); @@ -2509,7 +2438,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, // functions if (ps->o.dbus) { #ifdef CONFIG_DBUS - cdbus_init(ps, DisplayString(ps->dpy)); + cdbus_init(ps, DisplayString(ps->c.dpy)); if (!ps->dbus_data) { ps->o.dbus = false; } @@ -2519,7 +2448,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, #endif } - e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c)); + e = xcb_request_check(ps->c.c, xcb_grab_server_checked(ps->c.c)); if (e) { log_fatal_x_error(e, "Failed to grab X server"); free(e); @@ -2532,12 +2461,12 @@ static session_t *session_init(int argc, char **argv, Display *dpy, // earlier is irrelavant at this point. // A better solution is probably grabbing the server from the very start. But I // think there still could be race condition that mandates discarding the events. - x_discard_events(ps->c); + x_discard_events(&ps->c); - xcb_query_tree_reply_t *query_tree_reply = - xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, ps->root), NULL); + xcb_query_tree_reply_t *query_tree_reply = xcb_query_tree_reply( + ps->c.c, xcb_query_tree(ps->c.c, ps->c.screen_info->root), NULL); - e = xcb_request_check(ps->c, xcb_ungrab_server_checked(ps->c)); + e = xcb_request_check(ps->c.c, xcb_ungrab_server_checked(ps->c.c)); if (e) { log_fatal_x_error(e, "Failed to ungrab server"); free(e); @@ -2630,7 +2559,7 @@ static void session_destroy(session_t *ps) { ps->file_watch_handle = NULL; // Stop listening to events on root window - xcb_change_window_attributes(ps->c, ps->root, XCB_CW_EVENT_MASK, + xcb_change_window_attributes(ps->c.c, ps->c.screen_info->root, XCB_CW_EVENT_MASK, (const uint32_t[]){0}); #ifdef CONFIG_DBUS @@ -2681,32 +2610,17 @@ static void session_destroy(session_t *ps) { ps->track_atom_lst = NULL; } - // Free ignore linked list - { - pending_reply_t *next = NULL; - for (auto ign = ps->pending_reply_head; ign; ign = next) { - next = ign->next; - - free(ign); - } - - // Reset head and tail - ps->pending_reply_head = NULL; - ps->pending_reply_tail = &ps->pending_reply_head; - } - // Free tgt_{buffer,picture} and root_picture if (ps->tgt_buffer.pict == ps->tgt_picture) { ps->tgt_buffer.pict = XCB_NONE; } - if (ps->tgt_picture == ps->root_picture) { - ps->tgt_picture = XCB_NONE; - } else { - free_picture(ps->c, &ps->tgt_picture); + if (ps->tgt_picture != ps->root_picture) { + x_free_picture(&ps->c, ps->tgt_picture); } + x_free_picture(&ps->c, ps->root_picture); + ps->tgt_picture = ps->root_picture = XCB_NONE; - free_picture(ps->c, &ps->root_picture); free_paint(ps, &ps->tgt_buffer); pixman_region32_fini(&ps->screen_reg); @@ -2719,7 +2633,7 @@ static void session_destroy(session_t *ps) { } free(ps->o.blur_kerns); free(ps->o.glx_fshader_win_str); - x_free_randr_info(ps); + x_free_monitor_info(&ps->monitors); render_statistics_destroy(&ps->render_stats); @@ -2744,28 +2658,28 @@ static void session_destroy(session_t *ps) { // Release overlay window if (ps->overlay) { - xcb_composite_release_overlay_window(ps->c, ps->overlay); + xcb_composite_release_overlay_window(ps->c.c, ps->overlay); ps->overlay = XCB_NONE; } if (ps->sync_fence != XCB_NONE) { - xcb_sync_destroy_fence(ps->c, ps->sync_fence); + xcb_sync_destroy_fence(ps->c.c, ps->sync_fence); ps->sync_fence = XCB_NONE; } // Free reg_win if (ps->reg_win != XCB_NONE) { - xcb_destroy_window(ps->c, ps->reg_win); + xcb_destroy_window(ps->c.c, ps->reg_win); ps->reg_win = XCB_NONE; } if (ps->debug_window != XCB_NONE) { - xcb_destroy_window(ps->c, ps->debug_window); + xcb_destroy_window(ps->c.c, ps->debug_window); ps->debug_window = XCB_NONE; } if (ps->damaged_region != XCB_NONE) { - xcb_xfixes_destroy_region(ps->c, ps->damaged_region); + xcb_xfixes_destroy_region(ps->c.c, ps->damaged_region); ps->damaged_region = XCB_NONE; } @@ -2784,7 +2698,7 @@ static void session_destroy(session_t *ps) { #endif // Flush all events - x_sync(ps->c); + x_sync(&ps->c); ev_io_stop(ps->loop, &ps->xiow); if (ps->o.legacy_backends) { free_conv((conv *)ps->shadow_context); @@ -2796,8 +2710,6 @@ static void session_destroy(session_t *ps) { xrc_report_xid(); #endif - XSetErrorHandler(ps->previous_xerror_handler); - // Stop libev event handlers ev_timer_stop(ps->loop, &ps->unredir_timer); ev_timer_stop(ps->loop, &ps->fade_timer); @@ -2806,6 +2718,8 @@ static void session_destroy(session_t *ps) { ev_prepare_stop(ps->loop, &ps->event_check); ev_signal_stop(ps->loop, &ps->usr1_signal); ev_signal_stop(ps->loop, &ps->int_signal); + + free_x_connection(&ps->c); } /** @@ -2872,10 +2786,9 @@ int main(int argc, char **argv) { // Failed to read, the child has most likely died // We can probably waitpid() here. return 1; - } else { - // We are done - return 0; } + // We are done + return 0; } // We are the child close(pfds[0]); diff --git a/src/picom.h b/src/picom.h index 6f14cd0..e68b1e0 100644 --- a/src/picom.h +++ b/src/picom.h @@ -94,7 +94,7 @@ free_win_res_glx(session_t *ps attr_unused, struct managed_win *w attr_unused) { * Dump an drawable's info. */ static inline void dump_drawable(session_t *ps, xcb_drawable_t drawable) { - auto r = xcb_get_geometry_reply(ps->c, xcb_get_geometry(ps->c, drawable), NULL); + auto r = xcb_get_geometry_reply(ps->c.c, xcb_get_geometry(ps->c.c, drawable), NULL); if (!r) { log_trace("Drawable %#010x: Failed", drawable); return; diff --git a/src/render.c b/src/render.c index f4b3a97..65d02cf 100644 --- a/src/render.c +++ b/src/render.c @@ -48,20 +48,20 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h bool repeat, int depth, xcb_visualid_t visual, bool force) { #ifdef CONFIG_OPENGL // XXX This is a mess. But this will go away after the backend refactor. - if (!ppaint->pixmap) + if (!ppaint->pixmap) { return false; + } struct glx_fbconfig_info *fbcfg; if (!visual) { assert(depth == 32); if (!ps->argb_fbconfig) { - ps->argb_fbconfig = - glx_find_fbconfig(ps->dpy, ps->scr, - (struct xvisual_info){.red_size = 8, - .green_size = 8, - .blue_size = 8, - .alpha_size = 8, - .visual_depth = 32}); + ps->argb_fbconfig = glx_find_fbconfig( + &ps->c, (struct xvisual_info){.red_size = 8, + .green_size = 8, + .blue_size = 8, + .alpha_size = 8, + .visual_depth = 32}); } if (!ps->argb_fbconfig) { log_error("Failed to find appropriate FBConfig for 32 bit depth"); @@ -69,7 +69,7 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h } fbcfg = ps->argb_fbconfig; } else { - auto m = x_get_visual_info(ps->c, visual); + auto m = x_get_visual_info(&ps->c, visual); if (m.visual_depth < 0) { return false; } @@ -80,7 +80,7 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h } if (!ppaint->fbcfg) { - ppaint->fbcfg = glx_find_fbconfig(ps->dpy, ps->scr, m); + ppaint->fbcfg = glx_find_fbconfig(&ps->c, m); } if (!ppaint->fbcfg) { log_error("Failed to find appropriate FBConfig for X pixmap"); @@ -89,9 +89,10 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h fbcfg = ppaint->fbcfg; } - if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap)) + if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap)) { return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, repeat, fbcfg); + } #else (void)ps; (void)ppaint; @@ -129,7 +130,7 @@ static int get_buffer_age(session_t *ps) { } if (ps->o.use_damage) { unsigned int val; - glXQueryDrawable(ps->dpy, get_tgt_window(ps), + glXQueryDrawable(ps->c.dpy, get_tgt_window(ps), GLX_BACK_BUFFER_AGE_EXT, &val); return (int)val ?: -1; } @@ -144,7 +145,7 @@ static int get_buffer_age(session_t *ps) { */ static inline void xrfilter_reset(session_t *ps, xcb_render_picture_t p) { #define FILTER "Nearest" - xcb_render_set_picture_filter(ps->c, p, strlen(FILTER), FILTER, 0, NULL); + xcb_render_set_picture_filter(ps->c.c, p, strlen(FILTER), FILTER, 0, NULL); #undef FILTER } @@ -153,7 +154,7 @@ static inline void attr_nonnull(1, 2) set_tgt_clip(session_t *ps, region_t *reg) switch (ps->o.backend) { case BKEND_XRENDER: case BKEND_XR_GLX_HYBRID: - x_set_picture_clip_region(ps->c, ps->tgt_buffer.pict, 0, 0, reg); + x_set_picture_clip_region(&ps->c, ps->tgt_buffer.pict, 0, 0, reg); break; #ifdef CONFIG_OPENGL case BKEND_GLX: glx_set_clip(ps, reg); break; @@ -162,16 +163,6 @@ static inline void attr_nonnull(1, 2) set_tgt_clip(session_t *ps, region_t *reg) } } -/** - * Destroy a Picture. - */ -void free_picture(xcb_connection_t *c, xcb_render_picture_t *p) { - if (*p) { - xcb_render_free_picture(c, *p); - *p = XCB_NONE; - } -} - /** * Free paint_t. */ @@ -179,10 +170,14 @@ void free_paint(session_t *ps, paint_t *ppaint) { #ifdef CONFIG_OPENGL free_paint_glx(ps, ppaint); #endif - free_picture(ps->c, &ppaint->pict); - if (ppaint->pixmap) - xcb_free_pixmap(ps->c, ppaint->pixmap); - ppaint->pixmap = XCB_NONE; + if (ppaint->pict != XCB_NONE) { + x_free_picture(&ps->c, ppaint->pict); + ppaint->pict = XCB_NONE; + } + if (ppaint->pixmap) { + xcb_free_pixmap(ps->c.c, ppaint->pixmap); + ppaint->pixmap = XCB_NONE; + } } uint32_t @@ -253,8 +248,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f if (alpha_step != 0) { if (cr) { xcb_render_picture_t p_tmp = x_create_picture_with_standard( - ps->c, ps->root, fullwid, fullhei, - XCB_PICT_STANDARD_ARGB_32, 0, 0); + &ps->c, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0); xcb_render_color_t trans = { .red = 0, .blue = 0, .green = 0, .alpha = 0}; const xcb_rectangle_t rect = { @@ -262,7 +256,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f .y = 0, .width = to_u16_checked(fullwid), .height = to_u16_checked(fullhei)}; - xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, + xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, p_tmp, trans, 1, &rect); uint32_t max_ntraps = to_u32_checked(cr); @@ -272,25 +266,24 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f traps, max_ntraps, cr, fullwid, fullhei); xcb_render_trapezoids( - ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, - x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), + ps->c.c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp, + x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); xcb_render_composite( - ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp, + ps->c.c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp, ps->tgt_buffer.pict, to_i16_checked(x), to_i16_checked(y), to_i16_checked(x), to_i16_checked(y), to_i16_checked(dx), to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei)); - xcb_render_free_picture(ps->c, p_tmp); + x_free_picture(&ps->c, p_tmp); } else { xcb_render_picture_t p_tmp = alpha_pict; if (clip) { p_tmp = x_create_picture_with_standard( - ps->c, ps->root, wid, hei, - XCB_PICT_STANDARD_ARGB_32, 0, 0); + &ps->c, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); xcb_render_color_t black = { .red = 255, .blue = 255, .green = 255, .alpha = 255}; @@ -299,17 +292,18 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f .y = 0, .width = to_u16_checked(wid), .height = to_u16_checked(hei)}; - xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, + xcb_render_fill_rectangles(ps->c.c, + XCB_RENDER_PICT_OP_SRC, p_tmp, black, 1, &rect); if (alpha_pict) { xcb_render_composite( - ps->c, XCB_RENDER_PICT_OP_SRC, + ps->c.c, XCB_RENDER_PICT_OP_SRC, alpha_pict, XCB_NONE, p_tmp, 0, 0, 0, 0, 0, 0, to_u16_checked(wid), to_u16_checked(hei)); } xcb_render_composite( - ps->c, XCB_RENDER_PICT_OP_OUT_REVERSE, + ps->c.c, XCB_RENDER_PICT_OP_OUT_REVERSE, clip->pict, XCB_NONE, p_tmp, 0, 0, 0, 0, to_i16_checked(clip->x), to_i16_checked(clip->y), to_u16_checked(wid), to_u16_checked(hei)); @@ -319,12 +313,12 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f : XCB_RENDER_PICT_OP_OVER); xcb_render_composite( - ps->c, op, pict, p_tmp, ps->tgt_buffer.pict, + ps->c.c, op, pict, p_tmp, ps->tgt_buffer.pict, to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(dx), to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei)); if (clip) { - xcb_render_free_picture(ps->c, p_tmp); + x_free_picture(&ps->c, p_tmp); } } } @@ -375,15 +369,18 @@ paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) { // Don't check for presence of Pixmap here, because older X Composite doesn't // provide it - if (!ppaint) + if (!ppaint) { return false; + } - if (bkend_use_xrender(ps) && !ppaint->pict) + if (bkend_use_xrender(ps) && !ppaint->pict) { return false; + } #ifdef CONFIG_OPENGL - if (BKEND_GLX == ps->o.backend && !glx_tex_binded(ppaint->ptex, XCB_NONE)) + if (BKEND_GLX == ps->o.backend && !glx_tex_binded(ppaint->ptex, XCB_NONE)) { return false; + } #endif return true; @@ -395,9 +392,9 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) { void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) { // Fetch Pixmap if (!w->paint.pixmap) { - w->paint.pixmap = x_new_id(ps->c); - set_ignore_cookie(ps, xcb_composite_name_window_pixmap(ps->c, w->base.id, - w->paint.pixmap)); + w->paint.pixmap = x_new_id(&ps->c); + set_ignore_cookie(&ps->c, xcb_composite_name_window_pixmap( + ps->c.c, w->base.id, w->paint.pixmap)); } xcb_drawable_t draw = w->paint.pixmap; @@ -415,7 +412,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) }; w->paint.pict = x_create_picture_with_pictfmt_and_pixmap( - ps->c, w->pictfmt, draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); + &ps->c, w->pictfmt, draw, XCB_RENDER_CP_SUBWINDOW_MODE, &pa); } // GLX: Build texture @@ -442,8 +439,8 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) // Invert window color, if required if (bkend_use_xrender(ps) && w->invert_color) { - xcb_render_picture_t newpict = x_create_picture_with_pictfmt( - ps->c, ps->root, wid, hei, w->pictfmt, 0, NULL); + xcb_render_picture_t newpict = + x_create_picture_with_pictfmt(&ps->c, wid, hei, w->pictfmt, 0, NULL); if (newpict) { // Apply clipping region to save some CPU if (reg_paint) { @@ -456,17 +453,18 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) pixman_region32_fini(®); } - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, pict, XCB_NONE, - newpict, 0, 0, 0, 0, 0, 0, wid, hei); - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_DIFFERENCE, + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, pict, + XCB_NONE, newpict, 0, 0, 0, 0, 0, 0, wid, hei); + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_DIFFERENCE, ps->white_picture, XCB_NONE, newpict, 0, 0, 0, 0, 0, 0, wid, hei); // We use an extra PictOpInReverse operation to get correct // pixel alpha. There could be a better solution. - if (win_has_alpha(w)) - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_IN_REVERSE, + if (win_has_alpha(w)) { + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_IN_REVERSE, pict, XCB_NONE, newpict, 0, 0, 0, 0, 0, 0, wid, hei); + } pict = newpict; } } @@ -494,43 +492,51 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) // ctop = checked top // Make sure top margin is smaller than height int ctop = min2(body_height, t); - if (ctop > 0) + if (ctop > 0) { COMP_BDR(0, 0, wid, ctop); + } body_height -= ctop; - if (body_height <= 0) + if (body_height <= 0) { break; + } // bottom // cbot = checked bottom // Make sure bottom margin is not too large int cbot = min2(body_height, b); - if (cbot > 0) + if (cbot > 0) { COMP_BDR(0, hei - cbot, wid, cbot); + } // Height of window exclude the margin body_height -= cbot; - if (body_height <= 0) + if (body_height <= 0) { break; + } // left int body_width = wid; int cleft = min2(body_width, l); - if (cleft > 0) + if (cleft > 0) { COMP_BDR(0, ctop, cleft, body_height); + } body_width -= cleft; - if (body_width <= 0) + if (body_width <= 0) { break; + } // right int cright = min2(body_width, r); - if (cright > 0) + if (cright > 0) { COMP_BDR(wid - cright, ctop, cright, body_height); + } body_width -= cright; - if (body_width <= 0) + if (body_width <= 0) { break; + } // body paint_region(ps, w, cleft, ctop, body_width, body_height, @@ -540,14 +546,17 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) #undef COMP_BDR - if (pict != w->paint.pict) - free_picture(ps->c, &pict); + if (pict != w->paint.pict) { + x_free_picture(&ps->c, pict); + pict = XCB_NONE; + } // Dimming the window if needed if (w->dim) { double dim_opacity = ps->o.inactive_dim; - if (!ps->o.inactive_dim_fixed) + if (!ps->o.inactive_dim_fixed) { dim_opacity *= w->opacity; + } switch (ps->o.backend) { case BKEND_XRENDER: @@ -569,7 +578,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint) .height = hei, }; - xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_OVER, + xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_OVER, ps->tgt_buffer.pict, color, 1, &rect); } break; #ifdef CONFIG_OPENGL @@ -593,15 +602,17 @@ static bool get_root_tile(session_t *ps) { ps->root_tile_fill = false; bool fill = false; - xcb_pixmap_t pixmap = x_get_root_back_pixmap(ps->c, ps->root, ps->atoms); + xcb_pixmap_t pixmap = x_get_root_back_pixmap(&ps->c, ps->atoms); // Make sure the pixmap we got is valid - if (pixmap && !x_validate_pixmap(ps->c, pixmap)) + if (pixmap && !x_validate_pixmap(&ps->c, pixmap)) { pixmap = XCB_NONE; + } // Create a pixmap if there isn't any if (!pixmap) { - pixmap = x_create_pixmap(ps->c, (uint8_t)ps->depth, ps->root, 1, 1); + pixmap = + x_create_pixmap(&ps->c, (uint8_t)ps->c.screen_info->root_depth, 1, 1); if (pixmap == XCB_NONE) { log_error("Failed to create pixmaps for root tile."); return false; @@ -614,7 +625,7 @@ static bool get_root_tile(session_t *ps) { .repeat = true, }; ps->root_tile_paint.pict = x_create_picture_with_visual_and_pixmap( - ps->c, ps->vis, pixmap, XCB_RENDER_CP_REPEAT, &pa); + &ps->c, ps->c.screen_info->root_visual, pixmap, XCB_RENDER_CP_REPEAT, &pa); // Fill pixmap if needed if (fill) { @@ -627,15 +638,17 @@ static bool get_root_tile(session_t *ps) { rect.x = rect.y = 0; rect.width = rect.height = 1; - xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, + xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, ps->root_tile_paint.pict, col, 1, &rect); } ps->root_tile_fill = fill; ps->root_tile_paint.pixmap = pixmap; #ifdef CONFIG_OPENGL - if (BKEND_GLX == ps->o.backend) - return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0, ps->vis, false); + if (BKEND_GLX == ps->o.backend) { + return paint_bind_tex(ps, &ps->root_tile_paint, 0, 0, true, 0, + ps->c.screen_info->root_visual, false); + } #endif return true; @@ -668,16 +681,16 @@ static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacit xcb_render_picture_t shadow_picture = XCB_NONE, shadow_picture_argb = XCB_NONE; xcb_gcontext_t gc = XCB_NONE; - shadow_image = make_shadow(ps->c, (conv *)ps->shadow_context, opacity, width, height); + shadow_image = + make_shadow(&ps->c, (conv *)ps->shadow_context, opacity, width, height); if (!shadow_image) { log_error("failed to make shadow"); return XCB_NONE; } - shadow_pixmap = - x_create_pixmap(ps->c, 8, ps->root, shadow_image->width, shadow_image->height); + shadow_pixmap = x_create_pixmap(&ps->c, 8, shadow_image->width, shadow_image->height); shadow_pixmap_argb = - x_create_pixmap(ps->c, 32, ps->root, shadow_image->width, shadow_image->height); + x_create_pixmap(&ps->c, 32, shadow_image->width, shadow_image->height); if (!shadow_pixmap || !shadow_pixmap_argb) { log_error("failed to create shadow pixmaps"); @@ -685,18 +698,18 @@ static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacit } shadow_picture = x_create_picture_with_standard_and_pixmap( - ps->c, XCB_PICT_STANDARD_A_8, shadow_pixmap, 0, NULL); + &ps->c, XCB_PICT_STANDARD_A_8, shadow_pixmap, 0, NULL); shadow_picture_argb = x_create_picture_with_standard_and_pixmap( - ps->c, XCB_PICT_STANDARD_ARGB_32, shadow_pixmap_argb, 0, NULL); + &ps->c, XCB_PICT_STANDARD_ARGB_32, shadow_pixmap_argb, 0, NULL); if (!shadow_picture || !shadow_picture_argb) { goto shadow_picture_err; } - gc = x_new_id(ps->c); - xcb_create_gc(ps->c, gc, shadow_pixmap, 0, NULL); + gc = x_new_id(&ps->c); + xcb_create_gc(ps->c.c, gc, shadow_pixmap, 0, NULL); - xcb_image_put(ps->c, shadow_pixmap, gc, shadow_image, 0, 0, 0); - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, ps->cshadow_picture, + xcb_image_put(ps->c.c, shadow_pixmap, gc, shadow_image, 0, 0, 0); + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, ps->cshadow_picture, shadow_picture, shadow_picture_argb, 0, 0, 0, 0, 0, 0, shadow_image->width, shadow_image->height); @@ -705,26 +718,32 @@ static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacit assert(!w->shadow_paint.pict); w->shadow_paint.pict = shadow_picture_argb; - xcb_free_gc(ps->c, gc); + xcb_free_gc(ps->c.c, gc); xcb_image_destroy(shadow_image); - xcb_free_pixmap(ps->c, shadow_pixmap); - xcb_render_free_picture(ps->c, shadow_picture); + xcb_free_pixmap(ps->c.c, shadow_pixmap); + x_free_picture(&ps->c, shadow_picture); return true; shadow_picture_err: - if (shadow_image) + if (shadow_image) { xcb_image_destroy(shadow_image); - if (shadow_pixmap) - xcb_free_pixmap(ps->c, shadow_pixmap); - if (shadow_pixmap_argb) - xcb_free_pixmap(ps->c, shadow_pixmap_argb); - if (shadow_picture) - xcb_render_free_picture(ps->c, shadow_picture); - if (shadow_picture_argb) - xcb_render_free_picture(ps->c, shadow_picture_argb); - if (gc) - xcb_free_gc(ps->c, gc); + } + if (shadow_pixmap) { + xcb_free_pixmap(ps->c.c, shadow_pixmap); + } + if (shadow_pixmap_argb) { + xcb_free_pixmap(ps->c.c, shadow_pixmap_argb); + } + if (shadow_picture) { + x_free_picture(&ps->c, shadow_picture); + } + if (shadow_picture_argb) { + x_free_picture(&ps->c, shadow_picture_argb); + } + if (gc) { + xcb_free_gc(ps->c.c, gc); + } return false; } @@ -753,23 +772,22 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { traps, max_ntraps, w->corner_radius, w->widthb, w->heightb); td = x_create_picture_with_standard( - ps->c, ps->root, w->widthb, w->heightb, - XCB_PICT_STANDARD_ARGB_32, 0, 0); + &ps->c, w->widthb, w->heightb, XCB_PICT_STANDARD_ARGB_32, 0, 0); xcb_render_color_t trans = { .red = 0, .blue = 0, .green = 0, .alpha = 0}; const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(w->widthb), .height = to_u16_checked(w->heightb)}; - xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, + xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect); - auto solid = solid_picture(ps->c, ps->root, false, 1, 0, 0, 0); + auto solid = solid_picture(&ps->c, false, 1, 0, 0, 0); xcb_render_trapezoids( - ps->c, XCB_RENDER_PICT_OP_OVER, solid, td, - x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, + ps->c.c, XCB_RENDER_PICT_OP_OVER, solid, td, + x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); - xcb_render_free_picture(ps->c, solid); + x_free_picture(&ps->c, solid); } else { // Not implemented } @@ -785,7 +803,7 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) { w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, NULL, should_clip ? &clip : NULL); if (td) { - xcb_render_free_picture(ps->c, td); + x_free_picture(&ps->c, td); } } @@ -813,16 +831,17 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y // Directly copying from tgt_buffer to it does not work, so we create a // Picture in the middle. - xcb_render_picture_t tmp_picture = - x_create_picture_with_visual(ps->c, ps->root, wid, hei, ps->vis, 0, NULL); + xcb_render_picture_t tmp_picture = x_create_picture_with_visual( + &ps->c, wid, hei, ps->c.screen_info->root_visual, 0, NULL); if (!tmp_picture) { log_error("Failed to build intermediate Picture."); return false; } - if (reg_clip && tmp_picture) - x_set_picture_clip_region(ps->c, tmp_picture, 0, 0, reg_clip); + if (reg_clip && tmp_picture) { + x_set_picture_clip_region(&ps->c, tmp_picture, 0, 0, reg_clip); + } xcb_render_picture_t src_pict = tgt_buffer, dst_pict = tmp_picture; for (int i = 0; i < nkernels; ++i) { @@ -836,9 +855,9 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y // be applied on source picture, to get the nearby pixels outside the // window. xcb_render_set_picture_filter( - ps->c, src_pict, strlen(XRFILTER_CONVOLUTION), XRFILTER_CONVOLUTION, + ps->c.c, src_pict, strlen(XRFILTER_CONVOLUTION), XRFILTER_CONVOLUTION, (uint32_t)(kwid * khei + 2), convolution_blur); - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE, dst_pict, (rd_from_tgt ? x : 0), (rd_from_tgt ? y : 0), 0, 0, (rd_from_tgt ? 0 : x), (rd_from_tgt ? 0 : y), wid, hei); @@ -851,11 +870,12 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y } } - if (src_pict != tgt_buffer) - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded, + if (src_pict != tgt_buffer) { + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded, tgt_buffer, 0, 0, 0, 0, x, y, wid, hei); + } - free_picture(ps->c, &tmp_picture); + x_free_picture(&ps->c, tmp_picture); return true; } @@ -910,23 +930,23 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t make_rounded_window_shape(traps, max_ntraps, cr, wid, hei); td = x_create_picture_with_standard( - ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); + &ps->c, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0); xcb_render_color_t trans = { .red = 0, .blue = 0, .green = 0, .alpha = 0}; const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(wid), .height = to_u16_checked(hei)}; - xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, + xcb_render_fill_rectangles(ps->c.c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect); - auto solid = solid_picture(ps->c, ps->root, false, 1, 0, 0, 0); + auto solid = solid_picture(&ps->c, false, 1, 0, 0, 0); xcb_render_trapezoids( - ps->c, XCB_RENDER_PICT_OP_OVER, solid, td, - x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, + ps->c.c, XCB_RENDER_PICT_OP_OVER, solid, td, + x_get_pictfmt_for_standard(&ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps); - xcb_render_free_picture(ps->c, solid); + x_free_picture(&ps->c, solid); } // Minimize the region we try to blur, if the window itself is not @@ -946,7 +966,7 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache, ps->o.blur_kernel_count, ®_blur, td); if (td) { - xcb_render_free_picture(ps->c, td); + x_free_picture(&ps->c, td); } pixman_region32_clear(®_blur); } break; @@ -969,10 +989,10 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t /// region_real = the damage region void paint_all(session_t *ps, struct managed_win *t) { if (ps->o.xrender_sync_fence || (ps->drivers & DRIVER_NVIDIA)) { - if (ps->xsync_exists && !x_fence_sync(ps->c, ps->sync_fence)) { + if (ps->xsync_exists && !x_fence_sync(&ps->c, ps->sync_fence)) { log_error("x_fence_sync failed, xrender-sync-fence will be " "disabled from now on."); - xcb_sync_destroy_fence(ps->c, ps->sync_fence); + xcb_sync_destroy_fence(ps->c.c, ps->sync_fence); ps->sync_fence = XCB_NONE; ps->o.xrender_sync_fence = false; ps->xsync_exists = false; @@ -1010,7 +1030,7 @@ void paint_all(session_t *ps, struct managed_win *t) { if (!ps->tgt_buffer.pixmap) { free_paint(ps, &ps->tgt_buffer); ps->tgt_buffer.pixmap = - x_create_pixmap(ps->c, (uint8_t)ps->depth, ps->root, + x_create_pixmap(&ps->c, ps->c.screen_info->root_depth, ps->root_width, ps->root_height); if (ps->tgt_buffer.pixmap == XCB_NONE) { log_fatal("Failed to allocate a screen-sized pixmap for" @@ -1019,18 +1039,20 @@ void paint_all(session_t *ps, struct managed_win *t) { } } - if (BKEND_GLX != ps->o.backend) + if (BKEND_GLX != ps->o.backend) { ps->tgt_buffer.pict = x_create_picture_with_visual_and_pixmap( - ps->c, ps->vis, ps->tgt_buffer.pixmap, 0, 0); + &ps->c, ps->c.screen_info->root_visual, ps->tgt_buffer.pixmap, + 0, 0); + } } if (BKEND_XRENDER == ps->o.backend) { - x_set_picture_clip_region(ps->c, ps->tgt_picture, 0, 0, ®ion); + x_set_picture_clip_region(&ps->c, ps->tgt_picture, 0, 0, ®ion); } #ifdef CONFIG_OPENGL if (bkend_use_glx(ps)) { - ps->psglx->z = 0.0; + ps->psglx->z = 0; } #endif @@ -1066,18 +1088,21 @@ void paint_all(session_t *ps, struct managed_win *t) { // Painting shadow if (w->shadow) { // Lazy shadow building - if (!w->shadow_paint.pixmap) - if (!win_build_shadow(ps, w, 1)) + if (!w->shadow_paint.pixmap) { + if (!win_build_shadow(ps, w, 1)) { log_error("build shadow failed"); + } + } // Shadow doesn't need to be painted underneath the body // of the windows above. Because no one can see it pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore); // Mask out the region we don't want shadow on - if (pixman_region32_not_empty(&ps->shadow_exclude_reg)) + if (pixman_region32_not_empty(&ps->shadow_exclude_reg)) { pixman_region32_subtract(®_tmp, ®_tmp, &ps->shadow_exclude_reg); + } if (pixman_region32_not_empty(®_shadow_clip)) { pixman_region32_subtract(®_tmp, ®_tmp, ®_shadow_clip); } @@ -1093,11 +1118,12 @@ void paint_all(session_t *ps, struct managed_win *t) { // needed Doing it here instead of in make_shadow() for // saving GPU power and handling shaped windows (XXX // unconfirmed) - if (!ps->o.wintype_option[w->window_type].full_shadow) + if (!ps->o.wintype_option[w->window_type].full_shadow) { pixman_region32_subtract(®_tmp, ®_tmp, &bshape_no_corners); + } if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 && - w->randr_monitor < ps->randr_nmonitors) { + w->randr_monitor < ps->monitors.count) { // There can be a window where number of monitors is // updated, but the monitor number attached to the window // have not. @@ -1107,7 +1133,7 @@ void paint_all(session_t *ps, struct managed_win *t) { // bounds. pixman_region32_intersect( ®_tmp, ®_tmp, - &ps->randr_monitor_regs[w->randr_monitor]); + &ps->monitors.regions[w->randr_monitor]); } // Detect if the region is empty before painting @@ -1197,13 +1223,14 @@ void paint_all(session_t *ps, struct managed_win *t) { if (ps->o.vsync) { // Make sure all previous requests are processed to achieve best // effect - x_sync(ps->c); + x_sync(&ps->c); #ifdef CONFIG_OPENGL if (glx_has_context(ps)) { - if (ps->o.vsync_use_glfinish) + if (ps->o.vsync_use_glfinish) { glFinish(); - else + } else { glFlush(); + } glXWaitX(); } #endif @@ -1224,57 +1251,63 @@ void paint_all(session_t *ps, struct managed_win *t) { // First we create a new picture, and copy content from the buffer // to it - auto pictfmt = x_get_pictform_for_visual(ps->c, ps->vis); + auto pictfmt = x_get_pictform_for_visual( + &ps->c, ps->c.screen_info->root_visual); xcb_render_picture_t new_pict = x_create_picture_with_pictfmt( - ps->c, ps->root, rwidth, rheight, pictfmt, 0, NULL); - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, + &ps->c, rwidth, rheight, pictfmt, 0, NULL); + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, ps->tgt_buffer.pict, XCB_NONE, new_pict, 0, 0, 0, 0, 0, 0, rwidth, rheight); // Next, we set the region of paint and highlight it - x_set_picture_clip_region(ps->c, new_pict, 0, 0, ®ion); - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, ps->white_picture, + x_set_picture_clip_region(&ps->c, new_pict, 0, 0, ®ion); + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_OVER, ps->white_picture, ps->alpha_picts[MAX_ALPHA / 2], new_pict, 0, 0, 0, 0, 0, 0, rwidth, rheight); // Finally, clear clip regions of new_pict and the screen, and put // the whole thing on screen - x_set_picture_clip_region(ps->c, new_pict, 0, 0, &ps->screen_reg); - x_set_picture_clip_region(ps->c, ps->tgt_picture, 0, 0, &ps->screen_reg); - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, new_pict, + x_set_picture_clip_region(&ps->c, new_pict, 0, 0, &ps->screen_reg); + x_set_picture_clip_region(&ps->c, ps->tgt_picture, 0, 0, + &ps->screen_reg); + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, new_pict, XCB_NONE, ps->tgt_picture, 0, 0, 0, 0, 0, 0, rwidth, rheight); - xcb_render_free_picture(ps->c, new_pict); - } else - xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, + x_free_picture(&ps->c, new_pict); + } else { + xcb_render_composite(ps->c.c, XCB_RENDER_PICT_OP_SRC, ps->tgt_buffer.pict, XCB_NONE, ps->tgt_picture, 0, 0, 0, 0, 0, 0, rwidth, rheight); + } break; #ifdef CONFIG_OPENGL case BKEND_XR_GLX_HYBRID: - x_sync(ps->c); - if (ps->o.vsync_use_glfinish) + x_sync(&ps->c); + if (ps->o.vsync_use_glfinish) { glFinish(); - else + } else { glFlush(); + } glXWaitX(); assert(ps->tgt_buffer.pixmap); paint_bind_tex(ps, &ps->tgt_buffer, ps->root_width, ps->root_height, - false, ps->depth, ps->vis, !ps->o.glx_no_rebind_pixmap); - if (ps->o.vsync_use_glfinish) + false, ps->c.screen_info->root_depth, + ps->c.screen_info->root_visual, !ps->o.glx_no_rebind_pixmap); + if (ps->o.vsync_use_glfinish) { glFinish(); - else + } else { glFlush(); + } glXWaitX(); glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width, ps->root_height, 0, 1.0, false, false, ®ion, NULL); fallthrough(); - case BKEND_GLX: glXSwapBuffers(ps->dpy, get_tgt_window(ps)); break; + case BKEND_GLX: glXSwapBuffers(ps->c.dpy, get_tgt_window(ps)); break; #endif default: assert(0); } - x_sync(ps->c); + x_sync(&ps->c); #ifdef CONFIG_OPENGL if (glx_has_context(ps)) { @@ -1304,7 +1337,7 @@ void paint_all(session_t *ps, struct managed_win *t) { static bool xr_init_blur(session_t *ps) { // Query filters xcb_render_query_filters_reply_t *pf = xcb_render_query_filters_reply( - ps->c, xcb_render_query_filters(ps->c, get_tgt_window(ps)), NULL); + ps->c.c, xcb_render_query_filters(ps->c.c, get_tgt_window(ps)), NULL); if (pf) { xcb_str_iterator_t iter = xcb_render_query_filters_filters_iterator(pf); for (; iter.rem; xcb_str_next(&iter)) { @@ -1312,8 +1345,9 @@ static bool xr_init_blur(session_t *ps) { char *name = xcb_str_name(iter.data); // Check for the convolution filter if (strlen(XRFILTER_CONVOLUTION) == len && - !memcmp(XRFILTER_CONVOLUTION, name, strlen(XRFILTER_CONVOLUTION))) + !memcmp(XRFILTER_CONVOLUTION, name, strlen(XRFILTER_CONVOLUTION))) { ps->xrfilter_convolution_exists = true; + } } free(pf); } @@ -1337,9 +1371,10 @@ static bool init_alpha_picts(session_t *ps) { for (int i = 0; i <= MAX_ALPHA; ++i) { double o = (double)i / MAX_ALPHA; - ps->alpha_picts[i] = solid_picture(ps->c, ps->root, false, o, 0, 0, 0); - if (ps->alpha_picts[i] == XCB_NONE) + ps->alpha_picts[i] = solid_picture(&ps->c, false, o, 0, 0, 0); + if (ps->alpha_picts[i] == XCB_NONE) { return false; + } } return true; } @@ -1351,12 +1386,13 @@ bool init_render(session_t *ps) { // Initialize OpenGL as early as possible #ifdef CONFIG_OPENGL - glxext_init(ps->dpy, ps->scr); + glxext_init(ps->c.dpy, ps->c.screen); #endif if (bkend_use_glx(ps)) { #ifdef CONFIG_OPENGL - if (!glx_init(ps, true)) + if (!glx_init(ps, true)) { return false; + } #else log_error("GLX backend support not compiled in."); return false; @@ -1371,8 +1407,9 @@ bool init_render(session_t *ps) { // Initialize window GL shader if (BKEND_GLX == ps->o.backend && ps->o.glx_fshader_win_str) { #ifdef CONFIG_OPENGL - if (!glx_load_prog_main(NULL, ps->o.glx_fshader_win_str, &ps->glx_prog_win)) + if (!glx_load_prog_main(NULL, ps->o.glx_fshader_win_str, &ps->glx_prog_win)) { return false; + } #else log_error("GLSL supported not compiled in, can't load " "shader."); @@ -1411,8 +1448,8 @@ bool init_render(session_t *ps) { } } - ps->black_picture = solid_picture(ps->c, ps->root, true, 1, 0, 0, 0); - ps->white_picture = solid_picture(ps->c, ps->root, true, 1, 1, 1, 1); + ps->black_picture = solid_picture(&ps->c, true, 1, 0, 0, 0); + ps->white_picture = solid_picture(&ps->c, true, 1, 1, 1, 1); if (ps->black_picture == XCB_NONE || ps->white_picture == XCB_NONE) { log_error("Failed to create solid xrender pictures."); @@ -1424,7 +1461,7 @@ bool init_render(session_t *ps) { if (ps->o.shadow_red == 0 && ps->o.shadow_green == 0 && ps->o.shadow_blue == 0) { ps->cshadow_picture = ps->black_picture; } else { - ps->cshadow_picture = solid_picture(ps->c, ps->root, true, 1, ps->o.shadow_red, + ps->cshadow_picture = solid_picture(&ps->c, true, 1, ps->o.shadow_red, ps->o.shadow_green, ps->o.shadow_blue); if (ps->cshadow_picture == XCB_NONE) { log_error("Failed to create shadow picture."); @@ -1450,14 +1487,14 @@ bool init_render(session_t *ps) { * Free root tile related things. */ void free_root_tile(session_t *ps) { - free_picture(ps->c, &ps->root_tile_paint.pict); + x_free_picture(&ps->c, ps->root_tile_paint.pict); #ifdef CONFIG_OPENGL free_texture(ps, &ps->root_tile_paint.ptex); #else assert(!ps->root_tile_paint.ptex); #endif if (ps->root_tile_fill) { - xcb_free_pixmap(ps->c, ps->root_tile_paint.pixmap); + xcb_free_pixmap(ps->c.c, ps->root_tile_paint.pixmap); ps->root_tile_paint.pixmap = XCB_NONE; } ps->root_tile_paint.pixmap = XCB_NONE; @@ -1466,19 +1503,20 @@ void free_root_tile(session_t *ps) { void deinit_render(session_t *ps) { // Free alpha_picts - for (int i = 0; i <= MAX_ALPHA; ++i) - free_picture(ps->c, &ps->alpha_picts[i]); + for (int i = 0; i <= MAX_ALPHA; ++i) { + x_free_picture(&ps->c, ps->alpha_picts[i]); + } free(ps->alpha_picts); ps->alpha_picts = NULL; // Free cshadow_picture and black_picture - if (ps->cshadow_picture == ps->black_picture) - ps->cshadow_picture = XCB_NONE; - else - free_picture(ps->c, &ps->cshadow_picture); + if (ps->cshadow_picture != ps->black_picture) { + x_free_picture(&ps->c, ps->cshadow_picture); + } - free_picture(ps->c, &ps->black_picture); - free_picture(ps->c, &ps->white_picture); + x_free_picture(&ps->c, ps->black_picture); + x_free_picture(&ps->c, ps->white_picture); + ps->cshadow_picture = ps->black_picture = ps->white_picture = XCB_NONE; // Free other X resources free_root_tile(ps); diff --git a/src/render.h b/src/render.h index 249f7bf..4e0c7a8 100644 --- a/src/render.h +++ b/src/render.h @@ -39,8 +39,6 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint); void paint_all(session_t *ps, struct managed_win *const t); -void free_picture(xcb_connection_t *c, xcb_render_picture_t *p); - void free_paint(session_t *ps, paint_t *ppaint); void free_root_tile(session_t *ps); diff --git a/src/vsync.c b/src/vsync.c index 5980155..57fbb59 100644 --- a/src/vsync.c +++ b/src/vsync.c @@ -77,31 +77,35 @@ static bool vsync_drm_init(session_t *ps) { * @return true for success, false otherwise */ static bool vsync_opengl_init(session_t *ps) { - if (!ensure_glx_context(ps)) + if (!ensure_glx_context(ps)) { return false; + } return glxext.has_GLX_SGI_video_sync; } static bool vsync_opengl_oml_init(session_t *ps) { - if (!ensure_glx_context(ps)) + if (!ensure_glx_context(ps)) { return false; + } return glxext.has_GLX_OML_sync_control; } static inline bool vsync_opengl_swc_swap_interval(session_t *ps, int interval) { - if (glxext.has_GLX_MESA_swap_control) + if (glxext.has_GLX_MESA_swap_control) { return glXSwapIntervalMESA((uint)interval) == 0; - else if (glxext.has_GLX_SGI_swap_control) + } + if (glxext.has_GLX_SGI_swap_control) { return glXSwapIntervalSGI(interval) == 0; - else if (glxext.has_GLX_EXT_swap_control) { + } + if (glxext.has_GLX_EXT_swap_control) { GLXDrawable d = glXGetCurrentDrawable(); if (d == None) { // We don't have a context?? return false; } - glXSwapIntervalEXT(ps->dpy, glXGetCurrentDrawable(), interval); + glXSwapIntervalEXT(ps->c.dpy, glXGetCurrentDrawable(), interval); return true; } return false; @@ -140,8 +144,8 @@ static int vsync_opengl_wait(session_t *ps attr_unused) { static int vsync_opengl_oml_wait(session_t *ps) { int64_t ust = 0, msc = 0, sbc = 0; - glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc); - glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc); + glXGetSyncValuesOML(ps->c.dpy, ps->reg_win, &ust, &msc, &sbc); + glXWaitForMscOML(ps->c.dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc); return 0; } #endif diff --git a/src/win.c b/src/win.c index 1aa10fd..14e2953 100644 --- a/src/win.c +++ b/src/win.c @@ -324,7 +324,7 @@ static inline bool win_bind_pixmap(struct backend_base *b, struct managed_win *w assert(!w->win_image); auto pixmap = x_new_id(b->c); auto e = xcb_request_check( - b->c, xcb_composite_name_window_pixmap_checked(b->c, w->base.id, pixmap)); + b->c->c, xcb_composite_name_window_pixmap_checked(b->c->c, w->base.id, pixmap)); if (e) { log_error("Failed to get named pixmap for window %#010x(%s)", w->base.id, w->name); @@ -519,7 +519,7 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) { win_clear_flags(w, WIN_FLAGS_POSITION_STALE); } - win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, w); + win_update_monitor(&ps->monitors, w); } if (win_check_flags_all(w, WIN_FLAGS_PROPERTY_STALE)) { @@ -702,7 +702,7 @@ static inline bool win_bounding_shaped(const session_t *ps, xcb_window_t wid) { Bool bounding_shaped; reply = xcb_shape_query_extents_reply( - ps->c, xcb_shape_query_extents(ps->c, wid), NULL); + ps->c.c, xcb_shape_query_extents(ps->c.c, wid), NULL); bounding_shaped = reply && reply->bounding_shaped; free(reply); @@ -714,7 +714,7 @@ static inline bool win_bounding_shaped(const session_t *ps, xcb_window_t wid) { static wintype_t wid_get_prop_wintype(session_t *ps, xcb_window_t wid) { winprop_t prop = - x_get_prop(ps->c, wid, ps->atoms->a_NET_WM_WINDOW_TYPE, 32L, XCB_ATOM_ATOM, 32); + x_get_prop(&ps->c, wid, ps->atoms->a_NET_WM_WINDOW_TYPE, 32L, XCB_ATOM_ATOM, 32); for (unsigned i = 0; i < prop.nitems; ++i) { for (wintype_t j = 1; j < NUM_WINTYPES; ++j) { @@ -735,7 +735,7 @@ wid_get_opacity_prop(session_t *ps, xcb_window_t wid, opacity_t def, opacity_t * bool ret = false; *out = def; - winprop_t prop = x_get_prop(ps->c, wid, ps->atoms->a_NET_WM_WINDOW_OPACITY, 1L, + winprop_t prop = x_get_prop(&ps->c, wid, ps->atoms->a_NET_WM_WINDOW_OPACITY, 1L, XCB_ATOM_CARDINAL, 32); if (prop.nitems) { @@ -827,11 +827,12 @@ double win_calc_opacity_target(session_t *ps, const struct managed_win *w) { } else { // Respect active_opacity only when the window is physically // focused - if (win_is_focused_raw(ps, w)) + if (win_is_focused_raw(ps, w)) { opacity = ps->o.active_opacity; - else if (!w->focused) + } else if (!w->focused) { // Respect inactive_opacity in some cases opacity = ps->o.inactive_opacity; + } } // respect inactive override @@ -853,9 +854,8 @@ bool win_should_dim(session_t *ps, const struct managed_win *w) { if (ps->o.inactive_dim > 0 && !(w->focused)) { return true; - } else { - return false; } + return false; } /** @@ -887,7 +887,7 @@ bool win_should_fade(session_t *ps, const struct managed_win *w) { * The property must be set on the outermost window, usually the WM frame. */ void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w) { - winprop_t prop = x_get_prop(ps->c, w->base.id, ps->atoms->a_COMPTON_SHADOW, 1, + winprop_t prop = x_get_prop(&ps->c, w->base.id, ps->atoms->a_COMPTON_SHADOW, 1, XCB_ATOM_CARDINAL, 32); if (!prop.nitems) { @@ -1085,8 +1085,9 @@ void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val) { static void win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_background_new) { - if (w->blur_background == blur_background_new) + if (w->blur_background == blur_background_new) { return; + } w->blur_background = blur_background_new; @@ -1284,10 +1285,11 @@ void win_update_wintype(session_t *ps, struct managed_win *w) { // _NET_WM_WINDOW_TYPE_NORMAL, otherwise as _NET_WM_WINDOW_TYPE_DIALOG. if (WINTYPE_UNKNOWN == w->window_type) { if (w->a.override_redirect || - !wid_has_prop(ps, w->client_win, ps->atoms->aWM_TRANSIENT_FOR)) + !wid_has_prop(ps, w->client_win, ps->atoms->aWM_TRANSIENT_FOR)) { w->window_type = WINTYPE_NORMAL; - else + } else { w->window_type = WINTYPE_DIALOG; + } } if (w->window_type != wtype_old) { @@ -1312,9 +1314,9 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client) } auto e = xcb_request_check( - ps->c, xcb_change_window_attributes_checked( - ps->c, client, XCB_CW_EVENT_MASK, - (const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_CLIENT)})); + ps->c.c, xcb_change_window_attributes_checked( + ps->c.c, client, XCB_CW_EVENT_MASK, + (const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_CLIENT)})); if (e) { log_error("Failed to change event mask of window %#010x", client); free(e); @@ -1339,13 +1341,13 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client) win_on_factor_change(ps, w); auto r = xcb_get_window_attributes_reply( - ps->c, xcb_get_window_attributes(ps->c, w->client_win), &e); + ps->c.c, xcb_get_window_attributes(ps->c.c, w->client_win), &e); if (!r) { log_error_x_error(e, "Failed to get client window attributes"); return; } - w->client_pictfmt = x_get_pictform_for_visual(ps->c, r->visual); + w->client_pictfmt = x_get_pictform_for_visual(&ps->c, r->visual); free(r); } @@ -1364,7 +1366,7 @@ void win_unmark_client(session_t *ps, struct managed_win *w) { // Recheck event mask xcb_change_window_attributes( - ps->c, client, XCB_CW_EVENT_MASK, + ps->c.c, client, XCB_CW_EVENT_MASK, (const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_UNKNOWN)}); } @@ -1377,7 +1379,7 @@ static xcb_window_t find_client_win(session_t *ps, xcb_window_t w) { } xcb_query_tree_reply_t *reply = - xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, w), NULL); + xcb_query_tree_reply(ps->c.c, xcb_query_tree(ps->c.c, w), NULL); if (!reply) { return 0; } @@ -1451,7 +1453,7 @@ void free_win_res(session_t *ps, struct managed_win *w) { pixman_region32_fini(&w->bounding_shape); // BadDamage may be thrown if the window is destroyed - set_ignore_cookie(ps, xcb_damage_destroy(ps->c, w->damage)); + set_ignore_cookie(&ps->c, xcb_damage_destroy(ps->c.c, w->damage)); rc_region_unref(&w->reg_ignore); free(w->name); free(w->class_instance); @@ -1619,9 +1621,10 @@ struct win *fill_win(session_t *ps, struct win *w) { } log_debug("Managing window %#010x", w->id); - xcb_get_window_attributes_cookie_t acookie = xcb_get_window_attributes(ps->c, w->id); + xcb_get_window_attributes_cookie_t acookie = + xcb_get_window_attributes(ps->c.c, w->id); xcb_get_window_attributes_reply_t *a = - xcb_get_window_attributes_reply(ps->c, acookie, NULL); + xcb_get_window_attributes_reply(ps->c.c, acookie, NULL); if (!a || a->map_state == XCB_MAP_STATE_UNVIEWABLE) { // Failed to get window attributes or geometry probably means // the window is gone already. Unviewable means the window is @@ -1656,7 +1659,7 @@ struct win *fill_win(session_t *ps, struct win *w) { free(a); xcb_generic_error_t *e; - auto g = xcb_get_geometry_reply(ps->c, xcb_get_geometry(ps->c, w->id), &e); + auto g = xcb_get_geometry_reply(ps->c.c, xcb_get_geometry(ps->c.c, w->id), &e); if (!g) { log_error_x_error(e, "Failed to get geometry of window %#010x", w->id); free(e); @@ -1674,10 +1677,10 @@ struct win *fill_win(session_t *ps, struct win *w) { free(g); // Create Damage for window (if not Input Only) - new->damage = x_new_id(ps->c); + new->damage = x_new_id(&ps->c); e = xcb_request_check( - ps->c, xcb_damage_create_checked(ps->c, new->damage, w->id, - XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY)); + ps->c.c, xcb_damage_create_checked(ps->c.c, new->damage, w->id, + XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY)); if (e) { log_error_x_error(e, "Failed to create damage"); free(e); @@ -1687,15 +1690,15 @@ struct win *fill_win(session_t *ps, struct win *w) { // Set window event mask xcb_change_window_attributes( - ps->c, new->base.id, XCB_CW_EVENT_MASK, + ps->c.c, new->base.id, XCB_CW_EVENT_MASK, (const uint32_t[]){determine_evmask(ps, new->base.id, WIN_EVMODE_FRAME)}); // Get notification when the shape of a window changes if (ps->shape_exists) { - xcb_shape_select_input(ps->c, new->base.id, 1); + xcb_shape_select_input(ps->c.c, new->base.id, 1); } - new->pictfmt = x_get_pictform_for_visual(ps->c, new->a.visual); + new->pictfmt = x_get_pictform_for_visual(&ps->c, new->a.visual); new->client_pictfmt = NULL; list_replace(&w->stack_neighbour, &new->base.stack_neighbour); @@ -1765,12 +1768,12 @@ void win_update_leader(session_t *ps, struct managed_win *w) { // Read the leader properties if (ps->o.detect_transient && !leader) { leader = - wid_get_prop_window(ps->c, w->client_win, ps->atoms->aWM_TRANSIENT_FOR); + wid_get_prop_window(&ps->c, w->client_win, ps->atoms->aWM_TRANSIENT_FOR); } if (ps->o.detect_client_leader && !leader) { leader = - wid_get_prop_window(ps->c, w->client_win, ps->atoms->aWM_CLIENT_LEADER); + wid_get_prop_window(&ps->c, w->client_win, ps->atoms->aWM_CLIENT_LEADER); } win_set_leader(ps, w, leader); @@ -1786,8 +1789,9 @@ static xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int // Rebuild the cache if needed if (!w->cache_leader && (w->client_win || w->leader)) { // Leader defaults to client window - if (!(w->cache_leader = w->leader)) + if (!(w->cache_leader = w->leader)) { w->cache_leader = w->client_win; + } // If the leader of this window isn't itself, look for its // ancestors @@ -1795,8 +1799,9 @@ static xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int auto wp = find_toplevel(ps, w->cache_leader); if (wp) { // Dead loop? - if (recursions > WIN_GET_LEADER_MAX_RECURSION) + if (recursions > WIN_GET_LEADER_MAX_RECURSION) { return XCB_NONE; + } w->cache_leader = win_get_leader_raw(ps, wp, recursions + 1); } @@ -1815,8 +1820,9 @@ bool win_update_class(session_t *ps, struct managed_win *w) { int nstr = 0; // Can't do anything if there's no client window - if (!w->client_win) + if (!w->client_win) { return false; + } // Free and reset old strings free(w->class_instance); @@ -1956,8 +1962,9 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) { */ xcb_shape_get_rectangles_reply_t *r = xcb_shape_get_rectangles_reply( - ps->c, - xcb_shape_get_rectangles(ps->c, w->base.id, XCB_SHAPE_SK_BOUNDING), NULL); + ps->c.c, + xcb_shape_get_rectangles(ps->c.c, w->base.id, XCB_SHAPE_SK_BOUNDING), + NULL); if (!r) { break; @@ -2030,7 +2037,7 @@ void win_update_opacity_prop(session_t *ps, struct managed_win *w) { * Retrieve frame extents from a window. */ void win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t client) { - winprop_t prop = x_get_prop(ps->c, client, ps->atoms->a_NET_FRAME_EXTENTS, 4L, + winprop_t prop = x_get_prop(&ps->c, client, ps->atoms->a_NET_FRAME_EXTENTS, 4L, XCB_ATOM_CARDINAL, 32); if (prop.nitems == 4) { @@ -2085,7 +2092,7 @@ bool win_is_region_ignore_valid(session_t *ps, const struct managed_win *w) { * Stop listening for events on a particular window. */ void win_ev_stop(session_t *ps, const struct win *w) { - xcb_change_window_attributes(ps->c, w->id, XCB_CW_EVENT_MASK, (const uint32_t[]){0}); + xcb_change_window_attributes(ps->c.c, w->id, XCB_CW_EVENT_MASK, (const uint32_t[]){0}); if (!w->managed) { return; @@ -2093,12 +2100,12 @@ void win_ev_stop(session_t *ps, const struct win *w) { auto mw = (struct managed_win *)w; if (mw->client_win) { - xcb_change_window_attributes(ps->c, mw->client_win, XCB_CW_EVENT_MASK, + xcb_change_window_attributes(ps->c.c, mw->client_win, XCB_CW_EVENT_MASK, (const uint32_t[]){0}); } if (ps->shape_exists) { - xcb_shape_select_input(ps->c, w->id, 0); + xcb_shape_select_input(ps->c.c, w->id, 0); } } @@ -2449,10 +2456,10 @@ bool win_skip_fading(session_t *ps, struct managed_win *w) { // TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to // the x.c. -void win_update_monitor(int nmons, region_t *mons, struct managed_win *mw) { +void win_update_monitor(struct x_monitors *monitors, struct managed_win *mw) { mw->randr_monitor = -1; - for (int i = 0; i < nmons; i++) { - auto e = pixman_region32_extents(&mons[i]); + for (int i = 0; i < monitors->count; i++) { + auto e = pixman_region32_extents(&monitors->regions[i]); if (e->x1 <= mw->g.x && e->y1 <= mw->g.y && e->x2 >= mw->g.x + mw->widthb && e->y2 >= mw->g.y + mw->heightb) { mw->randr_monitor = i; @@ -2670,11 +2677,12 @@ struct managed_win *find_managed_window_or_parent(session_t *ps, xcb_window_t wi // We traverse through its ancestors to find out the frame // Using find_win here because if we found a unmanaged window we know // about, we can stop early. - while (wid && wid != ps->root && !(w = find_win(ps, wid))) { + while (wid && wid != ps->c.screen_info->root && !(w = find_win(ps, wid))) { // xcb_query_tree probably fails if you run picom when X is // somehow initializing (like add it in .xinitrc). In this case // just leave it alone. - auto reply = xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, wid), NULL); + auto reply = + xcb_query_tree_reply(ps->c.c, xcb_query_tree(ps->c.c, wid), NULL); if (reply == NULL) { break; } @@ -2811,7 +2819,7 @@ bool win_check_flags_all(struct managed_win *w, uint64_t flags) { */ bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) { if (!ps->o.no_ewmh_fullscreen && - win_is_fullscreen_xcb(ps->c, ps->atoms, w->client_win)) { + win_is_fullscreen_xcb(ps->c.c, ps->atoms, w->client_win)) { return true; } return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb) && @@ -2826,7 +2834,7 @@ bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) { bool win_is_bypassing_compositor(const session_t *ps, const struct managed_win *w) { bool ret = false; - auto prop = x_get_prop(ps->c, w->client_win, ps->atoms->a_NET_WM_BYPASS_COMPOSITOR, + auto prop = x_get_prop(&ps->c, w->client_win, ps->atoms->a_NET_WM_BYPASS_COMPOSITOR, 1L, XCB_ATOM_CARDINAL, 32); if (prop.nitems && *prop.c32 == 1) { @@ -2847,13 +2855,13 @@ bool win_is_focused_raw(const session_t *ps, const struct managed_win *w) { // Find the managed window immediately below `i` in the window stack struct managed_win * -win_stack_find_next_managed(const session_t *ps, const struct list_node *i) { - while (!list_node_is_last(&ps->window_stack, i)) { - auto next = list_entry(i->next, struct win, stack_neighbour); +win_stack_find_next_managed(const session_t *ps, const struct list_node *w) { + while (!list_node_is_last(&ps->window_stack, w)) { + auto next = list_entry(w->next, struct win, stack_neighbour); if (next->managed) { return (struct managed_win *)next; } - i = &next->stack_neighbour; + w = &next->stack_neighbour; } return NULL; } diff --git a/src/win.h b/src/win.h index da46572..b841ffc 100644 --- a/src/win.h +++ b/src/win.h @@ -341,9 +341,7 @@ void win_recheck_client(session_t *ps, struct managed_win *w); double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w); bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w); -// TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to -// the x.h. -void win_update_monitor(int nmons, region_t *mons, struct managed_win *mw); +void win_update_monitor(struct x_monitors *monitors, struct managed_win *mw); /** * Retrieve the bounding shape of a window. diff --git a/src/x.c b/src/x.c index a2a7153..46af709 100644 --- a/src/x.c +++ b/src/x.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -28,6 +29,72 @@ #include "utils.h" #include "x.h" +// === Error handling === + +/** + * Xlib error handler function. + */ +static int xerror(Display attr_unused *dpy, XErrorEvent *ev) { + if (!ps_g) { + // Do not ignore errors until the session has been initialized + return 0; + } + + // Fake a xcb error, fill in just enough information + xcb_generic_error_t xcb_err; + xcb_err.full_sequence = (uint32_t)ev->serial; + xcb_err.major_code = ev->request_code; + xcb_err.minor_code = ev->minor_code; + xcb_err.error_code = ev->error_code; + x_handle_error(&ps_g->c, &xcb_err); + return 0; +} + +void x_discard_pending(struct x_connection *c, uint32_t sequence) { + while (c->pending_reply_head && sequence > c->pending_reply_head->sequence) { + auto next = c->pending_reply_head->next; + free(c->pending_reply_head); + c->pending_reply_head = next; + } + if (!c->pending_reply_head) { + c->pending_reply_tail = &c->pending_reply_head; + } +} + +void x_handle_error(struct x_connection *c, xcb_generic_error_t *ev) { + x_discard_pending(c, ev->full_sequence); + if (c->pending_reply_head && c->pending_reply_head->sequence == ev->full_sequence) { + if (c->pending_reply_head->action != PENDING_REPLY_ACTION_IGNORE) { + x_log_error(LOG_LEVEL_ERROR, ev->full_sequence, ev->major_code, + ev->minor_code, ev->error_code); + } + switch (c->pending_reply_head->action) { + case PENDING_REPLY_ACTION_ABORT: + log_fatal("An unrecoverable X error occurred, aborting..."); + abort(); + case PENDING_REPLY_ACTION_DEBUG_ABORT: assert(false); break; + case PENDING_REPLY_ACTION_IGNORE: break; + } + return; + } + x_log_error(LOG_LEVEL_WARN, ev->full_sequence, ev->major_code, ev->minor_code, + ev->error_code); +} + +/// Initialize x_connection struct from an Xlib Display. +/// +/// Note this function doesn't take ownership of the Display, the caller is still +/// responsible for closing it after `free_x_connection` is called. +void x_connection_init(struct x_connection *c, Display *dpy) { + c->dpy = dpy; + c->c = XGetXCBConnection(dpy); + c->pending_reply_tail = &c->pending_reply_head; + c->previous_xerror_handler = XSetErrorHandler(xerror); + + c->screen = DefaultScreen(dpy); + c->screen_info = x_screen_of_display(c, c->screen); +} + /** * Get a specific attribute of a window. * @@ -43,11 +110,11 @@ * @return a winprop_t structure containing the attribute * and number of items. A blank one on failure. */ -winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom, +winprop_t x_get_prop_with_offset(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom, int offset, int length, xcb_atom_t rtype, int rformat) { xcb_get_property_reply_t *r = xcb_get_property_reply( - c, - xcb_get_property(c, 0, w, atom, rtype, to_u32_checked(offset), + c->c, + xcb_get_property(c->c, 0, w, atom, rtype, to_u32_checked(offset), to_u32_checked(length)), NULL); @@ -71,10 +138,10 @@ winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t } /// Get the type, format and size in bytes of a window's specific attribute. -winprop_info_t x_get_prop_info(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom) { +winprop_info_t x_get_prop_info(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom) { xcb_generic_error_t *e = NULL; auto r = xcb_get_property_reply( - c, xcb_get_property(c, 0, w, atom, XCB_ATOM_ANY, 0, 0), &e); + c->c, xcb_get_property(c->c, 0, w, atom, XCB_ATOM_ANY, 0, 0), &e); if (!r) { log_debug_x_error(e, "Failed to get property info for window %#010x", w); free(e); @@ -94,7 +161,7 @@ winprop_info_t x_get_prop_info(xcb_connection_t *c, xcb_window_t w, xcb_atom_t a * * @return the value if successful, 0 otherwise */ -xcb_window_t wid_get_prop_window(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t aprop) { +xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid, xcb_atom_t aprop) { // Get the attribute xcb_window_t p = XCB_NONE; winprop_t prop = x_get_prop(c, wid, aprop, 1L, XCB_ATOM_WINDOW, 32); @@ -115,7 +182,7 @@ xcb_window_t wid_get_prop_window(xcb_connection_t *c, xcb_window_t wid, xcb_atom bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst, int *pnstr) { assert(ps->server_grabbed); - auto prop_info = x_get_prop_info(ps->c, wid, prop); + auto prop_info = x_get_prop_info(&ps->c, wid, prop); auto type = prop_info.type; auto format = prop_info.format; auto length = prop_info.length; @@ -140,7 +207,7 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ** xcb_generic_error_t *e = NULL; auto word_count = (length + 4 - 1) / 4; auto r = xcb_get_property_reply( - ps->c, xcb_get_property(ps->c, 0, wid, prop, type, 0, word_count), &e); + ps->c.c, xcb_get_property(ps->c.c, 0, wid, prop, type, 0, word_count), &e); if (!r) { log_debug_x_error(e, "Failed to get window property for %#010x", wid); free(e); @@ -198,14 +265,14 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ** // of this program static thread_local xcb_render_query_pict_formats_reply_t *g_pictfmts = NULL; -static inline void x_get_server_pictfmts(xcb_connection_t *c) { +static inline void x_get_server_pictfmts(struct x_connection *c) { if (g_pictfmts) { return; } xcb_generic_error_t *e = NULL; // Get window picture format - g_pictfmts = - xcb_render_query_pict_formats_reply(c, xcb_render_query_pict_formats(c), &e); + g_pictfmts = xcb_render_query_pict_formats_reply( + c->c, xcb_render_query_pict_formats(c->c), &e); if (e || !g_pictfmts) { log_fatal("failed to get pict formats\n"); abort(); @@ -213,7 +280,7 @@ static inline void x_get_server_pictfmts(xcb_connection_t *c) { } const xcb_render_pictforminfo_t * -x_get_pictform_for_visual(xcb_connection_t *c, xcb_visualid_t visual) { +x_get_pictform_for_visual(struct x_connection *c, xcb_visualid_t visual) { x_get_server_pictfmts(c); xcb_render_pictvisual_t *pv = xcb_render_util_find_visual_format(g_pictfmts, visual); @@ -244,7 +311,7 @@ static xcb_visualid_t attr_pure x_get_visual_for_pictfmt(xcb_render_query_pict_f return XCB_NONE; } -xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) { +xcb_visualid_t x_get_visual_for_standard(struct x_connection *c, xcb_pict_standard_t std) { x_get_server_pictfmts(c); auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std); @@ -253,7 +320,7 @@ xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_ } xcb_render_pictformat_t -x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) { +x_get_pictfmt_for_standard(struct x_connection *c, xcb_pict_standard_t std) { x_get_server_pictfmts(c); auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std); @@ -261,8 +328,8 @@ x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) { return pictfmt->id; } -int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) { - auto setup = xcb_get_setup(c); +int x_get_visual_depth(struct x_connection *c, xcb_visualid_t visual) { + auto setup = xcb_get_setup(c->c); for (auto screen = xcb_setup_roots_iterator(setup); screen.rem; xcb_screen_next(&screen)) { for (auto depth = xcb_screen_allowed_depths_iterator(screen.data); @@ -280,7 +347,7 @@ int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) { } xcb_render_picture_t -x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c, +x_create_picture_with_pictfmt_and_pixmap(struct x_connection *c, const xcb_render_pictforminfo_t *pictfmt, xcb_pixmap_t pixmap, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) { @@ -294,9 +361,9 @@ x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c, } xcb_render_picture_t tmp_picture = x_new_id(c); - xcb_generic_error_t *e = - xcb_request_check(c, xcb_render_create_picture_checked( - c, tmp_picture, pixmap, pictfmt->id, valuemask, buf)); + xcb_generic_error_t *e = xcb_request_check( + c->c, xcb_render_create_picture_checked(c->c, tmp_picture, pixmap, + pictfmt->id, valuemask, buf)); free(buf); if (e) { log_error_x_error(e, "failed to create picture"); @@ -307,7 +374,7 @@ x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c, } xcb_render_picture_t -x_create_picture_with_visual_and_pixmap(xcb_connection_t *c, xcb_visualid_t visual, +x_create_picture_with_visual_and_pixmap(struct x_connection *c, xcb_visualid_t visual, xcb_pixmap_t pixmap, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) { const xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(c, visual); @@ -315,7 +382,7 @@ x_create_picture_with_visual_and_pixmap(xcb_connection_t *c, xcb_visualid_t visu } xcb_render_picture_t -x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard_t standard, +x_create_picture_with_standard_and_pixmap(struct x_connection *c, xcb_pict_standard_t standard, xcb_pixmap_t pixmap, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) { x_get_server_pictfmts(c); @@ -326,26 +393,26 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard } xcb_render_picture_t -x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h, +x_create_picture_with_standard(struct x_connection *c, int w, int h, xcb_pict_standard_t standard, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) { x_get_server_pictfmts(c); auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard); assert(pictfmt); - return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr); + return x_create_picture_with_pictfmt(c, w, h, pictfmt, valuemask, attr); } /** * Create an picture. */ xcb_render_picture_t -x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int w, int h, +x_create_picture_with_pictfmt(struct x_connection *c, int w, int h, const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) { uint8_t depth = pictfmt->depth; - xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, d, w, h); + xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, w, h); if (!tmp_pixmap) { return XCB_NONE; } @@ -353,23 +420,23 @@ x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int w, int xcb_render_picture_t picture = x_create_picture_with_pictfmt_and_pixmap( c, pictfmt, tmp_pixmap, valuemask, attr); - xcb_free_pixmap(c, tmp_pixmap); + set_cant_fail_cookie(c, xcb_free_pixmap(c->c, tmp_pixmap)); return picture; } xcb_render_picture_t -x_create_picture_with_visual(xcb_connection_t *c, xcb_drawable_t d, int w, int h, - xcb_visualid_t visual, uint32_t valuemask, +x_create_picture_with_visual(struct x_connection *c, int w, int h, xcb_visualid_t visual, + uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) { auto pictfmt = x_get_pictform_for_visual(c, visual); - return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr); + return x_create_picture_with_pictfmt(c, w, h, pictfmt, valuemask, attr); } -bool x_fetch_region(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_t *res) { +bool x_fetch_region(struct x_connection *c, xcb_xfixes_region_t r, pixman_region32_t *res) { xcb_generic_error_t *e = NULL; xcb_xfixes_fetch_region_reply_t *xr = - xcb_xfixes_fetch_region_reply(c, xcb_xfixes_fetch_region(c, r), &e); + xcb_xfixes_fetch_region_reply(c->c, xcb_xfixes_fetch_region(c->c, r), &e); if (!xr) { log_error_x_error(e, "Failed to fetch rectangles"); return false; @@ -390,7 +457,7 @@ bool x_fetch_region(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_ return ret; } -uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) { +uint32_t x_create_region(struct x_connection *c, const region_t *reg) { if (!reg) { return XCB_NONE; } @@ -410,8 +477,8 @@ uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) { } xcb_xfixes_region_t ret = x_new_id(c); - bool success = - XCB_AWAIT_VOID(xcb_xfixes_create_region, c, ret, to_u32_checked(nrects), xrects); + bool success = XCB_AWAIT_VOID(xcb_xfixes_create_region, c->c, ret, + to_u32_checked(nrects), xrects); free(xrects); if (!success) { return XCB_NONE; @@ -419,13 +486,13 @@ uint32_t x_create_region(xcb_connection_t *c, const region_t *reg) { return ret; } -void x_destroy_region(xcb_connection_t *c, xcb_xfixes_region_t r) { +void x_destroy_region(struct x_connection *c, xcb_xfixes_region_t r) { if (r != XCB_NONE) { - xcb_xfixes_destroy_region(c, r); + set_debug_cant_fail_cookie(c, xcb_xfixes_destroy_region(c->c, r)); } } -void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict, +void x_set_picture_clip_region(struct x_connection *c, xcb_render_picture_t pict, int16_t clip_x_origin, int16_t clip_y_origin, const region_t *reg) { int nrects; @@ -440,9 +507,10 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict, }; } - xcb_generic_error_t *e = xcb_request_check( - c, xcb_render_set_picture_clip_rectangles_checked( - c, pict, clip_x_origin, clip_y_origin, to_u32_checked(nrects), xrects)); + xcb_generic_error_t *e = + xcb_request_check(c->c, xcb_render_set_picture_clip_rectangles_checked( + c->c, pict, clip_x_origin, clip_y_origin, + to_u32_checked(nrects), xrects)); if (e) { log_error_x_error(e, "Failed to set clip region"); free(e); @@ -450,17 +518,28 @@ void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict, free(xrects); } -void x_clear_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict) { +void x_clear_picture_clip_region(struct x_connection *c, xcb_render_picture_t pict) { assert(pict != XCB_NONE); xcb_render_change_picture_value_list_t v = {.clipmask = XCB_NONE}; xcb_generic_error_t *e = xcb_request_check( - c, xcb_render_change_picture_checked(c, pict, XCB_RENDER_CP_CLIP_MASK, &v)); + c->c, xcb_render_change_picture_checked(c->c, pict, XCB_RENDER_CP_CLIP_MASK, &v)); if (e) { log_error_x_error(e, "failed to clear clip region"); free(e); } } +/** + * Destroy a Picture. + * + * Picture must be valid. + */ +void x_free_picture(struct x_connection *c, xcb_render_picture_t p) { + assert(p != XCB_NONE); + auto cookie = xcb_render_free_picture(c->c, p); + set_cant_fail_cookie(c, cookie); +} + enum { XSyncBadCounter = 0, XSyncBadAlarm = 1, @@ -593,12 +672,12 @@ const char *x_strerror(xcb_generic_error_t *e) { /** * Create a pixmap and check that creation succeeded. */ -xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t drawable, - int width, int height) { +xcb_pixmap_t x_create_pixmap(struct x_connection *c, uint8_t depth, int width, int height) { xcb_pixmap_t pix = x_new_id(c); - xcb_void_cookie_t cookie = xcb_create_pixmap_checked( - c, depth, pix, drawable, to_u16_checked(width), to_u16_checked(height)); - xcb_generic_error_t *err = xcb_request_check(c, cookie); + xcb_void_cookie_t cookie = + xcb_create_pixmap_checked(c->c, depth, pix, c->screen_info->root, + to_u16_checked(width), to_u16_checked(height)); + xcb_generic_error_t *err = xcb_request_check(c->c, cookie); if (err == NULL) { return pix; } @@ -614,12 +693,12 @@ xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t * Detect whether the pixmap is valid with XGetGeometry. Well, maybe there * are better ways. */ -bool x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) { +bool x_validate_pixmap(struct x_connection *c, xcb_pixmap_t pixmap) { if (pixmap == XCB_NONE) { return false; } - auto r = xcb_get_geometry_reply(c, xcb_get_geometry(c, pixmap), NULL); + auto r = xcb_get_geometry_reply(c->c, xcb_get_geometry(c->c, pixmap), NULL); if (!r) { return false; } @@ -641,14 +720,14 @@ bool x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) { /// https://github.com/ImageMagick/ImageMagick/blob/d04a47227637dbb3af9231b0107ccf9677bf985e/MagickCore/xwindow.c#L1853-L1922 /// https://www.fvwm.org/Archive/Manpages/fvwm-root.html -xcb_pixmap_t -x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms) { +xcb_pixmap_t x_get_root_back_pixmap(struct x_connection *c, struct atom *atoms) { xcb_pixmap_t pixmap = XCB_NONE; xcb_atom_t root_back_pixmap_atoms[] = {atoms->a_XROOTPMAP_ID, atoms->aESETROOT_PMAP_ID}; for (size_t i = 0; i < ARR_SIZE(root_back_pixmap_atoms); i++) { winprop_t prop = - x_get_prop(c, root, root_back_pixmap_atoms[i], 1, XCB_ATOM_PIXMAP, 32); + x_get_prop(c, c->screen_info->root, root_back_pixmap_atoms[i], 1, + XCB_ATOM_PIXMAP, 32); if (prop.nitems) { pixmap = (xcb_pixmap_t)*prop.p32; free_winprop(&prop); @@ -669,24 +748,24 @@ bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom) { * Synchronizes a X Render drawable to ensure all pending painting requests * are completed. */ -bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) { +bool x_fence_sync(struct x_connection *c, xcb_sync_fence_t f) { // TODO(richardgv): If everybody just follows the rules stated in X Sync // prototype, we need only one fence per screen, but let's stay a bit // cautious right now - auto e = xcb_request_check(c, xcb_sync_trigger_fence_checked(c, f)); + auto e = xcb_request_check(c->c, xcb_sync_trigger_fence_checked(c->c, f)); if (e) { log_error_x_error(e, "Failed to trigger the fence"); goto err; } - e = xcb_request_check(c, xcb_sync_await_fence_checked(c, 1, &f)); + e = xcb_request_check(c->c, xcb_sync_await_fence_checked(c->c, 1, &f)); if (e) { log_error_x_error(e, "Failed to await on a fence"); goto err; } - e = xcb_request_check(c, xcb_sync_reset_fence_checked(c, f)); + e = xcb_request_check(c->c, xcb_sync_reset_fence_checked(c->c, f)); if (e) { log_error_x_error(e, "Failed to reset the fence"); goto err; @@ -748,7 +827,7 @@ void x_create_convolution_kernel(const conv *kernel, double center, /// Generate a search criteria for fbconfig from a X visual. /// Returns {-1, -1, -1, -1, -1, 0} on failure -struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual) { +struct xvisual_info x_get_visual_info(struct x_connection *c, xcb_visualid_t visual) { auto pictfmt = x_get_pictform_for_visual(c, visual); auto depth = x_get_visual_depth(c, visual); if (!pictfmt || depth == -1) { @@ -776,10 +855,10 @@ struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual }; } -xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) { +xcb_screen_t *x_screen_of_display(struct x_connection *c, int screen) { xcb_screen_iterator_t iter; - iter = xcb_setup_roots_iterator(xcb_get_setup(c)); + iter = xcb_setup_roots_iterator(xcb_get_setup(c->c)); for (; iter.rem; --screen, xcb_screen_next(&iter)) { if (screen == 0) { return iter.data; @@ -789,39 +868,34 @@ xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen) { return NULL; } -void x_update_randr_monitors(session_t *ps) { - x_free_randr_info(ps); - - if (!ps->o.crop_shadow_to_monitor || !ps->randr_exists) { - return; - } +void x_update_monitors(struct x_connection *c, struct x_monitors *m) { + x_free_monitor_info(m); xcb_randr_get_monitors_reply_t *r = xcb_randr_get_monitors_reply( - ps->c, xcb_randr_get_monitors(ps->c, ps->root, true), NULL); + c->c, xcb_randr_get_monitors(c->c, c->screen_info->root, true), NULL); if (!r) { return; } - ps->randr_nmonitors = xcb_randr_get_monitors_monitors_length(r); - ps->randr_monitor_regs = ccalloc(ps->randr_nmonitors, region_t); + m->count = xcb_randr_get_monitors_monitors_length(r); + m->regions = ccalloc(m->count, region_t); xcb_randr_monitor_info_iterator_t monitor_info_it = xcb_randr_get_monitors_monitors_iterator(r); for (int i = 0; monitor_info_it.rem; xcb_randr_monitor_info_next(&monitor_info_it)) { xcb_randr_monitor_info_t *mi = monitor_info_it.data; - pixman_region32_init_rect(&ps->randr_monitor_regs[i++], mi->x, mi->y, - mi->width, mi->height); + pixman_region32_init_rect(&m->regions[i++], mi->x, mi->y, mi->width, mi->height); } free(r); } -void x_free_randr_info(session_t *ps) { - if (ps->randr_monitor_regs) { - for (int i = 0; i < ps->randr_nmonitors; i++) { - pixman_region32_fini(&ps->randr_monitor_regs[i]); +void x_free_monitor_info(struct x_monitors *m) { + if (m->regions) { + for (int i = 0; i < m->count; i++) { + pixman_region32_fini(&m->regions[i]); } - free(ps->randr_monitor_regs); - ps->randr_monitor_regs = NULL; + free(m->regions); + m->regions = NULL; } - ps->randr_nmonitors = 0; + m->count = 0; } diff --git a/src/x.h b/src/x.h index fc105c7..b5bd1a5 100644 --- a/src/x.h +++ b/src/x.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2018 Yuxuan Shui #pragma once +#include #include #include #include @@ -55,6 +56,42 @@ struct xvisual_info { xcb_visualid_t visual; }; +enum pending_reply_action { + PENDING_REPLY_ACTION_IGNORE, + PENDING_REPLY_ACTION_ABORT, + PENDING_REPLY_ACTION_DEBUG_ABORT, +}; + +typedef struct pending_reply { + struct pending_reply *next; + unsigned long sequence; + enum pending_reply_action action; +} pending_reply_t; + +struct x_connection { + /// XCB connection. + xcb_connection_t *c; + /// Display in use. + Display *dpy; + /// Head pointer of the error ignore linked list. + pending_reply_t *pending_reply_head; + /// Pointer to the next member of tail element of the error + /// ignore linked list. + pending_reply_t **pending_reply_tail; + /// Previous handler of X errors + XErrorHandler previous_xerror_handler; + /// Default screen + int screen; + /// Information about the default screen + xcb_screen_t *screen_info; +}; + +/// Monitor info +struct x_monitors { + int count; + region_t *regions; +}; + #define XCB_AWAIT_VOID(func, c, ...) \ ({ \ bool __success = true; \ @@ -92,8 +129,8 @@ struct xvisual_info { #define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t)(((double)(value)) * 65536)) /// Wraps x_new_id. abort the program if x_new_id returns error -static inline uint32_t x_new_id(xcb_connection_t *c) { - auto ret = xcb_generate_id(c); +static inline uint32_t x_new_id(struct x_connection *c) { + auto ret = xcb_generate_id(c->c); if (ret == (uint32_t)-1) { log_fatal("We seems to have run of XIDs. This is either a bug in the X " "server, or a resource leakage in the compositor. Please open " @@ -103,6 +140,73 @@ static inline uint32_t x_new_id(xcb_connection_t *c) { return ret; } +static void set_reply_action(struct x_connection *c, uint32_t sequence, + enum pending_reply_action action) { + auto i = cmalloc(pending_reply_t); + + i->sequence = sequence; + i->next = 0; + i->action = action; + *c->pending_reply_tail = i; + c->pending_reply_tail = &i->next; +} + +/** + * Ignore X errors caused by given X request. + */ +static inline void attr_unused set_ignore_cookie(struct x_connection *c, + xcb_void_cookie_t cookie) { + set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_IGNORE); +} + +static inline void attr_unused set_cant_fail_cookie(struct x_connection *c, + xcb_void_cookie_t cookie) { + set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_ABORT); +} + +static inline void attr_unused set_debug_cant_fail_cookie(struct x_connection *c, + xcb_void_cookie_t cookie) { +#ifndef NDEBUG + set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_DEBUG_ABORT); +#else + (void)c; + (void)cookie; +#endif +} + +static inline void attr_unused free_x_connection(struct x_connection *c) { + pending_reply_t *next = NULL; + for (auto ign = c->pending_reply_head; ign; ign = next) { + next = ign->next; + + free(ign); + } + + // Reset head and tail + c->pending_reply_head = NULL; + c->pending_reply_tail = &c->pending_reply_head; + + XSetErrorHandler(c->previous_xerror_handler); +} + +/// Initialize x_connection struct from an Xlib Display. +/// +/// Note this function doesn't take ownership of the Display, the caller is still +/// responsible for closing it after `free_x_connection` is called. +void x_connection_init(struct x_connection *c, Display *dpy); + +/// Discard queued pending replies. +/// +/// We have received reply with sequence number `sequence`, which means all pending +/// replies with sequence number less than `sequence` will never be received. So discard +/// them. +void x_discard_pending(struct x_connection *c, uint32_t sequence); + +/// Handle X errors. +/// +/// This function logs X errors, or aborts the program based on severity of the error. +void x_handle_error(struct x_connection *c, xcb_generic_error_t *ev); + /** * Send a request to X server and get the reply to make sure all previous * requests are processed, and their replies received @@ -110,8 +214,8 @@ static inline uint32_t x_new_id(xcb_connection_t *c) { * xcb_get_input_focus is used here because it is the same request used by * libX11 */ -static inline void x_sync(xcb_connection_t *c) { - free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), NULL)); +static inline void x_sync(struct x_connection *c) { + free(xcb_get_input_focus_reply(c->c, xcb_get_input_focus(c->c), NULL)); } /** @@ -129,25 +233,26 @@ static inline void x_sync(xcb_connection_t *c) { * @return a winprop_t structure containing the attribute * and number of items. A blank one on failure. */ -winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom, +winprop_t x_get_prop_with_offset(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom, int offset, int length, xcb_atom_t rtype, int rformat); /** * Wrapper of wid_get_prop_adv(). */ -static inline winprop_t x_get_prop(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t atom, - int length, xcb_atom_t rtype, int rformat) { +static inline winprop_t +x_get_prop(const struct x_connection *c, xcb_window_t wid, xcb_atom_t atom, int length, + xcb_atom_t rtype, int rformat) { return x_get_prop_with_offset(c, wid, atom, 0L, length, rtype, rformat); } /// Get the type, format and size in bytes of a window's specific attribute. -winprop_info_t x_get_prop_info(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom); +winprop_info_t x_get_prop_info(const struct x_connection *c, xcb_window_t w, xcb_atom_t atom); /// Discard all X events in queue or in flight. Should only be used when the server is /// grabbed -static inline void x_discard_events(xcb_connection_t *c) { +static inline void x_discard_events(struct x_connection *c) { xcb_generic_event_t *e; - while ((e = xcb_poll_for_event(c))) { + while ((e = xcb_poll_for_event(c->c))) { free(e); } } @@ -157,7 +262,7 @@ static inline void x_discard_events(xcb_connection_t *c) { * * @return the value if successful, 0 otherwise */ -xcb_window_t wid_get_prop_window(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t aprop); +xcb_window_t wid_get_prop_window(struct x_connection *c, xcb_window_t wid, xcb_atom_t aprop); /** * Get the value of a text property of a window. @@ -170,30 +275,30 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ** int *pnstr); const xcb_render_pictforminfo_t * -x_get_pictform_for_visual(xcb_connection_t *, xcb_visualid_t); -int x_get_visual_depth(xcb_connection_t *, xcb_visualid_t); +x_get_pictform_for_visual(struct x_connection *, xcb_visualid_t); +int x_get_visual_depth(struct x_connection *, xcb_visualid_t); xcb_render_picture_t -x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *, +x_create_picture_with_pictfmt_and_pixmap(struct x_connection *, const xcb_render_pictforminfo_t *pictfmt, xcb_pixmap_t pixmap, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) attr_nonnull(1, 2); xcb_render_picture_t -x_create_picture_with_visual_and_pixmap(xcb_connection_t *, xcb_visualid_t visual, +x_create_picture_with_visual_and_pixmap(struct x_connection *, xcb_visualid_t visual, xcb_pixmap_t pixmap, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) attr_nonnull(1); xcb_render_picture_t -x_create_picture_with_standard_and_pixmap(xcb_connection_t *, xcb_pict_standard_t standard, +x_create_picture_with_standard_and_pixmap(struct x_connection *, xcb_pict_standard_t standard, xcb_pixmap_t pixmap, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) attr_nonnull(1); xcb_render_picture_t -x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h, +x_create_picture_with_standard(struct x_connection *c, int w, int h, xcb_pict_standard_t standard, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) attr_nonnull(1); @@ -202,30 +307,37 @@ x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int * Create an picture. */ xcb_render_picture_t -x_create_picture_with_pictfmt(xcb_connection_t *, xcb_drawable_t, int w, int h, +x_create_picture_with_pictfmt(struct x_connection *, int w, int h, const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) - attr_nonnull(1, 5); + attr_nonnull(1, 4); xcb_render_picture_t -x_create_picture_with_visual(xcb_connection_t *, xcb_drawable_t, int w, int h, - xcb_visualid_t visual, uint32_t valuemask, +x_create_picture_with_visual(struct x_connection *, int w, int h, xcb_visualid_t visual, + uint32_t valuemask, const xcb_render_create_picture_value_list_t *attr) attr_nonnull(1); /// Fetch a X region and store it in a pixman region -bool x_fetch_region(xcb_connection_t *, xcb_xfixes_region_t r, region_t *res); +bool x_fetch_region(struct x_connection *, xcb_xfixes_region_t r, region_t *res); /// Create a X region from a pixman region -uint32_t x_create_region(xcb_connection_t *c, const region_t *reg); +uint32_t x_create_region(struct x_connection *c, const region_t *reg); /// Destroy a X region -void x_destroy_region(xcb_connection_t *c, uint32_t region); +void x_destroy_region(struct x_connection *c, uint32_t region); -void x_set_picture_clip_region(xcb_connection_t *, xcb_render_picture_t, int16_t clip_x_origin, - int16_t clip_y_origin, const region_t *); +void x_set_picture_clip_region(struct x_connection *, xcb_render_picture_t, + int16_t clip_x_origin, int16_t clip_y_origin, const region_t *); -void x_clear_picture_clip_region(xcb_connection_t *, xcb_render_picture_t pict); +void x_clear_picture_clip_region(struct x_connection *, xcb_render_picture_t pict); + +/** + * Destroy a Picture. + * + * Picture must be valid. + */ +void x_free_picture(struct x_connection *c, xcb_render_picture_t p); /** * Log a X11 error @@ -242,10 +354,9 @@ void x_log_error(enum log_level level, unsigned long serial, uint8_t major, */ const char *x_strerror(xcb_generic_error_t *e); -xcb_pixmap_t x_create_pixmap(xcb_connection_t *, uint8_t depth, xcb_drawable_t drawable, - int width, int height); +xcb_pixmap_t x_create_pixmap(struct x_connection *, uint8_t depth, int width, int height); -bool x_validate_pixmap(xcb_connection_t *, xcb_pixmap_t pxmap); +bool x_validate_pixmap(struct x_connection *, xcb_pixmap_t pxmap); /** * Free a winprop_t. @@ -254,22 +365,22 @@ bool x_validate_pixmap(xcb_connection_t *, xcb_pixmap_t pxmap); */ static inline void free_winprop(winprop_t *pprop) { // Empty the whole structure to avoid possible issues - if (pprop->r) + if (pprop->r) { free(pprop->r); + } pprop->ptr = NULL; pprop->r = NULL; pprop->nitems = 0; } /// Get the back pixmap of the root window -xcb_pixmap_t -x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms); +xcb_pixmap_t x_get_root_back_pixmap(struct x_connection *c, struct atom *atoms); /// Return true if the atom refers to a property name that is used for the /// root window background pixmap bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom); -bool x_fence_sync(xcb_connection_t *, xcb_sync_fence_t); +bool x_fence_sync(struct x_connection *, xcb_sync_fence_t); struct x_convolution_kernel { int size; @@ -293,23 +404,18 @@ void attr_nonnull(1, 3) x_create_convolution_kernel(const conv *kernel, double c /// Generate a search criteria for fbconfig from a X visual. /// Returns {-1, -1, -1, -1, -1, -1} on failure -struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual); +struct xvisual_info x_get_visual_info(struct x_connection *c, xcb_visualid_t visual); -xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std); +xcb_visualid_t x_get_visual_for_standard(struct x_connection *c, xcb_pict_standard_t std); xcb_render_pictformat_t -x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std); +x_get_pictfmt_for_standard(struct x_connection *c, xcb_pict_standard_t std); -xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen); +xcb_screen_t *x_screen_of_display(struct x_connection *c, int screen); -/** - * X RandR-related functions. - * - * The x_update_randr_monitors function populates ps->randr_nmonitors and - * ps->randr_monitor_regs with the data X RandR provided and the - * x_free_randr_info function frees them. - */ -void x_update_randr_monitors(session_t *ps); -void x_free_randr_info(session_t *ps); +/// Populates a `struct x_monitors` with the current monitor configuration. +void x_update_monitors(struct x_connection *, struct x_monitors *); +/// Free memory allocated for a `struct x_monitors`. +void x_free_monitor_info(struct x_monitors *); uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c); From 6bd780f10f32cbf0eeb05e538faf20e73a058525 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Tue, 4 Jul 2023 03:42:10 +0100 Subject: [PATCH 13/15] x: don't abort in release for double freeing a xrender picture Signed-off-by: Yuxuan Shui --- src/x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x.c b/src/x.c index 46af709..1840ebb 100644 --- a/src/x.c +++ b/src/x.c @@ -537,7 +537,7 @@ void x_clear_picture_clip_region(struct x_connection *c, xcb_render_picture_t pi void x_free_picture(struct x_connection *c, xcb_render_picture_t p) { assert(p != XCB_NONE); auto cookie = xcb_render_free_picture(c->c, p); - set_cant_fail_cookie(c, cookie); + set_debug_cant_fail_cookie(c, cookie); } enum { From 7a45e35ca06d019b7e83a1a211385972e8b6f738 Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Tue, 4 Jul 2023 20:47:56 +0300 Subject: [PATCH 14/15] backend: gl: set usage of buffer objects to GL_STREAM_DRAW it pretty much describes how we use buffer objects now reference: https://docs.gl/gl3/glBufferData --- src/backend/gl/blur.c | 10 +++++----- src/backend/gl/gl_common.c | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/backend/gl/blur.c b/src/backend/gl/blur.c index 9297038..6c2b717 100644 --- a/src/backend/gl/blur.c +++ b/src/backend/gl/blur.c @@ -23,7 +23,7 @@ struct gl_blur_context { struct texture_size { int width; int height; - } * texture_sizes; + } *texture_sizes; /// Cached dimensions of the offscreen framebuffer. It's the same size as the /// target but is expanded in either direction by resize_width / resize_height. @@ -347,9 +347,9 @@ bool gl_blur_impl(double opacity, struct gl_blur_context *bctx, void *mask, coor glBindVertexArray(vao[0]); glBindBuffer(GL_ARRAY_BUFFER, bo[0]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[1]); - glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * nrects * 16, coord, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * nrects * 16, coord, GL_STREAM_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * nrects * 6, - indices, GL_STATIC_DRAW); + indices, GL_STREAM_DRAW); glEnableVertexAttribArray(vert_coord_loc); glEnableVertexAttribArray(vert_in_texcoord_loc); glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 4, NULL); @@ -360,10 +360,10 @@ bool gl_blur_impl(double opacity, struct gl_blur_context *bctx, void *mask, coor glBindBuffer(GL_ARRAY_BUFFER, bo[2]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[3]); glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord_resized) * nrects_resized * 16, - coord_resized, GL_STATIC_DRAW); + coord_resized, GL_STREAM_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices_resized) * nrects_resized * 6, indices_resized, - GL_STATIC_DRAW); + GL_STREAM_DRAW); glEnableVertexAttribArray(vert_coord_loc); glEnableVertexAttribArray(vert_in_texcoord_loc); glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 4, NULL); diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index ef9a34b..01a83db 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -309,9 +309,9 @@ static GLuint gl_average_texture_color(backend_t *base, struct backend_image *im // Allocate buffers for render input GLint coord[16] = {0}; GLuint indices[] = {0, 1, 2, 2, 3, 0}; - glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * 16, coord, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * 16, coord, GL_STREAM_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * 6, indices, - GL_STATIC_DRAW); + GL_STREAM_DRAW); // Do actual recursive render to 1x1 texture GLuint result_texture = _gl_average_texture_color( @@ -448,9 +448,9 @@ static void _gl_compose(backend_t *base, struct backend_image *img, GLuint targe glGenBuffers(2, bo); glBindBuffer(GL_ARRAY_BUFFER, bo[0]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[1]); - glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * nrects * 16, coord, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * nrects * 16, coord, GL_STREAM_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * nrects * 6, - indices, GL_STATIC_DRAW); + indices, GL_STREAM_DRAW); glEnableVertexAttribArray(vert_coord_loc); glEnableVertexAttribArray(vert_in_texcoord_loc); @@ -1065,9 +1065,9 @@ static inline void gl_image_decouple(backend_t *base, struct backend_image *img) glGenBuffers(2, bo); glBindBuffer(GL_ARRAY_BUFFER, bo[0]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[1]); - glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * 16, coord, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * 16, coord, GL_STREAM_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * 6, indices, - GL_STATIC_DRAW); + GL_STREAM_DRAW); glEnableVertexAttribArray(vert_coord_loc); glEnableVertexAttribArray(vert_in_texcoord_loc); @@ -1368,9 +1368,9 @@ void *gl_shadow_from_mask(backend_t *base, void *mask, glGenBuffers(2, bo); glBindBuffer(GL_ARRAY_BUFFER, bo[0]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bo[1]); - glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * 8, coord, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, (long)sizeof(*coord) * 8, coord, GL_STREAM_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (long)sizeof(*indices) * 6, indices, - GL_STATIC_DRAW); + GL_STREAM_DRAW); glEnableVertexAttribArray(vert_coord_loc); glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 2, NULL); From e8477e0a730a33b71e29a31dd51fa1601d550735 Mon Sep 17 00:00:00 2001 From: Maxim Solovyov Date: Thu, 6 Jul 2023 01:12:09 +0300 Subject: [PATCH 15/15] backend: fix resize factor calculation the corresponding regions need to be resized once for each window in the stack above the damaged window including the damaged window itself. we were off by one. --- src/backend/backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/backend.c b/src/backend/backend.c index f094555..33a3d8b 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -154,7 +154,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) { // TODO(yshui): maybe we don't need to resize reg_damage, only reg_paint? int resize_factor = 1; if (t) { - resize_factor = t->stacking_rank; + resize_factor = t->stacking_rank + 1; } resize_region_in_place(®_damage, blur_width * resize_factor, blur_height * resize_factor);