Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 15/03/2015, à 19:30

Lolichou

Xunmapwindow : fenêtre toujours visible!

Salut, je suis entrain de créer une classe qui affiche et traite les événements pour une fenêtre X11.

Le problème c'est que je n'arrive pas à la rendre visible, voici le code source de la fenêtre :

#include "../../../include/odfaeg/Window/x11Window.hpp"
#include <iostream>
#include <chrono>
namespace {
    // Filter the events received by windows (only allow those matching a specific window)
    Bool checkEvent(::Display*, XEvent* event, XPointer userData)
    {
        // Just check if the event matches the window
        return event->xany.window == reinterpret_cast< ::Window >(userData);
    }
}
namespace odfaeg {
    namespace window {
        using namespace sf;
        Display* X11Window::display = nullptr;
        unsigned int X11Window::nbWindowCreated = 0;
        X11Window::X11Window() {
            opened = false;
            inputContext = nullptr;
            inputMethod = nullptr;
            atomClose = 0;
        }
        X11Window::X11Window(unsigned int width, unsigned int height, std::string title) {
            opened = false;
            inputContext = nullptr;
            inputMethod = nullptr;
            atomClose = 0;
            create(width, height, title);
        }
        void X11Window::create (unsigned int width, unsigned int height, std::string title) {
            if (display == nullptr)
                display = XOpenDisplay(nullptr);
            if (display == nullptr) {
                std::cerr<<"Cannot open display!"<<std::endl;
                exit(1);
            }
            screen = DefaultScreen(display);
            window = XCreateSimpleWindow(display, RootWindow(display, screen),
                                         (DisplayWidth(display, screen) - width) * 0.5f, (DisplayHeight(display, screen) - height) * 0.5f,
                                          width, height, 1, BlackPixel(display, screen), WhitePixel(display, screen));
            std::basic_string<Uint8> utf8Title;
            Utf32::toUtf8(title.begin(), title.end(), std::back_inserter(utf8Title));

            // Set the _NET_WM_NAME atom, which specifies a UTF-8 encoded window title.
            Atom wmName = XInternAtom(display, "_NET_WM_NAME", False);
            Atom useUtf8 = XInternAtom(display, "UTF8_STRING", False);
            XChangeProperty(display, window, wmName, useUtf8, 8,
                            PropModeReplace, utf8Title.c_str(), utf8Title.size());
            // Set the non-Unicode title as a fallback for window managers who don't support _NET_WM_NAME.
            XStoreName(display, window, title.c_str());
            XSelectInput(display, window, FocusChangeMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
                                          PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask |
                                          EnterWindowMask | LeaveWindowMask);
            // Get the atom defining the close event
            atomClose = XInternAtom(display, "WM_DELETE_WINDOW", false);
            XSetWMProtocols(display, window, &atomClose, 1);

            // Create the input context
            inputMethod = XOpenIM(display, NULL, NULL, NULL);
            if (inputMethod)
            {
                inputContext = XCreateIC(inputMethod,
                                           XNClientWindow, window,
                                           XNFocusWindow,  window,
                                           XNInputStyle,   XIMPreeditNothing  | XIMStatusNothing,
                                           (void*)NULL);
            }
            else
            {
                inputContext = NULL;
            }
            if (!inputContext)
                std::cerr<<"Failed to create input context for window -- TextEntered event won't be able to return unicode" << std::endl;
            XMapWindow(display, window);
            XFlush(display);
            nbWindowCreated++;
            opened = true;
        }
        void X11Window::setPosition(unsigned int x, unsigned int y) {
            XMoveWindow(display, window, x, y);
            XFlush(display);
        }
        void X11Window::setVisible(bool visible) {
            if (visible) {
                XMapWindow(display, window);
            } else {
                XUnmapWindow(display, window);
            }
            XFlush(display);
        }
        bool X11Window::pollEvent(IEvent& event) {

            XEvent xevent;
            if (opened && XCheckIfEvent(display, &xevent, &checkEvent, reinterpret_cast<XPointer>(window))) {
                if ((xevent.xclient.format == 32) && (xevent.xclient.data.l[0]) == static_cast<long>(atomClose))
                {
                    event.type = IEvent::EventType::WINDOW_EVENT;
                    std::chrono::time_point<std::chrono::system_clock> time = std::chrono::system_clock::now();
                    event.window.type = IEvent::EventType::WINDOW_EVENT;
                    event.window.timestamp = std::chrono::system_clock::to_time_t(time);
                    event.window.windowID = reinterpret_cast<unsigned long long int>(&window);
                    event.window.event = IEvent::WindowEventID::WINDOW_EVENT_CLOSED;
                }
                return true;
            }

            return false;
        }
        bool X11Window::isOpen() {
            return opened;
        }
        void X11Window::close () {
            if (opened) {
                XDestroyWindow(display, window);
                nbWindowCreated--;
                if (nbWindowCreated == 0) {
                    XCloseDisplay(display);
                    display = nullptr;
                    if (inputMethod)
                            XCloseIM(inputMethod);
                }
                opened = false;
            }
        }
        unsigned long long int X11Window::getID() {
            return reinterpret_cast<unsigned long long int>(&window);
        }
        X11Window::~X11Window() {
            if (opened) {
                XDestroyWindow(display, window);
                if (inputMethod)
                        XCloseIM(inputMethod);
                nbWindowCreated--;
                if (nbWindowCreated == 0) {
                    XCloseDisplay(display);
                    display = nullptr;
                }
                opened = false;
            }
        }
    }
}

