Comments (4)
@richardgv, thanks for the good work again. I feel really uneasy about performance hits. I want to leave this issue open for now. This was honestly the most minor of the 3 major bugs.
I've made you a core committer on compton. Ideally it would be good to discuss changes through pull requests, but you have commit access if you need it. Just be careful, a lot of packages point to this repo as a release since I don't do formal releases for compton.
And I hope you won't simply stop updating compton after the 3 issues get resolved.
I plan to maintain compton for as long as I can. It's just the past few months have been busy for me.
Change paint_all() so it paints in a different sequence: Paints the root window, paint the lowest window's shadow on it, paint the lowest window, paint the shadow of the second-lowest window... It looks a lot more intuitive, and it should be much easier to implement, perhaps helpful in performance. I'm afraid, nonetheless, these xcompmgr developers, with infinite wisdom, might choose the current seemingly-clumsy painting method on purpose. I believe it's the most promising fix, and it requires most code modification.
It might be interesting to start up a separate branch for this. I'm all for rewriting everything honestly. If we can make it better, let's do it.
from compton.
I feel really uneasy about performance hits. I want to leave this issue open for now. This was honestly the most minor of the 3 major bugs.
If you need a quick fix right now, my fix 2 combined with fix 8 shouldn't cause too aggressive a performance hit.
I looked into the source code of libXfixes and xorg-server, and seemingly the rounding shapes are returned by the program creating the window. Chromium has quite a huge amount of code, looks like ./ui/aura/root_window_host_linux.cc
contains the code that handles the window, I'm still searching for where exactly the bounding shapes are added and modified. Maybe it's better to ask Chromium devs firstly before I work on a patch to Chromium?
Update: chrome/browser/ui/gtk/rounded_window.cc
andchrome/browser/ui/gtk/browser_window_gtk.cc
may actually be the key files.
I've made you a core committer on compton. Ideally it would be good to discuss changes through pull requests, but you have commit access if you need it. Just be careful, a lot of packages point to this repo as a release since I don't do formal releases for compton.
I usually won't commit without prior discussion, unless my GitHub account is hacked, I assume.
I personally believe compton is stable enough for a formal release if it could be verified that my recent patches don't do something awful. With a formal release it helps to keep the snapshots of various distros in sync. Right now at least Fedora and Gentoo come with snapshots of different dates in their official repo.
I plan to maintain compton for as long as I can. It's just the past few months have been busy for me.
Awesome.
It might be interesting to start up a separate branch for this. I'm all for rewriting everything honestly. If we can make it better, let's do it.
xcompmgr has quite some ugly code that got inherited to compton, indeed. I will see what I can help.
from compton.
In Chromium's chrome/browser/ui/gtk/browser_window_gtk.cc
I found the code to update the bounding region:
void BrowserWindowGtk::UpdateWindowShape(int width, int height) {
GdkRegion* mask = GetWindowShape(width, height);
gdk_window_shape_combine_region(
gtk_widget_get_window(GTK_WIDGET(window_)), mask, 0, 0);
if (mask)
gdk_region_destroy(mask);
if (UseCustomFrame() && !IsFullscreen() && !IsMaximized()) {
gtk_alignment_set_padding(GTK_ALIGNMENT(window_container_), 1,
kFrameBorderThickness, kFrameBorderThickness, kFrameBorderThickness);
} else {
gtk_alignment_set_padding(GTK_ALIGNMENT(window_container_), 0, 0, 0, 0);
}
}
GdkRegion* BrowserWindowGtk::GetWindowShape(int width, int height) const {
if (UseCustomFrame() && !IsFullscreen() && !IsMaximized()) {
// Make the corners rounded. We set a mask that includes most of the
// window except for a few pixels in each corner.
GdkRectangle top_top_rect = { 3, 0, width - 6, 1 };
GdkRectangle top_mid_rect = { 1, 1, width - 2, 2 };
GdkRectangle mid_rect = { 0, 3, width, height - 6 };
// The bottom two rects are mirror images of the top two rects.
GdkRectangle bot_mid_rect = top_mid_rect;
bot_mid_rect.y = height - 3;
GdkRectangle bot_bot_rect = top_top_rect;
bot_bot_rect.y = height - 1;
GdkRegion* mask = gdk_region_rectangle(&top_top_rect);
gdk_region_union_with_rect(mask, &top_mid_rect);
gdk_region_union_with_rect(mask, &mid_rect);
gdk_region_union_with_rect(mask, &bot_mid_rect);
gdk_region_union_with_rect(mask, &bot_bot_rect);
return mask;
} else if (UseCustomFrame()) {
// Disable rounded corners. Simply passing in a NULL region doesn't
// seem to work on KWin, so manually set the shape to the whole window.
GdkRectangle rect = { 0, 0, width, height };
GdkRegion* mask = gdk_region_rectangle(&rect);
return mask;
} else {
// XFCE disables the system decorations if there's an xshape set. Do not
// use the KWin hack when the custom frame is not enabled.
return NULL;
}
}
UpdateWindowShape()
is called upon window changes, theme changes, etc. Unfortunately, I didn't find a way to update the bounding region before the window geometry changes -- I doubt if it's possible, actually, considering the design of X. I've reported this to Chromium, however I guess it's questionable whether they will fix it somehow or provide a workaround: https://code.google.com/p/chromium/issues/detail?id=147533
from compton.
Sorry that I didn't know there's a thing called ShapeNotify
previously. I'm able to write a patch with it that probably solved these two issues with minimal performance impact:
(Note this patched included and improved my "better debug" patch as I needed to include event debugging support for Shape extension, and don't feel like pushing out another patch just for "better debug with ShapeNotify support".)
diff --git a/Makefile b/Makefile
index b0c9d5e..60a5c7a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ PREFIX ?= /usr
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man/man1
-PACKAGES = x11 xcomposite xfixes xdamage xrender
+PACKAGES = x11 xcomposite xfixes xdamage xrender xext
LIBS = $(shell pkg-config --libs $(PACKAGES)) -lm
INCS = $(shell pkg-config --cflags $(PACKAGES))
CFLAGS += -Wall
diff --git a/src/compton.c b/src/compton.c
index b72dc59..7d66ec1 100644
--- a/src/compton.c
+++ b/src/compton.c
@@ -10,6 +10,10 @@
#include "compton.h"
+#if DEBUG_EVENTS
+static int window_get_name(Window w, char **name);
+#endif
+
/**
* Shared
*/
@@ -36,6 +40,10 @@ ignore *ignore_head, **ignore_tail = &ignore_head;
int xfixes_event, xfixes_error;
int damage_event, damage_error;
int composite_event, composite_error;
+/// Whether the Shape extension exists
+Bool shape_exists = True;
+/// event_base and error_base for Shape extension
+int shape_event, shape_error;
int render_event, render_error;
int composite_opcode;
@@ -954,12 +962,7 @@ paint_all(Display *dpy, XserverRegion region) {
win *t = 0;
if (!region) {
- XRectangle r;
- r.x = 0;
- r.y = 0;
- r.width = root_width;
- r.height = root_height;
- region = XFixesCreateRegion(dpy, &r, 1);
+ region = get_screen_region(dpy);
}
#if MONITOR_REPAINT
@@ -1029,11 +1032,7 @@ paint_all(Display *dpy, XserverRegion region) {
#endif
if (clip_changed) {
- if (w->border_size) {
- set_ignore(dpy, NextRequest(dpy));
- XFixesDestroyRegion(dpy, w->border_size);
- w->border_size = None;
- }
+ win_free_border_size(dpy, w);
if (w->extents) {
XFixesDestroyRegion(dpy, w->extents);
w->extents = None;
@@ -1372,6 +1371,10 @@ map_win(Display *dpy, Window id,
so that no property changes are lost */
if (!override_redirect) {
XSelectInput(dpy, id, PropertyChangeMask | FocusChangeMask);
+ // Notify compton when the shape of a window changes
+ if (shape_exists) {
+ XShapeSelectInput(dpy, id, ShapeNotifyMask);
+ }
}
// this causes problems for inactive transparency
@@ -1425,11 +1428,7 @@ finish_unmap_win(Display *dpy, win *w) {
w->picture = None;
}
- if (w->border_size) {
- set_ignore(dpy, NextRequest(dpy));
- XFixesDestroyRegion(dpy, w->border_size);
- w->border_size = None;
- }
+ win_free_border_size(dpy, w);
if (w->shadow) {
XRenderFreePicture(dpy, w->shadow);
@@ -1692,6 +1691,33 @@ restack_win(Display *dpy, win *w, Window new_above) {
w->next = *prev;
*prev = w;
+
+#if DEBUG_RESTACK
+ {
+ const char *desc;
+ char *window_name;
+ Bool to_free;
+ win* c = list;
+
+ printf("restack_win(%#010lx, %#010lx): Window stack modified. Current stack:\n", w->id, new_above);
+ for (; c; c = c->next) {
+ window_name = "(Failed to get title)";
+ if (root == c->id)
+ window_name = "(Root window)";
+ else
+ to_free = window_get_name(c->id, &window_name);
+ desc = "";
+ if (c->destroyed)
+ desc = "(D) ";
+ printf("%#010lx \"%s\" %s-> ", c->id, window_name, desc);
+ if (to_free) {
+ XFree(window_name);
+ window_name = NULL;
+ }
+ }
+ fputs("\n", stdout);
+ }
+#endif
}
}
@@ -1957,6 +1983,60 @@ error(Display *dpy, XErrorEvent *ev) {
break;
}
+ switch (ev->error_code) {
+ case BadAccess:
+ name = "BadAccess";
+ break;
+ case BadAlloc:
+ name = "BadAlloc";
+ break;
+ case BadAtom:
+ name = "BadAtom";
+ break;
+ case BadColor:
+ name = "BadColor";
+ break;
+ case BadCursor:
+ name = "BadCursor";
+ break;
+ case BadDrawable:
+ name = "BadDrawable";
+ break;
+ case BadFont:
+ name = "BadFont";
+ break;
+ case BadGC:
+ name = "BadGC";
+ break;
+ case BadIDChoice:
+ name = "BadIDChoice";
+ break;
+ case BadImplementation:
+ name = "BadImplementation";
+ break;
+ case BadLength:
+ name = "BadLength";
+ break;
+ case BadMatch:
+ name = "BadMatch";
+ break;
+ case BadName:
+ name = "BadName";
+ break;
+ case BadPixmap:
+ name = "BadPixmap";
+ break;
+ case BadRequest:
+ name = "BadRequest";
+ break;
+ case BadValue:
+ name = "BadValue";
+ break;
+ case BadWindow:
+ name = "BadWindow";
+ break;
+ }
+
printf("error %d (%s) request %d minor %d serial %lu\n",
ev->error_code, name, ev->request_code,
ev->minor_code, ev->serial);
@@ -1970,10 +2050,36 @@ expose_root(Display *dpy, Window root, XRectangle *rects, int nrects) {
add_damage(dpy, region);
}
-#if DEBUG_EVENTS
+#if DEBUG_EVENTS || DEBUG_RESTACK
+static int window_get_name(Window w, char **name) {
+ Atom prop = XInternAtom(dpy, "_NET_WM_NAME", False);
+ Atom utf8_type = XInternAtom(dpy, "UTF8_STRING", False);
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long leftover;
+ char *data = NULL;
+ Status ret;
+
+ set_ignore(dpy, NextRequest(dpy));
+ if (Success != (ret = XGetWindowProperty(dpy, w, prop, 0L, (long) BUFSIZ,
+ False, utf8_type, &actual_type, &actual_format, &nitems,
+ &leftover, (unsigned char **) &data))) {
+ if (BadWindow == ret)
+ return 0;
+ set_ignore(dpy, NextRequest(dpy));
+ printf("Window %#010lx: _NET_WM_NAME unset, falling back to WM_NAME.\n", w);
+ if (!XFetchName(dpy, w, &data))
+ return 0;
+ }
+ // if (actual_type == utf8_type && actual_format == 8)
+ *name = (char *) data;
+ return 1;
+}
+
static int
ev_serial(XEvent *ev) {
- if (ev->type & 0x7f != KeymapNotify) {
+ if ((ev->type & 0x7f) != KeymapNotify) {
return ev->xany.serial;
}
return NextRequest(ev->xany.display);
@@ -1983,8 +2089,16 @@ static char *
ev_name(XEvent *ev) {
static char buf[128];
switch (ev->type & 0x7f) {
- case Expose:
- return "Expose";
+ case FocusIn:
+ return "FocusIn";
+ case FocusOut:
+ return "FocusOut";
+ case CreateNotify:
+ return "CreateNotify";
+ case ConfigureNotify:
+ return "ConfigureNotify";
+ case DestroyNotify:
+ return "DestroyNotify";
case MapNotify:
return "Map";
case UnmapNotify:
@@ -1993,10 +2107,16 @@ ev_name(XEvent *ev) {
return "Reparent";
case CirculateNotify:
return "Circulate";
+ case Expose:
+ return "Expose";
+ case PropertyNotify:
+ return "PropertyNotify";
default:
if (ev->type == damage_event + XDamageNotify) {
return "Damage";
}
+ if (shape_exists && ev->type == shape_event)
+ return "ShapeNotify";
sprintf(buf, "Event %d", ev->type);
return buf;
}
@@ -2005,8 +2125,13 @@ ev_name(XEvent *ev) {
static Window
ev_window(XEvent *ev) {
switch (ev->type) {
- case Expose:
- return ev->xexpose.window;
+ case FocusIn:
+ case FocusOut:
+ return ev->xfocus.window;
+ case CreateNotify:
+ return ev->xcreatewindow.window;
+ case ConfigureNotify:
+ return ev->xconfigure.window;
case MapNotify:
return ev->xmap.window;
case UnmapNotify:
@@ -2015,10 +2140,16 @@ ev_window(XEvent *ev) {
return ev->xreparent.window;
case CirculateNotify:
return ev->xcirculate.window;
+ case Expose:
+ return ev->xexpose.window;
+ case PropertyNotify:
+ return ev->xproperty.window;
default:
if (ev->type == damage_event + XDamageNotify) {
return ((XDamageNotifyEvent *)ev)->drawable;
}
+ if (shape_exists && ev->type == shape_event)
+ return ((XShapeEvent *) ev)->window;
return 0;
}
}
@@ -2064,6 +2195,9 @@ ev_create_notify(XCreateWindowEvent *ev) {
inline static void
ev_configure_notify(XConfigureEvent *ev) {
+#if DEBUG_EVENTS
+ printf("{ send_event: %d, above: %08lx, override_redirect: %d }\n", ev->send_event, ev->above, ev->override_redirect);
+#endif
configure_win(dpy, ev);
}
@@ -2164,16 +2298,56 @@ ev_damage_notify(XDamageNotifyEvent *ev) {
damage_win(dpy, ev);
}
+static void ev_shape_notify(XShapeEvent *ev) {
+ win *w = find_win(dpy, ev->window);
+
+ /*
+ * Empty border size may indicated an
+ * unmapped/destoried window, in which case
+ * seemingly BadRegion errors would be triggered
+ * if we attempt to rebuild border_size
+ */
+ if (w->border_size) {
+ // Mark the old border_size as damaged
+ add_damage(dpy, w->border_size);
+
+ w->border_size = border_size(dpy, w);
+
+ // Mark the new border_size as damaged
+ add_damage(dpy, copy_region(dpy, w->border_size));
+ }
+
+}
+
inline static void
ev_handle(XEvent *ev) {
+
+#if DEBUG_EVENTS
+ Window w;
+ char *window_name;
+ Bool to_free = False;
+#endif
+
if ((ev->type & 0x7f) != KeymapNotify) {
discard_ignore(dpy, ev->xany.serial);
}
#if DEBUG_EVENTS
+ w = ev_window(ev);
+ window_name = "(Failed to get title)";
+ if (w) {
+ if (root == w)
+ window_name = "(Root window)";
+ else
+ to_free = window_get_name(w, &window_name);
+ }
if (ev->type != damage_event + XDamageNotify) {
- printf("event %10.10s serial 0x%08x window 0x%08x\n",
- ev_name(ev), ev_serial(ev), ev_window(ev));
+ printf("event %10.10s serial %#010x window %#010lx \"%s\"\n",
+ ev_name(ev), ev_serial(ev), w, window_name);
+ }
+ if (to_free) {
+ XFree(window_name);
+ window_name = NULL;
}
#endif
@@ -2212,6 +2386,10 @@ ev_handle(XEvent *ev) {
ev_property_notify((XPropertyEvent *)ev);
break;
default:
+ if (shape_exists && ev->type == shape_event) {
+ ev_shape_notify((XShapeEvent *) ev);
+ break;
+ }
if (ev->type == damage_event + XDamageNotify) {
ev_damage_notify((XDamageNotifyEvent *)ev);
}
@@ -2524,6 +2702,9 @@ main(int argc, char **argv) {
exit(1);
}
+ if (!XShapeQueryExtension(dpy, &shape_event, &shape_error))
+ shape_exists = False;
+
register_cm(scr);
if (fork_after_register) fork_after();
diff --git a/src/compton.h b/src/compton.h
index 18e3859..6f30391 100644
--- a/src/compton.h
+++ b/src/compton.h
@@ -20,6 +20,7 @@
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xrender.h>
+#include <X11/extensions/shape.h>
#if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2
#define HAS_NAME_WINDOW_PIXMAP 1
@@ -28,6 +29,7 @@
#define CAN_DO_USABLE 0
#define DEBUG_REPAINT 0
#define DEBUG_EVENTS 0
+#define DEBUG_RESTACK 0
#define DEBUG_WINTYPE 0
#define MONITOR_REPAINT 0
@@ -124,6 +126,7 @@ typedef struct _fade {
Display *dpy;
} fade;
+extern int root_height, root_width;
/**
* Functions
*/
@@ -345,6 +348,42 @@ ev_property_notify(XPropertyEvent *ev);
inline static void
ev_damage_notify(XDamageNotifyEvent *ev);
+/**
+ * Destory the cached border_size of a window.
+ */
+inline static void win_free_border_size(Display *dpy, win *w) {
+ if (w->border_size) {
+ set_ignore(dpy, NextRequest(dpy));
+ XFixesDestroyRegion(dpy, w->border_size);
+ w->border_size = None;
+ }
+}
+
+/**
+ * Get a region of the screen size.
+ */
+inline static XserverRegion get_screen_region(Display *dpy) {
+ XRectangle r;
+
+ r.x = 0;
+ r.y = 0;
+ r.width = root_width;
+ r.height = root_height;
+ return XFixesCreateRegion(dpy, &r, 1);
+}
+
+/**
+ * Copies a region
+ */
+inline static XserverRegion copy_region(Display *dpy,
+ XserverRegion oldregion) {
+ XserverRegion region = XFixesCreateRegion(dpy, NULL, 0);
+
+ XFixesCopyRegion(dpy, region, oldregion);
+
+ return region;
+}
+
inline static void
ev_handle(XEvent *ev);
It adds another dependency, libXext, for the X Shape extension function calls, which I suppose every sane X user has installed. I tried to make it work without X Shape extension, yet I did not test the support.
As the issues are tied to timing, I could not state that this patch absolutely resolves the issues. I could only confirm that I tried 30+ times without being able to reproduce the issue.
I personally use DoxyGen comment format. Change it to other styles if you don't like it.
A depressing news is, I rewrote paint_all()
to adapt the new painting sequence, and so far it does not render shaped windows correctly if I don't use the bounding regions. Much annoyance with how XRenderCreatePicture()
and XRenderComposite()
works. I'm still looking into the exact reasons.
By the way, I discovered two possible bugs in compton:
- If you set transparency of a window before compton starts running with compton-trans, after you run compton the window is rendered solid, i.e. compton-trans looks only effective for compton when it's running. xcompmgr respects transparency set when it's not running;
- When you make a specially shaped window (I triggered it with oclock) transparent, compton will render the completely tranparent parts (the corners of an oclock window, for example) incorrectly. xcompmgr doesn't show anything wrong. It's probably related to why my rewritting
paint_all()
does not work.
I don't have to time to look at them today. Too sleepy.
from compton.
Related Issues (20)
- Compton crashes after waking from suspend HOT 2
- [vsync_opengl_swc_init ERROR] Failed to load a swap control extension HOT 8
- [Feature Request] Allow multiple shadows on window
- [Feature Request] Remove saturation as an alternative or additional to blurring
- `compton-fake-transparency-fshader-win.glsl` is broken
- inactive-dim whitelist
- Compton no longer turns windows transparent on i3-gaps HOT 1
- g
- BadPixmap (invalid Pixmap parameter) HOT 2
- Complete OS Freeze using Android Studio Image Asset feature
- [Feature Request] Shrink unfocused windows to emphasize focus indicators in i3-gaps
- Can't make opacity-rule works as I would like
- x11 HOT 1
- Invalid blur method kawase HOT 2
- Make doesnt install HOT 1
- Archive this repository and redirect to picom
- rc/c2.c:600:37: warning: pointer used after 'free' [-Wuse-after-free]
- Using compton to optimize for two gstreamer video vindows to remove tearing and frame skipping
- Marco+compton: compton keeps crashing
- PCRE regular expression support not compiled in
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from compton.