Menu

Infinite loop occurs when using XNextEvent()

AcidHorse
2005-01-26
2013-03-22
  • AcidHorse

    AcidHorse - 2005-01-26

    // Infinite loop happens about the second time
    // that XNextEvent is reached.
    // In the libw11 code its at
    // void _XReadEvents(Display *display) {
    // _xtrace("_XReadEvents");
    // while(!display->qlen);
    // }
    // where display->qlen equals 0 no matter what.
    // I tested it with cygwin and msvc and its the
    // same behavior
    #include <stdio.h>
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>

    #define STRING  "Hello, world"
    #define BORDER  1
    #define FONT    "fixed"
       
    /*
    * This structure forms the WM_HINTS property of the window,
    * letting the window manager know how to handle this window.
    * See Section 9.1 of the Xlib manual.
    */     
    XWMHints        xwmh = {
        (InputHint|StateHint),      /* flags */
        False,                      /* input */
        NormalState,                /* initial_state */
        0,                          /* icon pixmap */
        0,                          /* icon window */
        0, 0,                       /* icon location */
        0,                          /* icon mask */
        0,                          /* Window group */
    };

    main(argc,argv)
        int argc;
        char **argv;
    {
        Display    *dpy;            /* X server connection */
        Window      win;            /* Window ID */
        GC          gc;             /* GC to draw with */
        XFontStruct *fontstruct;    /* Font descriptor */
        unsigned long fth, pad;     /* Font size parameters */
        unsigned long fg, bg, bd;   /* Pixel values */
        unsigned long bw;           /* Border width */
        XGCValues   gcv;            /* Struct for creating GC */
        XEvent      event;          /* Event received */
        XSizeHints  xsh;            /* Size hints for window manager */
        char       *geomSpec;       /* Window geometry string */
        XSetWindowAttributes xswa;  /* Temporary Set Window Attribute struct */

        /*
         * Open the display using the $DISPLAY environment variable to locate
         * the X server.  See Section 2.1.
         */
        if (!(dpy = XOpenDisplay(NULL))) {
            fprintf(stderr, "%s: can't open %s\en", argv[0]);
            exit(1);
        }

        /*
         * Load the font to use.  See Sections 10.2 & 6.5.1
         */
        if ((fontstruct = XLoadQueryFont(dpy, FONT)) == NULL) {
            fprintf(stderr, "%s: display %s doesn't know font %s\en",
                    argv[0], DisplayString(dpy), FONT);
            exit(1);
        }
        fth = fontstruct->max_bounds.ascent + fontstruct->max_bounds.descent;

        /*
         * Select colors for the border,  the window background,  and the
         * foreground.
         */
        bd = WhitePixel(dpy, DefaultScreen(dpy));
        bg = BlackPixel(dpy, DefaultScreen(dpy));
        fg = WhitePixel(dpy, DefaultScreen(dpy));

        /*
         * Set the border width of the window,  and the gap between the text
         * and the edge of the window, "pad".
         */
        pad = BORDER;
        bw = 1;

        /*
         * Deal with providing the window with an initial position & size.
         * Fill out the XSizeHints struct to inform the window manager. See
         * Sections 9.1.6 & 10.3.
         */
        xsh.flags = (PPosition | PSize);
        xsh.height = fth + pad * 64;
        xsh.width = XTextWidth(fontstruct, STRING, strlen(STRING)) + pad * 2;
        xsh.x = (DisplayWidth(dpy, DefaultScreen(dpy)) - xsh.width) / 2;
        xsh.y = (DisplayHeight(dpy, DefaultScreen(dpy)) - xsh.height) / 2;

        /*
         * Create the Window with the information in the XSizeHints, the
         * border width,  and the border & background pixels. See Section 3.3.
         */
        win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy),
                                  xsh.x, xsh.y, xsh.width, xsh.height,
                                  bw, bd, bg);

        /*
         * Set the standard properties for the window managers. See Section
         * 9.1.
         */
        XSetStandardProperties(dpy, win, STRING, STRING, None, argv, argc, &xsh);
        XSetWMHints(dpy, win, &xwmh);

        /*
         * Ensure that the window's colormap field points to the default
         * colormap,  so that the window manager knows the correct colormap to
         * use for the window.  See Section 3.2.9. Also,  set the window's Bit
         * Gravity to reduce Expose events.
         */
        xswa.colormap = DefaultColormap(dpy, DefaultScreen(dpy));
        xswa.bit_gravity = CenterGravity;
        XChangeWindowAttributes(dpy, win, (CWColormap | CWBitGravity), &xswa);

        /*
         * Create the GC for writing the text.  See Section 5.3.
         */
        gcv.font = fontstruct->fid;
        gcv.foreground = fg;
        gcv.background = bg;
        gc = XCreateGC(dpy, win, (GCFont | GCForeground | GCBackground), &gcv);

        /*
         * Specify the event types we're interested in - only Exposures.  See
         * Sections 8.5 & 8.4.5.1
         */
        XSelectInput(dpy, win, ExposureMask);

        /*
         * Map the window to make it visible.  See Section 3.5.
         */
        XMapWindow(dpy, win);

        /*
         * Loop forever,  examining each event.
         */
        while (1) {
            /*
             * Get the next event
             */
            XNextEvent(dpy, &event);

            /*
             * On the last of each group of Expose events,  repaint the entire
             * window.  See Section 8.4.5.1.
             */
            if (event.type == Expose && event.xexpose.count == 0) {
                XWindowAttributes xwa;      /* Temp Get Window Attribute struct */
                int         x, y;

                /*
                 * Remove any other pending Expose events from the queue to
                 * avoid multiple repaints. See Section 8.7.
                 */
                while (XCheckTypedEvent(dpy, Expose, &event));

                /*
                 * Find out how big the window is now,  so that we can center
                 * the text in it.
                 */
                if (XGetWindowAttributes(dpy, win, &xwa) == 0)
                    break;
                x = (xwa.width - XTextWidth(fontstruct, STRING, strlen(STRING))) / 2;
                y = (xwa.height + fontstruct->max_bounds.ascent
                     - fontstruct->max_bounds.descent) / 2;

                /*
                 * Fill the window with the background color,  and then paint
                 * the centered string.
                 */
                XClearWindow(dpy, win);
                XDrawString(dpy, win, gc, x, y, STRING, strlen(STRING));
            }
        }

        exit(1);
    }

     
    • Donald Becker

      Donald Becker - 2005-01-26

      while(!display->qlen); was a quick hack I put in when I added the 2nd thread to queue events. I plan on changing to WaitForSingleObject() and having _XEnq trigger the event when one arrives.

      There is another bug im trying to fix that causes programs to hang shortly after startup, but Im thinking it has something to do with how cygwin handles alarms and timers.  It causes odd behavior on xeyes also.  When you first run xeyes, the eyes follow the mouse all around the screen, but if you hit enter in the cygwin term, it will then be confined to just its own window. 

       
    • Donald Becker

      Donald Becker - 2005-01-26

      Damn im retarded.  The threads are lock each other out of the display variable.  Ill have to fix that.

       
    • Donald Becker

      Donald Becker - 2005-01-26

      For now in my current tree, I have _XReadEvents UnlockDisplay() then wait for the events, then LockDisplay().

      XPeekEvent and XPeekIfEvent had to have the display locks added to them. 

       
    • Samuel Vinson

      Samuel Vinson - 2005-01-27

      I have not this problem because I don't create thread in OpenDisplay Function. Because I think thread is beginning of several problems (synchronization, deadlock...).
      And I wrote _XEventsQueued and  _XReadEvents like this :
      int _XEventsQueued(Display *display, int mode)
      {
        MSG msg;

        if(mode == QueuedAfterFlush)
        {
          _XFlush(display);
          if(display->qlen)
             return (display->qlen);
        }

        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
           TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        return display->qlen;
      }

      void _XReadEvents(Display *display)
      {
         MSG msg;
         BOOL ret;

         while(!display->qlen)
         {
            if((ret = GetMessage(&msg, NULL, 0, 0)) != 0)
            {
               if (ret != -1)
               {
                  TranslateMessage(&msg);
                  DispatchMessage(&msg);
               }
            }
         }
      }

       
      • Donald Becker

        Donald Becker - 2005-01-27

        A few programs ive used for testing call sleep() in their code, assuming they are connected to a server.  when the code sleeps for a few seconds, no messages are processes, and the program displays the hourglass over it, and responds eratically to move events and such until the sleep() is complete. 

        The methods you mention were how I was going about reading events also, until I ran into the sleep() problem.

         
        • Samuel Vinson

          Samuel Vinson - 2005-01-27

          You are right, but windows places messages in a queue (PostMessge documentation says "Windows 2000/XP: There is a limit of 10,000 posted messages per message queue. [...] The minimum acceptable value is 4000."

          So any message has lost. Actually, if you call sleep() in your main thread, you block it. But it is right for all system (Unix/linux, windows...).

          I used XV and links with my libw11 implementation without thread and I had never blocked. I understand your problem, but I think it arrives when conception is wrong.

           
          • Donald Becker

            Donald Becker - 2005-01-27

            XV didnt block for me, but other samples did.

            Using threads the handle the message queue helps to ensure the maximum number of messages is never readed.  It pulls in the windows messages and addes them to the queue in the display variable.

            "So any message has lost. Actually, if you call sleep() in your main thread, you block it. But it is right for all system (Unix/linux, windows...). "

            It is right to the perspective of the running program, but not to the person using it.  Even when a client is sleeping, the X server is still letting them move windows and reading mouse events, the client just processes them after the sleep is over.  Using threads simulates that same set up.

            Also for threaded Xlib applications, with X11 any thread can read events for a window created in other threads.  With windows, only the thread that created the window can read events for it.  Using a thread for reading messages helps to enable threaded X11 applications.

             

Log in to post a comment.

MongoDB Logo MongoDB