Lors que j'appelle setVisible et que je passe false, les fenêtres sont toujours visible. hmm

int main()
{
    X11Window window1(800, 600, "test");
    X11Window window2(100, 100, "test2");
    X11Window window3(100, 100, "test3");
    window2.setVisible(false);
    window3.setVisible(false);
    while (window1.isOpen()) {
        IEvent event;
        while(window1.pollEvent(event)) {
            if (event.window.windowID == window1.getID() && event.window.event == IEvent::WindowEventID::WINDOW_EVENT_CLOSED) {
                window1.close();
                window2.close();
                window3.close();
            }
        }
        while(window2.pollEvent(event)) {
            if (event.window.windowID == window2.getID() && event.window.event == IEvent::WindowEventID::WINDOW_EVENT_CLOSED)
                window2.close();
        }
        while(window3.pollEvent(event)) {
            if (event.window.windowID == window3.getID() && event.window.event == IEvent::WindowEventID::WINDOW_EVENT_CLOSED)
                window3.close();
        }
    }
    return 0;

Pourquoi est ce que, mes fenêtre ne veulent pas se mettre en invisible ?

Et la position de la fenêtre il me semble que c'est par rapport au coin supérieur droit de l'écran et non pas par rapport au coin supérieur gauche de l'écran qu'elle est définie puisque la fenêtre pop toujours au milieu du bureau, quoi que je fasse. hmm

Hors ligne

#2 Le 16/03/2015, à 17:17

Lolichou

Re : Xunmapwindow : fenêtre toujours visible!

Bon, j'ai récupéré les sources de xorg-server, je cherche la définition de cette fonction mais pas moyen de la trouver, la seule chose que je trouve ce sont les endroits ou est appelée cette fonction :

 grep --include=\*.{c,h} -rnw 'xorg-server-1.15.1' -e "XUnmapWindow"
xorg-server-1.15.1/hw/xnest/Window.c:365:    XUnmapWindow(xnestDisplay, xnestWindow(pWin));
xorg-server-1.15.1/hw/xnest/Screen.c:85:            XUnmapWindow(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]);
xorg-server-1.15.1/hw/xnest/Screen.c:91:            XUnmapWindow(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]);
xorg-server-1.15.1/hw/xnest/Screen.c:96:            XUnmapWindow(xnestDisplay, xnestScreenSaverWindows[pScreen->myNum]);
xorg-server-1.15.1/hw/dmx/dmxscrinit.c:332:    XUnmapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin);
xorg-server-1.15.1/hw/dmx/dmxwindow.c:163:                XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window);
xorg-server-1.15.1/hw/dmx/dmxwindow.c:667:        XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window);
xorg-server-1.15.1/hw/xwin/winmultiwindowwm.c:800:            XUnmapWindow(pWMInfo->pDisplay, pNode->msg.iWindow);

Mais, aucun moyen de trouver l'endroit ou elle est définie, quelqu'un sait t'il dans quel paquet cette fonction est t'elle définie ?

