]> git.tdb.fi Git - geometrycompositor.git/blobdiff - source/main.c
React to ReparentNotify events
[geometrycompositor.git] / source / main.c
index 3f788848c119c6b230185a3878652566dd7214fd..c37ecc8d86f6f552a9cbe2ac481ad87a30065640 100644 (file)
@@ -2,6 +2,7 @@
 #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>
@@ -16,6 +17,7 @@ typedef struct CompositedWindow
        int y;
        unsigned width;
        unsigned height;
+       unsigned border;
        int map_state;
        Damage damage;
        Pixmap pixmap;
@@ -86,6 +88,15 @@ static const float vertices[] =
        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);
+       (void)display;
+       return 0;
+}
+
 int with_error(const char *message)
 {
        fprintf(stderr, "%s\n", message);
@@ -257,7 +268,11 @@ void add_window(Compositor *compositor, CompositedScreen *screen, Window w)
        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;
 
@@ -277,6 +292,7 @@ void add_window(Compositor *compositor, CompositedScreen *screen, Window w)
        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);
@@ -294,6 +310,31 @@ void add_window(Compositor *compositor, CompositedScreen *screen, Window w)
        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;
@@ -362,6 +403,8 @@ int initialize_screen(Compositor *compositor, unsigned number)
 
        XFree(children);
 
+       screen->dirty = 1;
+
        return 1;
 }
 
@@ -377,6 +420,8 @@ int initialize_compositor(Compositor *compositor)
        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))
@@ -415,25 +460,47 @@ int initialize_compositor(Compositor *compositor)
                if(!initialize_screen(compositor, i))
                        return 0;
 
+       compositor->dirty = 1;
+
        return 1;
 }
 
 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)
@@ -445,6 +512,15 @@ void process_create_window_event(Compositor *compositor, XCreateWindowEvent *eve
        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);
@@ -470,6 +546,18 @@ 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);
@@ -496,12 +584,18 @@ int process_event(Compositor *compositor)
        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);
@@ -526,8 +620,6 @@ 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];
@@ -535,13 +627,12 @@ void refresh_screens(Compositor *compositor)
                        {
                                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;
@@ -550,14 +641,23 @@ void refresh_screens(Compositor *compositor)
        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);