Merge remote-tracking branch 'yshui/next' into next

This commit is contained in:
Arda Atci
2023-07-14 02:45:02 +03:00
31 changed files with 1232 additions and 1116 deletions

View File

@@ -18,20 +18,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
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' }}
uses: actions/checkout@v3
# 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 +32,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

View File

@@ -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:

View File

@@ -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

0
.gitmodules vendored
View File

View File

@@ -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 <ajax@nwnk.net>
adelin-b <berard.adelin@gmail.com>
Alexander Kapshuna <kapsh@kap.sh>
Antonin Décimo <antonin.decimo@gmail.com>
Antonio Vivace <dev@avivace.com>
Avi-D-coder <avi.the.coder@gmail.com>
Ben Friesen <bfriesen95@gmail.com>
Bernd Busse <bernd@busse-net.de>
Bert Gijsbers <gijsbers@science.uva.nl>
bhagwan <bhagwan@disroot.org>
Bodhi <craig.langman@gmail.com>
Brottweiler <tibell.christoffer@gmail.com>
Carl Worth <cworth@cworth.org>
Christopher Jeffrey <chjjeffrey@gmail.com>
Corax26 <cor.ax26@gmail.com>
Dan Elkouby <streetwalkermc@gmail.com>
Dana Jansens <danakj@orodu.net>
Daniel Kwan <daniel.w.t.kwan@outlook.com>
Dave Airlie <airlied@linux.ie>
Adam Jackson <ajax at nwnk.net>
adelin-b <berard.adelin at gmail.com>
Alexander Kapshuna <kapsh at kap.sh>
Antonin Décimo <antonin.decimo at gmail.com>
Antonio Vivace <dev at avivace.com>
Avi ד <avi.the.coder at gmail.com>
Ben Friesen <bfriesen95 at gmail.com>
Bernd Busse <bernd at busse-net.de>
Bert Gijsbers <gijsbers at science.uva.nl>
bhagwan <bhagwan at disroot.org>
Bodhi <craig.langman at gmail.com>
Brottweiler <tibell.christoffer at gmail.com>
Carl Worth <cworth at cworth.org>
Christopher Jeffrey <chjjeffrey at gmail.com>
Corax26 <cor.ax26 at gmail.com>
Dan Elkouby <streetwalkermc at gmail.com>
Dana Jansens <danakj at orodu.net>
Daniel Kwan <daniel.w.t.kwan at outlook.com>
Dave Airlie <airlied at linux.ie>
David Schlachter
dolio
Duncan <duncan.britton@outlook.com>
Dylan Araps <dylan.araps@gmail.com>
Einar Lielmanis <einars@gmail.com>
Eric Anholt <anholt@freebsd.org> <eric@anholt.net>
Duncan <duncan.britton at outlook.com>
Dylan Araps <dylan.araps at gmail.com>
Einar Lielmanis <einars at gmail.com>
Eric Anholt <anholt at freebsd.org> <eric at anholt.net>
Evgeniy Baskov <j-basevgser at yandex.ru>
Greg Flynn
Harish Rajagopal <harish.rajagopals@gmail.com>
hasufell <julian.ospald@googlemail.com>
Ignacio Taranto <ignacio.taranto@eclypsium.com>
h7x4 <h7x4 at nani.wtf>
Harish Rajagopal <harish.rajagopals at gmail.com>
hasufell <julian.ospald at googlemail.com>
i-c-u-p
Ignacio Taranto <ignacio.taranto at eclypsium.com>
Istvan Petres
James Cloos <cloos@jhcloos.com>
Jamey Sharp <jamey@minilop.net>
Jan Beich <jbeich@FreeBSD.org>
Jarrad <jarrad.whitaker@gmail.com>
Javeed Shaikh <syscrash2k@gmail.com>
Jerónimo Navarro <jnavarro@ancasrl.com.ar>
jialeens <jialeadmin@163.com>
Johnny Pribyl <pribylsnbits@gmail.com>
Keith Packard <keithp@keithp.com>
Kevin Kelley <kelleyk@kelleyk.net>
ktprograms <ktprograms@gmail.com>
Lukas Schmelzeisen <l.schmelzeisen@gmx.de>
mæp <m.aep@live.com>
Mark Tiefenbruck <mark@fluxbox.org>
Matthew Allum <breakfast@10.am>
Maxim Solovyov <visleaf@protonmail.com>
Michael Reed <supertron421@gmail.com>
Michele Lambertucci <michele.lambertucci@mail.polimi.it>
Namkhai Bourquin <namkhai.n3@protonmail.com>
Nate Hart <nejthan@gmail.com>
nia <nia@netbsd.org>
notfoss <static.vortex@gmx.com>
Omar Polo <op@omarpolo.com>
orbea <orbea@riseup.net>
@Paradigm0001
Jake <jakeroggenbuck2 at gmail.com>
James Cloos <cloos at jhcloos.com>
Jamey Sharp <jamey at minilop.net>
Jan Beich <jbeich at freebsd.org>
Jarrad <jarrad.whitaker at gmail.com>
Javeed Shaikh <syscrash2k at gmail.com>
Jerónimo Navarro <jnavarro at ancasrl.com.ar>
jialeens <jialeadmin at 163.com>
Johnny Pribyl <pribylsnbits at gmail.com>
Keith Packard <keithp at keithp.com>
Kevin Kelley <kelleyk at kelleyk.net>
ktprograms <ktprograms at gmail.com>
Kurenshe Nurdaulet
Lukas Schmelzeisen <l.schmelzeisen at gmx.de>
Mark Tiefenbruck <mark at fluxbox.org>
Matthew Allum <breakfast at 10.am>
Maxim Solovyov <msolovyov at protonmail.com>
Michael Reed <supertron421 at gmail.com>
Michele Lambertucci <michele.lambertucci at mail.polimi.it>
mæp <m.aep at live.com>
Namkhai Bourquin <namkhai.n3 at protonmail.com>
Nate Hart <nejthan at gmail.com>
nia <nia at netbsd.org>
Nikolay Borodin <monsterovich at gmail.com>
notfoss <static.vortex at gmx.com>
Omar Polo <op at omarpolo.com>
oofsauce <alanpanayotov at gmail.com>
orbea <orbea at riseup.net>
Paradigm0001
Patrick Collins
Peter Mattern <matternp@arcor.de>
Phil Blundell <pb@reciva.com>
Que Quotion <quequotion@bugmenot.com> <the_q123@hotmail.com>
Rafael Kitover <rkitover@gmail.com>
Richard Grenville <pyxlcy@gmail.com>
Rytis Karpuska <rytis.karpuska@gmail.com>
Samuel Hand <samuel.d.hand@gmail.com>
Scott Leggett <scott@sl.id.au>
scrouthtv <lennivh24@gmail.com>
Sebastien Waegeneire <sebastien@waegeneire.com>
Subhaditya Nath <sn03.general@gmail.com>
Tasos Sahanidis <tasos@tasossah.com>
Thiago Kenji Okada <thiagokokada@gmail.com>
Tilman Sauerbeck <tilman@code-monkey.de>
Tim van Dalen <Tim@timvdalen.nl>
Tomas Janousek <tomi@nomi.cz>
Tom Dörr <tomdoerr96@gmail.com>
Peter Mattern <matternp at arcor.de>
Phil Blundell <pb at reciva.com>
Que Quotion <quequotion at bugmenot.com>
Rafael Kitover <rkitover at gmail.com>
Richard Grenville <pyxlcy at gmail.com>
Rytis Karpuska <rytis.karpuska at gmail.com>
Samuel Hand <samuel.d.hand at gmail.com>
Scott Leggett <scott at sl.id.au>
scrouthtv <lennivh24 at gmail.com>
Sebastien Waegeneire <sebastien at waegeneire.com>
Stefan Radziuk <stefan.radziuk19 at imperial.ac.uk>
Subhaditya Nath <sn03.general at gmail.com>
Tasos Sahanidis <tasos at tasossah.com>
Thiago Kenji Okada <thiagokokada at gmail.com>
Tilman Sauerbeck <tilman at code-monkey.de>
Tim Siegel <siegeltr at gmail.com>
Tim van Dalen <tim at timvdalen.nl>
tokyoneon78 <mockcoder at protonmail.ch>
Tom Dörr <tomdoerr96 at gmail.com>
Tomas Janousek <tomi at nomi.cz>
Toni Jarjour
Tuomas Kinnunen <tuomas.kinnunen@aalto.fi>
Uli Schlachter <psychon@znc.in>
Walter Lapchynski <wxl@ubuntu.com>
Will Dietz <w@wdtz.org>
XeCycle <XeCycle@Gmail.com>
Yuxuan Shui <yshuiv7@gmail.com>
Tuomas Kinnunen <tuomas.kinnunen at aalto.fi>
Uli Schlachter <psychon at znc.in>
Walter Lapchynski <wxl at ubuntu.com>
Will Dietz <w at wdtz.org>
XeCycle <xecycle at gmail.com>
Yuxuan Shui <yshuiv7 at gmail.com>
zilrich
ಠ_ಠ <easteregg@verfriemelt.org>
ಠ_ಠ <easteregg at verfriemelt.org>