Hors ligne

#3 Le 17/03/2015, à 12:45

claudius01

Re : Xunmapwindow : fenêtre toujours visible!

Lolichou a écrit :

Bon, j'ai récupéré les sources de xorg-server, je cherche la définition de cette fonction [XUnmapWindow()] mais pas moyen de la trouver, la seule chose que je trouve ce sont les endroits ou est appelée cette fonction :

A défaut de te dire où se trouve cette fonction XUnmapWindow() (toutes les librairies X11 sur mon Linux sont strippées ;-), j'ai le regret de t'annoncer qu'elle ne rend pas invisible une fenêtre ;-(

Explication: Je suis parti de l'exemple xdemo.c dans lequel j'ai encadré l'appel à XUnmapWindow() par

...
   /* Done */
   printf("Awaiting 3 Sec...\n");
   sleep(3);
   printf("Call XUnmapWindow()\n");
   XUnmapWindow(thedisplay,thewindow);

   printf("Awaiting 5 Sec...\n");
   sleep(5);

   printf("Bye bye\n");
   XFreeGC(thedisplay,thecontext);
   XDestroyWindow(thedisplay,thewindow);
   XCloseDisplay(thedisplay);
}

La compilation + exécution ne produit pas l'effet attendu; à savoir l'invisibilité de la fenêtre associée durant 5 secondes avant la sortie du programme

$ gcc -o xdemo xdemo.c -lX11

$ nm xdemo | grep XUnmapWindow
                 U XUnmapWindow
$ ldd xdemo
        linux-vdso.so.1 =>  (0x00007fff0cdff000)
        libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f1786dde000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1786a1f000)
        libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f1786800000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f17865fc000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f1787133000)
        libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f17863f9000)
        libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f17861f2000)

$ ./xdemo
Awaiting 3 Sec...
Call XUnmapWindow()
Awaiting 5 Sec...               => Fenêtre avec le carré Vert + triangle Rouge toujours visible
Bye bye

En espérant t'avoir aidé, il doit y avoir une autre méthode pour rendre invisible une fenêtre X11...
Tu peux essayer de faire un "nm | grep XUnmapWindow" sur les 'libX*.so*' et 'libx*.so*'

Dernière modification par claudius01 (Le 17/03/2015, à 12:56)

Hors ligne

#4 Le 17/03/2015, à 16:09

grim7reaper

Re : Xunmapwindow : fenêtre toujours visible!

claudius01 a écrit :

A défaut de te dire où se trouve cette fonction XUnmapWindow() (toutes les librairies X11 sur mon Linux sont strippées ;-), j'ai le regret de t'annoncer qu'elle ne rend pas invisible une fenêtre ;-(
[…]
En espérant t'avoir aidé, il doit y avoir une autre méthode pour rendre invisible une fenêtre X11...

En fait, c’est bien la bonne fonction mais il faut garder en tête que la Xlib c’est un système client-serveur.
Quand tu appelles XUnmapWindow le serveur va emettre une notification UnmapNotify. Si tu n’en fais rien, la notification va rester dans une file d’attente et ton affichage ne sera pas rafraîchi (et donc ta fenêtre va rester visible).

Une solution possible serait d’appeler XNextEvent pour traiter les évènements de ta file jusqu’a ce que tu tombes sur un évènement de type UnmapNotify.
C’est ce qui est fait (mais pour l’évènement MapNotify) dans le programme xdemo que tu cites.

    for (;;) {
        XNextEvent(thedisplay, &anevent);
        if (anevent.type == UnmapNotify)
            break;
    }

Une autre solution est d’appeler une fonction du genre XFlush.

@Lolichou : si tu veux plus d’aide, il faudrait que tu postes un SSCCE (Short, Self Contained, Correct (Compilable), Example) sinon on ne peux pas tester sur nos machine.

Hors ligne

#5 Le 17/03/2015, à 17:46

claudius01

Re : Xunmapwindow : fenêtre toujours visible!

Merci grim7reaper, j'ai bien le résultat attendu; à savoir la suppression de la fenêtre 5 secondes avant la sortie du programme.

$ ./xdemo

Receive MapNotify notification
Awaiting 3 Sec...
Call XUnmapWindow()
Wait UnmapNotify notification...
Receive UnmapNotify notification          => Suppression de la fenêtre avec le carré Vert + triangle Rouge
Awaiting 5 Sec...
Bye bye

