int y;
unsigned width;
unsigned height;
+ unsigned border;
int map_state;
Damage damage;
Pixmap pixmap;
CompositedWindow *windows;
unsigned nwindows;
unsigned windows_capacity;
+ int dirty;
} CompositedScreen;
typedef struct Compositor
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT;
PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT;
+ int dirty;
} Compositor;
static const char *vshader =
1.0f, 0.0f
};
+int x_error_handler(Display *display, XErrorEvent *event)
+{
+ printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
+ (void)display;
+ return 0;
+}
+
int with_error(const char *message)
{
fprintf(stderr, "%s\n", message);
if(w==screen->root || w==screen->overlay)
return;
- XGetWindowAttributes(compositor->display, w, &win_attr);
+ if(!XGetWindowAttributes(compositor->display, w, &win_attr))
+ {
+ printf("XGetWindowAttributes failed; probably the window was already destroyed\n");
+ return;
+ }
if(win_attr.class==InputOnly)
return;
window->y = win_attr.y;
window->width = win_attr.width;
window->height = win_attr.height;
+ window->border = win_attr.border_width;
window->map_state = win_attr.map_state;
window->damage = XDamageCreate(compositor->display, window->window, XDamageReportNonEmpty);
return NULL;
}
+CompositedScreen *find_screen_by_window(Compositor *compositor, Window w)
+{
+ unsigned i, j;
+
+ for(i=0; i<compositor->nscreens; ++i)
+ for(j=0; j<compositor->screens[i].nwindows; ++j)
+ if(compositor->screens[i].windows[j].window==w)
+ return &compositor->screens[i];
+
+ return NULL;
+}
+
int initialize_screen(Compositor *compositor, unsigned number)
{
CompositedScreen *screen;
XFree(children);
+ screen->dirty = 1;
+
return 1;
}
if(!compositor->display)
return with_error("Could not open X display");
+ XSetErrorHandler(&x_error_handler);
+
if(!XCompositeQueryExtension(compositor->display, &event_base, &error_base))
return with_error("XComposite is required but was not found");
else if(!XCompositeQueryVersion(compositor->display, &major_ver, &minor_ver))
if(!initialize_screen(compositor, i))
return 0;
+ compositor->dirty = 1;
+
return 1;
}
window->map_state = IsUnviewable;
}
-void process_event(Compositor *compositor)
+void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
+{
+ CompositedScreen *screen = find_screen_by_window(compositor, event->drawable);
+ if(!screen)
+ return;
+
+ screen->dirty = 1;
+ compositor->dirty = 1;
+}
+
+int process_event(Compositor *compositor)
{
XEvent event;
- XNextEvent(compositor->display, &event);
+ if(compositor->dirty)
+ {
+ if(!XCheckMaskEvent(compositor->display, -1, &event))
+ return 0;
+ }
+ else
+ XNextEvent(compositor->display, &event);
+
switch(event.type)
{
case CreateNotify:
process_unmap_event(compositor, &event.xunmap);
break;
default:
- if(event.type!=compositor->damage_event+XDamageNotify)
+ if(event.type==compositor->damage_event+XDamageNotify)
+ process_damage_event(compositor, (XDamageNotifyEvent *)&event);
+ else
printf("Event %d\n", event.type);
}
+
+ return 1;
}
void refresh_screens(Compositor *compositor)
glUseProgram(screen->program);
glBindVertexArray(screen->vertex_array);
- XGrabServer(compositor->display);
- glXWaitX();
for(j=0; j<screen->nwindows; ++j)
{
CompositedWindow *window = &screen->windows[j];
{
glBindTexture(GL_TEXTURE_2D, window->texture);
compositor->glXBindTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
- glUniform4f(screen->geometry_loc, (float)window->x/screen->width, (float)(screen->height-window->y-window->height)/screen->height, (float)window->width/screen->width, (float)window->height/screen->height);
+ glUniform4f(screen->geometry_loc, (float)window->x/screen->width, (float)(screen->height-window->y-window->height)/screen->height, (float)(window->width+2*window->border)/screen->width, (float)(window->height+2*window->border)/screen->height);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
compositor->glXReleaseTexImageEXT(compositor->display, window->glx_pixmap, GLX_FRONT_LEFT_EXT);
XDamageSubtract(compositor->display, window->damage, None, None);
}
}
- XUngrabServer(compositor->display);
glXSwapBuffers(compositor->display, screen->glx_window);
+
+ screen->dirty = 0;
}
+
+ compositor->dirty = 0;
}
int main()
while(1)
{
- process_event(&compositor);
- refresh_screens(&compositor);
+ if(!process_event(&compositor))
+ refresh_screens(&compositor);
}
shutdown_compositor(&compositor);