diff --git a/glfw_wcb.c b/glfw_wcb.c index 9fd931d..56ca2fd 100644 --- a/glfw_wcb.c +++ b/glfw_wcb.c @@ -128,6 +128,7 @@ static void swap_buffers(GLFWwindow* w) { static Display* get_x11_display(void) { return glfwGetX11Display(); } static Window get_x11_window (GLFWwindow* w) { return glfwGetX11Window(w); } static bool should_close (GLFWwindow* w) { return glfwWindowShouldClose(w); } +static bool should_render (GLFWwindow* w) { return true; } static void get_fbsize (GLFWwindow* w, int* d, int* h) { glfwGetFramebufferSize(w, d, h); } static void get_pos (GLFWwindow* w, int* x, int* y) { glfwGetWindowPos(w, x, y); } static double get_time (GLFWwindow* w) { return glfwGetTime(); } diff --git a/glx_wcb.c b/glx_wcb.c index b39c705..29ed469 100644 --- a/glx_wcb.c +++ b/glx_wcb.c @@ -175,7 +175,7 @@ struct glxwin { Window w; GLXContext context; double time; - bool should_close, clickthrough; + bool should_close, should_render, clickthrough; char override_state; }; @@ -274,10 +274,13 @@ static void* create_and_bind(const char* name, const char* class, int version_major, int version_minor, bool clickthrough) { struct glxwin* w = malloc(sizeof(struct glxwin)); - w->override_state = '\0'; - w->time = 0.0D; - w->should_close = false; - w->clickthrough = false; + *w = (struct glxwin) { + .override_state = '\0', + .time = 0.0D, + .should_close = false, + .should_render = true, + .clickthrough = false + }; XVisualInfo* vi; XSetWindowAttributes attr = {}; @@ -355,10 +358,11 @@ static void* create_and_bind(const char* name, const char* class, vi = glXGetVisualFromFBConfig(display, config); attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vi->visual, AllocNone); - attr.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask | PropertyChangeMask; + attr.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask; + attr.event_mask |= PropertyChangeMask | VisibilityChangeMask; attr.background_pixmap = None; attr.border_pixel = 0; - + unsigned long vmask = CWColormap | CWEventMask | CWBackPixmap | CWBorderPixel; if (type[0] == '!') { vmask |= CWOverrideRedirect; @@ -483,8 +487,14 @@ static void set_visible(struct glxwin* w, bool visible) { else XUnmapWindow(display, w->w); } -static bool should_close(struct glxwin* w) { - return w->should_close; +static bool should_close (struct glxwin* w) { return w->should_close; } +static bool should_render(struct glxwin* w) { + /* For nearly all window managers, windows are 'minimized' by unmapping parent windows. + VisibilityNotify events are not sent in these instances, so we have to read window + attributes to see if our window isn't viewable. */ + XWindowAttributes attrs; + XGetWindowAttributes(display, w->w, &attrs); + return w->should_render && attrs.map_state == IsViewable; } static void swap_buffers(struct glxwin* w) { @@ -500,6 +510,19 @@ static void swap_buffers(struct glxwin* w) { w->should_close = true; } break; + case VisibilityNotify: + switch (ev.xvisibility.state) { + case VisibilityFullyObscured: + w->should_render = false; + break; + case VisibilityUnobscured: + case VisibilityPartiallyObscured: + w->should_render = true; + break; + default: + fprintf(stderr, "Invalid VisibilityNotify event state (%d)\n", ev.xvisibility.state); + break; + } default: break; } } diff --git a/render.c b/render.c index 71063fd..f970607 100644 --- a/render.c +++ b/render.c @@ -724,7 +724,7 @@ struct renderer* rd_new(const char** paths, const char* entry, .sm_prog = 0, .copy_desktop = true, .premultiply_alpha = true, - .check_fullscreen = true, + .check_fullscreen = false, .smooth_pass = true, .fft_scale = 10.2F, .fft_cutoff = 0.3F, @@ -1329,7 +1329,7 @@ struct renderer* rd_new(const char** paths, const char* entry, overlay(&gl->overlay); glClearColor(gl->clear_color.r, gl->clear_color.g, gl->clear_color.b, gl->clear_color.a); - + gl->wcb->set_visible(gl->w, true); return r; @@ -1349,9 +1349,13 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi r->alive = false; return true; } + + /* Stop rendering if the backend has some reason not to render (minimized, obscured) */ + if (!gl->wcb->should_render(gl->w)) + return false; /* Stop rendering when fullscreen windows are focused */ - if (gl->check_fullscreen && !xwin_should_render(r)) + if (gl->check_fullscreen && !xwin_should_render(gl->wcb, gl->w)) return false; /* Force disable interpolation if the update rate is close to or higher than the frame rate */ diff --git a/render.h b/render.h index db043c2..32064bb 100644 --- a/render.h +++ b/render.h @@ -33,6 +33,7 @@ struct gl_wcb { int version_major, int version_minor, bool clickthrough); bool (*should_close) (void* ptr); + bool (*should_render) (void* ptr); void (*swap_buffers) (void* ptr); void (*raise) (void* ptr); void (*destroy) (void* ptr); @@ -68,6 +69,7 @@ struct gl_wcb { WCB_FUNC(init), \ WCB_FUNC(create_and_bind), \ WCB_FUNC(should_close), \ + WCB_FUNC(should_render), \ WCB_FUNC(swap_buffers), \ WCB_FUNC(raise), \ WCB_FUNC(destroy), \ diff --git a/shaders/rc.glsl b/shaders/rc.glsl index 9ac8a77..1eed4b5 100644 --- a/shaders/rc.glsl +++ b/shaders/rc.glsl @@ -128,11 +128,14 @@ simply set to zero (or lower) to disable the frame limiter. */ #request setframerate 0 -/* Enable/disable fullscreen checks. This looks at the currently - focused window and halts GLava's rendering if it is - fullscreen. This prevents rendering from interfering with - other graphically intensive tasks. */ -#request setfullscreencheck true +/* Suspends rendering if a fullscreen window is focused while + GLava is still visible (ie. on another monitor). This prevents + rendering from interfering with other graphically intensive + tasks. + + If GLava is minimized or completely obscured, it will not + render regardless of this option. */ +#request setfullscreencheck false /* Enable/disable printing framerate every second. 'FPS' stands for 'Frames Per Second', and 'UPS' stands for 'Updates Per diff --git a/xwin.c b/xwin.c index 15c47bb..3c223b0 100644 --- a/xwin.c +++ b/xwin.c @@ -140,14 +140,14 @@ const char* xwin_detect_wm(struct gl_wcb* wcb) { } -bool xwin_should_render(struct renderer* rd) { +bool xwin_should_render(struct gl_wcb* wcb, void* impl) { bool ret = true, should_close = false; - Display* d = rd_get_wcb(rd)->get_x11_display(); + Display* d = wcb->get_x11_display(); if (!d) { d = XOpenDisplay(0); should_close = true; } - + Atom prop = XInternAtom(d, "_NET_ACTIVE_WINDOW", true); Atom fullscreen = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", true); diff --git a/xwin.h b/xwin.h index 7e8f01b..a79048c 100644 --- a/xwin.h +++ b/xwin.h @@ -6,7 +6,7 @@ typedef unsigned long int Window; -bool xwin_should_render(struct renderer* rd); +bool xwin_should_render(struct gl_wcb* wcb, void* impl); void xwin_wait_for_wm(void); bool xwin_settype(struct gl_wcb* wcb, void* impl, const char* type); void xwin_setdesktop(struct gl_wcb* wcb, void* impl, unsigned long desktop);