#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xos.h>
#include <X11/Xutil.h>

#include <stdio.h>

Atom _XA_WM_PROTOCOLS;
Atom _XA_WM_TAKE_FOCUS; 

Display *display;
int screen_num;
Window root;

char *atomName, *atomValue;

Window create_window(char * name, Window parent, int x, int y, int width, int height) 
{
    XSizeHints *hints = XAllocSizeHints();
    XWMHints *wmHints = XAllocWMHints();

    Window win = XCreateSimpleWindow(display, parent, x, y, width, height,
                              2, // border width
                              BlackPixel(display, screen_num),
                              WhitePixel(display, screen_num));                 
    XStoreName(display, win, name);
    XSelectInput(display, win, ButtonPressMask | KeyPressMask);
    
    hints->width = width;
    hints->height = height;
    hints->x = x;
    hints->y = y;
    hints->flags = USPosition | USSize;
    XSetWMNormalHints(display, win, hints);
    XFree(hints);

    wmHints->input = False;
    wmHints->flags = InputHint;
    XSetWMHints(display, win, wmHints);
    XFree(wmHints);

    return win;
}

int main(int argc, char **argv)
{
    Window f1, d1, f2;
    XEvent ev;
    XClientMessageEvent cmev;

    long wm_protocols_data[1];

    char *display_name = NULL;
    if ((display = XOpenDisplay(display_name)) == NULL)
    {
        fprintf(stderr, "Couldn't open %s\n", XDisplayName(display_name));
        return -1;
    }
    screen_num = DefaultScreen(display);
    root = RootWindow(display, screen_num);

    _XA_WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", False);
    _XA_WM_TAKE_FOCUS = XInternAtom(display, "WM_TAKE_FOCUS", False);

    // create windows
    f1 = create_window("F1", root, 100, 100, 200, 100);
    d1 = create_window("D1", root, 150, 150, 200, 100);
    f2 = create_window("F2", root, 300, 300, 200, 100);

    // make d1 a child (Java-style) of f1
    XSetTransientForHint(display, d1, f1);

    // set WM_PROTOCOLS for all windows to WM_TAKE_FOCUS
    wm_protocols_data[0] = _XA_WM_TAKE_FOCUS;
    XChangeProperty(display, f1, _XA_WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace,
                    (unsigned char *)wm_protocols_data, 1);
    XChangeProperty(display, d1, _XA_WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace,
                    (unsigned char *)wm_protocols_data, 1);
    XChangeProperty(display, f2, _XA_WM_PROTOCOLS, XA_ATOM, 32, PropModeReplace,
                    (unsigned char *)wm_protocols_data, 1);

    XMapWindow(display, f1);
    XMapWindow(display, d1);
    XMapWindow(display, f2);

    XFlush(display);
    XSync(display, False);

    while (1)
    {
        XNextEvent(display, &ev);
        if (ev.type == ClientMessage)
        {
            cmev = ev.xclient;
            if (cmev.message_type == _XA_WM_PROTOCOLS)
            {
                fprintf(stderr, "WM_PROTOCOLS client message received\n");
                if ((cmev.window == f2) || (cmev.window == d1))
                {
                    fprintf(stderr, "Accepted\n");
                    XSetInputFocus(display, cmev.window, RevertToPointerRoot, cmev.data.l[1]);
                }
                else
                {
                    fprintf(stderr, "Declined\n");
                }
                fprintf(stderr, "\n");
            }
        }
        else
        {
            fprintf(stderr, "Another message received\n");
        }
        XFlush(display);
    }
    
    return 0;
}

