Run clang-format

Now we have a consistent style across the codebase.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-03-10 12:34:37 +00:00
parent 7845673734
commit 22da17630f
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
20 changed files with 8594 additions and 9013 deletions

2397
src/c2.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6,24 +6,24 @@
// === Includes === // === Includes ===
#include <stdlib.h>
#include <stdbool.h>
#include <locale.h> #include <locale.h>
#include <stdbool.h>
#include <stdlib.h>
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include "common.h"
#include "backend/backend.h" #include "backend/backend.h"
#include "win.h"
#include "x.h"
#include "c2.h" #include "c2.h"
#include "log.h" // XXX clean up #include "common.h"
#include "region.h"
#include "compiler.h" #include "compiler.h"
#include "config.h"
#include "log.h" // XXX clean up
#include "region.h"
#include "render.h"
#include "types.h" #include "types.h"
#include "utils.h" #include "utils.h"
#include "render.h" #include "win.h"
#include "config.h" #include "x.h"
// == Functions == // == Functions ==
// TODO move static inline functions that are only used in compton.c, into // TODO move static inline functions that are only used in compton.c, into
@ -36,21 +36,19 @@ void add_damage(session_t *ps, const region_t *damage);
long determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode); long determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode);
xcb_window_t xcb_window_t find_client_win(session_t *ps, xcb_window_t w);
find_client_win(session_t *ps, xcb_window_t w);
win *find_toplevel2(session_t *ps, xcb_window_t wid); win *find_toplevel2(session_t *ps, xcb_window_t wid);
/** /**
* Set a <code>switch_t</code> array of all unset wintypes to true. * Set a <code>switch_t</code> array of all unset wintypes to true.
*/ */
static inline void static inline void wintype_arr_enable_unset(switch_t arr[]) {
wintype_arr_enable_unset(switch_t arr[]) { wintype_t i;
wintype_t i;
for (i = 0; i < NUM_WINTYPES; ++i) for (i = 0; i < NUM_WINTYPES; ++i)
if (UNSET == arr[i]) if (UNSET == arr[i])
arr[i] = ON; arr[i] = ON;
} }
/** /**
@ -60,81 +58,76 @@ wintype_arr_enable_unset(switch_t arr[]) {
* @param count amount of elements in the array * @param count amount of elements in the array
* @param wid window ID to search for * @param wid window ID to search for
*/ */
static inline bool static inline bool array_wid_exists(const xcb_window_t *arr, int count, xcb_window_t wid) {
array_wid_exists(const xcb_window_t *arr, int count, xcb_window_t wid) { while (count--) {
while (count--) { if (arr[count] == wid) {
if (arr[count] == wid) { return true;
return true; }
} }
}
return false; return false;
} }
/** /**
* Destroy a condition list. * Destroy a condition list.
*/ */
static inline void static inline void free_wincondlst(c2_lptr_t **pcondlst) {
free_wincondlst(c2_lptr_t **pcondlst) { while ((*pcondlst = c2_free_lptr(*pcondlst)))
while ((*pcondlst = c2_free_lptr(*pcondlst))) continue;
continue;
} }
#ifndef CONFIG_OPENGL #ifndef CONFIG_OPENGL
static inline void static inline void free_paint_glx(session_t *ps, paint_t *p) {
free_paint_glx(session_t *ps, paint_t *p) {} }
static inline void static inline void free_win_res_glx(session_t *ps, win *w) {
free_win_res_glx(session_t *ps, win *w) {} }
#endif #endif
/** /**
* Create a XTextProperty of a single string. * Create a XTextProperty of a single string.
*/ */
static inline XTextProperty * static inline XTextProperty *make_text_prop(session_t *ps, char *str) {
make_text_prop(session_t *ps, char *str) { XTextProperty *pprop = ccalloc(1, XTextProperty);
XTextProperty *pprop = ccalloc(1, XTextProperty);
if (XmbTextListToTextProperty(ps->dpy, &str, 1, XStringStyle, pprop)) { if (XmbTextListToTextProperty(ps->dpy, &str, 1, XStringStyle, pprop)) {
cxfree(pprop->value); cxfree(pprop->value);
free(pprop); free(pprop);
pprop = NULL; pprop = NULL;
} }
return pprop; return pprop;
} }
/** /**
* Set a single-string text property on a window. * Set a single-string text property on a window.
*/ */
static inline bool static inline bool
wid_set_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop_atom, char *str) { wid_set_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop_atom, char *str) {
XTextProperty *pprop = make_text_prop(ps, str); XTextProperty *pprop = make_text_prop(ps, str);
if (!pprop) { if (!pprop) {
log_error("Failed to make text property: %s.", str); log_error("Failed to make text property: %s.", str);
return false; return false;
} }
XSetTextProperty(ps->dpy, wid, pprop, prop_atom); XSetTextProperty(ps->dpy, wid, pprop, prop_atom);
cxfree(pprop->value); cxfree(pprop->value);
cxfree(pprop); cxfree(pprop);
return true; return true;
} }
/** /**
* Dump an drawable's info. * Dump an drawable's info.
*/ */
static inline void static inline void dump_drawable(session_t *ps, xcb_drawable_t drawable) {
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, xcb_get_geometry(ps->c, drawable), NULL); if (!r) {
if (!r) { log_trace("Drawable %#010x: Failed", drawable);
log_trace("Drawable %#010x: Failed", drawable); return;
return; }
} log_trace("Drawable %#010x: x = %u, y = %u, wid = %u, hei = %d, b = %u, d = %u",
log_trace("Drawable %#010x: x = %u, y = %u, wid = %u, hei = %d, b = %u, d = %u", drawable, r->x, r->y, r->width, r->height, r->border_width, r->depth);
drawable, r->x, r->y, r->width, r->height, r->border_width, r->depth); free(r);
free(r);
} }
// vim: set et sw=2 : // vim: set et sw=2 :

View File

@ -2,22 +2,22 @@
// Copyright (c) 2011-2013, Christopher Jeffrey // Copyright (c) 2011-2013, Christopher Jeffrey
// Copyright (c) 2013 Richard Grenville <pyxlcy@gmail.com> // Copyright (c) 2013 Richard Grenville <pyxlcy@gmail.com>
#include <math.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h> #include <ctype.h>
#include <xcb/render.h> // for xcb_render_fixed_t, XXX #include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <xcb/render.h> // for xcb_render_fixed_t, XXX
#include "compiler.h"
#include "common.h"
#include "utils.h"
#include "c2.h" #include "c2.h"
#include "string_utils.h" #include "common.h"
#include "compiler.h"
#include "kernel.h"
#include "log.h" #include "log.h"
#include "region.h" #include "region.h"
#include "string_utils.h"
#include "types.h" #include "types.h"
#include "kernel.h" #include "utils.h"
#include "win.h" #include "win.h"
#include "config.h" #include "config.h"
@ -25,22 +25,21 @@
/** /**
* Parse a long number. * Parse a long number.
*/ */
bool bool parse_long(const char *s, long *dest) {
parse_long(const char *s, long *dest) { const char *endptr = NULL;
const char *endptr = NULL; long val = strtol(s, (char **)&endptr, 0);
long val = strtol(s, (char **) &endptr, 0); if (!endptr || endptr == s) {
if (!endptr || endptr == s) { log_error("Invalid number: %s", s);
log_error("Invalid number: %s", s); return false;
return false; }
} while (isspace(*endptr))
while (isspace(*endptr)) ++endptr;
++endptr; if (*endptr) {
if (*endptr) { log_error("Trailing characters: %s", s);
log_error("Trailing characters: %s", s); return false;
return false; }
} *dest = val;
*dest = val; return true;
return true;
} }
/** /**
@ -51,19 +50,18 @@ parse_long(const char *s, long *dest) {
* @param[out] dest return the number parsed from the string * @param[out] dest return the number parsed from the string
* @return pointer to the last character parsed * @return pointer to the last character parsed
*/ */
const char * const char *parse_readnum(const char *src, double *dest) {
parse_readnum(const char *src, double *dest) { const char *pc = NULL;
const char *pc = NULL; double val = strtod_simple(src, &pc);
double val = strtod_simple(src, &pc); if (!pc || pc == src) {
if (!pc || pc == src) { log_error("No number found: %s", src);
log_error("No number found: %s", src); return src;
return src; }
} while (*pc && (isspace(*pc) || *pc == ',')) {
while (*pc && (isspace(*pc) || *pc == ',')) { ++pc;
++pc; }
} *dest = val;
*dest = val; return pc;
return pc;
} }
/** /**
@ -73,93 +71,92 @@ parse_readnum(const char *src, double *dest) {
* @param[out] endptr return where the end of kernel is in the string * @param[out] endptr return where the end of kernel is in the string
* @param[out] hasneg whether the kernel has negative values * @param[out] hasneg whether the kernel has negative values
*/ */
conv * conv *parse_blur_kern(const char *src, const char **endptr, bool *hasneg) {
parse_blur_kern(const char *src, const char **endptr, bool *hasneg) { int width = 0, height = 0;
int width = 0, height = 0; *hasneg = false;
*hasneg = false;
const char *pc = NULL; const char *pc = NULL;
// Get matrix width and height // Get matrix width and height
double val = 0.0; double val = 0.0;
if (src == (pc = parse_readnum(src, &val))) if (src == (pc = parse_readnum(src, &val)))
goto err1; goto err1;
src = pc; src = pc;
width = val; width = val;
if (src == (pc = parse_readnum(src, &val))) if (src == (pc = parse_readnum(src, &val)))
goto err1; goto err1;
src = pc; src = pc;
height = val; height = val;
// Validate matrix width and height // Validate matrix width and height
if (width <= 0 || height <= 0) { if (width <= 0 || height <= 0) {
log_error("Blue kernel width/height can't be negative."); log_error("Blue kernel width/height can't be negative.");
goto err1; goto err1;
} }
if (!(width % 2 && height % 2)) { if (!(width % 2 && height % 2)) {
log_error("Blur kernel width/height must be odd."); log_error("Blur kernel width/height must be odd.");
goto err1; goto err1;
} }
if (width > 16 || height > 16) if (width > 16 || height > 16)
log_warn("Blur kernel width/height too large, may slow down" log_warn("Blur kernel width/height too large, may slow down"
"rendering, and/or consume lots of memory"); "rendering, and/or consume lots of memory");
// Allocate memory // Allocate memory
conv *matrix = cvalloc(sizeof(conv) + width * height * sizeof(double)); conv *matrix = cvalloc(sizeof(conv) + width * height * sizeof(double));
// Read elements // Read elements
int skip = height / 2 * width + width / 2; int skip = height / 2 * width + width / 2;
for (int i = 0; i < width * height; ++i) { for (int i = 0; i < width * height; ++i) {
// Ignore the center element // Ignore the center element
if (i == skip) { if (i == skip) {
matrix->data[i] = 0; matrix->data[i] = 0;
continue; continue;
} }
if (src == (pc = parse_readnum(src, &val))) { if (src == (pc = parse_readnum(src, &val))) {
goto err2; goto err2;
} }
src = pc; src = pc;
if (val < 0) { if (val < 0) {
*hasneg = true; *hasneg = true;
} }
matrix->data[i] = val; matrix->data[i] = val;
} }
// Detect trailing characters // Detect trailing characters
for (;*pc && *pc != ';'; pc++) { for (; *pc && *pc != ';'; pc++) {
if (!isspace(*pc) && *pc != ',') { if (!isspace(*pc) && *pc != ',') {
// TODO isspace is locale aware, be careful // TODO isspace is locale aware, be careful
log_error("Trailing characters in blur kernel string."); log_error("Trailing characters in blur kernel string.");
goto err2; goto err2;
} }
} }
// Jump over spaces after ';' // Jump over spaces after ';'
if (*pc == ';') { if (*pc == ';') {
pc++; pc++;
while (*pc && isspace(*pc)) { while (*pc && isspace(*pc)) {
++pc; ++pc;
} }
} }
// Require an end of string if endptr is not provided, otherwise // Require an end of string if endptr is not provided, otherwise
// copy end pointer to endptr // copy end pointer to endptr
if (endptr) { if (endptr) {
*endptr = pc; *endptr = pc;
} else if (*pc) { } else if (*pc) {
log_error("Only one blur kernel expected."); log_error("Only one blur kernel expected.");
goto err2; goto err2;
} }
// Fill in width and height // Fill in width and height
matrix->w = width; matrix->w = width;
matrix->h = height; matrix->h = height;
return matrix; return matrix;
err2: err2:
free(matrix); free(matrix);
err1: err1:
return NULL; return NULL;
} }
/** /**
@ -172,63 +169,104 @@ err1:
* @param[out] hasneg whether any of the kernels have negative values * @param[out] hasneg whether any of the kernels have negative values
* @return if the `src` string is a valid kernel list string * @return if the `src` string is a valid kernel list string
*/ */
bool bool parse_blur_kern_lst(const char *src, conv **dest, int max, bool *hasneg) {
parse_blur_kern_lst(const char *src, conv **dest, int max, bool *hasneg) { // TODO just return a predefined kernels, not parse predefined strings...
// TODO just return a predefined kernels, not parse predefined strings... static const struct {
static const struct { const char *name;
const char *name; const char *kern_str;
const char *kern_str; } CONV_KERN_PREDEF[] = {
} CONV_KERN_PREDEF[] = { {"3x3box", "3,3,1,1,1,1,1,1,1,1,"},
{ "3x3box", "3,3,1,1,1,1,1,1,1,1," }, {"5x5box", "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,"},
{ "5x5box", "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1," }, {"7x7box", "7,7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,"
{ "7x7box", "7,7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1," }, "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,"},
{ "3x3gaussian", "3,3,0.243117,0.493069,0.243117,0.493069,0.493069,0.243117,0.493069,0.243117," }, {"3x3gaussian", "3,3,0.243117,0.493069,0.243117,0.493069,0.493069,0.243117,0."
{ "5x5gaussian", "5,5,0.003493,0.029143,0.059106,0.029143,0.003493,0.029143,0.243117,0.493069,0.243117,0.029143,0.059106,0.493069,0.493069,0.059106,0.029143,0.243117,0.493069,0.243117,0.029143,0.003493,0.029143,0.059106,0.029143,0.003493," }, "493069,0.243117,"},
{ "7x7gaussian", "7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003," }, {"5x5gaussian", "5,5,0.003493,0.029143,0.059106,0.029143,0.003493,0.029143,0."
{ "9x9gaussian", "9,9,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000012,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000012,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000," }, "243117,0.493069,0.243117,0.029143,0.059106,0.493069,0."
{ "11x11gaussian", "11,11,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000000,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000000,0.000000,0.000012,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000012,0.000000,0.000000,0.000006,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000000,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000," }, "493069,0.059106,0.029143,0.243117,0.493069,0.243117,0."
}; "029143,0.003493,0.029143,0.059106,0.029143,0.003493,"},
{"7x7gaussian", "7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0."
"000003,0.000102,0.003493,0.029143,0.059106,0.029143,0."
"003493,0.000102,0.000849,0.029143,0.243117,0.493069,0."
"243117,0.029143,0.000849,0.001723,0.059106,0.493069,0."
"493069,0.059106,0.001723,0.000849,0.029143,0.243117,0."
"493069,0.243117,0.029143,0.000849,0.000102,0.003493,0."
"029143,0.059106,0.029143,0.003493,0.000102,0.000003,0."
"000102,0.000849,0.001723,0.000849,0.000102,0.000003,"},
{"9x9gaussian",
"9,9,0.000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0."
"000000,0.000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0."
"000102,0.000003,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0."
"029143,0.003493,0.000102,0.000001,0.000006,0.000849,0.029143,0.243117,0."
"493069,0.243117,0.029143,0.000849,0.000006,0.000012,0.001723,0.059106,0."
"493069,0.493069,0.059106,0.001723,0.000012,0.000006,0.000849,0.029143,0."
"243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000001,0.000102,0."
"003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0."
"000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000000,0."
"000000,0.000000,0.000001,0.000006,0.000012,0.000006,0.000001,0.000000,0."
"000000,"},
{"11x11gaussian",
"11,11,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0."
"000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0."
"000006,0.000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0."
"000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0."
"000000,0.000000,0.000000,0.000001,0.000102,0.003493,0.029143,0.059106,0."
"029143,0.003493,0.000102,0.000001,0.000000,0.000000,0.000006,0.000849,0."
"029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000006,0.000000,0."
"000000,0.000012,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0."
"000012,0.000000,0.000000,0.000006,0.000849,0.029143,0.243117,0.493069,0."
"243117,0.029143,0.000849,0.000006,0.000000,0.000000,0.000001,0.000102,0."
"003493,0.029143,0.059106,0.029143,0.003493,0.000102,0.000001,0.000000,0."
"000000,0.000000,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0."
"000003,0.000000,0.000000,0.000000,0.000000,0.000000,0.000001,0.000006,0."
"000012,0.000006,0.000001,0.000000,0.000000,0.000000,0.000000,0.000000,0."
"000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0."
"000000,"},
};
*hasneg = false; *hasneg = false;
for (unsigned int i = 0; for (unsigned int i = 0;
i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i) { i < sizeof(CONV_KERN_PREDEF) / sizeof(CONV_KERN_PREDEF[0]); ++i) {
if (!strcmp(CONV_KERN_PREDEF[i].name, src)) if (!strcmp(CONV_KERN_PREDEF[i].name, src))
return parse_blur_kern_lst(CONV_KERN_PREDEF[i].kern_str, dest, max, hasneg); return parse_blur_kern_lst(CONV_KERN_PREDEF[i].kern_str, dest,
} max, hasneg);
}
int i = 0; int i = 0;
const char *pc = src; const char *pc = src;
// Free old kernels // Free old kernels
for (i = 0; i < max; ++i) { for (i = 0; i < max; ++i) {
free(dest[i]); free(dest[i]);
dest[i] = NULL; dest[i] = NULL;
} }
// Continue parsing until the end of source string // Continue parsing until the end of source string
i = 0; i = 0;
while (pc && *pc && i < max - 1) { while (pc && *pc && i < max - 1) {
bool tmp_hasneg; bool tmp_hasneg;
dest[i] = parse_blur_kern(pc, &pc, &tmp_hasneg); dest[i] = parse_blur_kern(pc, &pc, &tmp_hasneg);
if (!dest[i]) { if (!dest[i]) {
return false; return false;
} }
i++; i++;
*hasneg |= tmp_hasneg; *hasneg |= tmp_hasneg;
} }
if (i > 1) { if (i > 1) {
log_warn("You are seeing this message because your are using multipassblur. Please " log_warn("You are seeing this message because your are using "
"report an issue to us so we know multipass blur is actually been used. " "multipassblur. Please "
"Otherwise it might be removed in future releases"); "report an issue to us so we know multipass blur is actually "
} "been used. "
"Otherwise it might be removed in future releases");
}
if (*pc) { if (*pc) {
log_error("Too many blur kernels!"); log_error("Too many blur kernels!");
return false; return false;
} }
return true; return true;
} }
/** /**
@ -236,187 +274,184 @@ parse_blur_kern_lst(const char *src, conv **dest, int max, bool *hasneg) {
* *
* ps->root_width and ps->root_height must be valid * ps->root_width and ps->root_height must be valid
*/ */
bool bool parse_geometry(session_t *ps, const char *src, region_t *dest) {
parse_geometry(session_t *ps, const char *src, region_t *dest) { pixman_region32_clear(dest);
pixman_region32_clear(dest); if (!src)
if (!src) return true;
return true; if (!ps->root_width || !ps->root_height)
if (!ps->root_width || !ps->root_height) return true;
return true;
geometry_t geom = { .wid = ps->root_width, .hei = ps->root_height, .x = 0, .y = 0 }; geometry_t geom = {.wid = ps->root_width, .hei = ps->root_height, .x = 0, .y = 0};
long val = 0L; long val = 0L;
char *endptr = NULL; char *endptr = NULL;
src = skip_space(src); src = skip_space(src);
if (!*src) if (!*src)
goto parse_geometry_end; goto parse_geometry_end;
// Parse width // Parse width
// Must be base 10, because "0x0..." may appear // Must be base 10, because "0x0..." may appear
if (!('+' == *src || '-' == *src)) { if (!('+' == *src || '-' == *src)) {
val = strtol(src, &endptr, 10); val = strtol(src, &endptr, 10);
assert(endptr); assert(endptr);
if (src != endptr) { if (src != endptr) {
geom.wid = val; geom.wid = val;
if (geom.wid < 0) { if (geom.wid < 0) {
log_error("Invalid width: %s", src); log_error("Invalid width: %s", src);
return false; return false;
} }
src = endptr; src = endptr;
} }
src = skip_space(src); src = skip_space(src);
} }
// Parse height // Parse height
if ('x' == *src) { if ('x' == *src) {
++src; ++src;
val = strtol(src, &endptr, 10); val = strtol(src, &endptr, 10);
assert(endptr); assert(endptr);
if (src != endptr) { if (src != endptr) {
geom.hei = val; geom.hei = val;
if (geom.hei < 0) { if (geom.hei < 0) {
log_error("Invalid height: %s", src); log_error("Invalid height: %s", src);
return false; return false;
} }
src = endptr; src = endptr;
} }
src = skip_space(src); src = skip_space(src);
} }
// Parse x // Parse x
if ('+' == *src || '-' == *src) { if ('+' == *src || '-' == *src) {
val = strtol(src, &endptr, 10); val = strtol(src, &endptr, 10);
if (endptr && src != endptr) { if (endptr && src != endptr) {
geom.x = val; geom.x = val;
if (*src == '-') if (*src == '-')
geom.x += ps->root_width - geom.wid; geom.x += ps->root_width - geom.wid;
src = endptr; src = endptr;
} }
src = skip_space(src); src = skip_space(src);
} }
// Parse y // Parse y
if ('+' == *src || '-' == *src) { if ('+' == *src || '-' == *src) {
val = strtol(src, &endptr, 10); val = strtol(src, &endptr, 10);
if (endptr && src != endptr) { if (endptr && src != endptr) {
geom.y = val; geom.y = val;
if (*src == '-') if (*src == '-')
geom.y += ps->root_height - geom.hei; geom.y += ps->root_height - geom.hei;
src = endptr; src = endptr;
} }
src = skip_space(src); src = skip_space(src);
} }
if (*src) { if (*src) {
log_error("Trailing characters: %s", src); log_error("Trailing characters: %s", src);
return false; return false;
} }
parse_geometry_end: parse_geometry_end:
pixman_region32_union_rect(dest, dest, geom.x, geom.y, geom.wid, geom.hei); pixman_region32_union_rect(dest, dest, geom.x, geom.y, geom.wid, geom.hei);
return true; return true;
} }
/** /**
* Parse a list of opacity rules. * Parse a list of opacity rules.
*/ */
bool parse_rule_opacity(c2_lptr_t **res, const char *src) { bool parse_rule_opacity(c2_lptr_t **res, const char *src) {
// Find opacity value // Find opacity value
char *endptr = NULL; char *endptr = NULL;
long val = strtol(src, &endptr, 0); long val = strtol(src, &endptr, 0);
if (!endptr || endptr == src) { if (!endptr || endptr == src) {
log_error("No opacity specified: %s", src); log_error("No opacity specified: %s", src);
return false; return false;
} }
if (val > 100 || val < 0) { if (val > 100 || val < 0) {
log_error("Opacity %ld invalid: %s", val, src); log_error("Opacity %ld invalid: %s", val, src);
return false; return false;
} }
// Skip over spaces // Skip over spaces
while (*endptr && isspace(*endptr)) while (*endptr && isspace(*endptr))
++endptr; ++endptr;
if (':' != *endptr) { if (':' != *endptr) {
log_error("Opacity terminator not found: %s", src); log_error("Opacity terminator not found: %s", src);
return false; return false;
} }
++endptr; ++endptr;
// Parse pattern // Parse pattern
// I hope 1-100 is acceptable for (void *) // I hope 1-100 is acceptable for (void *)
return c2_parse(res, endptr, (void *) val); return c2_parse(res, endptr, (void *)val);
} }
/** /**
* Add a pattern to a condition linked list. * Add a pattern to a condition linked list.
*/ */
bool bool condlst_add(c2_lptr_t **pcondlst, const char *pattern) {
condlst_add(c2_lptr_t **pcondlst, const char *pattern) { if (!pattern)
if (!pattern) return false;
return false;
if (!c2_parse(pcondlst, pattern, NULL)) if (!c2_parse(pcondlst, pattern, NULL))
exit(1); exit(1);
return true; return true;
} }
void set_default_winopts(options_t *opt, win_option_mask_t *mask, bool shadow_enable, bool fading_enable) { void set_default_winopts(options_t *opt, win_option_mask_t *mask, bool shadow_enable,
// Apply default wintype options. bool fading_enable) {
if (!mask[WINTYPE_DESKTOP].shadow) { // Apply default wintype options.
// Desktop windows are always drawn without shadow by default. if (!mask[WINTYPE_DESKTOP].shadow) {
mask[WINTYPE_DESKTOP].shadow = true; // Desktop windows are always drawn without shadow by default.
opt->wintype_option[WINTYPE_DESKTOP].shadow = false; mask[WINTYPE_DESKTOP].shadow = true;
} opt->wintype_option[WINTYPE_DESKTOP].shadow = false;
}
// Focused/unfocused state only apply to a few window types, all other windows // Focused/unfocused state only apply to a few window types, all other windows
// are always considered focused. // are always considered focused.
const wintype_t nofocus_type[] = const wintype_t nofocus_type[] = {WINTYPE_UNKNOWN, WINTYPE_NORMAL, WINTYPE_UTILITY};
{ WINTYPE_UNKNOWN, WINTYPE_NORMAL, WINTYPE_UTILITY }; for (unsigned long i = 0; i < ARR_SIZE(nofocus_type); i++) {
for (unsigned long i = 0; i < ARR_SIZE(nofocus_type); i++) { if (!mask[nofocus_type[i]].focus) {
if (!mask[nofocus_type[i]].focus) { mask[nofocus_type[i]].focus = true;
mask[nofocus_type[i]].focus = true; opt->wintype_option[nofocus_type[i]].focus = false;
opt->wintype_option[nofocus_type[i]].focus = false; }
} }
} for (unsigned long i = 0; i < NUM_WINTYPES; i++) {
for (unsigned long i = 0; i < NUM_WINTYPES; i++) { if (!mask[i].shadow) {
if (!mask[i].shadow) { mask[i].shadow = true;
mask[i].shadow = true; opt->wintype_option[i].shadow = shadow_enable;
opt->wintype_option[i].shadow = shadow_enable; }
} if (!mask[i].fade) {
if (!mask[i].fade) { mask[i].fade = true;
mask[i].fade = true; opt->wintype_option[i].fade = fading_enable;
opt->wintype_option[i].fade = fading_enable; }
} if (!mask[i].focus) {
if (!mask[i].focus) { mask[i].focus = true;
mask[i].focus = true; opt->wintype_option[i].focus = true;
opt->wintype_option[i].focus = true; }
} if (!mask[i].full_shadow) {
if (!mask[i].full_shadow) { mask[i].full_shadow = true;
mask[i].full_shadow = true; opt->wintype_option[i].full_shadow = false;
opt->wintype_option[i].full_shadow = false; }
} if (!mask[i].redir_ignore) {
if (!mask[i].redir_ignore) { mask[i].redir_ignore = true;
mask[i].redir_ignore = true; opt->wintype_option[i].redir_ignore = false;
opt->wintype_option[i].redir_ignore = false; }
} if (!mask[i].opacity) {
if (!mask[i].opacity) { mask[i].opacity = true;
mask[i].opacity = true; // Opacity is not set to a concrete number here because the
// Opacity is not set to a concrete number here because the opacity logic // opacity logic is complicated, and needs an "unset" state
// is complicated, and needs an "unset" state opt->wintype_option[i].opacity = NAN;
opt->wintype_option[i].opacity = NAN; }
} }
}
} }
char *parse_config(options_t *opt, const char *config_file, char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
bool *shadow_enable, bool *fading_enable, bool *hasneg, bool *fading_enable, bool *hasneg, win_option_mask_t *winopt_mask) {
win_option_mask_t *winopt_mask) { char *ret = NULL;
char *ret = NULL;
#ifdef CONFIG_LIBCONFIG #ifdef CONFIG_LIBCONFIG
ret = parse_config_libconfig(opt, config_file, shadow_enable, fading_enable, ret = parse_config_libconfig(opt, config_file, shadow_enable, fading_enable,
hasneg, winopt_mask); hasneg, winopt_mask);
#endif #endif
return ret; return ret;
} }

