From d8b437aca3c2acffd7b15cdf15d1da9f4496191c Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 5 Nov 2011 21:39:58 -0500 Subject: [PATCH 1/2] frame opacity --- xcompmgr.c | 140 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 112 insertions(+), 28 deletions(-) diff --git a/xcompmgr.c b/xcompmgr.c index a2925eb..db84db7 100644 --- a/xcompmgr.c +++ b/xcompmgr.c @@ -88,6 +88,7 @@ typedef struct _win { Damage damage; Picture picture; Picture alpha_pict; + Picture alpha_border_pict; Picture shadow_pict; XserverRegion border_size; XserverRegion extents; @@ -100,6 +101,7 @@ typedef struct _win { wintype window_type; unsigned long damage_sequence; /* sequence when damage was created */ Bool destroyed; + unsigned int top_width; Bool need_configure; XConfigureEvent queue_configure; @@ -190,6 +192,7 @@ int fade_time = 0; Bool fade_trans = False; double inactive_opacity = 0; +double frame_opacity = 0; #define INACTIVE_OPACITY \ (unsigned long)((double)inactive_opacity * OPAQUE) @@ -937,6 +940,71 @@ border_size(Display *dpy, win *w) { return border; } +static Window +find_client_win(Display *dpy, Window win) { + Atom WM_STATE = XInternAtom(dpy, "WM_STATE", False); + + Window root, parent; + Window *children; + unsigned int nchildren; + unsigned int i; + Atom type = None; + int format; + unsigned long nitems, after; + unsigned char *data; + Window client = 0; + + XGetWindowProperty( + dpy, win, WM_STATE, 0, 0, False, + AnyPropertyType, &type, &format, &nitems, + &after, &data); + + if (type) return win; + + if (!XQueryTree(dpy, win, &root, + &parent, &children, &nchildren)) { + return 0; + } + + for (i = 0; i < nchildren; i++) { + client = find_client_win(dpy, children[i]); + if (client) break; + } + + if (children) XFree((char *)children); + + return client; +} + +static void +get_frame_extents(Display *dpy, Window w, int *top) { + long *extents; + Atom type; + int format; + unsigned long nitems, after; + unsigned char *data = NULL; + int result; + + *top = 0; + + w = find_client_win(dpy, w); + if (!w) return; + + result = XGetWindowProperty( + dpy, w, XInternAtom(dpy, "_NET_FRAME_EXTENTS", False), + 0L, 4L, False, AnyPropertyType, + &type, &format, &nitems, &after, + (unsigned char **)&data); + + if (result == Success) { + if (nitems == 4 && after == 0) { + extents = (long *)data; + *top = (int) *(extents + 2); + } + XFree(data); + } +} + static void paint_all(Display *dpy, XserverRegion region) { win *w; @@ -1042,7 +1110,8 @@ paint_all(Display *dpy, XserverRegion region) { w->extents = win_extents(dpy, w); } - if (w->mode == WINDOW_SOLID) { + if (!(frame_opacity && w->top_width) + && w->mode == WINDOW_SOLID) { int x, y, wid, hei; #if HAS_NAME_WINDOW_PIXMAP @@ -1099,12 +1168,19 @@ paint_all(Display *dpy, XserverRegion region) { w->shadow_width, w->shadow_height); } - if (w->opacity != OPAQUE && !w->alpha_pict) { + if (((frame_opacity && w->top_width) || w->opacity != OPAQUE) + && !w->alpha_pict) { w->alpha_pict = solid_picture( dpy, False, (double)w->opacity / OPAQUE, 0, 0, 0); } - if (w->mode == WINDOW_TRANS) { + if (((frame_opacity && w->top_width) || w->opacity != OPAQUE) + && !w->alpha_border_pict) { + w->alpha_border_pict = solid_picture( + dpy, False, frame_opacity, 0, 0, 0); + } + + if ((frame_opacity && w->top_width) || w->mode != WINDOW_SOLID) { int x, y, wid, hei; #if HAS_NAME_WINDOW_PIXMAP @@ -1121,30 +1197,21 @@ paint_all(Display *dpy, XserverRegion region) { set_ignore(dpy, NextRequest(dpy)); - XRenderComposite( - dpy, PictOpOver, w->picture, w->alpha_pict, - root_buffer, 0, 0, 0, 0, x, y, wid, hei); - } else if (w->mode == WINDOW_ARGB) { - int x, y, wid, hei; - -#if HAS_NAME_WINDOW_PIXMAP - x = w->a.x; - y = w->a.y; - wid = w->a.width + w->a.border_width * 2; - hei = w->a.height + w->a.border_width * 2; -#else - x = w->a.x + w->a.border_width; - y = w->a.y + w->a.border_width; - wid = w->a.width; - hei = w->a.height; -#endif - - set_ignore(dpy, NextRequest(dpy)); - - XRenderComposite( - dpy, PictOpOver, w->picture, w->alpha_pict, - root_buffer, 0, 0, 0, 0, - x, y, wid, hei); + if (!frame_opacity || !w->top_width) { + XRenderComposite( + dpy, PictOpOver, w->picture, w->alpha_pict, + root_buffer, 0, 0, 0, 0, x, y, wid, hei); + } else { + unsigned int t = w->top_width; + /* transparent title bar */ + XRenderComposite( + dpy, PictOpOver, w->picture, w->alpha_border_pict, + root_buffer, 0, 0, 0, 0, x, y, wid, t); + /* rest of the window */ + XRenderComposite( + dpy, PictOpOver, w->picture, w->alpha_pict, + root_buffer, 0, t, 0, t, x, y + t, wid, hei - t); + } } XFixesDestroyRegion(dpy, w->border_clip); @@ -1500,6 +1567,11 @@ determine_mode(Display *dpy, win *w) { w->alpha_pict = None; } + if (w->alpha_border_pict) { + XRenderFreePicture(dpy, w->alpha_border_pict); + w->alpha_border_pict = None; + } + if (w->shadow_pict) { XRenderFreePicture(dpy, w->shadow_pict); w->shadow_pict = None; @@ -1573,6 +1645,7 @@ add_win(Display *dpy, Window id, Window prev) { } new->alpha_pict = None; + new->alpha_border_pict = None; new->shadow_pict = None; new->border_size = None; new->extents = None; @@ -1591,6 +1664,9 @@ add_win(Display *dpy, Window id, Window prev) { new->next = *p; *p = new; + new->top_width = 0; + get_frame_extents(dpy, id, &new->top_width); + if (new->a.map_state == IsViewable) { new->window_type = determine_wintype(dpy, id, id); if (inactive_opacity && new->window_type == WINTYPE_NORMAL) { @@ -1734,6 +1810,11 @@ finish_destroy_win(Display *dpy, Window id) { w->alpha_pict = None; } + if (w->alpha_border_pict) { + XRenderFreePicture(dpy, w->alpha_border_pict); + w->alpha_border_pict = None; + } + if (w->shadow_pict) { XRenderFreePicture(dpy, w->shadow_pict); w->shadow_pict = None; @@ -2100,7 +2181,7 @@ main(int argc, char **argv) { /* don't bother to draw a shadow for the desktop */ win_type_shadow[WINTYPE_DESKTOP] = False; - while ((o = getopt(argc, argv, "D:I:O:d:r:o:m:l:t:i:scnfFCaS")) != -1) { + while ((o = getopt(argc, argv, "D:I:O:d:r:o:m:l:t:i:z:scnfFCaS")) != -1) { switch (o) { case 'd': display = optarg; @@ -2161,6 +2242,9 @@ main(int argc, char **argv) { exit(1); } break; + case 'z': + frame_opacity = (double)atof(optarg); + break; case 'c': case 'n': case 'a': From cde4d0c75ffaf3eb7b4480bb5eec251a71d08574 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 5 Nov 2011 22:33:50 -0500 Subject: [PATCH 2/2] complete frame opacity --- README.md | 12 +++++++--- xcompmgr.c | 64 +++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 4fbbd0c..62f3eae 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,17 @@ partially doing this out of a desire to learn Xlib. ## Changes from xcompmgr: * __inactive window transparency__ (specified with `-i`) +* __titlebar/frame transparency__ (specified with `-e`) * shadows are now enabled for argb windows, e.g. terminals with transparency * removed serverside shadows (and simple compositing) to clean the code, the only option that remains is clientside shadows -* titlebar transparency (and possibly border transparency) is on the way * menu transparency (thanks to Dana) +The above features give compton a feature set similar to the xfce compositor. + +Compton has only been tested with openbox so far, but frame transparency +should work with any window manager that properly sets `_NET_FRAME_EXTENTS`. + ## Fixes from the original xcompmgr: * fixed a segfault when opening certain window types @@ -64,7 +69,8 @@ The above will produce a single binary. ## Usage ``` bash -$ xcompmgr -cC -t -5 -l -5 -r 5 -o 0.5 -fF -I 0.065 -O 0.065 -D 6 -m 0.8 -i & +$ xcompmgr -cC -t -5 -l -5 -r 5 -o 0.4 \ + -fF -I 0.065 -O 0.065 -D 6 -m 0.8 -i 0.6 -e 0.6 & -$ xcompmgr -cC -t -5 -l -5 -r 5 -o 0.5 -i & +$ xcompmgr -cC -t -5 -l -5 -r 5 -o 0.4 -i 0.6 -e 0.6 & ``` diff --git a/xcompmgr.c b/xcompmgr.c index db84db7..5a84406 100644 --- a/xcompmgr.c +++ b/xcompmgr.c @@ -101,7 +101,10 @@ typedef struct _win { wintype window_type; unsigned long damage_sequence; /* sequence when damage was created */ Bool destroyed; + unsigned int left_width; + unsigned int right_width; unsigned int top_width; + unsigned int bottom_width; Bool need_configure; XConfigureEvent queue_configure; @@ -977,7 +980,8 @@ find_client_win(Display *dpy, Window win) { } static void -get_frame_extents(Display *dpy, Window w, int *top) { +get_frame_extents(Display *dpy, Window w, + int *left, int *right, int *top, int *bottom) { long *extents; Atom type; int format; @@ -985,7 +989,10 @@ get_frame_extents(Display *dpy, Window w, int *top) { unsigned char *data = NULL; int result; + *left = 0; + *right = 0; *top = 0; + *bottom = 0; w = find_client_win(dpy, w); if (!w) return; @@ -999,7 +1006,10 @@ get_frame_extents(Display *dpy, Window w, int *top) { if (result == Success) { if (nitems == 4 && after == 0) { extents = (long *)data; + *left = (int) *extents; + *right = (int) *(extents + 1); *top = (int) *(extents + 2); + *bottom = (int) *(extents + 3); } XFree(data); } @@ -1202,15 +1212,36 @@ paint_all(Display *dpy, XserverRegion region) { dpy, PictOpOver, w->picture, w->alpha_pict, root_buffer, 0, 0, 0, 0, x, y, wid, hei); } else { + /* TODO - clean me */ unsigned int t = w->top_width; - /* transparent title bar */ + unsigned int l = w->left_width; + unsigned int b = w->bottom_width; + unsigned int r = w->right_width; + + /* top */ XRenderComposite( - dpy, PictOpOver, w->picture, w->alpha_border_pict, - root_buffer, 0, 0, 0, 0, x, y, wid, t); - /* rest of the window */ + dpy, PictOpOver, w->picture, w->alpha_border_pict, root_buffer, + 0, 0, 0, 0, x, y, wid, t); + + /* left */ XRenderComposite( - dpy, PictOpOver, w->picture, w->alpha_pict, - root_buffer, 0, t, 0, t, x, y + t, wid, hei - t); + dpy, PictOpOver, w->picture, w->alpha_border_pict, root_buffer, + 0, t, 0, t, x, y + t, l, hei - t); + + /* bottom */ + XRenderComposite( + dpy, PictOpOver, w->picture, w->alpha_border_pict, root_buffer, + l, hei - b, l, hei - b, x + l, y + hei - b, wid - l - r, b); + + /* right */ + XRenderComposite( + dpy, PictOpOver, w->picture, w->alpha_border_pict, root_buffer, + wid - r, t, wid - r, t, x + wid - r, y + t, r, hei - t); + + /* body */ + XRenderComposite( + dpy, PictOpOver, w->picture, w->alpha_pict, root_buffer, + l, t, l, t, x + l, y + t, wid - l - r, hei - t - b); } } @@ -1664,8 +1695,12 @@ add_win(Display *dpy, Window id, Window prev) { new->next = *p; *p = new; + new->left_width = 0; + new->right_width = 0; new->top_width = 0; - get_frame_extents(dpy, id, &new->top_width); + new->bottom_width = 0; + get_frame_extents(dpy, id, + &new->left_width, &new->right_width, &new->top_width, &new->bottom_width); if (new->a.map_state == IsViewable) { new->window_type = determine_wintype(dpy, id, id); @@ -2113,6 +2148,9 @@ usage(char *program) { fprintf(stderr, " -i opacity\n " "Opacity of inactive windows. (0.1 - 1.0)\n"); + fprintf(stderr, + " -e opacity\n " + "Opacity of window titlebars and borders. (0.1 - 1.0)\n"); fprintf(stderr, " -S\n " "Enable synchronous operation (for debugging).\n"); @@ -2181,7 +2219,7 @@ main(int argc, char **argv) { /* don't bother to draw a shadow for the desktop */ win_type_shadow[WINTYPE_DESKTOP] = False; - while ((o = getopt(argc, argv, "D:I:O:d:r:o:m:l:t:i:z:scnfFCaS")) != -1) { + while ((o = getopt(argc, argv, "D:I:O:d:r:o:m:l:t:i:e:scnfFCaS")) != -1) { switch (o) { case 'd': display = optarg; @@ -2236,13 +2274,8 @@ main(int argc, char **argv) { break; case 'i': inactive_opacity = (double)atof(optarg); - if (inactive_opacity < 0.1 - || inactive_opacity > 1.0) { - fprintf(stderr, "Opacity must be 0.1 - 1.0.\n"); - exit(1); - } break; - case 'z': + case 'e': frame_opacity = (double)atof(optarg); break; case 'c': @@ -2423,6 +2456,7 @@ main(int argc, char **argv) { break; } case CreateNotify: + //if (ev.xcreatewindow.override_redirect) break; add_win(dpy, ev.xcreatewindow.window, 0); break; case ConfigureNotify: