[comp.windows.x] Help! What is the magic of the sleep

csuyk@warwick.ac.uk (FUNG Wai Wa) (01/09/91)

Hi, there,

I am new to Xlib programming. I am now stuck at a very funny(?) problem
that I can't solve. Would any Xlib expert give me a hand? Thanks.

The following few statements attempt to create a window and draw a line
with some strings. I found that the sleep(1) statement is very crucial
for its success. Its presence can make the program work as I expect but
its absence make the program map the windows only. No drawing at all, if
I run this program from another machine. Occasionally I can get it running
in the same workstation where I started X.

Would any guru give me some hints to get around  this nasty problem?


Regards,
FUNG W.W.


----cut here
#include <stdio.h>
#include <X11/Xlib.h>

main()
{
    Display              *dpy;
    int                  scr;
    Window               win;
    GC                   gc;

    XGCValues            gcvalues;
    XSetWindowAttributes attributes;
    Visual               *visual = CopyFromParent;

    dpy = XOpenDisplay(NULL);     /* connect to the default display */
    if (dpy != (Display*)NULL)
        scr = DefaultScreen(dpy);
    else {
        printf("Cannot connect to server\n");
        exit(0);
    }

    /* creating a very simple window */
    attributes.background_pixel = BlackPixel(dpy, scr);
    win = XCreateWindow(dpy, RootWindow(dpy, scr),
                        100, 100, 500, 500, 1,
                        CopyFromParent,
                        InputOutput,
                        visual,
                        CWBackPixel, &attributes);
    XMapRaised(dpy, win);
    XFlush(dpy);

    /* create the pen */
    gcvalues.foreground = WhitePixel(dpy, scr);
    gc = XCreateGC(dpy, win, GCForeground, &gcvalues);

    /* nasty stmt that its existence is crucial
       if this stmt is omitted, there is chance to get the program
           working in the same workstation that I started X. However,
           if I compile and execute this program in another machine
           over the network, only a blank window appeared but no
           drawing will be done.
       However, with this sleep stmt, everything OK. Why???
    */
    sleep(1);

    XDrawLine(dpy, win, gc, 0, 0, 300, 300);
    XDrawString(dpy, win, gc, 100, 100, "Xlib", 4);
    XDrawString(dpy, win, gc, 200, 200, "Hello", 5);
    XDrawString(dpy, win, gc, 300, 300, "Xlib", 4);
    XFlush(dpy);

    while (1);
}

jon@infonode.ingr.com (Jon Stone) (01/10/91)

In article <1991Jan9.150326.6248@warwick.ac.uk> csuyk@warwick.ac.uk (FUNG Wai Wa) writes:
>The following few statements attempt to create a window and draw a line
>with some strings. I found that the sleep(1) statement is very crucial
>for its success. Its presence can make the program work as I expect but
>its absence make the program map the windows only. No drawing at all, if
>I run this program from another machine. Occasionally I can get it running
>in the same workstation where I started X.

I'm no x-spert, but I think you need to wait for an Expose event before
doing any drawing.  X automagically queues up an Expose event when you
map your window.  This code is far from perfect.  Try reading Chapter 3
of the Xlib Programming Manual.  It should fill you in on the details.

Try something like this:

	all your init stuff.
	XMapRaised
	XSelectInput (dpy, win, ExposureMask);

	while (1) {
		XNextEvent (dpy, &event);

		if (event.type == Expose)
			draw
	}

  Jon
-- 
_______________________________________________________________________________
Jon D. Stone				jon@ingr.com -or- ..!uunet!ingr!jon
Intergraph Corporation, Huntsville, AL	(205)730-8594
_______________________________________________________________________________

klee@wsl.dec.com (Ken Lee) (01/10/91)

In article <1991Jan9.150326.6248@warwick.ac.uk>, csuyk@warwick.ac.uk (FUNG Wai Wa) writes:
|> The following few statements attempt to create a window and draw a line
|> with some strings. I found that the sleep(1) statement is very crucial
|> for its success.

This is one of the most common X beginners problems.  X is
asynchronous, so there is no guarantee that your window is mapped
before you start drawing.  Instead, you should only draw on a window
after receiving an expose event.  Most people use the X Toolkit, which
worries about this for you.

-- 
Ken Lee
DEC Western Software Laboratory, Palo Alto, Calif.
Internet: klee@wsl.dec.com
uucp: uunet!decwrl!klee

mouse@larry.mcrcim.mcgill.EDU (01/10/91)

>> The following few statements attempt to create a window and draw a
>> line with some strings.  I found that the sleep(1) statement is very
>> crucial for its success.  Its presence can make the program work as
>> I expect but its absence make the program map the windows only.  No
>> drawing at all, if I run this program from another machine.
>> Occasionally I can get it running in the same workstation where I
>> started X.

I haven't seen the original posting, but I would guess this is the
common problem about not waiting for the Expose event.  I will append
the response to question 74 from the FAQ posting, which addresses this.

> Try something like this:

> 	all your init stuff.
> 	XMapRaised
> 	XSelectInput (dpy, win, ExposureMask);

Whoops.  The XSelectInput should be before the XMapRaised.  I would
recommend that you set the event mask when you create the window.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

----------------------------------------------------------------------
Subject: 74)  Why doesn't anything appear when I run this simple program?

> ...
> the_window = XCreateSimpleWindow(the_display,
>      root_window,size_hints.x,size_hints.y,
>      size_hints.width,size_hints.height,BORDER_WIDTH,
>      BlackPixel(the_display,the_screen),
>      WhitePixel(the_display,the_screen));
> ...
> XSelectInput(the_display,the_window,ExposureMask|ButtonPressMask|
> 	ButtonReleaseMask);
> XMapWindow(the_display,the_window);
> ...
> XDrawLine(the_display,the_window,the_GC,5,5,100,100);
> ...

	You are right to map the window before drawing into it. However, the
window is not ready to be drawn into until it actually appears on the screen --
until your application receives an Expose event. Drawing done before that will
generally not appear. You'll see code like this in many programs; this code
would appear after window was created and mapped:
  while (!done)
    {
      XNextEvent(the_display,&the_event);
      switch (the_event.type) {
	case Expose:	 /* On expose events, redraw */
		XDrawLine(the_display,the_window,the_GC,5,5,100,100);
		break;
	...
	}
    }

	Note that there is a second problem: some X servers don't set up the
default graphics context to have reasonable foreground/background colors, and
your program should not assume that the server does, so this program could
previously include this code to prevent the case of having the foreground and
background colors the same:
  ...
  the_GC_values.foreground=BlackPixel(the_display,the_screen);	/* e.g. */
  the_GC_values.background=WhitePixel(the_display,the_screen);	/* e.g. */
  the_GC = XCreateGC(the_display,the_window,
                GCForeground|GCBackground,&the_GC_values);
  ...

Note: the code uses BlackPixel and WhitePixel to avoid assuming that 1 is
black and 0 is white or vice-versa.  The relationship between pixels 0 and 1
and the colors black and white is implementation-dependent.  They may be
reversed, or they may not even correspond to black and white at all.

----------------------------------------------------------------------