View File

@ -7,24 +7,24 @@
/// Common functions and definitions for configuration parsing /// Common functions and definitions for configuration parsing
/// Used for command line arguments and config files /// Used for command line arguments and config files
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h> #include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <xcb/render.h> // for xcb_render_fixed_t, XXX
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <xcb/render.h> // for xcb_render_fixed_t, XXX
#include <xcb/xfixes.h> #include <xcb/xfixes.h>
#ifdef CONFIG_LIBCONFIG #ifdef CONFIG_LIBCONFIG
#include <libconfig.h> #include <libconfig.h>
#endif #endif
#include "region.h"
#include "log.h"
#include "compiler.h" #include "compiler.h"
#include "win.h"
#include "types.h"
#include "kernel.h" #include "kernel.h"
#include "log.h"
#include "region.h"
#include "types.h"
#include "win.h"
typedef struct session session_t; typedef struct session session_t;
@ -242,8 +242,7 @@ extern const char *const VSYNC_STRS[NUM_VSYNC + 1];
extern const char *const BACKEND_STRS[NUM_BKEND + 1]; extern const char *const BACKEND_STRS[NUM_BKEND + 1];
attr_warn_unused_result bool parse_long(const char *, long *); attr_warn_unused_result bool parse_long(const char *, long *);
attr_warn_unused_result bool attr_warn_unused_result bool parse_blur_kern_lst(const char *, conv **, int, bool *hasneg);
parse_blur_kern_lst(const char *, conv **, int, bool *hasneg);
attr_warn_unused_result bool parse_geometry(session_t *, const char *, region_t *); attr_warn_unused_result bool parse_geometry(session_t *, const char *, region_t *);
attr_warn_unused_result bool parse_rule_opacity(c2_lptr_t **, const char *); attr_warn_unused_result bool parse_rule_opacity(c2_lptr_t **, const char *);

View File