View File

@@ -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
```

View File

@@ -143,10 +143,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;
@@ -206,7 +206,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(&reg_damage, blur_width * resize_factor,
blur_height * resize_factor);
@@ -401,7 +401,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.
@@ -411,7 +411,7 @@ void paint_all_new(session_t *ps, struct managed_win *t) {
// bounds.
pixman_region32_intersect(
&reg_shadow, &reg_shadow,
&ps->randr_monitor_regs[w->randr_monitor]);
&ps->monitors.regions[w->randr_monitor]);
}
if (ps->o.transparent_clipping) {

View File

@@ -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

View File

@@ -19,17 +19,18 @@
/**
* Generate a 1x1 <code>Picture</code> 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 <code>Picture</code> 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;
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
@@ -1074,9 +1074,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);
@@ -1377,9 +1377,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);

View File

@@ -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));

View File

@@ -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;

View File

@@ -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(&reg, (region_t *)reg_paint, (region_t *)reg_visible);
x_set_picture_clip_region(xd->base.c, result, 0, 0, &reg);
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), &reg);
// 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(&reg);
}
@@ -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(&reg_op);
pixman_region32_intersect(&reg_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, &reg_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, &reg_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(&reg_op);
pixman_region32_fini(&reg_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, &reg);
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");

116
src/c2.c
View File

@@ -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;
}
}

View File

@@ -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,
@@ -188,30 +176,13 @@ 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;
int selmon_center_x;
int selmon_center_y;
int root_height;
/// X Composite overlay window.
xcb_window_t overlay;
/// The target window for debug mode
@@ -400,10 +371,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.
@@ -501,7 +470,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;
}
/**
@@ -511,35 +480,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.
*
@@ -550,7 +490,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;
}

View File

@@ -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;
}

View File

@@ -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,8 +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;
@@ -474,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)});
@@ -587,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);
}
@@ -668,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);
@@ -690,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.
@@ -702,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;
}
@@ -737,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);

View File

@@ -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;
}

View File

@@ -16,6 +16,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sched.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
@@ -128,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();
@@ -148,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;
}
@@ -351,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;
@@ -405,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 ===
/**
@@ -481,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.
@@ -509,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;
@@ -718,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();
@@ -794,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;
}
@@ -1265,10 +1226,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,
@@ -1283,27 +1245,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.
*/
@@ -1338,10 +1279,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.");
@@ -1360,10 +1302,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]);
@@ -1373,9 +1315,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);
@@ -1389,10 +1331,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");
@@ -1408,16 +1350,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);
@@ -1429,7 +1371,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;
}
@@ -1437,7 +1379,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
@@ -1445,7 +1387,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;
@@ -1475,9 +1417,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);
@@ -1487,13 +1428,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.");
@@ -1501,7 +1442,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
@@ -1509,7 +1450,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.");
@@ -1520,27 +1461,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;
}
@@ -1555,7 +1498,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) {
@@ -1585,18 +1528,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;
@@ -1625,16 +1568,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.
@@ -1649,13 +1592,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);
@@ -1675,10 +1618,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
@@ -1690,15 +1634,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.");
@@ -1722,9 +1666,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;
@@ -1771,7 +1715,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.
@@ -1792,7 +1736,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);
};
@@ -1801,9 +1745,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);
@@ -1866,7 +1810,7 @@ static void animation_timer_callback(EV_P attr_unused, ev_timer *w, int revents
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);
@@ -1892,7 +1836,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);
}
@@ -1902,7 +1846,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);
@@ -2050,7 +1994,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);
@@ -2148,12 +2092,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,
@@ -2239,52 +2177,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);
@@ -2292,7 +2220,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);
@@ -2303,8 +2231,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);
@@ -2316,45 +2244,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;
@@ -2409,7 +2337,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
@@ -2471,25 +2399,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) {
@@ -2499,14 +2427,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))) {
@@ -2517,9 +2445,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. "
@@ -2596,7 +2525,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
@@ -2637,26 +2566,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);
@@ -2693,7 +2625,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;
}
@@ -2703,7 +2635,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);
@@ -2716,12 +2648,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);
@@ -2763,30 +2695,35 @@ 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) {
struct rlimit rlim;
if (getrlimit(RLIMIT_RTPRIO, &rlim) != 0) {
log_warn("Failed to get RLIMIT_RTPRIO, not setting real-time priority");
return;
}
int old_policy;
int priority = sched_get_priority_min(SCHED_RR);
int ret;
struct sched_param param;
ret = pthread_getschedparam(pthread_self(), &old_policy, &param);
ret = sched_getparam(0, &param);
if (ret != 0) {
log_debug("Failed to get old scheduling priority");
return;
}
param.sched_priority = (int)rlim.rlim_cur;
ret = pthread_setschedparam(pthread_self(), SCHED_RR, &param);
param.sched_priority = priority;
ret = sched_setscheduler(0, SCHED_RR, &param);
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);
}
/**
@@ -2811,7 +2748,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
@@ -2862,32 +2799,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);
@@ -2900,7 +2822,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);
@@ -2925,28 +2847,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;
}
@@ -2965,7 +2887,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);
@@ -2977,8 +2899,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);
@@ -2988,6 +2908,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);
}
/**
@@ -3054,10 +2976,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]);

View File

@@ -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;

View File

@@ -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 <code>Picture</code>.
*/
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(&reg);
}
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, &reg_blur, td);
if (td) {
xcb_render_free_picture(ps->c, td);
x_free_picture(&ps->c, td);
}
pixman_region32_clear(&reg_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, &region);
x_set_picture_clip_region(&ps->c, ps->tgt_picture, 0, 0, &region);
}
#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(&reg_tmp, &region, 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(&reg_tmp, &reg_tmp,
&ps->shadow_exclude_reg);
}
if (pixman_region32_not_empty(&reg_shadow_clip)) {
pixman_region32_subtract(&reg_tmp, &reg_tmp, &reg_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(&reg_tmp, &reg_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(
&reg_tmp, &reg_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, &region);
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, ps->white_picture,
x_set_picture_clip_region(&ps->c, new_pict, 0, 0, &region);
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, &region, 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);

View File

@@ -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);

View File

@@ -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

129
src/win.c
View File

@@ -331,7 +331,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);
@@ -375,7 +375,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) {
@@ -473,15 +476,15 @@ static void init_animation(session_t *ps, struct managed_win *w) {
CLEAR_MASK(w->animation_is_tag)
static int32_t randr_mon_center_x, randr_mon_center_y;
if (w->randr_monitor == -1) {
win_update_monitor(ps->randr_nmonitors, ps->randr_monitor_regs, w);
win_update_monitor(&ps->monitors, w);
if (w->randr_monitor != -1) {
auto e = pixman_region32_extents(&ps->randr_monitor_regs[w->randr_monitor]);
auto e = pixman_region32_extents(&ps->monitors.regions[w->randr_monitor]);
randr_mon_center_x = (e->x2 + e->x1) / 2, randr_mon_center_y = (e->y2 + e->y1) / 2;
} else {
randr_mon_center_x = ps->root_width / 2, randr_mon_center_y = ps->root_height / 2;
}
} else {
auto e = pixman_region32_extents(&ps->randr_monitor_regs[w->randr_monitor]);
auto e = pixman_region32_extents(&ps->monitors.regions[w->randr_monitor]);
randr_mon_center_x = (e->x2 + e->x1) / 2, randr_mon_center_y = (e->y2 + e->y1) / 2;
}
static double *anim_x, *anim_y, *anim_w, *anim_h;
@@ -768,7 +771,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)) {
@@ -951,7 +954,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);
@@ -963,7 +966,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) {
@@ -984,7 +987,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) {
@@ -1080,11 +1083,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
@@ -1106,9 +1110,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;
}
/**
@@ -1158,7 +1161,7 @@ bool win_should_animate(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) {
@@ -1356,8 +1359,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;
@@ -1557,10 +1561,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) {
@@ -1585,9 +1590,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);
@@ -1612,13 +1617,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);
}
@@ -1637,7 +1642,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)});
}
@@ -1650,7 +1655,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;
}
@@ -1724,7 +1729,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);
@@ -1898,9 +1903,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
@@ -1935,7 +1941,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);
@@ -1953,10 +1959,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);
@@ -1966,15 +1972,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);
@@ -2044,12 +2050,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);
@@ -2065,8 +2071,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
@@ -2074,8 +2081,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);
}
@@ -2094,8 +2102,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);
@@ -2235,8 +2244,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;
@@ -2309,7 +2319,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) {
@@ -2364,7 +2374,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;
@@ -2372,12 +2382,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);
}
}
@@ -2766,12 +2776,12 @@ 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) {
for (int i = 0; i < nmons; i++) {
auto e = pixman_region32_extents(&mons[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) {
if (e->x1 <= mw->g.x && e->x2 >= mw->g.x + mw->widthb) {
void win_update_monitor(struct x_monitors *monitors, struct managed_win *mw) {
mw->randr_monitor = -1;
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;
log_debug("Window %#010x (%s), %dx%d+%dx%d, is entirely on the "
"monitor %d (%dx%d+%dx%d)",
@@ -2988,11 +2998,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;
}
@@ -3137,7 +3148,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) &&
@@ -3152,7 +3163,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) {
@@ -3173,13 +3184,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;
}

View File

@@ -11,11 +11,6 @@
#include "uthash_extra.h"
// FIXME shouldn't need this
#ifdef CONFIG_OPENGL
#include <GL/gl.h>
#endif
#include "c2.h"
#include "compiler.h"
#include "list.h"
@@ -380,9 +375,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.

230
src/x.c
View File

@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <X11/Xlib-xcb.h>
#include <X11/Xutil.h>
#include <pixman.h>
#include <xcb/composite.h>
@@ -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 <code>winprop_t</code> 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 <code>Picture</code>.
*
* 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_debug_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->o.animations) || !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;
}

200
src/x.h
View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <X11/Xlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
@@ -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 <code>next</code> 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 <code>winprop_t</code> 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 <code>Picture</code>.
*
* 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 <code>winprop_t</code>.
@@ -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);