// File: /workspace/github_cpp_makefile_star2_O2/kazzmir[P]xborder/src/main.cpp
// Function: run_xborder(bool)
void run_xborder(bool glow){
    Display * display;

    display = XOpenDisplay(NULL);
    if (display == NULL){
        std::cerr << "Cannot open display" << std::endl;
        return;
    }

    srand(time(NULL));

    XSetErrorHandler(x_error);

    /*
    std::cout << "Once a window has been selected you can press the following keys in the selected window" << std::endl;
    std::cout << "Press 'right alt + right shift' to bring up the options window" << std::endl;
    std::cout << "Press 'left shift + right shift' to close the border" << std::endl;
    */
    std::cout << "Select an existing window to wrap in xborder" << std::endl;
    std::cout << "kill the xborder program with ctrl-c, or press the X window button will also stop the xborder program" << std::endl;

    struct sigaction action;
    action.sa_handler = &handle_signal;
    action.sa_flags = SA_RESTART;
    sigfillset(&action.sa_mask);
    sigaction(SIGHUP, &action, NULL);
    sigaction(SIGINT, &action, NULL);

    int screen = DefaultScreen(display);

    Window child_window = find_terminal(display);
    if (child_window == RootWindow(display, screen) || child_window == 0){
        std::cout << "Invalid window chosen" << std::endl;
        return;
    }
    std::cout << "Child window " << child_window << std::endl;

    int child_x, child_y;
    XWindowAttributes child_attributes;
    XGetWindowAttributes(display, child_window, &child_attributes);
    Window child;
    XTranslateCoordinates(display, child_window, child_attributes.root, 0, 0, &child_x, &child_y, &child);
    // std::cout << "Window at " << child_x << ", " << child_y << std::endl;

    int border_size = 3;

    int use_width = child_attributes.width + border_size * 2;
    int use_height = child_attributes.height + border_size * 2;
    window = XCreateSimpleWindow(display, RootWindow(display, screen), child_x, child_y, use_width, use_height, 1, BlackPixel(display, screen), start_color(display).pixel);

    set_xborder_window(display, window);

    XSelectInput(display, window,
                 ExposureMask |
                 FocusChangeMask |
                 SubstructureNotifyMask |
                 StructureNotifyMask);
    std::cout << "Xborder window " << window << std::endl;
    XMapWindow(display, window);

    Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", false);
    XSetWMProtocols(display, window, &wm_delete_window, 1);

    // delete_properties(display, child_window);
    set_override_redirect(display, child_window, true);

    XReparentWindow(display, child_window, window, border_size, border_size);
    /*
    std::cout << "Child root window " << get_root_window(display, child_window) << std::endl;
    std::cout << "Child parent window " << get_parent_window(display, child_window) << std::endl;
    // xdebug("XReparentWindow: %d\n", XReparentWindow(display, child_window, window, border_size, border_size));
    std::cout << "Child root window after reparent " << get_root_window(display, child_window) << std::endl;
    std::cout << "Child parent window after reparent " << get_parent_window(display, child_window) << std::endl;
    */
    // XSelectInput(display, child_window, KeyPressMask | KeyReleaseMask);
    XMoveWindow(display, window, child_x, child_y);

    Atom wm_protocols_atom = XInternAtom(display, "WM_PROTOCOLS", true);

    bool shift_pressed = false;
    bool alt_pressed = false;

    OptionWindow* optionWindow = NULL;
    // Window option_window = 0;
    // int palette_start = 20;
    std::string window_title = get_window_title(display, child_window);

    GC graphics = NULL;
    XStoreName(display, window, window_title.c_str());

    uint64_t glow_start = time_now();
    int glow_color = rand() % 360;
    int glow_speed = 0;
    if (glow){
        glow_speed = 50;
    }
    
    Atom xborder_atom = XInternAtom(display, "xborder", false);

    while (1){
        if (quit_now){
            std::cout << "Bye!" << std::endl;
            break;
        }

        /* TODO: move all the glow code into an object */
        if (glow_speed > 0){
            uint64_t check = time_now();
            int use_speed = glow_max_speed - glow_speed;
            if (use_speed < 1){
                use_speed = 1;
            }
            int move = (check - glow_start) / use_speed / 2;
            if (move > 0){
                glow_color = (glow_color + move) % 360;
                rgb next_color = get_rgb(glow_color, 1.0, 1.0);
                change_background_color(display, window, next_color);
                glow_start += move * use_speed;
            }
        }

        if (get_parent_window(display, child_window) != window){
            XReparentWindow(display, child_window, window, border_size, border_size);
        }

        if (XPending(display) == 0){
            usleep(1000);
            continue;
        }

        /*
        Window focus;
        int state;
        XGetInputFocus(display, &focus, &state);
        std::cout << "Focus state " << focus << std::endl;
        */

        XEvent event;
        XNextEvent(display, &event);

        if (optionWindow != NULL){
            optionWindow->handleEvent(&event, &glow_speed);
            if (optionWindow->isDead()){
                delete optionWindow;
                optionWindow = NULL;
            }
        }

        if (event.xany.window == window){
            if (event.type == Expose){
                /* anything to do here? the child already seems to get expose events */
            } else if (event.type == FocusIn){
                if (child_window != 0){
                    /* FIXME: somehow the child_window can be destroyed before we get here. check that the child is a valid window? */
                    XSetInputFocus(display, child_window, RevertToPointerRoot, CurrentTime);
                }
            } else if (event.type == ClientMessage){
                XClientMessageEvent * client = &event.xclient;

                // std::cout << "Got client message: " << XGetAtomName(display, client->message_type) << std::endl;

                if (client->message_type == xborder_atom &&
                    client->data.b[0] == XBorderConfigure){
                    std::cout << "Reconfigure xborder" << std::endl;

                    if (optionWindow != NULL){
                        optionWindow->raise();
                    } else {
                        optionWindow = OptionWindow::create(display, window);
                    }
                } else if (client->message_type == wm_protocols_atom &&
                           (Atom) client->data.l[0] == wm_delete_window){
                    break;
                }
            } else if (event.type == DestroyNotify){
                // std::cout << "Child window " << child_window << " event.event " << event.xdestroywindow.event << " event.window " << event.xdestroywindow.window << std::endl;
                /* there is no more child to deal with */
                if (event.xdestroywindow.window == child_window){
                    child_window = 0;
                    break;
                }
            } else if (event.type == ConfigureNotify){
                XWindowAttributes self;
                XGetWindowAttributes(display, window, &self);
                XResizeWindow(display, child_window, self.width - border_size * 2, self.height - border_size * 2);
            }
        }
    }

    if (optionWindow != NULL){
        delete optionWindow;
        optionWindow = NULL;
    }

    if (child_window != 0){
        set_override_redirect(display, child_window, false);
        Window child_root = child_attributes.root;
        /* Place the window wherever the container is now */
        XGetWindowAttributes(display, window, &child_attributes);
        XReparentWindow(display, child_window, child_root, child_attributes.x, child_attributes.y);
        XTranslateCoordinates(display, window, child_attributes.root, 0, 0, &child_x, &child_y, &child);
        XMoveWindow(display, child_window, child_x, child_y - border_size * 2);
    }

    XDestroyWindow(display, window);
    XCloseDisplay(display);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2f8, %rsp            # imm = 0x2F8
movl %edi, %r15d
xorl %edi, %edi
callq 0x33b0
testq %rax, %rax
je 0x47b9
movq %rax, %rbx
xorl %edi, %edi
callq 0x3270
movl %eax, %edi
callq 0x32a0
leaq -0x43d(%rip), %rdi      # 0x3e51
callq 0x30d0
movq 0x4d36(%rip), %r14      # 0x8fd0
leaq 0x1f5f(%rip), %rsi      # 0x6200
movq %r14, %rdi
callq 0x32b0
movq %rax, %rdi
callq 0x3140
leaq 0x1f75(%rip), %rsi      # 0x622d
movq %r14, %rdi
callq 0x32b0
movq %rax, %rdi
callq 0x3140
leaq -0x4d6(%rip), %rax      # 0x3df9
leaq -0x310(%rbp), %rdi
movq %rax, -0x8(%rdi)
movl $0x10000000, 0x80(%rdi) # imm = 0x10000000
callq 0x30e0
pushq $0x1
popq %rdi
leaq -0x318(%rbp), %r14
movq %r14, %rsi
xorl %edx, %edx
callq 0x3370
pushq $0x2
popq %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0x3370
movslq 0xe0(%rbx), %r12
movq %rbx, %rdi
callq 0x38d6
testq %rax, %rax
je 0x47e5
movq %rax, %r14
movq 0xe8(%rbx), %rax
shlq $0x7, %r12
cmpq 0x10(%rax,%r12), %r14
je 0x47e5
movl %r15d, -0x54(%rbp)
movq 0x4c8a(%rip), %rdi      # 0x8fd0
leaq 0x1f5c(%rip), %rsi      # 0x62a9
callq 0x32b0
movq %rax, %rdi
movq %r14, %rsi
callq 0x31c0
movq %rax, %rdi
callq 0x3140
leaq -0x1f8(%rbp), %r13
movq %rbx, %rdi
movq %r14, %rsi
movq %r13, %rdx
callq 0x3520
movq 0x20(%r13), %rdx
leaq -0x78(%rbp), %rax
leaq -0x30(%rbp), %r10
leaq -0x34(%rbp), %r9
movq %rbx, %rdi
movq %r14, %rsi
xorl %ecx, %ecx
xorl %r8d, %r8d
pushq %rax
pushq %r10
callq 0x34e0
addq $0x10, %rsp
movl 0x8(%r13), %r15d
movl 0xc(%r13), %r13d
addl $0x6, %r15d
addl $0x6, %r13d
movq 0xe8(%rbx), %rax
leaq -0x34(%rbp), %rcx
movl (%rcx), %ecx
movl %ecx, -0x2c(%rbp)
leaq -0x30(%rbp), %rcx
movl (%rcx), %ecx
movl %ecx, -0x40(%rbp)
movq 0x10(%rax,%r12), %rcx
movq %rcx, -0x50(%rbp)
movq %r14, -0x68(%rbp)
movq 0x60(%rax,%r12), %r14
movq %rbx, %rdi
callq 0x3e06
subq $0x8, %rsp
movq %rbx, %rdi
movq -0x50(%rbp), %rsi
movl -0x2c(%rbp), %edx
movl -0x40(%rbp), %ecx
movl %r15d, %r8d
movl %r13d, %r9d
pushq %rax
pushq %r14
movq -0x68(%rbp), %r13
pushq $0x1
callq 0x30c0
addq $0x20, %rsp
movq %rax, 0x4ef4(%rip)      # 0x9308
movq %rbx, %rdi
movq %rax, %rsi
callq 0x420a
movq 0x4ee2(%rip), %rsi      # 0x9308
movl $0x2a8000, %edx         # imm = 0x2A8000
movq %rbx, %rdi
callq 0x31b0
leaq 0x1e7d(%rip), %rsi      # 0x62b7
movq 0x4b8f(%rip), %rdi      # 0x8fd0
callq 0x32b0
movq 0x4ebb(%rip), %rsi      # 0x9308
movq %rax, %rdi
callq 0x31c0
movq %rax, %rdi
callq 0x3140
movq 0x4ea4(%rip), %rsi      # 0x9308
movq %rbx, %rdi
callq 0x3320
leaq 0x1e54(%rip), %rsi      # 0x62c7
movq %rbx, %rdi
xorl %edx, %edx
callq 0x31f0
leaq -0x70(%rbp), %rdx
movq %rax, (%rdx)
movq 0x4e7d(%rip), %rsi      # 0x9308
pushq $0x1
popq %r15
movq %rbx, %rdi
movl %r15d, %ecx
callq 0x3180
movq %rbx, %rdi
movq %r13, %rsi
movl %r15d, %edx
callq 0x41a2
movq 0x4e59(%rip), %rdx      # 0x9308
pushq $0x3
popq %rcx
movq %rbx, %rdi
movq %r13, %rsi
movl %ecx, %r8d
callq 0x3030
movq 0x4e41(%rip), %rsi      # 0x9308
leaq -0x34(%rbp), %rax
movl (%rax), %edx
leaq -0x30(%rbp), %rax
movl (%rax), %ecx
movq %rbx, %rdi
callq 0x3230
leaq 0x1df6(%rip), %rsi      # 0x62d8
movq %rbx, %rdi
movl %r15d, %edx
callq 0x31f0
movq %rax, -0x60(%rbp)
leaq -0xb0(%rbp), %r15
movq %r15, %rdi
movq %rbx, %rsi
movq %r13, %rdx
callq 0x3fa8
movq 0x4dfb(%rip), %rsi      # 0x9308
movq (%r15), %rdx
movq %rbx, %rdi
callq 0x3050
callq 0x3c88
movq %rax, %r15
callq 0x3080
movl %eax, %r12d
cmpb $0x0, -0x54(%rbp)
pushq $0x32
popq %rax
movl $0x0, %ecx
cmovel %ecx, %eax
movl %eax, -0x44(%rbp)
leaq 0x1db5(%rip), %rsi      # 0x62f6
movq %rbx, %rdi
xorl %edx, %edx
callq 0x31f0
movq %rax, -0x50(%rbp)
movl $0x168, %ecx            # imm = 0x168
movl %r12d, %eax
cltd
idivl %ecx
movl %edx, -0x2c(%rbp)
movq $0x0, -0x40(%rbp)
movb 0x4d96(%rip), %al       # 0x9301
cmpb $0x1, %al
je 0x4805
cmpl $0x0, -0x44(%rbp)
jle 0x4611
callq 0x3c88
pushq $0x64
popq %rcx
movl %ecx, %r14d
subl -0x44(%rbp), %r14d
cmpl $0x2, %r14d
pushq $0x1
popq %rcx
cmovll %ecx, %r14d
movq %r15, %r12
subq %r15, %rax
xorl %edx, %edx
divq %r14
movq %rax, %r15
shrq %r15
testl %r15d, %r15d
jle 0x460e
movl -0x2c(%rbp), %eax
addl %r15d, %eax
cltd
movl $0x168, %ecx            # imm = 0x168
idivl %ecx
leaq -0x90(%rbp), %rdi
movl %edx, -0x2c(%rbp)
movl %edx, %esi
movss 0x1a9d(%rip), %xmm0     # 0x606c
movaps %xmm0, %xmm1
callq 0x3b8f
movq 0x4d2a(%rip), %rsi      # 0x9308
subq $0x20, %rsp
movq -0x80(%rbp), %rax
movq %rax, 0x10(%rsp)
movups -0x90(%rbp), %xmm0
movups %xmm0, (%rsp)
movq %rbx, %rdi
callq 0x3da2
addq $0x20, %rsp
imull %r15d, %r14d
movq %r12, %r15
addq %r14, %r15
jmp 0x4611
movq %r12, %r15
movq %rbx, %rdi
movq %r13, %rsi
callq 0x41c1
movq 0x4ce5(%rip), %rdx      # 0x9308
cmpq %rdx, %rax
je 0x4639
movq %rbx, %rdi
movq %r13, %rsi
pushq $0x3
popq %rcx
movl %ecx, %r8d
callq 0x3030
movq %rbx, %rdi
callq 0x3260
testl %eax, %eax
jne 0x4654
movl $0x3e8, %edi            # imm = 0x3E8
callq 0x33c0
jmp 0x4565
movq %rbx, %rdi
leaq -0x170(%rbp), %rsi
callq 0x33d0
movq -0x40(%rbp), %r12
testq %r12, %r12
je 0x4691
movq %r12, %rdi
leaq -0x170(%rbp), %rsi
leaq -0x44(%rbp), %rdx
callq 0x4c44
cmpb $0x1, 0x28(%r12)
jne 0x4699
movq (%r12), %rax
movq %r12, %rdi
callq *0x8(%rax)
movq $0x0, -0x40(%rbp)
movq -0x150(%rbp), %rsi
cmpq 0x4c61(%rip), %rsi      # 0x9308
jne 0x4565
movl -0x170(%rbp), %eax
cmpl $0xc, %eax
je 0x4565
cmpl $0x16, %eax
je 0x4700
cmpl $0x21, %eax
jne 0x4731
movq -0x148(%rbp), %rax
cmpq -0x50(%rbp), %rax
jne 0x46e0
cmpb $0x0, -0x138(%rbp)
je 0x476b
cmpq -0x60(%rbp), %rax
jne 0x4565
movq -0x138(%rbp), %rax
cmpq -0x70(%rbp), %rax
jne 0x4565
jmp 0x4820
movq %rbx, %rdi
leaq -0x280(%rbp), %rdx
callq 0x3520
movl -0x278(%rbp), %edx
movl -0x274(%rbp), %ecx
addl $-0x6, %edx
addl $-0x6, %ecx
movq %rbx, %rdi
movq %r13, %rsi
callq 0x3430
jmp 0x4565
cmpl $0x11, %eax
je 0x4759
cmpl $0x9, %eax
jne 0x4565
testq %r13, %r13
je 0x4799
movq %rbx, %rdi
movq %r13, %rsi
pushq $0x1
popq %rdx
xorl %ecx, %ecx
callq 0x3200
jmp 0x4565
cmpq %r13, -0x148(%rbp)
jne 0x4565
jmp 0x48ee
movq 0x485e(%rip), %rdi      # 0x8fd0
leaq 0x1b71(%rip), %rsi      # 0x62ea
callq 0x32b0
movq %rax, %rdi
callq 0x3140
movq -0x40(%rbp), %rdi
testq %rdi, %rdi
je 0x47a1
callq 0x4f4a
jmp 0x4565
xorl %r13d, %r13d
jmp 0x4565
movq 0x4b60(%rip), %rsi      # 0x9308
movq %rbx, %rdi
callq 0x4f5c
movq %rax, -0x40(%rbp)
jmp 0x4565
movq 0x4830(%rip), %rdi      # 0x8ff0
leaq 0x1a25(%rip), %rsi      # 0x61ec
callq 0x32b0
movq %rax, %rdi
addq $0x2f8, %rsp            # imm = 0x2F8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x3140
movq 0x47e4(%rip), %rdi      # 0x8fd0
leaq 0x1aa0(%rip), %rsi      # 0x6293
callq 0x32b0
movq %rax, %rdi
callq 0x3140
jmp 0x48dc
movq 0x47c4(%rip), %rdi      # 0x8fd0
leaq 0x1ad2(%rip), %rsi      # 0x62e5
callq 0x32b0
movq %rax, %rdi
callq 0x3140
movq -0x40(%rbp), %rdi
testq %rdi, %rdi
je 0x482f
movq (%rdi), %rax
callq *0x8(%rax)
testq %r13, %r13
je 0x48b9
movq %rbx, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x41a2
leaq -0x1f8(%rbp), %rdx
movq 0x20(%rdx), %r15
movq 0x4ab1(%rip), %rsi      # 0x9308
movq %rbx, %rdi
callq 0x3520
movl -0x1f8(%rbp), %ecx
movl -0x1f4(%rbp), %r8d
movq %rbx, %rdi
movq %r13, %rsi
movq %r15, %rdx
callq 0x3030
movq 0x4a87(%rip), %rsi      # 0x9308
movq -0x1d8(%rbp), %rdx
leaq -0x34(%rbp), %r9
movq %rbx, %rdi
xorl %ecx, %ecx
xorl %r8d, %r8d
leaq -0x78(%rbp), %rax
pushq %rax
leaq -0x30(%rbp), %rax
pushq %rax
callq 0x34e0
popq %rcx
popq %rdx
movl -0x34(%rbp), %edx
movl -0x30(%rbp), %ecx
addl $-0x6, %ecx
movq %rbx, %rdi
movq %r13, %rsi
callq 0x3230
movq 0x4a48(%rip), %rsi      # 0x9308
movq %rbx, %rdi
callq 0x3480
movq %rbx, %rdi
callq 0x3560
leaq -0xb0(%rbp), %rdi
callq 0x3130
addq $0x2f8, %rsp            # imm = 0x2F8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
xorl %r13d, %r13d
jmp 0x4820
jmp 0x4906
jmp 0x4906
jmp 0x4906
jmp 0x4906
jmp 0x4906
jmp 0x4906
jmp 0x4906
jmp 0x4906
movq %rax, %rbx
leaq -0xb0(%rbp), %rdi
callq 0x3130
movq %rbx, %rdi
callq 0x3510