#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <signal.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
1.0f, 0.0f
};
+int terminate_requested = 0;
+
int x_error_handler(Display *display, XErrorEvent *event)
{
printf("Ignoring X error %d on resource %lx\n", event->error_code, event->resourceid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
+void remove_window(Compositor *compositor, CompositedScreen *screen, Window w, int destroyed)
+{
+ unsigned i;
+
+ for(i=0; i<screen->nwindows; ++i)
+ if(screen->windows[i].window==w)
+ {
+ glDeleteTextures(1, &screen->windows[i].texture);
+ if(!destroyed)
+ {
+ XDamageDestroy(compositor->display, screen->windows[i].damage);
+ if(screen->windows[i].pixmap)
+ {
+ glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
+ XFreePixmap(compositor->display, screen->windows[i].pixmap);
+ }
+ XCompositeUnredirectWindow(compositor->display, screen->windows[i].window, CompositeRedirectManual);
+ }
+
+ --screen->nwindows;
+ for(; i<screen->nwindows; ++i)
+ screen->windows[i] = screen->windows[i+1];
+ }
+}
+
CompositedScreen *find_screen_by_root(Compositor *compositor, Window root)
{
unsigned i;
void shutdown_screen(Compositor *compositor, CompositedScreen *screen)
{
+ unsigned i;
+
+ use_gl(compositor, screen);
+
+ for(i=0; i<screen->nwindows; ++i)
+ {
+ glDeleteTextures(1, &screen->windows[i].texture);
+ if(screen->windows[i].pixmap)
+ {
+ glXDestroyPixmap(compositor->display, screen->windows[i].glx_pixmap);
+ XFreePixmap(compositor->display, screen->windows[i].pixmap);
+ XDamageDestroy(compositor->display, screen->windows[i].damage);
+ }
+ }
+
+ glXMakeContextCurrent(compositor->display, 0, 0, NULL);
glXDestroyContext(compositor->display, screen->glx_context);
glXDestroyWindow(compositor->display, screen->glx_window);
XDestroyWindow(compositor->display, screen->render_window);
XCompositeReleaseOverlayWindow(compositor->display, screen->overlay);
+
+ free(screen->windows);
}
void shutdown_compositor(Compositor *compositor)
{
unsigned i;
- glXMakeContextCurrent(compositor->display, 0, 0, NULL);
for(i=0; i<compositor->nscreens; ++i)
shutdown_screen(compositor, &compositor->screens[i]);
+ free(compositor->screens);
+
+ XCloseDisplay(compositor->display);
}
void process_create_window_event(Compositor *compositor, XCreateWindowEvent *event)
add_window(compositor, screen, event->window);
}
+void process_destroy_window_event(Compositor *compositor, XDestroyWindowEvent *event)
+{
+ CompositedScreen *screen = find_screen_by_root(compositor, event->event);
+ if(!screen)
+ return;
+
+ remove_window(compositor, screen, event->window, 1);
+}
+
void process_map_event(Compositor *compositor, XMapEvent *event)
{
CompositedScreen *screen = find_screen_by_root(compositor, event->event);
return;
CompositedWindow *window = find_window(screen, event->window);
- if(window)
- {
- window->map_state = IsViewable;
- create_window_pixmap(compositor, screen, window);
- }
+ if(!window)
+ return;
+
+ window->map_state = IsViewable;
+ create_window_pixmap(compositor, screen, window);
}
void process_unmap_event(Compositor *compositor, XUnmapEvent *event)
window->map_state = IsUnviewable;
}
+void process_reparent_event(Compositor *compositor, XReparentEvent *event)
+{
+ CompositedScreen *screen = find_screen_by_root(compositor, event->event);
+ if(!screen)
+ return;
+
+ if(event->parent==screen->root)
+ add_window(compositor, screen, event->window);
+ else
+ remove_window(compositor, screen, event->window, 0);
+}
+
void process_damage_event(Compositor *compositor, XDamageNotifyEvent *event)
{
CompositedScreen *screen = find_screen_by_window(compositor, event->drawable);
case CreateNotify:
process_create_window_event(compositor, &event.xcreatewindow);
break;
+ case DestroyNotify:
+ process_destroy_window_event(compositor, &event.xdestroywindow);
+ break;
case MapNotify:
process_map_event(compositor, &event.xmap);
break;
case UnmapNotify:
process_unmap_event(compositor, &event.xunmap);
break;
+ case ReparentNotify:
+ process_reparent_event(compositor, &event.xreparent);
+ break;
default:
if(event.type==compositor->damage_event+XDamageNotify)
process_damage_event(compositor, (XDamageNotifyEvent *)&event);
compositor->dirty = 0;
}
+void sighandler(int sig)
+{
+ terminate_requested = 1;
+ (void)sig;
+}
+
int main()
{
Compositor compositor;
+ signal(SIGINT, &sighandler);
+ signal(SIGTERM, &sighandler);
+
if(!initialize_compositor(&compositor))
return 1;
- while(1)
+ while(!terminate_requested)
{
if(!process_event(&compositor))
refresh_screens(&compositor);