@ -1,22 +1,22 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
// Copyright (c) 2012-2014 Richard Grenville <pyxlcy@gmail.com> // Copyright (c) 2012-2014 Richard Grenville <pyxlcy@gmail.com>
#include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <libconfig.h>
#include <basedir_fs.h> #include <basedir_fs.h>
#include <libconfig.h>
#include <libgen.h>
#include "err.h"
#include "common.h" #include "common.h"
#include "compiler.h" #include "compiler.h"
#include "config.h" #include "config.h"
#include "string_utils.h" #include "err.h"
#include "options.h"
#include "log.h" #include "log.h"
#include "options.h"
#include "string_utils.h"
#include "utils.h" #include "utils.h"
#include "win.h" #include "win.h"
@ -27,37 +27,32 @@
* *
* So it takes a pointer to bool. * So it takes a pointer to bool.
*/ */
static inline int static inline int lcfg_lookup_bool(const config_t *config, const char *path, bool *value) {
lcfg_lookup_bool(const config_t *config, const char *path, bool *value) { int ival;
int ival;
int ret = config_lookup_bool(config, path, &ival); int ret = config_lookup_bool(config, path, &ival);
if (ret) if (ret)
*value = ival; *value = ival;
return ret; return ret;
} }
/// Search for config file under a base directory /// Search for config file under a base directory
FILE * FILE *open_config_file_at(const char *base, char **out_path) {
open_config_file_at(const char *base, char **out_path) { static const char *config_paths[] = {"/compton.conf", "/compton/compton.conf"};
static const char *config_paths[] = { for (size_t i = 0; i < ARR_SIZE(config_paths); i++) {
"/compton.conf", char *path = mstrjoin(base, config_paths[i]);
"/compton/compton.conf" FILE *ret = fopen(path, "r");
}; if (ret && out_path) {
for (size_t i = 0; i < ARR_SIZE(config_paths); i++) { *out_path = path;
char *path = mstrjoin(base, config_paths[i]); } else {
FILE *ret = fopen(path, "r"); free(path);
if (ret && out_path) { }
*out_path = path; if (ret) {
} else { return ret;
free(path); }
} }
if (ret) { return NULL;
return ret;
}
}
return NULL;
} }
/** /**
@ -65,73 +60,71 @@ open_config_file_at(const char *base, char **out_path) {
* *
* Follows the XDG specification to search for the configuration file. * Follows the XDG specification to search for the configuration file.
*/ */
FILE * FILE *open_config_file(const char *cpath, char **ppath) {
open_config_file(const char *cpath, char **ppath) { static const char config_filename_legacy[] = "/.compton.conf";
static const char config_filename_legacy[] = "/.compton.conf";
if (cpath) { if (cpath) {
FILE *ret = fopen(cpath, "r"); FILE *ret = fopen(cpath, "r");
if (ret && ppath) if (ret && ppath)
*ppath = strdup(cpath); *ppath = strdup(cpath);
return ret; return ret;
} }
// First search for config file in user config directory // First search for config file in user config directory
auto config_home = xdgConfigHome(NULL); auto config_home = xdgConfigHome(NULL);
auto ret = open_config_file_at(config_home, ppath); auto ret = open_config_file_at(config_home, ppath);
free((void *)config_home); free((void *)config_home);
if (ret) { if (ret) {
return ret; return ret;
} }
// Fall back to legacy config file in user home directory // Fall back to legacy config file in user home directory
const char *home = getenv("HOME"); const char *home = getenv("HOME");
if (home && strlen(home)) { if (home && strlen(home)) {
auto path = mstrjoin(home, config_filename_legacy); auto path = mstrjoin(home, config_filename_legacy);
ret = fopen(path, "r"); ret = fopen(path, "r");
if (ret && ppath) { if (ret && ppath) {
*ppath = path; *ppath = path;
} else { } else {
free(path); free(path);
} }
if (ret) { if (ret) {
return ret; return ret;
} }
} }
// Fall back to config file in system config directory // Fall back to config file in system config directory
auto config_dirs = xdgConfigDirectories(NULL); auto config_dirs = xdgConfigDirectories(NULL);
for (int i = 0; config_dirs[i]; i++) { for (int i = 0; config_dirs[i]; i++) {
ret = open_config_file_at(config_dirs[i], ppath); ret = open_config_file_at(config_dirs[i], ppath);
if (ret) { if (ret) {
free((void *)config_dirs); free((void *)config_dirs);
return ret; return ret;
} }
} }
free((void *)config_dirs); free((void *)config_dirs);
return NULL; return NULL;
} }
/** /**
* Parse a condition list in configuration file. * Parse a condition list in configuration file.
*/ */
void void parse_cfg_condlst(const config_t *pcfg, c2_lptr_t **pcondlst, const char *name) {
parse_cfg_condlst(const config_t *pcfg, c2_lptr_t **pcondlst, config_setting_t *setting = config_lookup(pcfg, name);
const char *name) { if (setting) {
config_setting_t *setting = config_lookup(pcfg, name); // Parse an array of options
if (setting) { if (config_setting_is_array(setting)) {
// Parse an array of options int i = config_setting_length(setting);
if (config_setting_is_array(setting)) { while (i--)
int i = config_setting_length(setting); condlst_add(pcondlst,
while (i--) config_setting_get_string_elem(setting, i));
condlst_add(pcondlst, config_setting_get_string_elem(setting, i)); }
} // Treat it as a single pattern if it's a string
// Treat it as a single pattern if it's a string else if (CONFIG_TYPE_STRING == config_setting_type(setting)) {
else if (CONFIG_TYPE_STRING == config_setting_type(setting)) { condlst_add(pcondlst, config_setting_get_string(setting));
condlst_add(pcondlst, config_setting_get_string(setting)); }
} }
}
} }
/** /**
@ -139,22 +132,24 @@ parse_cfg_condlst(const config_t *pcfg, c2_lptr_t **pcondlst,
*/ */
static inline void static inline void
parse_cfg_condlst_opct(options_t *opt, const config_t *pcfg, const char *name) { parse_cfg_condlst_opct(options_t *opt, const config_t *pcfg, const char *name) {
config_setting_t *setting = config_lookup(pcfg, name); config_setting_t *setting = config_lookup(pcfg, name);
if (setting) { if (setting) {
// Parse an array of options // Parse an array of options
if (config_setting_is_array(setting)) { if (config_setting_is_array(setting)) {
int i = config_setting_length(setting); int i = config_setting_length(setting);
while (i--) while (i--)
if (!parse_rule_opacity(&opt->opacity_rules, if (!parse_rule_opacity(
config_setting_get_string_elem(setting, i))) &opt->opacity_rules,
exit(1); config_setting_get_string_elem(setting, i)))
} exit(1);
// Treat it as a single pattern if it's a string }
else if (config_setting_type(setting) == CONFIG_TYPE_STRING) { // Treat it as a single pattern if it's a string
if (!parse_rule_opacity(&opt->opacity_rules, config_setting_get_string(setting))) else if (config_setting_type(setting) == CONFIG_TYPE_STRING) {
exit(1); if (!parse_rule_opacity(&opt->opacity_rules,
} config_setting_get_string(setting)))
} exit(1);
}
}
} }
/** /**
@ -163,316 +158,311 @@ parse_cfg_condlst_opct(options_t *opt, const config_t *pcfg, const char *name) {
* Returns the actually config_file name * Returns the actually config_file name
*/ */
char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shadow_enable, char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shadow_enable,
bool *fading_enable, bool *conv_kern_hasneg, win_option_mask_t *winopt_mask) bool *fading_enable, bool *conv_kern_hasneg,
{ win_option_mask_t *winopt_mask) {
char *path = NULL; char *path = NULL;
FILE *f; FILE *f;
config_t cfg; config_t cfg;
int ival = 0; int ival = 0;
bool bval; bool bval;
double dval = 0.0; double dval = 0.0;
// libconfig manages string memory itself, so no need to manually free // libconfig manages string memory itself, so no need to manually free
// anything // anything
const char *sval = NULL; const char *sval = NULL;
f = open_config_file(config_file, &path); f = open_config_file(config_file, &path);
if (!f) { if (!f) {
free(path); free(path);
if (config_file) { if (config_file) {
log_fatal("Failed to read configuration file \"%s\".", config_file); log_fatal("Failed to read configuration file \"%s\".", config_file);
return ERR_PTR(-1); return ERR_PTR(-1);
} }
return NULL; return NULL;
} }
config_init(&cfg); config_init(&cfg);
{ {
// dirname() could modify the original string, thus we must pass a // dirname() could modify the original string, thus we must pass a
// copy // copy
char *path2 = strdup(path); char *path2 = strdup(path);
char *parent = dirname(path2); char *parent = dirname(path2);
if (parent) if (parent)
config_set_include_dir(&cfg, parent); config_set_include_dir(&cfg, parent);
free(path2); free(path2);
} }
{ {
int read_result = config_read(&cfg, f); int read_result = config_read(&cfg, f);
fclose(f); fclose(f);
f = NULL; f = NULL;
if (read_result == CONFIG_FALSE) { if (read_result == CONFIG_FALSE) {
log_fatal("Error when reading configuration file \"%s\", line %d: %s", log_fatal("Error when reading configuration file \"%s\", line "
path, config_error_line(&cfg), config_error_text(&cfg)); "%d: %s",
goto err; path, config_error_line(&cfg), config_error_text(&cfg));
} goto err;
} }
config_set_auto_convert(&cfg, 1); }
config_set_auto_convert(&cfg, 1);
// Get options from the configuration file. We don't do range checking // Get options from the configuration file. We don't do range checking
// right now. It will be done later // right now. It will be done later
// -D (fade_delta) // -D (fade_delta)
if (config_lookup_int(&cfg, "fade-delta", &ival)) if (config_lookup_int(&cfg, "fade-delta", &ival))
opt->fade_delta = ival; opt->fade_delta = ival;
// -I (fade_in_step) // -I (fade_in_step)
if (config_lookup_float(&cfg, "fade-in-step", &dval)) if (config_lookup_float(&cfg, "fade-in-step", &dval))
opt->fade_in_step = normalize_d(dval); opt->fade_in_step = normalize_d(dval);
// -O (fade_out_step) // -O (fade_out_step)
if (config_lookup_float(&cfg, "fade-out-step", &dval)) if (config_lookup_float(&cfg, "fade-out-step", &dval))
opt->fade_out_step = normalize_d(dval); opt->fade_out_step = normalize_d(dval);
// -r (shadow_radius) // -r (shadow_radius)
config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius); config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius);
// -o (shadow_opacity) // -o (shadow_opacity)
config_lookup_float(&cfg, "shadow-opacity", &opt->shadow_opacity); config_lookup_float(&cfg, "shadow-opacity", &opt->shadow_opacity);
// -l (shadow_offset_x) // -l (shadow_offset_x)
config_lookup_int(&cfg, "shadow-offset-x", &opt->shadow_offset_x); config_lookup_int(&cfg, "shadow-offset-x", &opt->shadow_offset_x);
// -t (shadow_offset_y) // -t (shadow_offset_y)
config_lookup_int(&cfg, "shadow-offset-y", &opt->shadow_offset_y); config_lookup_int(&cfg, "shadow-offset-y", &opt->shadow_offset_y);
// -i (inactive_opacity) // -i (inactive_opacity)
if (config_lookup_float(&cfg, "inactive-opacity", &dval)) if (config_lookup_float(&cfg, "inactive-opacity", &dval))
opt->inactive_opacity = normalize_d(dval); opt->inactive_opacity = normalize_d(dval);
// --active_opacity // --active_opacity
if (config_lookup_float(&cfg, "active-opacity", &dval)) if (config_lookup_float(&cfg, "active-opacity", &dval))
opt->active_opacity = normalize_d(dval); opt->active_opacity = normalize_d(dval);
// -e (frame_opacity) // -e (frame_opacity)
config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity); config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity);
// -c (shadow_enable) // -c (shadow_enable)
if (config_lookup_bool(&cfg, "shadow", &ival)) if (config_lookup_bool(&cfg, "shadow", &ival))
*shadow_enable = ival; *shadow_enable = ival;
// -C (no_dock_shadow) // -C (no_dock_shadow)
if (config_lookup_bool(&cfg, "no-dock-shadow", &ival)) { if (config_lookup_bool(&cfg, "no-dock-shadow", &ival)) {
log_warn("Option `no-dock-shadow` is deprecated, and will be removed." log_warn("Option `no-dock-shadow` is deprecated, and will be removed."
" Please use the wintype option `shadow` of `dock` instead."); " Please use the wintype option `shadow` of `dock` instead.");
opt->wintype_option[WINTYPE_DOCK].shadow = false; opt->wintype_option[WINTYPE_DOCK].shadow = false;
winopt_mask[WINTYPE_DOCK].shadow = true; winopt_mask[WINTYPE_DOCK].shadow = true;
} }
// -G (no_dnd_shadow) // -G (no_dnd_shadow)
if (config_lookup_bool(&cfg, "no-dnd-shadow", &ival)) { if (config_lookup_bool(&cfg, "no-dnd-shadow", &ival)) {
log_warn("Option `no-dnd-shadow` is deprecated, and will be removed." log_warn("Option `no-dnd-shadow` is deprecated, and will be removed."
" Please use the wintype option `shadow` of `dnd` instead."); " Please use the wintype option `shadow` of `dnd` instead.");
opt->wintype_option[WINTYPE_DND].shadow = false; opt->wintype_option[WINTYPE_DND].shadow = false;
winopt_mask[WINTYPE_DND].shadow = true; winopt_mask[WINTYPE_DND].shadow = true;
}; };
// -m (menu_opacity) // -m (menu_opacity)
if (config_lookup_float(&cfg, "menu-opacity", &dval)) { if (config_lookup_float(&cfg, "menu-opacity", &dval)) {
log_warn("Option `menu-opacity` is deprecated, and will be removed.Please use the " log_warn("Option `menu-opacity` is deprecated, and will be "
"wintype option `opacity` of `popup_menu` and `dropdown_menu` instead."); "removed.Please use the "
opt->wintype_option[WINTYPE_DROPDOWN_MENU].opacity = dval; "wintype option `opacity` of `popup_menu` and `dropdown_menu` "
opt->wintype_option[WINTYPE_POPUP_MENU].opacity = dval; "instead.");
winopt_mask[WINTYPE_DROPDOWN_MENU].opacity = true; opt->wintype_option[WINTYPE_DROPDOWN_MENU].opacity = dval;
winopt_mask[WINTYPE_POPUP_MENU].opacity = true; opt->wintype_option[WINTYPE_POPUP_MENU].opacity = dval;
} winopt_mask[WINTYPE_DROPDOWN_MENU].opacity = true;
// -f (fading_enable) winopt_mask[WINTYPE_POPUP_MENU].opacity = true;
if (config_lookup_bool(&cfg, "fading", &ival)) }
*fading_enable = ival; // -f (fading_enable)
// --no-fading-open-close if (config_lookup_bool(&cfg, "fading", &ival))
lcfg_lookup_bool(&cfg, "no-fading-openclose", &opt->no_fading_openclose); *fading_enable = ival;
// --no-fading-destroyed-argb // --no-fading-open-close
lcfg_lookup_bool(&cfg, "no-fading-destroyed-argb", lcfg_lookup_bool(&cfg, "no-fading-openclose", &opt->no_fading_openclose);
&opt->no_fading_destroyed_argb); // --no-fading-destroyed-argb
// --shadow-red lcfg_lookup_bool(&cfg, "no-fading-destroyed-argb", &opt->no_fading_destroyed_argb);
config_lookup_float(&cfg, "shadow-red", &opt->shadow_red); // --shadow-red
// --shadow-green config_lookup_float(&cfg, "shadow-red", &opt->shadow_red);
config_lookup_float(&cfg, "shadow-green", &opt->shadow_green); // --shadow-green
// --shadow-blue config_lookup_float(&cfg, "shadow-green", &opt->shadow_green);
config_lookup_float(&cfg, "shadow-blue", &opt->shadow_blue); // --shadow-blue
// --shadow-exclude-reg config_lookup_float(&cfg, "shadow-blue", &opt->shadow_blue);
if (config_lookup_string(&cfg, "shadow-exclude-reg", &sval)) // --shadow-exclude-reg
opt->shadow_exclude_reg_str = strdup(sval); if (config_lookup_string(&cfg, "shadow-exclude-reg", &sval))
// --inactive-opacity-override opt->shadow_exclude_reg_str = strdup(sval);
lcfg_lookup_bool(&cfg, "inactive-opacity-override", // --inactive-opacity-override
&opt->inactive_opacity_override); lcfg_lookup_bool(&cfg, "inactive-opacity-override", &opt->inactive_opacity_override);
// --inactive-dim // --inactive-dim
config_lookup_float(&cfg, "inactive-dim", &opt->inactive_dim); config_lookup_float(&cfg, "inactive-dim", &opt->inactive_dim);
// --mark-wmwin-focused // --mark-wmwin-focused
lcfg_lookup_bool(&cfg, "mark-wmwin-focused", &opt->mark_wmwin_focused); lcfg_lookup_bool(&cfg, "mark-wmwin-focused", &opt->mark_wmwin_focused);
// --mark-ovredir-focused // --mark-ovredir-focused
lcfg_lookup_bool(&cfg, "mark-ovredir-focused", lcfg_lookup_bool(&cfg, "mark-ovredir-focused", &opt->mark_ovredir_focused);
&opt->mark_ovredir_focused); // --shadow-ignore-shaped
// --shadow-ignore-shaped lcfg_lookup_bool(&cfg, "shadow-ignore-shaped", &opt->shadow_ignore_shaped);
lcfg_lookup_bool(&cfg, "shadow-ignore-shaped", // --detect-rounded-corners
&opt->shadow_ignore_shaped); lcfg_lookup_bool(&cfg, "detect-rounded-corners", &opt->detect_rounded_corners);
// --detect-rounded-corners // --xinerama-shadow-crop
lcfg_lookup_bool(&cfg, "detect-rounded-corners", lcfg_lookup_bool(&cfg, "xinerama-shadow-crop", &opt->xinerama_shadow_crop);
&opt->detect_rounded_corners); // --detect-client-opacity
// --xinerama-shadow-crop lcfg_lookup_bool(&cfg, "detect-client-opacity", &opt->detect_client_opacity);
lcfg_lookup_bool(&cfg, "xinerama-shadow-crop", // --refresh-rate
&opt->xinerama_shadow_crop); config_lookup_int(&cfg, "refresh-rate", &opt->refresh_rate);
// --detect-client-opacity // --vsync
lcfg_lookup_bool(&cfg, "detect-client-opacity", if (config_lookup_string(&cfg, "vsync", &sval)) {
&opt->detect_client_opacity); opt->vsync = parse_vsync(sval);
// --refresh-rate if (opt->vsync >= NUM_VSYNC) {
config_lookup_int(&cfg, "refresh-rate", &opt->refresh_rate); log_fatal("Cannot parse vsync");
// --vsync goto err;
if (config_lookup_string(&cfg, "vsync", &sval)) { }
opt->vsync = parse_vsync(sval); }
if (opt->vsync >= NUM_VSYNC) { // --backend
log_fatal("Cannot parse vsync"); if (config_lookup_string(&cfg, "backend", &sval)) {
goto err; opt->backend = parse_backend(sval);
} if (opt->backend >= NUM_BKEND) {
} log_fatal("Cannot parse backend");
// --backend goto err;
if (config_lookup_string(&cfg, "backend", &sval)) { }
opt->backend = parse_backend(sval); }
if (opt->backend >= NUM_BKEND) { // --log-level
log_fatal("Cannot parse backend"); if (config_lookup_string(&cfg, "log-level", &sval)) {
goto err; auto level = string_to_log_level(sval);
} if (level == LOG_LEVEL_INVALID) {
} log_warn("Invalid log level, defaults to WARN");
// --log-level } else {
if (config_lookup_string(&cfg, "log-level", &sval)) { log_set_level_tls(level);
auto level = string_to_log_level(sval); }
if (level == LOG_LEVEL_INVALID) { }
log_warn("Invalid log level, defaults to WARN"); // --log-file
} else { if (config_lookup_string(&cfg, "log-file", &sval)) {
log_set_level_tls(level); if (*sval != '/') {
} log_warn("The log-file in your configuration file is not an "
} "absolute path");
// --log-file }
if (config_lookup_string(&cfg, "log-file", &sval)) { opt->logpath = strdup(sval);
if (*sval != '/') { }
log_warn("The log-file in your configuration file is not an absolute path"); // --sw-opti
} lcfg_lookup_bool(&cfg, "sw-opti", &opt->sw_opti);
opt->logpath = strdup(sval); // --use-ewmh-active-win
} lcfg_lookup_bool(&cfg, "use-ewmh-active-win", &opt->use_ewmh_active_win);
// --sw-opti // --unredir-if-possible
lcfg_lookup_bool(&cfg, "sw-opti", &opt->sw_opti); lcfg_lookup_bool(&cfg, "unredir-if-possible", &opt->unredir_if_possible);
// --use-ewmh-active-win // --unredir-if-possible-delay
lcfg_lookup_bool(&cfg, "use-ewmh-active-win", if (config_lookup_int(&cfg, "unredir-if-possible-delay", &ival))
&opt->use_ewmh_active_win); opt->unredir_if_possible_delay = ival;
// --unredir-if-possible // --inactive-dim-fixed
lcfg_lookup_bool(&cfg, "unredir-if-possible", lcfg_lookup_bool(&cfg, "inactive-dim-fixed", &opt->inactive_dim_fixed);
&opt->unredir_if_possible); // --detect-transient
// --unredir-if-possible-delay lcfg_lookup_bool(&cfg, "detect-transient", &opt->detect_transient);
if (config_lookup_int(&cfg, "unredir-if-possible-delay", &ival)) // --detect-client-leader
opt->unredir_if_possible_delay = ival; lcfg_lookup_bool(&cfg, "detect-client-leader", &opt->detect_client_leader);
// --inactive-dim-fixed // --shadow-exclude
lcfg_lookup_bool(&cfg, "inactive-dim-fixed", &opt->inactive_dim_fixed); parse_cfg_condlst(&cfg, &opt->shadow_blacklist, "shadow-exclude");
// --detect-transient // --fade-exclude
lcfg_lookup_bool(&cfg, "detect-transient", &opt->detect_transient); parse_cfg_condlst(&cfg, &opt->fade_blacklist, "fade-exclude");
// --detect-client-leader // --focus-exclude
lcfg_lookup_bool(&cfg, "detect-client-leader", parse_cfg_condlst(&cfg, &opt->focus_blacklist, "focus-exclude");
&opt->detect_client_leader); // --invert-color-include
// --shadow-exclude parse_cfg_condlst(&cfg, &opt->invert_color_list, "invert-color-include");
parse_cfg_condlst(&cfg, &opt->shadow_blacklist, "shadow-exclude"); // --blur-background-exclude
// --fade-exclude parse_cfg_condlst(&cfg, &opt->blur_background_blacklist, "blur-background-exclude");
parse_cfg_condlst(&cfg, &opt->fade_blacklist, "fade-exclude"); // --opacity-rule
// --focus-exclude parse_cfg_condlst_opct(opt, &cfg, "opacity-rule");
parse_cfg_condlst(&cfg, &opt->focus_blacklist, "focus-exclude"); // --unredir-if-possible-exclude
// --invert-color-include parse_cfg_condlst(&cfg, &opt->unredir_if_possible_blacklist,
parse_cfg_condlst(&cfg, &opt->invert_color_list, "invert-color-include"); "unredir-if-possible-exclude");
// --blur-background-exclude // --blur-background
parse_cfg_condlst(&cfg, &opt->blur_background_blacklist, "blur-background-exclude"); lcfg_lookup_bool(&cfg, "blur-background", &opt->blur_background);
// --opacity-rule // --blur-background-frame
parse_cfg_condlst_opct(opt, &cfg, "opacity-rule"); lcfg_lookup_bool(&cfg, "blur-background-frame", &opt->blur_background_frame);
// --unredir-if-possible-exclude // --blur-background-fixed
parse_cfg_condlst(&cfg, &opt->unredir_if_possible_blacklist, "unredir-if-possible-exclude"); lcfg_lookup_bool(&cfg, "blur-background-fixed", &opt->blur_background_fixed);
// --blur-background // --blur-kern
lcfg_lookup_bool(&cfg, "blur-background", &opt->blur_background); if (config_lookup_string(&cfg, "blur-kern", &sval) &&
// --blur-background-frame !parse_blur_kern_lst(sval, opt->blur_kerns, MAX_BLUR_PASS, conv_kern_hasneg)) {
lcfg_lookup_bool(&cfg, "blur-background-frame", log_fatal("Cannot parse \"blur-kern\"");
&opt->blur_background_frame); goto err;
// --blur-background-fixed }
lcfg_lookup_bool(&cfg, "blur-background-fixed", // --resize-damage
&opt->blur_background_fixed); config_lookup_int(&cfg, "resize-damage", &opt->resize_damage);
// --blur-kern // --glx-no-stencil
if (config_lookup_string(&cfg, "blur-kern", &sval) && lcfg_lookup_bool(&cfg, "glx-no-stencil", &opt->glx_no_stencil);
!parse_blur_kern_lst(sval, opt->blur_kerns, MAX_BLUR_PASS, conv_kern_hasneg)) { // --glx-no-rebind-pixmap
log_fatal("Cannot parse \"blur-kern\""); lcfg_lookup_bool(&cfg, "glx-no-rebind-pixmap", &opt->glx_no_rebind_pixmap);
goto err; // --glx-swap-method
} if (config_lookup_string(&cfg, "glx-swap-method", &sval)) {
// --resize-damage opt->glx_swap_method = parse_glx_swap_method(sval);
config_lookup_int(&cfg, "resize-damage", &opt->resize_damage); if (opt->glx_swap_method == -2) {
// --glx-no-stencil log_fatal("Cannot parse \"glx-swap-method\"");
lcfg_lookup_bool(&cfg, "glx-no-stencil", &opt->glx_no_stencil); goto err;
// --glx-no-rebind-pixmap }
lcfg_lookup_bool(&cfg, "glx-no-rebind-pixmap", &opt->glx_no_rebind_pixmap); }
// --glx-swap-method // --glx-use-gpushader4
if (config_lookup_string(&cfg, "glx-swap-method", &sval)) { if (config_lookup_bool(&cfg, "glx-use-gpushader4", &ival) && ival) {
opt->glx_swap_method = parse_glx_swap_method(sval); log_warn("glx-use-gpushader4 is deprecated since v6, please remove it "
if (opt->glx_swap_method == -2) { "from"
log_fatal("Cannot parse \"glx-swap-method\""); "your config file");
goto err; }
} // --xrender-sync
} if (config_lookup_bool(&cfg, "xrender-sync", &ival) && ival) {
// --glx-use-gpushader4 log_warn("Please use xrender-sync-fence instead of xrender-sync.");
if (config_lookup_bool(&cfg, "glx-use-gpushader4", &ival) && ival) { opt->xrender_sync_fence = true;
log_warn("glx-use-gpushader4 is deprecated since v6, please remove it from" }
"your config file"); // --xrender-sync-fence
} lcfg_lookup_bool(&cfg, "xrender-sync-fence", &opt->xrender_sync_fence);
// --xrender-sync
if (config_lookup_bool(&cfg, "xrender-sync", &ival) && ival) {
log_warn("Please use xrender-sync-fence instead of xrender-sync.");
opt->xrender_sync_fence = true;
}
// --xrender-sync-fence
lcfg_lookup_bool(&cfg, "xrender-sync-fence", &opt->xrender_sync_fence);
if (lcfg_lookup_bool(&cfg, "clear-shadow", &bval)) if (lcfg_lookup_bool(&cfg, "clear-shadow", &bval))
log_warn("\"clear-shadow\" is removed as an option, and is always" log_warn("\"clear-shadow\" is removed as an option, and is always"
" enabled now. Consider removing it from your config file"); " enabled now. Consider removing it from your config file");
if (lcfg_lookup_bool(&cfg, "paint-on-overlay", &bval)) if (lcfg_lookup_bool(&cfg, "paint-on-overlay", &bval))
log_warn("\"paint-on-overlay\" has been removed as an option, and " log_warn("\"paint-on-overlay\" has been removed as an option, and "
"is enabled whenever possible"); "is enabled whenever possible");
if (config_lookup_float(&cfg, "alpha-step", &dval)) if (config_lookup_float(&cfg, "alpha-step", &dval))
log_warn("\"alpha-step\" has been removed, compton now tries to make use" log_warn("\"alpha-step\" has been removed, compton now tries to make use"
" of all alpha values"); " of all alpha values");
const char *deprecation_message = "has been removed. If you encounter problems " const char *deprecation_message =
"without this feature, please feel free to open a bug report"; "has been removed. If you encounter problems "
if (lcfg_lookup_bool(&cfg, "glx-use-copysubbuffermesa", &bval) && bval) "without this feature, please feel free to open a bug report";
log_warn("\"glx-use-copysubbuffermesa\" %s", deprecation_message); if (lcfg_lookup_bool(&cfg, "glx-use-copysubbuffermesa", &bval) && bval)
if (lcfg_lookup_bool(&cfg, "glx-copy-from-front", &bval) && bval) log_warn("\"glx-use-copysubbuffermesa\" %s", deprecation_message);
log_warn("\"glx-copy-from-front\" %s", deprecation_message); if (lcfg_lookup_bool(&cfg, "glx-copy-from-front", &bval) && bval)
log_warn("\"glx-copy-from-front\" %s", deprecation_message);
// Wintype settings // Wintype settings
// XXX ! Refactor all the wintype_* arrays into a struct // XXX ! Refactor all the wintype_* arrays into a struct
for (wintype_t i = 0; i < NUM_WINTYPES; ++i) { for (wintype_t i = 0; i < NUM_WINTYPES; ++i) {
char *str = mstrjoin("wintypes.", WINTYPES[i]); char *str = mstrjoin("wintypes.", WINTYPES[i]);
config_setting_t *setting = config_lookup(&cfg, str); config_setting_t *setting = config_lookup(&cfg, str);
free(str); free(str);
win_option_t *o = &opt->wintype_option[i]; win_option_t *o = &opt->wintype_option[i];
win_option_mask_t *mask = &winopt_mask[i]; win_option_mask_t *mask = &winopt_mask[i];
if (setting) { if (setting) {
if (config_setting_lookup_bool(setting, "shadow", &ival)) { if (config_setting_lookup_bool(setting, "shadow", &ival)) {
o->shadow = ival; o->shadow = ival;
mask->shadow = true; mask->shadow = true;
} }
if (config_setting_lookup_bool(setting, "fade", &ival)) { if (config_setting_lookup_bool(setting, "fade", &ival)) {
o->fade = ival; o->fade = ival;
mask->fade = true; mask->fade = true;
} }
if (config_setting_lookup_bool(setting, "focus", &ival)) { if (config_setting_lookup_bool(setting, "focus", &ival)) {
o->focus = ival; o->focus = ival;
mask->focus = true; mask->focus = true;
} }
if (config_setting_lookup_bool(setting, "full-shadow", &ival)) { if (config_setting_lookup_bool(setting, "full-shadow", &ival)) {
o->full_shadow = ival; o->full_shadow = ival;
mask->full_shadow = true; mask->full_shadow = true;
} }
if (config_setting_lookup_bool(setting, "redir-ignore", &ival)) { if (config_setting_lookup_bool(setting, "redir-ignore", &ival)) {
o->redir_ignore = ival; o->redir_ignore = ival;
mask->redir_ignore = true; mask->redir_ignore = true;
} }
double fval; double fval;
if (config_setting_lookup_float(setting, "opacity", &fval)) { if (config_setting_lookup_float(setting, "opacity", &fval)) {
o->opacity = normalize_d(fval); o->opacity = normalize_d(fval);
mask->opacity = true; mask->opacity = true;
} }
} }
} }
config_destroy(&cfg); config_destroy(&cfg);
return path; return path;
err: err:
config_destroy(&cfg); config_destroy(&cfg);
free(path); free(path);
return ERR_PTR(-1); return ERR_PTR(-1);
} }

