1 /*
    2   gcc -lXcomposite -lXrender -lX11 xcomposite.c
    3  */
    4 #include <X11/X.h>
    5 #include <X11/Xlib.h>
    6 #include <X11/Xutil.h>
    7 
    8 #include <X11/extensions/Xcomposite.h>
    9 #include <X11/extensions/Xrender.h>
   10 
   11 #include <string.h>
   12 #include <stdlib.h>
   13 #include <stdio.h>
   14 
   15 int main(void)
   16 {
   17         int run = 1, status = EXIT_FAILURE, evbase, errbase;
   18         unsigned int width = 640, height = 480;
   19         Window wnd, wnd1, wnd2, wnd_mouse = 0;
   20         XRenderPictFormat* format;
   21         Atom atom_wm_delete;
   22         Picture wndpic;
   23         Display* dpy;
   24         Picture pic;
   25         XEvent e;
   26 
   27         /* open a conenction to the display server */
   28         dpy = XOpenDisplay(NULL);
   29         if (!dpy)
   30                 return EXIT_FAILURE;
   31 
   32         if (!XCompositeQueryExtension(dpy, &evbase, &errbase)) {
   33                 fputs("XComposite extension missing!\n", stderr);
   34                 goto outdpy;
   35         }
   36 
   37         if (!XRenderQueryExtension(dpy, &evbase, &errbase)) {
   38                 fputs("XRender extension missing!\n", stderr);
   39                 goto outdpy;
   40         }
   41 
   42         atom_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", True);
   43 
   44         /* create window with an XRender context */
   45         wnd = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
   46                                   0, 0, width, height, 0, 0, 0);
   47 
   48         if (!wnd)
   49                 goto outdpy;
   50 
   51         format = XRenderFindStandardFormat(dpy, PictStandardRGB24);
   52         pic = XRenderCreatePicture(dpy, wnd, format, 0, NULL);
   53         if (!pic)
   54                 goto outpic;
   55 
   56         XSelectInput(dpy, wnd, ExposureMask | PointerMotionMask);
   57         XSetWMProtocols(dpy, wnd, &atom_wm_delete, 1);
   58         XFlush(dpy);
   59 
   60         XStoreName(dpy, wnd, "X11 test");
   61         XMapWindow(dpy, wnd);
   62 
   63         /*
   64           Create child window at (10,10) from the top left that
   65           has half the size of the parent window
   66         */
   67         wnd1 = XCreateSimpleWindow(dpy, wnd, 10, 10, width / 2, height / 2,
   68                                    0, 0, 0xFFFFFFFF);
   69 
   70         if (!wnd1)
   71                 goto outwnd;
   72 
   73         XSelectInput(dpy, wnd1, ExposureMask | PointerMotionMask);
   74         XMapWindow(dpy, wnd1);
   75         XFlush(dpy);
   76 
   77         /*
   78           Use XComposite to redirect the window, create an XRender picture
   79           that we use to actually draw it.
   80          */
   81         XCompositeRedirectWindow(dpy, wnd1, CompositeRedirectManual);
   82 
   83         wndpic = XRenderCreatePicture(dpy, wnd1, format, 0, NULL);
   84         if (!wndpic)
   85                 goto outpic1;
   86 
   87         /*
   88           Create a nested child inside child the window. This one will be
   89           blissfully unaware that it's are being redirected and composited.
   90           We also don't need to care about the compositing and rendering of
   91           that one.
   92          */
   93         wnd2 = XCreateSimpleWindow(dpy, wnd1, 10, 10,
   94                                    width / 8, height / 8, 0, 0,
   95                                    0xFFFF0000);
   96         if (!wnd2)
   97                 goto outwnd1;
   98 
   99         XSelectInput(dpy, wnd2, ExposureMask | PointerMotionMask);
  100         XMapWindow(dpy, wnd2);
  101         XFlush(dpy);
  102 
  103         /* event loop */
  104         while (run) {
  105                 XNextEvent(dpy, &e);
  106 
  107                 switch (e.type) {
  108                 case MotionNotify:
  109                         if (wnd_mouse == e.xany.window)
  110                                 break;
  111 
  112                         wnd_mouse = e.xany.window;
  113 
  114                         /*
  115                           You will see, the composited windows and sub-windows
  116                           still receive events as normal. The XServer pretends
  117                           they are still there and expects us to render them
  118                           at their position.
  119                          */
  120                         printf("Pointer inside %s\n",
  121                                wnd_mouse == wnd  ? "main window" :
  122                                wnd_mouse == wnd1 ? "composited sub window" :
  123                                wnd_mouse == wnd2 ? "sub-sub window" :
  124                                "dunno?");
  125                         break;
  126                 case Expose:
  127                         XClearWindow(dpy, e.xany.window);
  128 
  129                         /*
  130                           Composite the sub-window onto the main window
  131                          */
  132                         if (e.xany.window == wnd || e.xany.window == wnd1) {
  133                                 XRenderComposite(dpy, PictOpOver, wndpic, 0, pic,
  134                                                  0, 0, 0, 0,
  135                                                  10, 10, width / 2, height / 2);
  136                         }
  137 
  138                         XFlush(dpy);
  139                         break;
  140                 case ClientMessage:
  141                         if (e.xclient.data.l[0] == (long)atom_wm_delete) {
  142                                 XUnmapWindow(dpy, wnd);
  143                                 run = 0;
  144                         }
  145                         break;
  146                 }
  147         }
  148 
  149         status = EXIT_SUCCESS;
  150 
  151         /* cleanup */
  152         XDestroyWindow(dpy, wnd2);
  153 outwnd1:
  154         XRenderFreePicture(dpy, wndpic);
  155 outpic1:
  156         XDestroyWindow(dpy, wnd1);
  157 outwnd:
  158         XRenderFreePicture(dpy, pic);
  159 outpic:
  160         XDestroyWindow(dpy, wnd);
  161 outdpy:
  162         XCloseDisplay(dpy);
  163         return status;
  164 }