En complétant le code par

...
   /* Done */
   printf("Awaiting 3 Sec...\n");
   sleep(3);
   printf("Call XUnmapWindow()\n");
   XUnmapWindow(thedisplay,thewindow);

   /* Wait for the UnmapNotify event */
   printf("Wait UnmapNotify notification...\n");
   for (;;) {
      XNextEvent(thedisplay, &anevent);
      if (anevent.type == UnmapNotify) {
         printf("Receive UnmapNotify notification\n");
         break;
      }
   }
   
   printf("Awaiting 5 Sec...\n");
   sleep(5);

   printf("Bye bye\n");
   XFreeGC(thedisplay,thecontext);
   XDestroyWindow(thedisplay,thewindow);
   XCloseDisplay(thedisplay);
}

En résumé, XUnmapWindow fait bien son travail ;-)

Dernière modification par claudius01 (Le 17/03/2015, à 17:47)

Hors ligne

#6 Le 18/03/2015, à 16:36

Lolichou

Re : Xunmapwindow : fenêtre toujours visible!

Salut, oui lorsque j'endors le thread courant pendant 5 secondes, la fenêtre redevient invisible après 5 secondes, par contre si je veux la rendre invisible tout de suite, là, ça ne fonctionne plus. hmm

int main()
{
    Display* display = XOpenDisplay(nullptr);
    int screen = DefaultScreen(display);
    ::Window window = XCreateSimpleWindow(display, DefaultRootWindow(display),
                                 (DisplayWidth(display, screen) - 800) * 0.5f, (DisplayHeight(display, screen) - 600) * 0.5f,
                                  800, 600, 1, BlackPixel(display, screen), WhitePixel(display, screen));
    std::string title = "test";
    std::basic_string<Uint8> utf8Title;
    Utf32::toUtf8(title.begin(), title.end(), std::back_inserter(utf8Title));

    // Set the _NET_WM_NAME atom, which specifies a UTF-8 encoded window title.
    Atom wmName = XInternAtom(display, "_NET_WM_NAME", False);
    Atom useUtf8 = XInternAtom(display, "UTF8_STRING", False);
    XChangeProperty(display, window, wmName, useUtf8, 8,
                    PropModeReplace, utf8Title.c_str(), utf8Title.size());
    // Set the non-Unicode title as a fallback for window managers who don't support _NET_WM_NAME.
    XStoreName(display, window, title.c_str());
    XSelectInput(display, window, StructureNotifyMask | FocusChangeMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
                                  PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask |
                                  EnterWindowMask | LeaveWindowMask);
    XMapWindow(display, window);
    XFlush(display);   
    XUnmapWindow(display, window);
    XFlush(display);
    bool terminated = false;
    while(!terminated) {
        XEvent xevent;
        if (XPending(display) > 0) {
            XNextEvent(display, &xevent);
            if (xevent.type == MapNotify) {
                printf("Receive map notification\n");
            }
            if (xevent.type == UnmapNotify) {
                printf("Receive UnmapNotify notification\n");
            }
            if (xevent.type == DestroyNotify)
                terminated = true;
        }
    }
    XDestroyWindow(display, window);
    XCloseDisplay(display);
    return 0;

Et puis j'ai remarqué que la fenêtre "loupe" des événements parfois. hmm

Avec atomClose je dois parfois cliquer plusieurs fois sur la croix pour que la fenêtre se referme. (Je n'utilise pas DestroyNotify sinon j'ai une erreur sur le terminal)

Dernière modification par Lolichou (Le 18/03/2015, à 16:51)

Hors ligne

#7 Le 18/03/2015, à 17:25

claudius01

Re : Xunmapwindow : fenêtre toujours visible!

Lolichou a écrit :

... Et puis j'ai remarqué que la fenêtre "loupe" des événements parfois.

Avec atomClose je dois parfois cliquer plusieurs fois sur la croix pour que la fenêtre se referme. (Je n'utilise pas DestroyNotify sinon j'ai une erreur sur le terminal)

Faut instrumenter le code, s'appuyer sur les logs du serveur X et sans doute examiner la queue des événements avec XPeekEvent.

Hors ligne