Handle window map_state and VisibilityNotify events, closes #68

This commit is contained in:
Jarcode
2018-10-08 11:18:45 -07:00
parent acdbb8f3b5
commit 83a94e3eb4
7 changed files with 54 additions and 21 deletions

View File

@@ -128,6 +128,7 @@ static void swap_buffers(GLFWwindow* w) {
static Display* get_x11_display(void) { return glfwGetX11Display(); } static Display* get_x11_display(void) { return glfwGetX11Display(); }
static Window get_x11_window (GLFWwindow* w) { return glfwGetX11Window(w); } static Window get_x11_window (GLFWwindow* w) { return glfwGetX11Window(w); }
static bool should_close (GLFWwindow* w) { return glfwWindowShouldClose(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_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 void get_pos (GLFWwindow* w, int* x, int* y) { glfwGetWindowPos(w, x, y); }
static double get_time (GLFWwindow* w) { return glfwGetTime(); } static double get_time (GLFWwindow* w) { return glfwGetTime(); }

View File

@@ -175,7 +175,7 @@ struct glxwin {
Window w; Window w;
GLXContext context; GLXContext context;
double time; double time;
bool should_close, clickthrough; bool should_close, should_render, clickthrough;
char override_state; char override_state;
}; };
@@ -274,10 +274,13 @@ static void* create_and_bind(const char* name, const char* class,
int version_major, int version_minor, int version_major, int version_minor,
bool clickthrough) { bool clickthrough) {
struct glxwin* w = malloc(sizeof(struct glxwin)); struct glxwin* w = malloc(sizeof(struct glxwin));
w->override_state = '\0'; *w = (struct glxwin) {
w->time = 0.0D; .override_state = '\0',
w->should_close = false; .time = 0.0D,
w->clickthrough = false; .should_close = false,
.should_render = true,
.clickthrough = false
};
XVisualInfo* vi; XVisualInfo* vi;
XSetWindowAttributes attr = {}; XSetWindowAttributes attr = {};
@@ -355,10 +358,11 @@ static void* create_and_bind(const char* name, const char* class,
vi = glXGetVisualFromFBConfig(display, config); vi = glXGetVisualFromFBConfig(display, config);
attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vi->visual, AllocNone); 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.background_pixmap = None;
attr.border_pixel = 0; attr.border_pixel = 0;
unsigned long vmask = CWColormap | CWEventMask | CWBackPixmap | CWBorderPixel; unsigned long vmask = CWColormap | CWEventMask | CWBackPixmap | CWBorderPixel;
if (type[0] == '!') { if (type[0] == '!') {
vmask |= CWOverrideRedirect; vmask |= CWOverrideRedirect;
@@ -483,8 +487,14 @@ static void set_visible(struct glxwin* w, bool visible) {
else XUnmapWindow(display, w->w); else XUnmapWindow(display, w->w);
} }
static bool should_close(struct glxwin* w) { static bool should_close (struct glxwin* w) { return w->should_close; }
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) { static void swap_buffers(struct glxwin* w) {
@@ -500,6 +510,19 @@ static void swap_buffers(struct glxwin* w) {
w->should_close = true; w->should_close = true;
} }
break; 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; default: break;
} }
} }

View File

@@ -724,7 +724,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
.sm_prog = 0, .sm_prog = 0,
.copy_desktop = true, .copy_desktop = true,
.premultiply_alpha = true, .premultiply_alpha = true,
.check_fullscreen = true, .check_fullscreen = false,
.smooth_pass = true, .smooth_pass = true,
.fft_scale = 10.2F, .fft_scale = 10.2F,
.fft_cutoff = 0.3F, .fft_cutoff = 0.3F,
@@ -1329,7 +1329,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
overlay(&gl->overlay); overlay(&gl->overlay);
glClearColor(gl->clear_color.r, gl->clear_color.g, gl->clear_color.b, gl->clear_color.a); glClearColor(gl->clear_color.r, gl->clear_color.g, gl->clear_color.b, gl->clear_color.a);
gl->wcb->set_visible(gl->w, true); gl->wcb->set_visible(gl->w, true);
return r; return r;
@@ -1349,9 +1349,13 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
r->alive = false; r->alive = false;
return true; 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 */ /* 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; return false;
/* Force disable interpolation if the update rate is close to or higher than the frame rate */ /* Force disable interpolation if the update rate is close to or higher than the frame rate */

View File

@@ -33,6 +33,7 @@ struct gl_wcb {
int version_major, int version_minor, int version_major, int version_minor,
bool clickthrough); bool clickthrough);
bool (*should_close) (void* ptr); bool (*should_close) (void* ptr);
bool (*should_render) (void* ptr);
void (*swap_buffers) (void* ptr); void (*swap_buffers) (void* ptr);
void (*raise) (void* ptr); void (*raise) (void* ptr);
void (*destroy) (void* ptr); void (*destroy) (void* ptr);
@@ -68,6 +69,7 @@ struct gl_wcb {
WCB_FUNC(init), \ WCB_FUNC(init), \
WCB_FUNC(create_and_bind), \ WCB_FUNC(create_and_bind), \
WCB_FUNC(should_close), \ WCB_FUNC(should_close), \
WCB_FUNC(should_render), \
WCB_FUNC(swap_buffers), \ WCB_FUNC(swap_buffers), \
WCB_FUNC(raise), \ WCB_FUNC(raise), \
WCB_FUNC(destroy), \ WCB_FUNC(destroy), \

View File

@@ -128,11 +128,14 @@
simply set to zero (or lower) to disable the frame limiter. */ simply set to zero (or lower) to disable the frame limiter. */
#request setframerate 0 #request setframerate 0
/* Enable/disable fullscreen checks. This looks at the currently /* Suspends rendering if a fullscreen window is focused while
focused window and halts GLava's rendering if it is GLava is still visible (ie. on another monitor). This prevents
fullscreen. This prevents rendering from interfering with rendering from interfering with other graphically intensive
other graphically intensive tasks. */ tasks.
#request setfullscreencheck true
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 /* Enable/disable printing framerate every second. 'FPS' stands
for 'Frames Per Second', and 'UPS' stands for 'Updates Per for 'Frames Per Second', and 'UPS' stands for 'Updates Per

6
xwin.c
View File

@@ -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; bool ret = true, should_close = false;
Display* d = rd_get_wcb(rd)->get_x11_display(); Display* d = wcb->get_x11_display();
if (!d) { if (!d) {
d = XOpenDisplay(0); d = XOpenDisplay(0);
should_close = true; should_close = true;
} }
Atom prop = XInternAtom(d, "_NET_ACTIVE_WINDOW", true); Atom prop = XInternAtom(d, "_NET_ACTIVE_WINDOW", true);
Atom fullscreen = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", true); Atom fullscreen = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", true);

2
xwin.h
View File

@@ -6,7 +6,7 @@
typedef unsigned long int Window; 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); void xwin_wait_for_wm(void);
bool xwin_settype(struct gl_wcb* wcb, void* impl, const char* type); bool xwin_settype(struct gl_wcb* wcb, void* impl, const char* type);
void xwin_setdesktop(struct gl_wcb* wcb, void* impl, unsigned long desktop); void xwin_setdesktop(struct gl_wcb* wcb, void* impl, unsigned long desktop);