1869
src/dbus.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -12,193 +12,160 @@
#pragma once #pragma once
#include "common.h" #include "common.h"
#include "compiler.h"
#include "log.h"
#include "region.h" #include "region.h"
#include "render.h" #include "render.h"
#include "compiler.h"
#include "win.h" #include "win.h"
#include "log.h"
#include <xcb/xcb.h> #include <GL/gl.h>
#include <xcb/render.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> #include <ctype.h>
#include <locale.h> #include <locale.h>
#include <GL/gl.h> #include <stdlib.h>
#include <string.h>
#include <xcb/render.h>
#include <xcb/xcb.h>
bool bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor, const region_t *reg_tgt);
GLfloat factor, const region_t *reg_tgt);
bool bool glx_render(session_t *ps, const glx_texture_t *ptex, int x, int y, int dx, int dy,
glx_render(session_t *ps, const glx_texture_t *ptex, int width, int height, int z, double opacity, bool argb, bool neg,
int x, int y, int dx, int dy, int width, int height, int z, const region_t *reg_tgt, const glx_prog_main_t *pprogram);
double opacity, bool argb, bool neg,
const region_t *reg_tgt,
const glx_prog_main_t *pprogram);
bool bool glx_init(session_t *ps, bool need_render);
glx_init(session_t *ps, bool need_render);
void void glx_destroy(session_t *ps);
glx_destroy(session_t *ps);
void void glx_on_root_change(session_t *ps);
glx_on_root_change(session_t *ps);
bool bool glx_init_blur(session_t *ps);
glx_init_blur(session_t *ps);
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
bool bool glx_load_prog_main(session_t *ps, const char *vshader_str, const char *fshader_str,
glx_load_prog_main(session_t *ps, glx_prog_main_t *pprogram);
const char *vshader_str, const char *fshader_str,
glx_prog_main_t *pprogram);
#endif #endif
bool bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, unsigned width,
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, unsigned height, bool repeat, const struct glx_fbconfig_info *);
unsigned width, unsigned height, bool repeat, const struct glx_fbconfig_info *);
void void glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
void glx_paint_pre(session_t *ps, region_t *preg) void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2);
attr_nonnull(1, 2);
/** /**
* Check if a texture is binded, or is binded to the given pixmap. * Check if a texture is binded, or is binded to the given pixmap.
*/ */
static inline bool static inline bool glx_tex_binded(const glx_texture_t *ptex, xcb_pixmap_t pixmap) {
glx_tex_binded(const glx_texture_t *ptex, xcb_pixmap_t pixmap) { return ptex && ptex->glpixmap && ptex->texture && (!pixmap || pixmap == ptex->pixmap);
return ptex && ptex->glpixmap && ptex->texture
&& (!pixmap || pixmap == ptex->pixmap);
} }
void void glx_set_clip(session_t *ps, const region_t *reg);
glx_set_clip(session_t *ps, const region_t *reg);
bool bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z, GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc);
GLfloat factor_center,
const region_t *reg_tgt,
glx_blur_cache_t *pbc);
GLuint GLuint glx_create_shader(GLenum shader_type, const char *shader_str);
glx_create_shader(GLenum shader_type, const char *shader_str);
GLuint GLuint glx_create_program(const GLuint *const shaders, int nshaders);
glx_create_program(const GLuint * const shaders, int nshaders);
GLuint GLuint glx_create_program_from_str(const char *vert_shader_str, const char *frag_shader_str);
glx_create_program_from_str(const char *vert_shader_str,
const char *frag_shader_str);
unsigned char * unsigned char *glx_take_screenshot(session_t *ps, int *out_length);
glx_take_screenshot(session_t *ps, int *out_length);
/** /**
* Check if there's a GLX context. * Check if there's a GLX context.
*/ */
static inline bool static inline bool glx_has_context(session_t *ps) {
glx_has_context(session_t *ps) { return ps->psglx && ps->psglx->context;
return ps->psglx && ps->psglx->context;
} }
/** /**
* Ensure we have a GLX context. * Ensure we have a GLX context.
*/ */
static inline bool static inline bool ensure_glx_context(session_t *ps) {
ensure_glx_context(session_t *ps) { // Create GLX context
// Create GLX context if (!glx_has_context(ps))
if (!glx_has_context(ps)) glx_init(ps, false);
glx_init(ps, false);
return ps->psglx->context; return ps->psglx->context;
} }
/** /**
* Free a GLX texture. * Free a GLX texture.
*/ */
static inline void static inline void free_texture_r(session_t *ps, GLuint *ptexture) {
free_texture_r(session_t *ps, GLuint *ptexture) { if (*ptexture) {
if (*ptexture) { assert(glx_has_context(ps));
assert(glx_has_context(ps)); glDeleteTextures(1, ptexture);
glDeleteTextures(1, ptexture); *ptexture = 0;
*ptexture = 0; }
}
} }
/** /**
* Free a GLX Framebuffer object. * Free a GLX Framebuffer object.
*/ */
static inline void static inline void free_glx_fbo(session_t *ps, GLuint *pfbo) {
free_glx_fbo(session_t *ps, GLuint *pfbo) { if (*pfbo) {
if (*pfbo) { glDeleteFramebuffers(1, pfbo);
glDeleteFramebuffers(1, pfbo); *pfbo = 0;
*pfbo = 0; }
} assert(!*pfbo);
assert(!*pfbo);
} }
/** /**
* Free data in glx_blur_cache_t on resize. * Free data in glx_blur_cache_t on resize.
*/ */
static inline void static inline void free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) {
free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) { free_texture_r(ps, &pbc->textures[0]);
free_texture_r(ps, &pbc->textures[0]); free_texture_r(ps, &pbc->textures[1]);
free_texture_r(ps, &pbc->textures[1]); pbc->width = 0;
pbc->width = 0; pbc->height = 0;
pbc->height = 0;
} }
/** /**
* Free a glx_blur_cache_t * Free a glx_blur_cache_t
*/ */
static inline void static inline void free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) { free_glx_fbo(ps, &pbc->fbo);
free_glx_fbo(ps, &pbc->fbo); free_glx_bc_resize(ps, pbc);
free_glx_bc_resize(ps, pbc);
} }
/** /**
* Free a glx_texture_t. * Free a glx_texture_t.
*/ */
static inline void static inline void free_texture(session_t *ps, glx_texture_t **pptex) {
free_texture(session_t *ps, glx_texture_t **pptex) { glx_texture_t *ptex = *pptex;
glx_texture_t *ptex = *pptex;
// Quit if there's nothing // Quit if there's nothing
if (!ptex) if (!ptex)
return; return;
glx_release_pixmap(ps, ptex); glx_release_pixmap(ps, ptex);
free_texture_r(ps, &ptex->texture); free_texture_r(ps, &ptex->texture);
// Free structure itself // Free structure itself
free(ptex); free(ptex);
*pptex = NULL; *pptex = NULL;
assert(!*pptex); assert(!*pptex);
} }
/** /**
* Free GLX part of paint_t. * Free GLX part of paint_t.
*/ */
static inline void static inline void free_paint_glx(session_t *ps, paint_t *ppaint) {
free_paint_glx(session_t *ps, paint_t *ppaint) { free_texture(ps, &ppaint->ptex);
free_texture(ps, &ppaint->ptex);
} }
/** /**
* Free GLX part of win. * Free GLX part of win.
*/ */
static inline void static inline void free_win_res_glx(session_t *ps, win *w) {
free_win_res_glx(session_t *ps, win *w) { free_paint_glx(ps, &w->paint);
free_paint_glx(ps, &w->paint); free_paint_glx(ps, &w->shadow_paint);
free_paint_glx(ps, &w->shadow_paint);
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
free_glx_bc(ps, &w->glx_blur_cache); free_glx_bc(ps, &w->glx_blur_cache);
free(w->paint.fbcfg); free(w->paint.fbcfg);
#endif #endif
} }

View File

@ -55,31 +55,31 @@ void mstrextend(char **psrc1, const char *src2) {
/// Parse a floating point number of form (+|-)?[0-9]*(\.[0-9]*) /// Parse a floating point number of form (+|-)?[0-9]*(\.[0-9]*)
double strtod_simple(const char *src, const char **end) { double strtod_simple(const char *src, const char **end) {
double neg = 1; double neg = 1;
if (*src == '-') { if (*src == '-') {
neg = -1; neg = -1;
src++; src++;
} else if (*src == '+') { } else if (*src == '+') {
src++; src++;
} }
double ret = 0; double ret = 0;
while (*src >= '0' && *src <= '9') { while (*src >= '0' && *src <= '9') {
ret = ret * 10 + (*src - '0'); ret = ret * 10 + (*src - '0');
src++; src++;
} }
if (*src == '.') { if (*src == '.') {
double frac = 0, mult = 0.1; double frac = 0, mult = 0.1;
src++; src++;
while (*src >= '0' && *src <= '9') { while (*src >= '0' && *src <= '9') {
frac += mult * (*src - '0'); frac += mult * (*src - '0');
mult *= 0.1; mult *= 0.1;
src++; src++;
} }
ret += frac; ret += frac;
} }
*end = src; *end = src;
return ret * neg; return ret * neg;
} }

View File

@ -7,51 +7,46 @@
#define mstrncmp(s1, s2) strncmp((s1), (s2), strlen(s1)) #define mstrncmp(s1, s2) strncmp((s1), (s2), strlen(s1))
char *mstrjoin(const char *src1, const char *src2); char *mstrjoin(const char *src1, const char *src2);
char * char *mstrjoin3(const char *src1, const char *src2, const char *src3);
mstrjoin3(const char *src1, const char *src2, const char *src3);
void mstrextend(char **psrc1, const char *src2); void mstrextend(char **psrc1, const char *src2);
/// Parse a floating point number of form (+|-)?[0-9]*(\.[0-9]*) /// Parse a floating point number of form (+|-)?[0-9]*(\.[0-9]*)
double strtod_simple(const char *, const char **); double strtod_simple(const char *, const char **);
static inline int uitostr(unsigned int n, char *buf) { static inline int uitostr(unsigned int n, char *buf) {
int ret = 0; int ret = 0;
unsigned int tmp = n; unsigned int tmp = n;
while (tmp > 0) { while (tmp > 0) {
tmp /= 10; tmp /= 10;
ret++; ret++;
} }
if (ret == 0) if (ret == 0)
ret = 1; ret = 1;
int pos = ret; int pos = ret;
while (pos--) { while (pos--) {
buf[pos] = n%10 + '0'; buf[pos] = n % 10 + '0';
n /= 10; n /= 10;
} }
return ret; return ret;
} }
static inline const char * static inline const char *skip_space_const(const char *src) {
skip_space_const(const char *src) { if (!src)
if (!src) return NULL;
return NULL; while (*src && isspace(*src))
while (*src && isspace(*src)) src++;
src++; return src;
return src;
} }
static inline char * static inline char *skip_space_mut(char *src) {
skip_space_mut(char *src) { if (!src)
if (!src) return NULL;
return NULL; while (*src && isspace(*src))
while (*src && isspace(*src)) src++;
src++; return src;
return src;
} }
#define skip_space(x) _Generic((x), \ #define skip_space(x) \
char *: skip_space_mut, \ _Generic((x), char * : skip_space_mut, const char * : skip_space_const)(x)
const char *: skip_space_const \
)(x)

View File

@ -9,27 +9,28 @@
/// Enumeration type to represent switches. /// Enumeration type to represent switches.
typedef enum { typedef enum {
OFF = 0, // false OFF = 0, // false
ON, // true ON, // true
UNSET UNSET
} switch_t; } switch_t;
/// Structure representing a X geometry. /// Structure representing a X geometry.
typedef struct { typedef struct {
int wid; int wid;
int hei; int hei;
int x; int x;
int y; int y;
} geometry_t; } geometry_t;
/// A structure representing margins around a rectangle. /// A structure representing margins around a rectangle.
typedef struct { typedef struct {
unsigned int top; unsigned int top;
unsigned int left; unsigned int left;
unsigned int bottom; unsigned int bottom;
unsigned int right; unsigned int right;
} margin_t; } margin_t;
typedef uint32_t opacity_t; typedef uint32_t opacity_t;
#define MARGIN_INIT { 0, 0, 0, 0 } #define MARGIN_INIT \
{ 0, 0, 0, 0 }

