2

Why does the following X11/Xorg code not hide the mouse cursor under Ubuntu 18.04? If this is not the way to do it what is? Is there some missing dependency/library/.dev package?

My intuition says this may be a bug in Ubuntu's (or Debian) X11/Xorg packages or some such. This is how Haxe/Kha does Mouse hiding in order to be compatible across platforms.

#include <iostream>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>

#include <string>
#include <iostream>

Window window;
void show();

int main()
{
    Display *display;
    XEvent e;
    std::string msg = "Hello, World!";
    int screen;

    display = XOpenDisplay(nullptr);
    if (display == nullptr)
    {
        std::cerr << "Cannot open display\n";
        throw;
    }

    screen = XDefaultScreen(display);
    window = XCreateSimpleWindow(display, RootWindow(display, screen), 10, 10, 500, 500, 1,
                                 BlackPixel(display, screen), WhitePixel(display, screen));
    XStoreName(display, window, "Silly Window");
    XSelectInput(display, window, ExposureMask | KeyPressMask );
    XMapWindow(display, window);

    while (true)
    {
        XNextEvent(display, &e);
        if (e.type == Expose)
        {
            std::cout << "Window Exposed!\n";
            XExposeEvent ev = e.xexpose;
            if (ev.window != window) continue;
            XFillRectangle(display, window, DefaultGC(display, screen), 50, 50, 400, 50);
            XDrawString(display, window, DefaultGC(display, screen), 220, 220, msg.c_str(), msg.length());
            XFillRectangle(display, window, DefaultGC(display, screen), 50, 400, 400, 50);
        }
        else if (e.type == KeyPress)
        {
            char buf[128] = {0};
            KeySym keysym;
            int len = XLookupString(&e.xkey, buf, sizeof buf, &keysym, NULL);
            if (keysym == XK_Escape)
            {
                break;
            }
            else if (keysym == XK_space)
            {
                show();
                XAllowEvents(display, SyncBoth, CurrentTime);
            }
        }

    }

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

bool toggle = false;
void show()
{
    Display* dpy = XOpenDisplay(0);
    if (toggle)
    {
        std::cout << "toggle On\n";
        XUndefineCursor(dpy, window);
    }
    else
    {
        std::cout << "toggle Off\n";
        XColor col;
        char data[1] = {0X00};
        Pixmap blank = XCreateBitmapFromData(dpy, window, data, 1, 1);
        Cursor cursor = XCreatePixmapCursor(dpy, blank, blank, &col, &col, 0, 0);
        XDefineCursor(dpy, window, cursor);
        // XSetWindowAttributes wa;
        // XChangeWindowAttributes(dpy, window, CWCursor, &wa);
        // wa.cursor = cursor;
        XFreePixmap(dpy, blank);
    }
    toggle = !toggle;
}
Gama11
  • 31,714
  • 9
  • 78
  • 100
vivichrist
  • 309
  • 2
  • 9
  • 1
    The best way these days is to use the Xfixes extension. Have a look at unclutter-xfixes on Github (disclaimer: it's my project) if you wanna see an example. – Ingo Bürk Aug 31 '18 at 21:32
  • Ok will look into it... – vivichrist Sep 01 '18 at 02:45
  • A further addendum, I would like the mouse cursor to show up again if the mouse leaves the root window and disappear when entering the root window again, if it is hidden. Is there any easy way of doing this besides having to program it of which I have done but it's not pretty. – vivichrist Sep 07 '18 at 04:05

1 Answers1

2

Yes I can confirm that is code definitely works

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xfixes.h>
#include <string>
#include <iostream>

Window window;
void show(Display *dispy);

int main()
{
    Display *display;
    XEvent e;
    std::string msg = "Hello, World!";
    int screen;

    display = XOpenDisplay(nullptr);
    if (display == nullptr)
    {
        std::cerr << "Cannot open display\n";
        throw;
    }

    screen = XDefaultScreen(display);
    window = XCreateSimpleWindow(display, RootWindow(display, screen), 10, 10, 500, 500, 1,
                                 BlackPixel(display, screen), WhitePixel(display, screen));
    XStoreName(display, window, "Silly Window");
    XSelectInput(display, window, ExposureMask | KeyPressMask );
    XMapWindow(display, window);

    while (true)
    {
        XNextEvent(display, &e);
        if (e.type == Expose)
        {
            std::cout << "Window Exposed!\n";
            XExposeEvent ev = e.xexpose;
            if (ev.window != window) continue;
            XFillRectangle(display, window, DefaultGC(display, screen), 50, 50, 400, 50);
            XDrawString(display, window, DefaultGC(display, screen), 220, 150, msg.c_str(), msg.length());
            XDrawString(display, window, DefaultGC(display, screen), 220, 220, msg.c_str(), msg.length());
            XDrawString(display, window, DefaultGC(display, screen), 220, 300, msg.c_str(), msg.length());
            XFillRectangle(display, window, DefaultGC(display, screen), 50, 400, 400, 50);
        }
        else if (e.type == KeyPress)
        {
            char buf[128] = {0};
            KeySym keysym;
            XLookupString(&e.xkey, buf, sizeof buf, &keysym, NULL);
            if (keysym == XK_Escape)
            {
                break;
            }
            else if (keysym == XK_space)
            {
                show(display);
                XAllowEvents(display, SyncBoth, CurrentTime);
            }
        }

    }

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

bool toggle = true;
void show(Display *dpy)
{
    if (toggle)
    {
        std::cout << "toggle On->Off\n";
        XFixesHideCursor(dpy, window);
        XFlush(dpy);
    }
    else
    {
        std::cout << "toggle Off->On\n";
        XFixesShowCursor(dpy, window);
        XFlush(dpy);
    }
    toggle = !toggle;
}
vivichrist
  • 309
  • 2
  • 9