Robb Main wrote:

What I find hard to reconcile is:
1. I was told that fltk should be finished with the image to be displayed by 
the time show() returns.

As Ian already wrote, that's not what Matthias wanted to tell you. I think you mean the following from fltk.development [1].

You wrote: "However, if I call show() immediately after the constructor returns, the image is not yet ready to display - it seems there the image is still being decompressed / rendered."

Matthias replied: "There is no parallel processing when loading the image. It is all ready as soon as your image loading function returns."

As Ian wrote, this should only be read as: The image loading from the image file is complete. Everything is decompressed, all pixel info is loaded in memory. However, no drawing happened when you load the image with

pBGImage = new Fl_PNG_Image( pszBGImage );

Matthias continued: "There will be a delay if you do not call Fl::flush(), Fl::wait() or Fl::run() though."

This is "normal" GUI behavior. Please look at your constructor again. There is no drawing. All drawing happens in your draw() method. But the draw() method will not be called by show(). This is delayed until FLTK decides that there is nothing else to do, and there are no more window messages (mouse movement, keyboard events and so on). Then FLTK will eventually call your draw() method, and your image will be rendered on the screen.

2. usleep() is a "system call", so it will put the current (fltk) application to sleep, 
granting CPU cycles to any other running applications/processes/threads (i.e., X). So if fltk is 
indead "finished with the image", WHY does sleeping the fltk application for a longer 
period extend the delay? If the hold up was anything to do with X, one would expect a longer sleep 
of the fltk processs would speed up the display, since X would get a larger share of the CPU.

X is a client-server protocol. In this case FLTK implements the client side and sends messages to the X server and gets replies. This server can be on the local node or on a remote host. In any case, there will be a delay between messages and replies. Bringing a window on an X display needs more than one client/server communication, and there you can see the delay. Making it simple, you can assume that FLTK can send exactly one message to the X server when you call Fl::check() once. Because there is a delay before the X server sends the reply, FLTK returns control to you before the answer arrived. So far nothing visible may have happened, but you call usleep with a 1 sec. delay. That's where the delay comes from. Then, when you call Fl::check() again, FLTK sees the X server's reply and sends the next message, and so on... One message per Fl::check() call.

Okay, that's only a model, and nothing real, but that's how it works in general.

My own suspicion is that there IS still some level of "background processing" 
being done by fltk before the image will be displayed, that explains why usleep() 
increases the delay, and why frequently yielding to background processing via wait() or 
run(), etc. speeds up the delay.

Yes and no. This is the normal GUI behavior. You _must_ call the FLTK event handling functions regularly, otherwise it will "hang". If you don't call Fl::run() to let FLTK do it, you should really know what you're doing.

Which brings me to another question: does "Fl::Window->shown()" report true if 
fltk THINKS the window is visible, or if it has ACTUALLY been rendered to the screen? (and 
if the latter, how does it KNOW?)

FLTK doesn't "know". There is some delaying of message processing, e.g. there's a flag "wait-for-expose" or similar, so that FLTK can delay drawing to a window until it gets an "expose" event from the (X) windowing system, but this is what FLTK does for you. You shouldn't need to know the details. And to answer your question: Fl_Window::shown() is true directly after the show() call, even if the window is not yet visible on the screen.

Back to your problem: As I wrote above, your image will be rendered on the screen in your draw() method. To see what happens, you can add a print statement to your draw() method and watch the output.

Then, if you want to be sure that your image has been drawn, you could add a flag to your splash window class, let's call it "drawn_" and initialize it to 0 in the constructor, and set it to 1 when draw() is called. Then add a method drawn() that returns the flag. With all this you can do:

splashWindow->show();
while (!splashWindow->drawn()) Fl::check();

This will wait until your window and the image is really rendered on the screen.

Just for curiosity I wrote a small variation of FLTK's hello.cxx demo program. I'll append it to this message: see wait_check.cxx.

Under Windows (default gdi version) I see:
 (1) an empty and _transparent_ window frame
 (2) the rendered box with text

The output is:

window shown(): 1, visible(): 1, box visible(): 1
sleep  5.000 s ... drawn=0, Fl::check() # 1 ... MyBox::draw()... drawn=1
sleep  5.000 s ... drawn=1, Fl::check() # 2 ... drawn=1
sleep  5.000 s ... drawn=1, Fl::check() # 3 ... drawn=1
sleep  2.500 s ... drawn=1, Fl::check() # 4 ... drawn=1
setting new label: "Hello, World!"
sleep  0.000 s ... drawn=1, Fl::check() # 5 ... MyBox::draw()... drawn=2

This is what I would expect. The first Fl::check() call does all the drawing, and changing the label triggers another draw.

Under Windows with a local X server I see:
 (1) nothing (no window, first delay...)
 (2) an empty window with a gray background
 (3) the rendered box with text

The output is:

window shown(): 1, visible(): 1, box visible(): 1
sleep  5.000 s ... drawn=0, Fl::check() # 1 ... drawn=0
sleep  5.000 s ... drawn=0, Fl::check() # 2 ... MyBox::draw()... drawn=1
sleep  5.000 s ... drawn=1, Fl::check() # 3 ... drawn=1
sleep  2.500 s ... drawn=1, Fl::check() # 4 ... drawn=1
setting new label: "Hello, World!"
sleep  0.000 s ... drawn=1, Fl::check() # 5 ... MyBox::draw()... drawn=2

You can see that the first call of Fl::check() does NOT call MyBox::draw(), although there are 5 seconds delay between the show() and Fl::check().

You should also see what happens, if you occlude the window with another window between two Fl::check() calls, or if you minimize and restore it. With my cygwin X server the window is "magically" redrawn (without calling draw() again), but with native Windows draw() is called always after minimizing and after occlusion by another window.

There are more options in the source file to discover. If you uncomment

  while (!box->drawn()) my_sleep(0.001);

you will see something like:

window shown(): 1, visible(): 1, box visible(): 1
sleep  0.001 s ... drawn=0, Fl::check() # 1 ... drawn=0
sleep  0.001 s ... drawn=0, Fl::check() # 2 ... MyBox::draw()... drawn=1
sleep  5.000 s ... drawn=1, Fl::check() # 3 ... drawn=1
sleep  5.000 s ... drawn=1, Fl::check() # 4 ... drawn=1
sleep  5.000 s ... drawn=1, Fl::check() # 5 ... drawn=1

With a remote (LAN) X server I could see that the first draw() call happened somewhere between the 3rd and the 9th Fl::check() call (with 0.001 sec. delay).

With another remote X server over a VPN (internet) I just saw that it took up to 98 Fl::check() calls before draw() was called.

If you intend to do initialization work and show a progress bar, you must call Fl::wait() or Fl::check() at regular/short intervals, otherwise strange things may happen.

Albrecht

[1] http://www.fltk.org/newsgroups.php?gfltk.development+v:7784
//
// This is a modified version of FLTK's test/hello.cxx 
//
// Hello, World! program for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2009 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please *DO* *NOT* report bugs and problems on the following page:
//
//     http://www.fltk.org/str.php
//
// ===================================================================
//
// This modified version is intended to show differences of drawing
// that are operating system dependent.
//
// compile, link, and run with:
//
//   fltk-config --compile wait_check.cxx && ./wait_check
//
// Note to Windows users: You won't see any output, unless you use
// MinGW or Cygwin (gcc) to compile and link this program (and run
// it from a command shell).
//
// If you're using VC++ or maybe other tools, you may try to redirect
// the output to a file, like (in a "DOS" window)
//   C:\> wait_check > test.txt
//

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>

#include <stdio.h>      // printf

#ifdef WIN32
# include <windows.h>
#else
# include <unistd.h>
#endif

class MyBox : public Fl_Box {
  int drawn_;
protected:
  void draw ();
public:
  MyBox (Fl_Boxtype,int,int,int,int,char *);
  int drawn() {return drawn_;}
};

MyBox::MyBox (Fl_Boxtype B, int X, int Y, int W, int H, char *L)
 : Fl_Box (B,X,Y,W,H,L), drawn_(0) {}

void MyBox::draw() {
  printf ("MyBox::draw()... ");
  Fl_Box::draw();
  drawn_++;
}

static Fl_Window *window = 0;
static MyBox *box = 0;

// special sleep function
void my_sleep(double secs) {

  static int count = 0;

  printf("sleep%7.3f s ... ",secs);

  int msec = int(secs*1000.);
#ifdef WIN32
  Sleep (msec);
#else
  usleep (msec * 1000);
#endif
  printf ("drawn=%d, Fl::check() # %d ... ",box->drawn(),++count);
  Fl::check();
  printf("drawn=%d\n",box->drawn());
  if (!window->shown()) {
    printf ("*** window has been closed, exiting ...\n");
    exit(0);
  }
}

int main(int argc, char **argv) {
  window = new Fl_Window(300,180);
  box = new MyBox(FL_UP_BOX,20,40,260,100,"Testing ...");
  box->labelfont(FL_BOLD+FL_ITALIC);
  box->labelsize(36);
  box->labeltype(FL_SHADOW_LABEL);
  window->end();
  window->show(argc, argv);

  setvbuf (stdout,NULL,_IONBF,0); // stdout unbuffered

  printf ("window shown(): %d, visible(): %d, box visible(): %d\n",
    window->shown(),window->visible(),box->visible());

  // remove the comment from the following while loop to see what
  // happens (if you can, try this on Windows and with X)

  // wait until box is drawn ...
  // while (!box->drawn()) my_sleep(0.001);

  // if you remove the comment from the following line, then the
  // window will be displayed for 1 second, and the program will
  // exit after this.

  // my_sleep(1); window->hide(); my_sleep(0);

  // while the program is running, try to see what is different, if
  // you occlude the box part of the display or if you minimize the
  // window ...

  my_sleep(5);
  my_sleep(5);
  my_sleep(5);
  my_sleep(2.5);

  printf("setting new label: \"Hello, World!\"\n");
  box->label("Hello, World!");
  my_sleep(0);

  return Fl::run();
}
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk

Reply via email to