View File

@ -12,12 +12,12 @@
#endif #endif
#ifdef CONFIG_VSYNC_DRM #ifdef CONFIG_VSYNC_DRM
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <drm.h> #include <drm.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif #endif
#include "config.h" #include "config.h"
@ -27,26 +27,24 @@
/** /**
* Wait for next VSync, DRM method. * Wait for next VSync, DRM method.
* *
* Stolen from: https://github.com/MythTV/mythtv/blob/master/mythtv/libs/libmythtv/vsync.cpp * Stolen from:
* https://github.com/MythTV/mythtv/blob/master/mythtv/libs/libmythtv/vsync.cpp
*/ */
static int static int vsync_drm_wait(session_t *ps) {
vsync_drm_wait(session_t *ps) { int ret = -1;
int ret = -1; drm_wait_vblank_t vbl;
drm_wait_vblank_t vbl;
vbl.request.type = _DRM_VBLANK_RELATIVE, vbl.request.type = _DRM_VBLANK_RELATIVE, vbl.request.sequence = 1;
vbl.request.sequence = 1;
do { do {
ret = ioctl(ps->drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl); ret = ioctl(ps->drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl);
vbl.request.type &= ~_DRM_VBLANK_RELATIVE; vbl.request.type &= ~_DRM_VBLANK_RELATIVE;
} while (ret && errno == EINTR); } while (ret && errno == EINTR);
if (ret) if (ret)
log_error("VBlank ioctl did not work, unimplemented in this drmver?"); log_error("VBlank ioctl did not work, unimplemented in this drmver?");
return ret;
return ret;
} }
#endif #endif
@ -55,126 +53,120 @@ vsync_drm_wait(session_t *ps) {
* *
* @return true for success, false otherwise * @return true for success, false otherwise
*/ */
static bool static bool vsync_drm_init(session_t *ps) {
vsync_drm_init(session_t *ps) {
#ifdef CONFIG_VSYNC_DRM #ifdef CONFIG_VSYNC_DRM
// Should we always open card0? // Should we always open card0?
if (ps->drm_fd < 0 && (ps->drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) { if (ps->drm_fd < 0 && (ps->drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) {
log_error("Failed to open device."); log_error("Failed to open device.");
return false; return false;
} }
if (vsync_drm_wait(ps)) if (vsync_drm_wait(ps))
return false; return false;
return true; return true;
#else #else
log_error("compton is not compiled with DRM VSync support."); log_error("compton is not compiled with DRM VSync support.");
return false; return false;
#endif #endif
} }
/** /**
* Initialize OpenGL VSync. * Initialize OpenGL VSync.
* *
* Stolen from: http://git.tuxfamily.org/?p=ccm/cairocompmgr.git;a=commitdiff;h=efa4ceb97da501e8630ca7f12c99b1dce853c73e * Stolen from:
* http://git.tuxfamily.org/?p=ccm/cairocompmgr.git;a=commitdiff;h=efa4ceb97da501e8630ca7f12c99b1dce853c73e
* Possible original source: http://www.inb.uni-luebeck.de/~boehme/xvideo_sync.html * Possible original source: http://www.inb.uni-luebeck.de/~boehme/xvideo_sync.html
* *
* @return true for success, false otherwise * @return true for success, false otherwise
*/ */
static bool static bool vsync_opengl_init(session_t *ps) {
vsync_opengl_init(session_t *ps) {
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (!ensure_glx_context(ps)) if (!ensure_glx_context(ps))
return false; return false;
return glxext.has_GLX_SGI_video_sync; return glxext.has_GLX_SGI_video_sync;
#else #else
log_error("compton is not compiled with OpenGL VSync support."); log_error("compton is not compiled with OpenGL VSync support.");
return false; return false;
#endif #endif
} }
static bool static bool vsync_opengl_oml_init(session_t *ps) {
vsync_opengl_oml_init(session_t *ps) {
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (!ensure_glx_context(ps)) if (!ensure_glx_context(ps))
return false; return false;
return glxext.has_GLX_OML_sync_control; return glxext.has_GLX_OML_sync_control;
#else #else
log_error("compton is not compiled with OpenGL VSync support."); log_error("compton is not compiled with OpenGL VSync support.");
return false; return false;
#endif #endif
} }
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
static inline bool static inline bool vsync_opengl_swc_swap_interval(session_t *ps, unsigned int interval) {
vsync_opengl_swc_swap_interval(session_t *ps, unsigned int interval) { if (glxext.has_GLX_MESA_swap_control)
if (glxext.has_GLX_MESA_swap_control) return glXSwapIntervalMESA(interval) == 0;
return glXSwapIntervalMESA(interval) == 0; else if (glxext.has_GLX_SGI_swap_control)
else if (glxext.has_GLX_SGI_swap_control) return glXSwapIntervalSGI(interval) == 0;
return glXSwapIntervalSGI(interval) == 0; else if (glxext.has_GLX_EXT_swap_control) {
else if (glxext.has_GLX_EXT_swap_control) { GLXDrawable d = glXGetCurrentDrawable();
GLXDrawable d = glXGetCurrentDrawable(); if (d == None) {
if (d == None) { // We don't have a context??
// We don't have a context?? return false;
return false; }
} glXSwapIntervalEXT(ps->dpy, glXGetCurrentDrawable(), interval);
glXSwapIntervalEXT(ps->dpy, glXGetCurrentDrawable(), interval); return true;
return true; }
} return false;
return false;
} }
#endif #endif
static bool static bool vsync_opengl_swc_init(session_t *ps) {
vsync_opengl_swc_init(session_t *ps) {
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (!bkend_use_glx(ps)) { if (!bkend_use_glx(ps)) {
log_warn("OpenGL swap control requires the GLX backend."); log_warn("OpenGL swap control requires the GLX backend.");
return false; return false;
} }
if (!vsync_opengl_swc_swap_interval(ps, 1)) { if (!vsync_opengl_swc_swap_interval(ps, 1)) {
log_error("Failed to load a swap control extension."); log_error("Failed to load a swap control extension.");
return false; return false;
} }
return true; return true;
#else #else
log_error("compton is not compiled with OpenGL VSync support."); log_error("compton is not compiled with OpenGL VSync support.");
return false; return false;
#endif #endif
} }
static bool static bool vsync_opengl_mswc_init(session_t *ps) {
vsync_opengl_mswc_init(session_t *ps) { log_warn("opengl-mswc is deprecated, please use opengl-swc instead.");
log_warn("opengl-mswc is deprecated, please use opengl-swc instead."); return vsync_opengl_swc_init(ps);
return vsync_opengl_swc_init(ps);
} }
bool (*const VSYNC_FUNCS_INIT[NUM_VSYNC])(session_t *ps) = { bool (*const VSYNC_FUNCS_INIT[NUM_VSYNC])(session_t *ps) = {
[VSYNC_DRM ] = vsync_drm_init, [VSYNC_DRM] = vsync_drm_init,
[VSYNC_OPENGL ] = vsync_opengl_init, [VSYNC_OPENGL] = vsync_opengl_init,
[VSYNC_OPENGL_OML ] = vsync_opengl_oml_init, [VSYNC_OPENGL_OML] = vsync_opengl_oml_init,
[VSYNC_OPENGL_SWC ] = vsync_opengl_swc_init, [VSYNC_OPENGL_SWC] = vsync_opengl_swc_init,
[VSYNC_OPENGL_MSWC ] = vsync_opengl_mswc_init, [VSYNC_OPENGL_MSWC] = vsync_opengl_mswc_init,
}; };
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
/** /**
* Wait for next VSync, OpenGL method. * Wait for next VSync, OpenGL method.
*/ */
static int static int vsync_opengl_wait(session_t *ps) {
vsync_opengl_wait(session_t *ps) { unsigned vblank_count = 0;
unsigned vblank_count = 0;
glXGetVideoSyncSGI(&vblank_count); glXGetVideoSyncSGI(&vblank_count);
glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count); glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count);
// I see some code calling glXSwapIntervalSGI(1) afterwards, is it required? // I see some code calling glXSwapIntervalSGI(1) afterwards, is it required?
return 0; return 0;
} }
/** /**
@ -182,15 +174,13 @@ vsync_opengl_wait(session_t *ps) {
* *
* https://mail.gnome.org/archives/clutter-list/2012-November/msg00031.html * https://mail.gnome.org/archives/clutter-list/2012-November/msg00031.html
*/ */
static int static int vsync_opengl_oml_wait(session_t *ps) {
vsync_opengl_oml_wait(session_t *ps) { int64_t ust = 0, msc = 0, sbc = 0;
int64_t ust = 0, msc = 0, sbc = 0;
glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc); glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc);
glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc);
&ust, &msc, &sbc);
return 0; return 0;
} }
#endif #endif
@ -198,27 +188,25 @@ vsync_opengl_oml_wait(session_t *ps) {
/// Function pointers to wait for VSync. /// Function pointers to wait for VSync.
int (*const VSYNC_FUNCS_WAIT[NUM_VSYNC])(session_t *ps) = { int (*const VSYNC_FUNCS_WAIT[NUM_VSYNC])(session_t *ps) = {
#ifdef CONFIG_VSYNC_DRM #ifdef CONFIG_VSYNC_DRM
[VSYNC_DRM ] = vsync_drm_wait, [VSYNC_DRM] = vsync_drm_wait,
#endif #endif
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
[VSYNC_OPENGL ] = vsync_opengl_wait, [VSYNC_OPENGL] = vsync_opengl_wait,
[VSYNC_OPENGL_OML ] = vsync_opengl_oml_wait, [VSYNC_OPENGL_OML] = vsync_opengl_oml_wait,
#endif #endif
}; };
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
static void static void vsync_opengl_swc_deinit(session_t *ps) {
vsync_opengl_swc_deinit(session_t *ps) { vsync_opengl_swc_swap_interval(ps, 0);
vsync_opengl_swc_swap_interval(ps, 0);
} }
#endif #endif
/// Function pointers to deinitialize VSync. /// Function pointers to deinitialize VSync.
void (*const VSYNC_FUNCS_DEINIT[NUM_VSYNC])(session_t *ps) = { void (*const VSYNC_FUNCS_DEINIT[NUM_VSYNC])(session_t *ps) = {
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
[VSYNC_OPENGL_SWC ] = vsync_opengl_swc_deinit, [VSYNC_OPENGL_SWC] = vsync_opengl_swc_deinit,
[VSYNC_OPENGL_MSWC ] = vsync_opengl_swc_deinit, [VSYNC_OPENGL_MSWC] = vsync_opengl_swc_deinit,
#endif #endif
}; };
@ -226,36 +214,34 @@ void (*const VSYNC_FUNCS_DEINIT[NUM_VSYNC])(session_t *ps) = {
* Initialize current VSync method. * Initialize current VSync method.
*/ */
bool vsync_init(session_t *ps) { bool vsync_init(session_t *ps) {
// Mesa turns on swap control by default, undo that // Mesa turns on swap control by default, undo that
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (bkend_use_glx(ps)) if (bkend_use_glx(ps))
vsync_opengl_swc_swap_interval(ps, 0); vsync_opengl_swc_swap_interval(ps, 0);
#endif #endif
if (ps->o.vsync && VSYNC_FUNCS_INIT[ps->o.vsync] if (ps->o.vsync && VSYNC_FUNCS_INIT[ps->o.vsync] && !VSYNC_FUNCS_INIT[ps->o.vsync](ps)) {
&& !VSYNC_FUNCS_INIT[ps->o.vsync](ps)) { ps->o.vsync = VSYNC_NONE;
ps->o.vsync = VSYNC_NONE; return false;
return false; } else
} return true;
else
return true;
} }
/** /**
* Wait for next VSync. * Wait for next VSync.
*/ */
void vsync_wait(session_t *ps) { void vsync_wait(session_t *ps) {
if (!ps->o.vsync) if (!ps->o.vsync)
return; return;
if (VSYNC_FUNCS_WAIT[ps->o.vsync]) if (VSYNC_FUNCS_WAIT[ps->o.vsync])
VSYNC_FUNCS_WAIT[ps->o.vsync](ps); VSYNC_FUNCS_WAIT[ps->o.vsync](ps);
} }
/** /**
* Deinitialize current VSync method. * Deinitialize current VSync method.
*/ */
void vsync_deinit(session_t *ps) { void vsync_deinit(session_t *ps) {
if (ps->o.vsync && VSYNC_FUNCS_DEINIT[ps->o.vsync]) if (ps->o.vsync && VSYNC_FUNCS_DEINIT[ps->o.vsync])
VSYNC_FUNCS_DEINIT[ps->o.vsync](ps); VSYNC_FUNCS_DEINIT[ps->o.vsync](ps);
} }

2350
src/win.c

File diff suppressed because it is too large Load Diff

429
src/win.h
View File

@ -3,22 +3,22 @@
// Copyright (c) 2013 Richard Grenville <pyxlcy@gmail.com> // Copyright (c) 2013 Richard Grenville <pyxlcy@gmail.com>
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include <xcb/xcb.h>
#include <xcb/render.h>
#include <xcb/damage.h> #include <xcb/damage.h>
#include <xcb/render.h>
#include <xcb/xcb.h>
// FIXME shouldn't need this // FIXME shouldn't need this
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
#include <GL/gl.h> #include <GL/gl.h>
#endif #endif
#include "x.h" #include "c2.h"
#include "compiler.h" #include "compiler.h"
#include "region.h" #include "region.h"
#include "types.h"
#include "c2.h"
#include "render.h" #include "render.h"
#include "types.h"
#include "utils.h" #include "utils.h"
#include "x.h"
typedef struct session session_t; typedef struct session session_t;
typedef struct _glx_texture glx_texture_t; typedef struct _glx_texture glx_texture_t;
@ -27,41 +27,41 @@ typedef struct _glx_texture glx_texture_t;
// FIXME this type should be in opengl.h // FIXME this type should be in opengl.h
// it is very unideal for it to be here // it is very unideal for it to be here
typedef struct { typedef struct {
/// Framebuffer used for blurring. /// Framebuffer used for blurring.
GLuint fbo; GLuint fbo;
/// Textures used for blurring. /// Textures used for blurring.
GLuint textures[2]; GLuint textures[2];
/// Width of the textures. /// Width of the textures.
int width; int width;
/// Height of the textures. /// Height of the textures.
int height; int height;
} glx_blur_cache_t; } glx_blur_cache_t;
#endif #endif
typedef enum { typedef enum {
WINTYPE_UNKNOWN, WINTYPE_UNKNOWN,
WINTYPE_DESKTOP, WINTYPE_DESKTOP,
WINTYPE_DOCK, WINTYPE_DOCK,
WINTYPE_TOOLBAR, WINTYPE_TOOLBAR,
WINTYPE_MENU, WINTYPE_MENU,
WINTYPE_UTILITY, WINTYPE_UTILITY,
WINTYPE_SPLASH, WINTYPE_SPLASH,
WINTYPE_DIALOG, WINTYPE_DIALOG,
WINTYPE_NORMAL, WINTYPE_NORMAL,
WINTYPE_DROPDOWN_MENU, WINTYPE_DROPDOWN_MENU,
WINTYPE_POPUP_MENU, WINTYPE_POPUP_MENU,
WINTYPE_TOOLTIP, WINTYPE_TOOLTIP,
WINTYPE_NOTIFY, WINTYPE_NOTIFY,
WINTYPE_COMBO, WINTYPE_COMBO,
WINTYPE_DND, WINTYPE_DND,
NUM_WINTYPES NUM_WINTYPES
} wintype_t; } wintype_t;
/// Enumeration type of window painting mode. /// Enumeration type of window painting mode.
typedef enum { typedef enum {
WMODE_TRANS, // The window body is (potentially) transparent WMODE_TRANS, // The window body is (potentially) transparent
WMODE_FRAME_TRANS, // The window body is opaque, but the frame is not WMODE_FRAME_TRANS, // The window body is opaque, but the frame is not
WMODE_SOLID, // The window is opaque including the frame WMODE_SOLID, // The window is opaque including the frame
} winmode_t; } winmode_t;
/// Transition table: /// Transition table:
@ -90,18 +90,18 @@ typedef enum {
/// | |unmapped |destroyed | |change | | | | /// | |unmapped |destroyed | |change | | | |
/// +-------------+---------+----------+-------+-------+--------+--------+---------+ /// +-------------+---------+----------+-------+-------+--------+--------+---------+
typedef enum { typedef enum {
// The window is being faded out because it's unmapped. // The window is being faded out because it's unmapped.
WSTATE_UNMAPPING, WSTATE_UNMAPPING,
// The window is being faded out because it's destroyed, // The window is being faded out because it's destroyed,
WSTATE_DESTROYING, WSTATE_DESTROYING,
// The window is being faded in // The window is being faded in
WSTATE_MAPPING, WSTATE_MAPPING,
// Window opacity is not at the target level // Window opacity is not at the target level
WSTATE_FADING, WSTATE_FADING,
// The window is mapped, no fading is in progress. // The window is mapped, no fading is in progress.
WSTATE_MAPPED, WSTATE_MAPPED,
// The window is unmapped, no fading is in progress. // The window is unmapped, no fading is in progress.
WSTATE_UNMAPPED, WSTATE_UNMAPPED,
} winstate_t; } winstate_t;
/** /**
@ -118,167 +118,167 @@ typedef enum {
/// Structure representing a top-level window compton manages. /// Structure representing a top-level window compton manages.
typedef struct win win; typedef struct win win;
struct win { struct win {
/// backend data attached to this window. Only available when /// backend data attached to this window. Only available when
/// `state` is not UNMAPPED /// `state` is not UNMAPPED
void *win_image; void *win_image;
void *shadow_image; void *shadow_image;
/// Pointer to the next lower window in window stack. /// Pointer to the next lower window in window stack.
win *next; win *next;
/// Pointer to the next higher window to paint. /// Pointer to the next higher window to paint.
win *prev_trans; win *prev_trans;
// TODO rethink reg_ignore // TODO rethink reg_ignore
// Core members // Core members
/// ID of the top-level frame window. /// ID of the top-level frame window.
xcb_window_t id; xcb_window_t id;
/// The "mapped state" of this window, doesn't necessary /// The "mapped state" of this window, doesn't necessary
/// match X mapped state, because of fading. /// match X mapped state, because of fading.
winstate_t state; winstate_t state;
/// Window attributes. /// Window attributes.
xcb_get_window_attributes_reply_t a; xcb_get_window_attributes_reply_t a;
xcb_get_geometry_reply_t g; xcb_get_geometry_reply_t g;
/// Xinerama screen this window is on. /// Xinerama screen this window is on.
int xinerama_scr; int xinerama_scr;
/// Window visual pict format; /// Window visual pict format;
const xcb_render_pictforminfo_t *pictfmt; const xcb_render_pictforminfo_t *pictfmt;
/// Window painting mode. /// Window painting mode.
winmode_t mode; winmode_t mode;
/// Whether the window has been damaged at least once. /// Whether the window has been damaged at least once.
bool ever_damaged; bool ever_damaged;
/// Whether the window was damaged after last paint. /// Whether the window was damaged after last paint.
bool pixmap_damaged; bool pixmap_damaged;
/// Damage of the window. /// Damage of the window.
xcb_damage_damage_t damage; xcb_damage_damage_t damage;
/// Paint info of the window. /// Paint info of the window.
paint_t paint; paint_t paint;
/// Bounding shape of the window. In local coordinates. /// Bounding shape of the window. In local coordinates.
/// See above about coordinate systems. /// See above about coordinate systems.
region_t bounding_shape; region_t bounding_shape;
/// Window flags. Definitions above. /// Window flags. Definitions above.
int_fast16_t flags; int_fast16_t flags;
/// Whether there's a pending <code>ConfigureNotify</code> happening /// Whether there's a pending <code>ConfigureNotify</code> happening
/// when the window is unmapped. /// when the window is unmapped.
bool need_configure; bool need_configure;
/// Queued <code>ConfigureNotify</code> when the window is unmapped. /// Queued <code>ConfigureNotify</code> when the window is unmapped.
xcb_configure_notify_event_t queue_configure; xcb_configure_notify_event_t queue_configure;
/// The region of screen that will be obscured when windows above is painted, /// The region of screen that will be obscured when windows above is painted,
/// in global coordinates. /// in global coordinates.
/// We use this to reduce the pixels that needed to be paint when painting /// We use this to reduce the pixels that needed to be paint when painting
/// this window and anything underneath. Depends on window frame /// this window and anything underneath. Depends on window frame
/// opacity state, window geometry, window mapped/unmapped state, /// opacity state, window geometry, window mapped/unmapped state,
/// window mode of the windows above. DOES NOT INCLUDE the body of THIS WINDOW. /// window mode of the windows above. DOES NOT INCLUDE the body of THIS WINDOW.
/// NULL means reg_ignore has not been calculated for this window. /// NULL means reg_ignore has not been calculated for this window.
rc_region_t *reg_ignore; rc_region_t *reg_ignore;
/// Whether the reg_ignore of all windows beneath this window are valid /// Whether the reg_ignore of all windows beneath this window are valid
bool reg_ignore_valid; bool reg_ignore_valid;
/// Cached width/height of the window including border. /// Cached width/height of the window including border.
int widthb, heightb; int widthb, heightb;
/// Whether the window is bounding-shaped. /// Whether the window is bounding-shaped.
bool bounding_shaped; bool bounding_shaped;
/// Whether the window just have rounded corners. /// Whether the window just have rounded corners.
bool rounded_corners; bool rounded_corners;
/// Whether this window is to be painted. /// Whether this window is to be painted.
bool to_paint; bool to_paint;
/// Whether the window is painting excluded. /// Whether the window is painting excluded.
bool paint_excluded; bool paint_excluded;
/// Whether the window is unredirect-if-possible excluded. /// Whether the window is unredirect-if-possible excluded.
bool unredir_if_possible_excluded; bool unredir_if_possible_excluded;
/// Whether this window is in open/close state. /// Whether this window is in open/close state.
bool in_openclose; bool in_openclose;
// Client window related members // Client window related members
/// ID of the top-level client window of the window. /// ID of the top-level client window of the window.
xcb_window_t client_win; xcb_window_t client_win;
/// Type of the window. /// Type of the window.
wintype_t window_type; wintype_t window_type;
/// Whether it looks like a WM window. We consider a window WM window if /// Whether it looks like a WM window. We consider a window WM window if
/// it does not have a decedent with WM_STATE and it is not override- /// it does not have a decedent with WM_STATE and it is not override-
/// redirected itself. /// redirected itself.
bool wmwin; bool wmwin;
/// Leader window ID of the window. /// Leader window ID of the window.
xcb_window_t leader; xcb_window_t leader;
/// Cached topmost window ID of the window. /// Cached topmost window ID of the window.
xcb_window_t cache_leader; xcb_window_t cache_leader;
// Focus-related members // Focus-related members
/// Whether the window is to be considered focused. /// Whether the window is to be considered focused.
bool focused; bool focused;
/// Override value of window focus state. Set by D-Bus method calls. /// Override value of window focus state. Set by D-Bus method calls.
switch_t focused_force; switch_t focused_force;
// Blacklist related members // Blacklist related members
/// Name of the window. /// Name of the window.
char *name; char *name;
/// Window instance class of the window. /// Window instance class of the window.
char *class_instance; char *class_instance;
/// Window general class of the window. /// Window general class of the window.
char *class_general; char *class_general;
/// <code>WM_WINDOW_ROLE</code> value of the window. /// <code>WM_WINDOW_ROLE</code> value of the window.
char *role; char *role;
// Opacity-related members // Opacity-related members
/// Current window opacity. /// Current window opacity.
double opacity; double opacity;
/// Target window opacity. /// Target window opacity.
double opacity_tgt; double opacity_tgt;
/// true if window (or client window, for broken window managers /// true if window (or client window, for broken window managers
/// not transferring client window's _NET_WM_OPACITY value) has opacity prop /// not transferring client window's _NET_WM_OPACITY value) has opacity prop
bool has_opacity_prop; bool has_opacity_prop;
/// Cached value of opacity window attribute. /// Cached value of opacity window attribute.
opacity_t opacity_prop; opacity_t opacity_prop;
/// true if opacity is set by some rules /// true if opacity is set by some rules
bool opacity_is_set; bool opacity_is_set;
/// Last window opacity value we set. /// Last window opacity value we set.
double opacity_set; double opacity_set;
// Fading-related members // Fading-related members
/// Override value of window fade state. Set by D-Bus method calls. /// Override value of window fade state. Set by D-Bus method calls.
switch_t fade_force; switch_t fade_force;
// Frame-opacity-related members // Frame-opacity-related members
/// Current window frame opacity. Affected by window opacity. /// Current window frame opacity. Affected by window opacity.
double frame_opacity; double frame_opacity;
/// Frame extents. Acquired from _NET_FRAME_EXTENTS. /// Frame extents. Acquired from _NET_FRAME_EXTENTS.
margin_t frame_extents; margin_t frame_extents;
// Shadow-related members // Shadow-related members
/// Whether a window has shadow. Calculated. /// Whether a window has shadow. Calculated.
bool shadow; bool shadow;
/// Override value of window shadow state. Set by D-Bus method calls. /// Override value of window shadow state. Set by D-Bus method calls.
switch_t shadow_force; switch_t shadow_force;
/// Opacity of the shadow. Affected by window opacity and frame opacity. /// Opacity of the shadow. Affected by window opacity and frame opacity.
double shadow_opacity; double shadow_opacity;
/// X offset of shadow. Affected by commandline argument. /// X offset of shadow. Affected by commandline argument.
int shadow_dx; int shadow_dx;
/// Y offset of shadow. Affected by commandline argument. /// Y offset of shadow. Affected by commandline argument.
int shadow_dy; int shadow_dy;
/// Width of shadow. Affected by window size and commandline argument. /// Width of shadow. Affected by window size and commandline argument.
int shadow_width; int shadow_width;
/// Height of shadow. Affected by window size and commandline argument. /// Height of shadow. Affected by window size and commandline argument.
int shadow_height; int shadow_height;
/// Picture to render shadow. Affected by window size. /// Picture to render shadow. Affected by window size.
paint_t shadow_paint; paint_t shadow_paint;
/// The value of _COMPTON_SHADOW attribute of the window. Below 0 for /// The value of _COMPTON_SHADOW attribute of the window. Below 0 for
/// none. /// none.
long prop_shadow; long prop_shadow;
// Dim-related members // Dim-related members
/// Whether the window is to be dimmed. /// Whether the window is to be dimmed.
bool dim; bool dim;
/// Whether to invert window color. /// Whether to invert window color.
bool invert_color; bool invert_color;
/// Override value of window color inversion state. Set by D-Bus method /// Override value of window color inversion state. Set by D-Bus method
/// calls. /// calls.
switch_t invert_color_force; switch_t invert_color_force;
/// Whether to blur window background. /// Whether to blur window background.
bool blur_background; bool blur_background;
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
/// Textures and FBO background blur use. /// Textures and FBO background blur use.
glx_blur_cache_t glx_blur_cache; glx_blur_cache_t glx_blur_cache;
#endif #endif
}; };
@ -363,8 +363,7 @@ region_t win_get_region_frame_local_by_val(const win *w);
/** /**
* Retrieve frame extents from a window. * Retrieve frame extents from a window.
*/ */
void void win_update_frame_extents(session_t *ps, win *w, xcb_window_t client);
win_update_frame_extents(session_t *ps, win *w, xcb_window_t client);
void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev); void add_win(session_t *ps, xcb_window_t id, xcb_window_t prev);
/// Unmap or destroy a window /// Unmap or destroy a window
void unmap_win(session_t *ps, win **, bool destroy); void unmap_win(session_t *ps, win **, bool destroy);
@ -375,8 +374,7 @@ void map_win_by_id(session_t *ps, xcb_window_t id);
/** /**
* Execute fade callback of a window if fading finished. * Execute fade callback of a window if fading finished.
*/ */
void void win_check_fade_finished(session_t *ps, win **_w);
win_check_fade_finished(session_t *ps, win **_w);
// Stop receiving events (except ConfigureNotify, XXX why?) from a window // Stop receiving events (except ConfigureNotify, XXX why?) from a window
void win_ev_stop(session_t *ps, const win *w); void win_ev_stop(session_t *ps, const win *w);
@ -390,9 +388,8 @@ void win_skip_fading(session_t *ps, win **_w);
* *
* This function updates w->cache_leader if necessary. * This function updates w->cache_leader if necessary.
*/ */
static inline xcb_window_t static inline xcb_window_t win_get_leader(session_t *ps, win *w) {
win_get_leader(session_t *ps, win *w) { return win_get_leader_raw(ps, w, 0);
return win_get_leader_raw(ps, w, 0);
} }
/// check if window has ARGB visual /// check if window has ARGB visual
@ -404,35 +401,31 @@ bool attr_pure win_is_region_ignore_valid(session_t *ps, const win *w);
/// Free all resources in a struct win /// Free all resources in a struct win
void free_win_res(session_t *ps, win *w); void free_win_res(session_t *ps, win *w);
static inline region_t static inline region_t win_get_bounding_shape_global_by_val(win *w) {
win_get_bounding_shape_global_by_val(win *w) { region_t ret;
region_t ret; pixman_region32_init(&ret);
pixman_region32_init(&ret); pixman_region32_copy(&ret, &w->bounding_shape);
pixman_region32_copy(&ret, &w->bounding_shape); pixman_region32_translate(&ret, w->g.x, w->g.y);
pixman_region32_translate(&ret, w->g.x, w->g.y); return ret;
return ret;
} }
/** /**
* Calculate the extents of the frame of the given window based on EWMH * Calculate the extents of the frame of the given window based on EWMH
* _NET_FRAME_EXTENTS and the X window border width. * _NET_FRAME_EXTENTS and the X window border width.
*/ */
static inline margin_t attr_pure static inline margin_t attr_pure win_calc_frame_extents(const win *w) {
win_calc_frame_extents(const win *w) { margin_t result = w->frame_extents;
margin_t result = w->frame_extents; result.top = max_i(result.top, w->g.border_width);
result.top = max_i(result.top, w->g.border_width); result.left = max_i(result.left, w->g.border_width);
result.left = max_i(result.left, w->g.border_width); result.bottom = max_i(result.bottom, w->g.border_width);
result.bottom = max_i(result.bottom, w->g.border_width); result.right = max_i(result.right, w->g.border_width);
result.right = max_i(result.right, w->g.border_width); return result;
return result;
} }
/** /**
* Check whether a window has WM frames. * Check whether a window has WM frames.
*/ */
static inline bool attr_pure static inline bool attr_pure win_has_frame(const win *w) {
win_has_frame(const win *w) { return w->g.border_width || w->frame_extents.top || w->frame_extents.left ||
return w->g.border_width w->frame_extents.right || w->frame_extents.bottom;
|| w->frame_extents.top || w->frame_extents.left
|| w->frame_extents.right || w->frame_extents.bottom;
} }

761
src/x.c
View File

@ -4,23 +4,23 @@
#include <stdlib.h> #include <stdlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <xcb/xcb.h> #include <pixman.h>
#include <xcb/xcb_renderutil.h>
#include <xcb/xfixes.h>
#include <xcb/sync.h>
#include <xcb/composite.h> #include <xcb/composite.h>
#include <xcb/damage.h> #include <xcb/damage.h>
#include <xcb/render.h> #include <xcb/render.h>
#include <pixman.h> #include <xcb/sync.h>
#include <xcb/xcb.h>
#include <xcb/xcb_renderutil.h>
#include <xcb/xfixes.h>
#include "utils.h"
#include "region.h"
#include "compiler.h"
#include "common.h"
#include "kernel.h"
#include "x.h"
#include "log.h"
#include "backend/gl/glx.h" #include "backend/gl/glx.h"
#include "common.h"
#include "compiler.h"
#include "kernel.h"
#include "log.h"
#include "region.h"
#include "utils.h"
#include "x.h"
/** /**
* Get a specific attribute of a window. * Get a specific attribute of a window.
@ -37,34 +37,28 @@
* @return a <code>winprop_t</code> structure containing the attribute * @return a <code>winprop_t</code> structure containing the attribute
* and number of items. A blank one on failure. * and number of items. A blank one on failure.
*/ */
winprop_t winprop_t wid_get_prop_adv(const session_t *ps, xcb_window_t w, xcb_atom_t atom,
wid_get_prop_adv(const session_t *ps, xcb_window_t w, xcb_atom_t atom, long offset, long offset, long length, xcb_atom_t rtype, int rformat) {
long length, xcb_atom_t rtype, int rformat) { xcb_get_property_reply_t *r = xcb_get_property_reply(
xcb_get_property_reply_t *r = xcb_get_property_reply(ps->c, ps->c, xcb_get_property(ps->c, 0, w, atom, rtype, offset, length), NULL);
xcb_get_property(ps->c, 0, w, atom, rtype, offset, length), NULL);
if (r && xcb_get_property_value_length(r) && if (r && xcb_get_property_value_length(r) &&
(rtype == XCB_GET_PROPERTY_TYPE_ANY || r->type == rtype) && (rtype == XCB_GET_PROPERTY_TYPE_ANY || r->type == rtype) &&
(!rformat || r->format == rformat) && (!rformat || r->format == rformat) &&
(r->format == 8 || r->format == 16 || r->format == 32)) (r->format == 8 || r->format == 16 || r->format == 32)) {
{ int len = xcb_get_property_value_length(r);
int len = xcb_get_property_value_length(r); return (winprop_t){
return (winprop_t) { .ptr = xcb_get_property_value(r),
.ptr = xcb_get_property_value(r), .nitems = len / (r->format / 8),
.nitems = len/(r->format/8), .type = r->type,
.type = r->type, .format = r->format,
.format = r->format, .r = r,
.r = r, };
}; }
}
free(r); free(r);
return (winprop_t) { return (winprop_t){
.ptr = NULL, .ptr = NULL, .nitems = 0, .type = XCB_GET_PROPERTY_TYPE_ANY, .format = 0};
.nitems = 0,
.type = XCB_GET_PROPERTY_TYPE_ANY,
.format = 0
};
} }
/** /**
@ -72,44 +66,42 @@ wid_get_prop_adv(const session_t *ps, xcb_window_t w, xcb_atom_t atom, long offs
* *
* @return the value if successful, 0 otherwise * @return the value if successful, 0 otherwise
*/ */
xcb_window_t xcb_window_t wid_get_prop_window(session_t *ps, xcb_window_t wid, xcb_atom_t aprop) {
wid_get_prop_window(session_t *ps, xcb_window_t wid, xcb_atom_t aprop) { // Get the attribute
// Get the attribute xcb_window_t p = XCB_NONE;
xcb_window_t p = XCB_NONE; winprop_t prop = wid_get_prop(ps, wid, aprop, 1L, XCB_ATOM_WINDOW, 32);
winprop_t prop = wid_get_prop(ps, wid, aprop, 1L, XCB_ATOM_WINDOW, 32);
// Return it // Return it
if (prop.nitems) { if (prop.nitems) {
p = *prop.p32; p = *prop.p32;
} }
free_winprop(&prop); free_winprop(&prop);
return p; return p;
} }
/** /**
* Get the value of a text property of a window. * Get the value of a text property of a window.
*/ */
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
char ***pstrlst, int *pnstr) { int *pnstr) {
XTextProperty text_prop = { NULL, XCB_NONE, 0, 0 }; XTextProperty text_prop = {NULL, XCB_NONE, 0, 0};
if (!(XGetTextProperty(ps->dpy, wid, &text_prop, prop) && text_prop.value)) if (!(XGetTextProperty(ps->dpy, wid, &text_prop, prop) && text_prop.value))
return false; return false;
if (Success != if (Success != XmbTextPropertyToTextList(ps->dpy, &text_prop, pstrlst, pnstr) ||
XmbTextPropertyToTextList(ps->dpy, &text_prop, pstrlst, pnstr) !*pnstr) {
|| !*pnstr) { *pnstr = 0;
*pnstr = 0; if (*pstrlst)
if (*pstrlst) XFreeStringList(*pstrlst);
XFreeStringList(*pstrlst); cxfree(text_prop.value);
cxfree(text_prop.value); return false;
return false; }
}
cxfree(text_prop.value); cxfree(text_prop.value);
return true; return true;
} }
// A cache of pict formats. We assume they don't change during the lifetime // A cache of pict formats. We assume they don't change during the lifetime
@ -117,128 +109,120 @@ bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop,
static thread_local xcb_render_query_pict_formats_reply_t *g_pictfmts = NULL; 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(xcb_connection_t *c) {
if (g_pictfmts) if (g_pictfmts)
return; return;
xcb_generic_error_t *e = NULL; xcb_generic_error_t *e = NULL;
// Get window picture format // Get window picture format
g_pictfmts = g_pictfmts =
xcb_render_query_pict_formats_reply(c, xcb_render_query_pict_formats_reply(c, xcb_render_query_pict_formats(c), &e);
xcb_render_query_pict_formats(c), &e); if (e || !g_pictfmts) {
if (e || !g_pictfmts) { log_fatal("failed to get pict formats\n");
log_fatal("failed to get pict formats\n"); abort();
abort(); }
}
} }
const xcb_render_pictforminfo_t * const xcb_render_pictforminfo_t *
x_get_pictform_for_visual(xcb_connection_t *c, xcb_visualid_t visual) { x_get_pictform_for_visual(xcb_connection_t *c, xcb_visualid_t visual) {
x_get_server_pictfmts(c); x_get_server_pictfmts(c);
xcb_render_pictvisual_t *pv = xcb_render_util_find_visual_format(g_pictfmts, visual); xcb_render_pictvisual_t *pv = xcb_render_util_find_visual_format(g_pictfmts, visual);
for(xcb_render_pictforminfo_iterator_t i = for (xcb_render_pictforminfo_iterator_t i =
xcb_render_query_pict_formats_formats_iterator(g_pictfmts); i.rem; xcb_render_query_pict_formats_formats_iterator(g_pictfmts);
xcb_render_pictforminfo_next(&i)) { i.rem; xcb_render_pictforminfo_next(&i)) {
if (i.data->id == pv->format) { if (i.data->id == pv->format) {
return i.data; return i.data;
} }
} }
return NULL; return NULL;
} }
static xcb_visualid_t attr_pure static xcb_visualid_t attr_pure x_get_visual_for_pictfmt(xcb_render_query_pict_formats_reply_t *r,
x_get_visual_for_pictfmt(xcb_render_query_pict_formats_reply_t *r, xcb_render_pictformat_t fmt) {
xcb_render_pictformat_t fmt) { for (auto screen = xcb_render_query_pict_formats_screens_iterator(r); screen.rem;
for (auto screen = xcb_render_query_pict_formats_screens_iterator(r); xcb_render_pictscreen_next(&screen)) {
screen.rem; xcb_render_pictscreen_next(&screen)) { for (auto depth = xcb_render_pictscreen_depths_iterator(screen.data);
for (auto depth = xcb_render_pictscreen_depths_iterator(screen.data); depth.rem; xcb_render_pictdepth_next(&depth)) {
depth.rem; xcb_render_pictdepth_next(&depth)) { for (auto pv = xcb_render_pictdepth_visuals_iterator(depth.data);
for (auto pv = xcb_render_pictdepth_visuals_iterator(depth.data); pv.rem; pv.rem; xcb_render_pictvisual_next(&pv)) {
xcb_render_pictvisual_next(&pv)) { if (pv.data->format == fmt) {
if (pv.data->format == fmt) { return pv.data->visual;
return pv.data->visual; }
} }
} }
} }
} return XCB_NONE;
return XCB_NONE;
} }
xcb_visualid_t xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) {
x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) { x_get_server_pictfmts(c);
x_get_server_pictfmts(c);
auto pictfmt = auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std);
xcb_render_util_find_standard_format(g_pictfmts, std);
return x_get_visual_for_pictfmt(g_pictfmts, pictfmt->id); return x_get_visual_for_pictfmt(g_pictfmts, pictfmt->id);
} }
int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) { int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
auto setup = xcb_get_setup(c); auto setup = xcb_get_setup(c);
for (auto screen = xcb_setup_roots_iterator(setup); screen.rem; xcb_screen_next(&screen)) { for (auto screen = xcb_setup_roots_iterator(setup); screen.rem;
for (auto depth = xcb_screen_allowed_depths_iterator(screen.data); depth.rem; xcb_depth_next(&depth)) { xcb_screen_next(&screen)) {
const int len = xcb_depth_visuals_length(depth.data); for (auto depth = xcb_screen_allowed_depths_iterator(screen.data);
const xcb_visualtype_t *visuals = xcb_depth_visuals(depth.data); depth.rem; xcb_depth_next(&depth)) {
for (int i = 0; i < len; i++) { const int len = xcb_depth_visuals_length(depth.data);
if (visual == visuals[i].visual_id) { const xcb_visualtype_t *visuals = xcb_depth_visuals(depth.data);
return depth.data->depth; for (int i = 0; i < len; i++) {
} if (visual == visuals[i].visual_id) {
} return depth.data->depth;
} }
} }
return -1; }
}
return -1;
} }
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_pictfmt_and_pixmap( x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *c,
xcb_connection_t *c, const xcb_render_pictforminfo_t * pictfmt, const xcb_render_pictforminfo_t *pictfmt,
xcb_pixmap_t pixmap, unsigned long valuemask, xcb_pixmap_t pixmap, unsigned long valuemask,
const xcb_render_create_picture_value_list_t *attr) const xcb_render_create_picture_value_list_t *attr) {
{ void *buf = NULL;
void *buf = NULL; if (attr) {
if (attr) { xcb_render_create_picture_value_list_serialize(&buf, valuemask, attr);
xcb_render_create_picture_value_list_serialize(&buf, valuemask, attr); if (!buf) {
if (!buf) { log_error("failed to serialize picture attributes");
log_error("failed to serialize picture attributes"); return XCB_NONE;
return XCB_NONE; }
} }
}
xcb_render_picture_t tmp_picture = xcb_generate_id(c); xcb_render_picture_t tmp_picture = xcb_generate_id(c);
xcb_generic_error_t *e = xcb_generic_error_t *e =
xcb_request_check(c, xcb_render_create_picture_checked(c, tmp_picture, xcb_request_check(c, xcb_render_create_picture_checked(
pixmap, pictfmt->id, valuemask, buf)); c, tmp_picture, pixmap, pictfmt->id, valuemask, buf));
free(buf); free(buf);
if (e) { if (e) {
x_print_error(e->full_sequence, e->major_code, e->minor_code, e->error_code); x_print_error(e->full_sequence, e->major_code, e->minor_code, e->error_code);
log_error("failed to create picture"); log_error("failed to create picture");
return XCB_NONE; return XCB_NONE;
} }
return tmp_picture; return tmp_picture;
} }
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_visual_and_pixmap( x_create_picture_with_visual_and_pixmap(xcb_connection_t *c, xcb_visualid_t visual,
xcb_connection_t *c, xcb_visualid_t visual, xcb_pixmap_t pixmap, unsigned long valuemask,
xcb_pixmap_t pixmap, unsigned long valuemask, const xcb_render_create_picture_value_list_t *attr) {
const xcb_render_create_picture_value_list_t *attr) const xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(c, visual);
{ return x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, pixmap, valuemask, attr);
const xcb_render_pictforminfo_t *pictfmt = x_get_pictform_for_visual(c, visual);
return x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, pixmap, valuemask, attr);
} }
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_standard_and_pixmap( x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard_t standard,
xcb_connection_t *c, xcb_pict_standard_t standard, xcb_pixmap_t pixmap, unsigned long valuemask,
xcb_pixmap_t pixmap, unsigned long valuemask, const xcb_render_create_picture_value_list_t *attr) {
const xcb_render_create_picture_value_list_t *attr) x_get_server_pictfmts(c);
{
x_get_server_pictfmts(c);
auto pictfmt = auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard);
xcb_render_util_find_standard_format(g_pictfmts, standard); assert(pictfmt);
assert(pictfmt); return x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, pixmap, valuemask, attr);
return x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, pixmap, valuemask, attr);
} }
/** /**
@ -246,98 +230,90 @@ x_create_picture_with_standard_and_pixmap(
*/ */
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int wid, int hei, x_create_picture_with_pictfmt(xcb_connection_t *c, xcb_drawable_t d, int wid, int hei,
const xcb_render_pictforminfo_t *pictfmt, unsigned long valuemask, const xcb_render_pictforminfo_t *pictfmt, unsigned long valuemask,
const xcb_render_create_picture_value_list_t *attr) const xcb_render_create_picture_value_list_t *attr) {
{ int depth = pictfmt->depth;
int depth = pictfmt->depth;
xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, d, wid, hei); xcb_pixmap_t tmp_pixmap = x_create_pixmap(c, depth, d, wid, hei);
if (!tmp_pixmap) if (!tmp_pixmap)
return XCB_NONE; return XCB_NONE;
xcb_render_picture_t picture = xcb_render_picture_t picture = x_create_picture_with_pictfmt_and_pixmap(
x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, tmp_pixmap, valuemask, attr); c, pictfmt, tmp_pixmap, valuemask, attr);
xcb_free_pixmap(c, tmp_pixmap); xcb_free_pixmap(c, tmp_pixmap);
return picture; return picture;
} }
xcb_render_picture_t xcb_render_picture_t
x_create_picture_with_visual(xcb_connection_t *c, xcb_drawable_t d, int w, int h, x_create_picture_with_visual(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
xcb_visualid_t visual, unsigned long valuemask, xcb_visualid_t visual, unsigned long valuemask,
const xcb_render_create_picture_value_list_t *attr) const xcb_render_create_picture_value_list_t *attr) {
{ auto pictfmt = x_get_pictform_for_visual(c, visual);
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, d, 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(xcb_connection_t *c, xcb_xfixes_region_t r, pixman_region32_t *res) {
xcb_generic_error_t *e = NULL; xcb_generic_error_t *e = NULL;
xcb_xfixes_fetch_region_reply_t *xr = xcb_xfixes_fetch_region_reply(c, xcb_xfixes_fetch_region_reply_t *xr =
xcb_xfixes_fetch_region(c, r), &e); xcb_xfixes_fetch_region_reply(c, xcb_xfixes_fetch_region(c, r), &e);
if (!xr) { if (!xr) {
log_error("Failed to fetch rectangles"); log_error("Failed to fetch rectangles");
return false; return false;
} }
int nrect = xcb_xfixes_fetch_region_rectangles_length(xr); int nrect = xcb_xfixes_fetch_region_rectangles_length(xr);
auto b = ccalloc(nrect, pixman_box32_t); auto b = ccalloc(nrect, pixman_box32_t);
xcb_rectangle_t *xrect = xcb_xfixes_fetch_region_rectangles(xr); xcb_rectangle_t *xrect = xcb_xfixes_fetch_region_rectangles(xr);
for (int i = 0; i < nrect; i++) { for (int i = 0; i < nrect; i++) {
b[i] = (pixman_box32_t) { b[i] = (pixman_box32_t){.x1 = xrect[i].x,
.x1 = xrect[i].x, .y1 = xrect[i].y,
.y1 = xrect[i].y, .x2 = xrect[i].x + xrect[i].width,
.x2 = xrect[i].x + xrect[i].width, .y2 = xrect[i].y + xrect[i].height};
.y2 = xrect[i].y + xrect[i].height }
}; bool ret = pixman_region32_init_rects(res, b, nrect);
} free(b);
bool ret = pixman_region32_init_rects(res, b, nrect); free(xr);
free(b); return ret;
free(xr);
return ret;
} }
void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict, void x_set_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict,
int clip_x_origin, int clip_y_origin, const region_t *reg) { int clip_x_origin, int clip_y_origin, const region_t *reg) {
int nrects; int nrects;
const rect_t *rects = pixman_region32_rectangles((region_t *)reg, &nrects); const rect_t *rects = pixman_region32_rectangles((region_t *)reg, &nrects);
auto xrects = ccalloc(nrects, xcb_rectangle_t); auto xrects = ccalloc(nrects, xcb_rectangle_t);
for (int i = 0; i < nrects; i++) for (int i = 0; i < nrects; i++)
xrects[i] = (xcb_rectangle_t){ xrects[i] = (xcb_rectangle_t){
.x = rects[i].x1, .x = rects[i].x1,
.y = rects[i].y1, .y = rects[i].y1,
.width = rects[i].x2 - rects[i].x1, .width = rects[i].x2 - rects[i].x1,
.height = rects[i].y2 - rects[i].y1, .height = rects[i].y2 - rects[i].y1,
}; };
xcb_generic_error_t *e = xcb_generic_error_t *e =
xcb_request_check(c, xcb_render_set_picture_clip_rectangles_checked(c, pict, xcb_request_check(c, xcb_render_set_picture_clip_rectangles_checked(
clip_x_origin, clip_y_origin, nrects, xrects)); c, pict, clip_x_origin, clip_y_origin, nrects, xrects));
if (e) if (e)
log_error("Failed to set clip region"); log_error("Failed to set clip region");
free(e); free(e);
free(xrects); free(xrects);
return; return;
} }
void x_clear_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict) { void x_clear_picture_clip_region(xcb_connection_t *c, xcb_render_picture_t pict) {
xcb_render_change_picture_value_list_t v = { xcb_render_change_picture_value_list_t v = {.clipmask = XCB_NONE};
.clipmask = XCB_NONE xcb_generic_error_t *e = xcb_request_check(
}; c, xcb_render_change_picture(c, pict, XCB_RENDER_CP_CLIP_MASK, &v));
xcb_generic_error_t *e = if (e)
xcb_request_check(c, xcb_render_change_picture(c, pict, log_error("failed to clear clip region");
XCB_RENDER_CP_CLIP_MASK, &v)); free(e);
if (e) return;
log_error("failed to clear clip region");
free(e);
return;
} }
enum { enum { XSyncBadCounter = 0,
XSyncBadCounter = 0, XSyncBadAlarm = 1,
XSyncBadAlarm = 1, XSyncBadFence = 2,
XSyncBadFence = 2,
}; };
/** /**
@ -345,106 +321,102 @@ enum {
* *
* XXX consider making this error to string * XXX consider making this error to string
*/ */
void void x_print_error(unsigned long serial, uint8_t major, uint8_t minor, uint8_t error_code) {
x_print_error(unsigned long serial, uint8_t major, uint8_t minor, uint8_t error_code) { session_t *const ps = ps_g;
session_t * const ps = ps_g;
int o = 0; int o = 0;
const char *name = "Unknown"; const char *name = "Unknown";
if (major == ps->composite_opcode if (major == ps->composite_opcode && minor == XCB_COMPOSITE_REDIRECT_SUBWINDOWS) {
&& minor == XCB_COMPOSITE_REDIRECT_SUBWINDOWS) { log_fatal("Another composite manager is already running "
log_fatal("Another composite manager is already running " "(and does not handle _NET_WM_CM_Sn correctly)");
"(and does not handle _NET_WM_CM_Sn correctly)"); exit(1);
exit(1); }
}
#define CASESTRRET2(s) case s: name = #s; break #define CASESTRRET2(s) \
case s: name = #s; break
o = error_code - ps->xfixes_error; o = error_code - ps->xfixes_error;
switch (o) { switch (o) { CASESTRRET2(XCB_XFIXES_BAD_REGION); }
CASESTRRET2(XCB_XFIXES_BAD_REGION);
}
o = error_code - ps->damage_error; o = error_code - ps->damage_error;
switch (o) { switch (o) { CASESTRRET2(XCB_DAMAGE_BAD_DAMAGE); }
CASESTRRET2(XCB_DAMAGE_BAD_DAMAGE);
}
o = error_code - ps->render_error; o = error_code - ps->render_error;
switch (o) { switch (o) {
CASESTRRET2(XCB_RENDER_PICT_FORMAT); CASESTRRET2(XCB_RENDER_PICT_FORMAT);
CASESTRRET2(XCB_RENDER_PICTURE); CASESTRRET2(XCB_RENDER_PICTURE);
CASESTRRET2(XCB_RENDER_PICT_OP); CASESTRRET2(XCB_RENDER_PICT_OP);
CASESTRRET2(XCB_RENDER_GLYPH_SET); CASESTRRET2(XCB_RENDER_GLYPH_SET);
CASESTRRET2(XCB_RENDER_GLYPH); CASESTRRET2(XCB_RENDER_GLYPH);
} }
#ifdef CONFIG_OPENGL #ifdef CONFIG_OPENGL
if (ps->glx_exists) { if (ps->glx_exists) {
o = error_code - ps->glx_error; o = error_code - ps->glx_error;
switch (o) { switch (o) {
CASESTRRET2(GLX_BAD_SCREEN); CASESTRRET2(GLX_BAD_SCREEN);
CASESTRRET2(GLX_BAD_ATTRIBUTE); CASESTRRET2(GLX_BAD_ATTRIBUTE);
CASESTRRET2(GLX_NO_EXTENSION); CASESTRRET2(GLX_NO_EXTENSION);
CASESTRRET2(GLX_BAD_VISUAL); CASESTRRET2(GLX_BAD_VISUAL);
CASESTRRET2(GLX_BAD_CONTEXT); CASESTRRET2(GLX_BAD_CONTEXT);
CASESTRRET2(GLX_BAD_VALUE); CASESTRRET2(GLX_BAD_VALUE);
CASESTRRET2(GLX_BAD_ENUM); CASESTRRET2(GLX_BAD_ENUM);
} }
} }
#endif #endif
if (ps->xsync_exists) { if (ps->xsync_exists) {
o = error_code - ps->xsync_error; o = error_code - ps->xsync_error;
switch (o) { switch (o) {
CASESTRRET2(XSyncBadCounter); CASESTRRET2(XSyncBadCounter);
CASESTRRET2(XSyncBadAlarm); CASESTRRET2(XSyncBadAlarm);
CASESTRRET2(XSyncBadFence); CASESTRRET2(XSyncBadFence);
} }
} }
switch (error_code) { switch (error_code) {
CASESTRRET2(BadAccess); CASESTRRET2(BadAccess);
CASESTRRET2(BadAlloc); CASESTRRET2(BadAlloc);
CASESTRRET2(BadAtom); CASESTRRET2(BadAtom);
CASESTRRET2(BadColor); CASESTRRET2(BadColor);
CASESTRRET2(BadCursor); CASESTRRET2(BadCursor);
CASESTRRET2(BadDrawable); CASESTRRET2(BadDrawable);
CASESTRRET2(BadFont); CASESTRRET2(BadFont);
CASESTRRET2(BadGC); CASESTRRET2(BadGC);
CASESTRRET2(BadIDChoice); CASESTRRET2(BadIDChoice);
CASESTRRET2(BadImplementation); CASESTRRET2(BadImplementation);
CASESTRRET2(BadLength); CASESTRRET2(BadLength);
CASESTRRET2(BadMatch); CASESTRRET2(BadMatch);
CASESTRRET2(BadName); CASESTRRET2(BadName);
CASESTRRET2(BadPixmap); CASESTRRET2(BadPixmap);
CASESTRRET2(BadRequest); CASESTRRET2(BadRequest);
CASESTRRET2(BadValue); CASESTRRET2(BadValue);
CASESTRRET2(BadWindow); CASESTRRET2(BadWindow);
} }
#undef CASESTRRET2 #undef CASESTRRET2
log_debug("X error %d %s request %d minor %d serial %lu", log_debug("X error %d %s request %d minor %d serial %lu", error_code, name, major,
error_code, name, major, minor, serial); minor, serial);
} }
/** /**
* Create a pixmap and check that creation succeeded. * Create a pixmap and check that creation succeeded.
*/ */
xcb_pixmap_t xcb_pixmap_t x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t drawable,
x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t drawable, uint16_t width, uint16_t height) { uint16_t width, uint16_t height) {
xcb_pixmap_t pix = xcb_generate_id(c); xcb_pixmap_t pix = xcb_generate_id(c);
xcb_void_cookie_t cookie = xcb_create_pixmap_checked(c, depth, pix, drawable, width, height); xcb_void_cookie_t cookie =
xcb_generic_error_t *err = xcb_request_check(c, cookie); xcb_create_pixmap_checked(c, depth, pix, drawable, width, height);
if (err == NULL) xcb_generic_error_t *err = xcb_request_check(c, cookie);
return pix; if (err == NULL)
return pix;
log_error("Failed to create pixmap:"); log_error("Failed to create pixmap:");
x_print_error(err->sequence, err->major_code, err->minor_code, err->error_code); x_print_error(err->sequence, err->major_code, err->minor_code, err->error_code);
free(err); free(err);
return XCB_NONE; return XCB_NONE;
} }
/** /**
@ -453,55 +425,54 @@ x_create_pixmap(xcb_connection_t *c, uint8_t depth, xcb_drawable_t drawable, uin
* Detect whether the pixmap is valid with XGetGeometry. Well, maybe there * Detect whether the pixmap is valid with XGetGeometry. Well, maybe there
* are better ways. * are better ways.
*/ */
bool bool x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) {
x_validate_pixmap(xcb_connection_t *c, xcb_pixmap_t pixmap) { if (pixmap == XCB_NONE) {
if (pixmap == XCB_NONE) { return false;
return false; }
}
auto r = xcb_get_geometry_reply(c, xcb_get_geometry(c, pixmap), NULL); auto r = xcb_get_geometry_reply(c, xcb_get_geometry(c, pixmap), NULL);
if (!r) { if (!r) {
return false; return false;
} }
bool ret = r->width && r->height; bool ret = r->width && r->height;
free(r); free(r);
return ret; return ret;
} }
/// Names of root window properties that could point to a pixmap of /// Names of root window properties that could point to a pixmap of
/// background. /// background.
static const char *background_props_str[] = { static const char *background_props_str[] = {
"_XROOTPMAP_ID", "_XROOTPMAP_ID",
"_XSETROOT_ID", "_XSETROOT_ID",
0, 0,
}; };
xcb_pixmap_t x_get_root_back_pixmap(session_t *ps) { xcb_pixmap_t x_get_root_back_pixmap(session_t *ps) {
xcb_pixmap_t pixmap = XCB_NONE; xcb_pixmap_t pixmap = XCB_NONE;
// Get the values of background attributes // Get the values of background attributes
for (int p = 0; background_props_str[p]; p++) { for (int p = 0; background_props_str[p]; p++) {
xcb_atom_t prop_atom = get_atom(ps, background_props_str[p]); xcb_atom_t prop_atom = get_atom(ps, background_props_str[p]);
winprop_t prop = winprop_t prop =
wid_get_prop(ps, ps->root, prop_atom, 1, XCB_ATOM_PIXMAP, 32); wid_get_prop(ps, ps->root, prop_atom, 1, XCB_ATOM_PIXMAP, 32);
if (prop.nitems) { if (prop.nitems) {
pixmap = *prop.p32; pixmap = *prop.p32;
free_winprop(&prop); free_winprop(&prop);
break; break;
} }
free_winprop(&prop); free_winprop(&prop);
} }
return pixmap; return pixmap;
} }
bool x_is_root_back_pixmap_atom(session_t *ps, xcb_atom_t atom) { bool x_is_root_back_pixmap_atom(session_t *ps, xcb_atom_t atom) {
for (int p = 0; background_props_str[p]; p++) { for (int p = 0; background_props_str[p]; p++) {
xcb_atom_t prop_atom = get_atom(ps, background_props_str[p]); xcb_atom_t prop_atom = get_atom(ps, background_props_str[p]);
if (prop_atom == atom) if (prop_atom == atom)
return true; return true;
} }
return false; return false;
} }
/** /**
@ -509,36 +480,36 @@ bool x_is_root_back_pixmap_atom(session_t *ps, xcb_atom_t atom) {
* are completed. * are completed.
*/ */
bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) { bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) {
// TODO(richardgv): If everybody just follows the rules stated in X Sync // 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 // prototype, we need only one fence per screen, but let's stay a bit
// cautious right now // cautious right now
auto e = xcb_request_check(c, xcb_sync_trigger_fence_checked(c, f)); auto e = xcb_request_check(c, xcb_sync_trigger_fence_checked(c, f));
if (e) { if (e) {
log_error("Failed to trigger the fence."); log_error("Failed to trigger the fence.");
free(e); free(e);
return false; return false;
} }
e = xcb_request_check(c, xcb_sync_await_fence_checked(c, 1, &f)); e = xcb_request_check(c, xcb_sync_await_fence_checked(c, 1, &f));
if (e) { if (e) {
log_error("Failed to await on a fence."); log_error("Failed to await on a fence.");
free(e); free(e);
return false; return false;
} }
e = xcb_request_check(c, xcb_sync_reset_fence_checked(c, f)); e = xcb_request_check(c, xcb_sync_reset_fence_checked(c, f));
if (e) { if (e) {
log_error("Failed to reset the fence."); log_error("Failed to reset the fence.");
free(e); free(e);
return false; return false;
} }
return true; return true;
} }
// xcb-render specific macros // xcb-render specific macros
#define XFIXED_TO_DOUBLE(value) (((double) (value)) / 65536) #define XFIXED_TO_DOUBLE(value) (((double)(value)) / 65536)
#define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t) (((double) (value)) * 65536)) #define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t)(((double)(value)) * 65536))
/** /**
* Convert a struct conv to a X picture convolution filter, normalizing the kernel * Convert a struct conv to a X picture convolution filter, normalizing the kernel
@ -552,35 +523,35 @@ bool x_fence_sync(xcb_connection_t *c, xcb_sync_fence_t f) {
* @param[inout] size size of the array pointed to by `ret`, in number of elements * @param[inout] size size of the array pointed to by `ret`, in number of elements
* @return number of elements filled into `*ret` * @return number of elements filled into `*ret`
*/ */
size_t x_picture_filter_from_conv(const conv *kernel, double center, xcb_render_fixed_t **ret, size_t x_picture_filter_from_conv(const conv *kernel, double center,
size_t *size) { xcb_render_fixed_t **ret, size_t *size) {
if (*size < (size_t)(kernel->w * kernel->h + 2)) { if (*size < (size_t)(kernel->w * kernel->h + 2)) {
*size = kernel->w * kernel->h + 2; *size = kernel->w * kernel->h + 2;
*ret = crealloc(*ret, *size); *ret = crealloc(*ret, *size);
} }
auto buf = *ret; auto buf = *ret;
buf[0] = DOUBLE_TO_XFIXED(kernel->w); buf[0] = DOUBLE_TO_XFIXED(kernel->w);
buf[1] = DOUBLE_TO_XFIXED(kernel->h); buf[1] = DOUBLE_TO_XFIXED(kernel->h);
double sum = center; double sum = center;
for (int i = 0; i < kernel->w * kernel->h; i++) { for (int i = 0; i < kernel->w * kernel->h; i++) {
sum += kernel->data[i]; sum += kernel->data[i];
} }
// Note for floating points a / b != a * (1 / b), but this shouldn't have any real // Note for floating points a / b != a * (1 / b), but this shouldn't have any real
// impact on the result // impact on the result
double factor = sum != 0 ? 1.0 / sum : 1; double factor = sum != 0 ? 1.0 / sum : 1;
for (int i = 0; i < kernel->w * kernel->h; i++) { for (int i = 0; i < kernel->w * kernel->h; i++) {
buf[i + 2] = DOUBLE_TO_XFIXED(kernel->data[i] * factor); buf[i + 2] = DOUBLE_TO_XFIXED(kernel->data[i] * factor);
} }
buf[kernel->h / 2 * kernel->w + kernel->w / 2 + 2] = DOUBLE_TO_XFIXED(center * factor); buf[kernel->h / 2 * kernel->w + kernel->w / 2 + 2] =
return kernel->w * kernel->h + 2; DOUBLE_TO_XFIXED(center * factor);
return kernel->w * kernel->h + 2;
} }
/// Generate a search criteria for fbconfig from a X visual. /// Generate a search criteria for fbconfig from a X visual.
/// Returns {-1, -1, -1, -1, -1, -1} on failure /// Returns {-1, -1, -1, -1, -1, -1} on failure
struct xvisual_info struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual) {
x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual) {
auto pictfmt = x_get_pictform_for_visual(c, visual); auto pictfmt = x_get_pictform_for_visual(c, visual);
auto depth = x_get_visual_depth(c, visual); auto depth = x_get_visual_depth(c, visual);
if (!pictfmt || depth == -1) { if (!pictfmt || depth == -1) {

25
src/x.h
View File

@ -137,16 +137,17 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *, xcb_pict_standard_
/** /**
* Create an picture. * Create an picture.
*/ */
xcb_render_picture_t attr_nonnull(1, 5) xcb_render_picture_t
x_create_picture_with_pictfmt(xcb_connection_t *, xcb_drawable_t, int wid, int hei, x_create_picture_with_pictfmt(xcb_connection_t *, xcb_drawable_t, int wid, int hei,
const xcb_render_pictforminfo_t *pictfmt, const xcb_render_pictforminfo_t *pictfmt, unsigned long valuemask,
unsigned long valuemask, const xcb_render_create_picture_value_list_t *attr)
const xcb_render_create_picture_value_list_t *attr); attr_nonnull(1, 5);
xcb_render_picture_t attr_nonnull(1) xcb_render_picture_t
x_create_picture_with_visual(xcb_connection_t *, xcb_drawable_t, int w, int h, x_create_picture_with_visual(xcb_connection_t *, xcb_drawable_t, int w, int h,
xcb_visualid_t visual, unsigned long valuemask, xcb_visualid_t visual, unsigned long valuemask,
const xcb_render_create_picture_value_list_t *attr); const xcb_render_create_picture_value_list_t *attr)
attr_nonnull(1);
/// Fetch a X region and store it in a pixman region /// 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(xcb_connection_t *, xcb_xfixes_region_t r, region_t *res);
@ -206,8 +207,6 @@ size_t x_picture_filter_from_conv(const conv *kernel, double center,
/// Generate a search criteria for fbconfig from a X visual. /// Generate a search criteria for fbconfig from a X visual.
/// Returns {-1, -1, -1, -1, -1, -1} on failure /// Returns {-1, -1, -1, -1, -1, -1} on failure
struct xvisual_info struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual);
x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual);
xcb_visualid_t xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);

View File

@ -8,64 +8,58 @@
static xrc_xid_record_t *gs_xid_records = NULL; static xrc_xid_record_t *gs_xid_records = NULL;
#define HASH_ADD_XID(head, xidfield, add) \ #define HASH_ADD_XID(head, xidfield, add) HASH_ADD(hh, head, xidfield, sizeof(xid), add)
HASH_ADD(hh, head, xidfield, sizeof(xid), add)
#define HASH_FIND_XID(head, findxid, out) \ #define HASH_FIND_XID(head, findxid, out) HASH_FIND(hh, head, findxid, sizeof(xid), out)
HASH_FIND(hh, head, findxid, sizeof(xid), out)
#define M_CPY_POS_DATA(prec) \ #define M_CPY_POS_DATA(prec) \
prec->file = file; \ prec->file = file; \
prec->func = func; \ prec->func = func; \
prec->line = line; \ prec->line = line;
/** /**
* @brief Add a record of given XID to the allocation table. * @brief Add a record of given XID to the allocation table.
*/ */
void void xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS) {
xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS) { auto prec = ccalloc(1, xrc_xid_record_t);
auto prec = ccalloc(1, xrc_xid_record_t); prec->xid = xid;
prec->xid = xid; prec->type = type;
prec->type = type; M_CPY_POS_DATA(prec);
M_CPY_POS_DATA(prec);
HASH_ADD_XID(gs_xid_records, xid, prec); HASH_ADD_XID(gs_xid_records, xid, prec);
} }
/** /**
* @brief Delete a record of given XID in the allocation table. * @brief Delete a record of given XID in the allocation table.
*/ */
void void xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS) {
xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS) { xrc_xid_record_t *prec = NULL;
xrc_xid_record_t *prec = NULL; HASH_FIND_XID(gs_xid_records, &xid, prec);
HASH_FIND_XID(gs_xid_records, &xid, prec); if (!prec) {
if (!prec) { log_error("XRC: %s:%d %s(): Can't find XID %#010lx we want to delete.",
log_error("XRC: %s:%d %s(): Can't find XID %#010lx we want to delete.", file, line, func, xid);
file, line, func, xid); return;
return; }
} HASH_DEL(gs_xid_records, prec);
HASH_DEL(gs_xid_records, prec); free(prec);
free(prec);
} }
/** /**
* @brief Report about issues found in the XID allocation table. * @brief Report about issues found in the XID allocation table.
*/ */
void void xrc_report_xid(void) {
xrc_report_xid(void) { for (xrc_xid_record_t *prec = gs_xid_records; prec; prec = prec->hh.next)
for (xrc_xid_record_t *prec = gs_xid_records; prec; prec = prec->hh.next) log_trace("XRC: %s:%d %s(): %#010lx (%s) not freed.\n", prec->file,
log_trace("XRC: %s:%d %s(): %#010lx (%s) not freed.\n", prec->line, prec->func, prec->xid, prec->type);
prec->file, prec->line, prec->func, prec->xid, prec->type);
} }
/** /**
* @brief Clear the XID allocation table. * @brief Clear the XID allocation table.
*/ */
void void xrc_clear_xid(void) {
xrc_clear_xid(void) { xrc_xid_record_t *prec = NULL, *ptmp = NULL;
xrc_xid_record_t *prec = NULL, *ptmp = NULL; HASH_ITER(hh, gs_xid_records, prec, ptmp) {
HASH_ITER(hh, gs_xid_records, prec, ptmp) { HASH_DEL(gs_xid_records, prec);
HASH_DEL(gs_xid_records, prec); free(prec);
free(prec); }
}
} }

View File

@ -6,60 +6,57 @@
#include "uthash.h" #include "uthash.h"
typedef struct { typedef struct {
XID xid; XID xid;
const char *type; const char *type;
const char *file; const char *file;
const char *func; const char *func;
int line; int line;
UT_hash_handle hh; UT_hash_handle hh;
} xrc_xid_record_t; } xrc_xid_record_t;
#define M_POS_DATA_PARAMS const char *file, int line, const char *func #define M_POS_DATA_PARAMS const char *file, int line, const char *func
#define M_POS_DATA_PASSTHROUGH file, line, func #define M_POS_DATA_PASSTHROUGH file, line, func
#define M_POS_DATA __FILE__, __LINE__, __func__ #define M_POS_DATA __FILE__, __LINE__, __func__
void void xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS);
xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS);
#define xrc_add_xid(xid, type) xrc_add_xid_(xid, type, M_POS_DATA) #define xrc_add_xid(xid, type) xrc_add_xid_(xid, type, M_POS_DATA)
void void xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS);
xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS);
#define xrc_delete_xid(xid) xrc_delete_xid_(xid, M_POS_DATA) #define xrc_delete_xid(xid) xrc_delete_xid_(xid, M_POS_DATA)
void void xrc_report_xid(void);
xrc_report_xid(void);
void void xrc_clear_xid(void);
xrc_clear_xid(void);
// Pixmap // Pixmap
static inline void static inline void xcb_create_pixmap_(xcb_connection_t *c, uint8_t depth,
xcb_create_pixmap_(xcb_connection_t *c, uint8_t depth, xcb_pixmap_t pixmap, xcb_pixmap_t pixmap, xcb_drawable_t drawable,
xcb_drawable_t drawable, uint16_t width, uint16_t height, M_POS_DATA_PARAMS) { uint16_t width, uint16_t height, M_POS_DATA_PARAMS) {
xcb_create_pixmap(c, depth, pixmap, drawable, width, height); xcb_create_pixmap(c, depth, pixmap, drawable, width, height);
xrc_add_xid_(pixmap, "Pixmap", M_POS_DATA_PASSTHROUGH); xrc_add_xid_(pixmap, "Pixmap", M_POS_DATA_PASSTHROUGH);
} }
#define xcb_create_pixmap(c, depth, pixmap, drawable, width, height) \ #define xcb_create_pixmap(c, depth, pixmap, drawable, width, height) \
xcb_create_pixmap_(c, depth, pixmap, drawable, width, height, M_POS_DATA) xcb_create_pixmap_(c, depth, pixmap, drawable, width, height, M_POS_DATA)
static inline xcb_void_cookie_t static inline xcb_void_cookie_t
xcb_composite_name_window_pixmap_(xcb_connection_t *c, xcb_window_t window, xcb_pixmap_t pixmap, M_POS_DATA_PARAMS) { xcb_composite_name_window_pixmap_(xcb_connection_t *c, xcb_window_t window,
xcb_void_cookie_t ret = xcb_composite_name_window_pixmap(c, window, pixmap); xcb_pixmap_t pixmap, M_POS_DATA_PARAMS) {
xrc_add_xid_(pixmap, "PixmapC", M_POS_DATA_PASSTHROUGH); xcb_void_cookie_t ret = xcb_composite_name_window_pixmap(c, window, pixmap);
return ret; xrc_add_xid_(pixmap, "PixmapC", M_POS_DATA_PASSTHROUGH);
return ret;
} }
#define xcb_composite_name_window_pixmap(dpy, window, pixmap) \ #define xcb_composite_name_window_pixmap(dpy, window, pixmap) \
xcb_composite_name_window_pixmap_(dpy, window, pixmap, M_POS_DATA) xcb_composite_name_window_pixmap_(dpy, window, pixmap, M_POS_DATA)
static inline void static inline void
xcb_free_pixmap_(xcb_connection_t *c, xcb_pixmap_t pixmap, M_POS_DATA_PARAMS) { xcb_free_pixmap_(xcb_connection_t *c, xcb_pixmap_t pixmap, M_POS_DATA_PARAMS) {
xcb_free_pixmap(c, pixmap); xcb_free_pixmap(c, pixmap);
xrc_delete_xid_(pixmap, M_POS_DATA_PASSTHROUGH); xrc_delete_xid_(pixmap, M_POS_DATA_PASSTHROUGH);
} }
#define xcb_free_pixmap(c, pixmap) xcb_free_pixmap_(c, pixmap, M_POS_DATA); #define xcb_free_pixmap(c, pixmap) xcb_free_pixmap_(c, pixmap, M_POS_DATA);