# ...a simple screen saver program.

In this tutorial lesson, I am going to try and show how you can create a simple screen saver program. The main screen will be a simple black background, in the 'popup' style we used in lesson 17 to create an un-titled message box. In this, we will create a second window, which will contain the eu.bmp bitmap. The second window will be constantly re-located by an onTimer[] event handler, in a simple 'bouncing' fashion, whenever the bitmap 'hits' the edges of the main window.

Since a screen saver should cover the whole screen, and users may have different screen sizes set up on their system, we can't declare our main window's size directly. We will instead use the GetSystemMetrics() function to 'discover' the user's screen size before we create the main window. The values returned by this function will then be used to create our main window, so it fills the whole screen, no matter what it's size.

-- screen1.exw

    --screen1.exw--
    include win32lib.ew
    without warning

    constant
    -- get the users screen size
    CXFULL = w32Func( xGetSystemMetrics, {SM_CXSCREEN} ),
    CYFULL = w32Func( xGetSystemMetrics, {SM_CYSCREEN} ),
    -- use these values to create our main
    Win1   = create( Window, "", 0, 0, 0, CXFULL, CYFULL, #80400000 ),
    -- next, create our 'bitmap' window
    Win2   = create( Window, "", Win1, 0, 0, 330, 148, #80400000 ),
    -- leaving a little room for some text
    Title5 = create( CText, "_empowered by WIN32LIB_", Win2, 1, 121, 322, 20, 0 ),
    -- then the actual bitmap area
    Bitmap2 = create( Bitmap, "", Win2, 0, 0, 324, 120, 0 ),
    -- set up a timerId for an onTimer[] event handler
    Mytimer1 = 1,
    -- and calculate the 'extents' of how far
    -- we allow our secondary window to move
    -- within the main window
    CX = CXFULL-330,
    CY = CYFULL-148

    setBitmap( Bitmap2, ".\\Bin\\eu.bmp" )
    setFont( Title5, "Arial", 12, 3 )

    setWindowBackColor( Win1, rgb(0,0,0) )
    atom rgbColor
    rgbColor = getSysColor( COLOR_BTNFACE )
    setWindowBackColor( Win2, rgbColor )

    atom posx, posy, xsize, ysize, xdir, ydir
    xdir = 1   ydir = 1

    -- always start with a centered bitmap
    procedure center_win( atom win_id )
      sequence loc
      loc = getRect( win_id )
      xsize = loc[3]-loc[1]
      ysize = loc[4]-loc[2]
      posx = floor(( w32Func( xGetSystemMetrics, {SM_CXFULLSCREEN} )/2)-(xsize/2) )
      posy = floor(( w32Func( xGetSystemMetrics, {SM_CYFULLSCREEN} )/2)-(ysize/2) )
      setRect(win_id,posx,posy,xsize,ysize,1 )
    end procedure

    procedure start_up( integer self, integer event, sequence params )
      center_win(Win2)
      openWindow(Win2,Modal)
      setTimer( Win1, Mytimer1, 25 )  -- 40 moves/sec. maximum
    end procedure

    -- this moves the bitmap,
    -- and changes direction
    -- if we hit a main window 'border'
    procedure next_pos( integer self, integer event, sequence params )
      if posx < 1 or posx > CX then
          xdir = -xdir
      end if
      if posy < 1 or posy > CY then
          ydir = -ydir
      end if
      posx = posx + xdir
      posy = posy - ydir
      setRect(Win2,posx,posy,xsize,ysize,1 )
    end procedure

    -- closes everything on exit
    procedure exit_prog( integer self, integer event, sequence params )
      closeWindow(Win2)
      closeWindow(Win1)
    end procedure

    -- shut-down, if a key is pressed
    procedure blah( integer self, integer event, sequence params )
      exit_prog()
    end procedure

    setHandler( Win1, w32HOpen, routine_id("start_up") )
    setHandler( Win1, w32HTimer, routine_id("next_pos") )
    setHandler( Win2, w32HKeyDown, routine_id("blah") )
    setHandler( Win2, w32HClick, routine_id("exit_prog") )

    WinMain( Win1,Maximize )
    --end code--

Hitting any normal key on the keyboard, or left-clicking on the 'bitmap' secondary window will stop the program.

...of interest.

I originally posted an example of this program on the Euphoria mailing list. I was trying to find out what setting I should use for Mytimer1, to allow the bitmap to to be displayed at a reasonable speed, without 'blurring', and still allow a user to click on it, to stop the program.

I guess I needn't have worried ... :)
Brian Broker kindly tested the program for me on a 550 mhz. dual processor system, and found out that setting the timer value below 15 had no further effect in speeding up the bitmap moves. Apparently, the minimum 'response' time for a timer is about 15 milliseconds, so the bitmap won't move more than 66 times a second, no matter how small a timer value is used, or how fast the computer is. If you want to move something faster than this, you can't use a simple timer call !

...on my 'ancient' 486/DX/4/100, it moves only 22 times/second... :(

Just to prove this to myself, I wrote screen2.exw. This uses a MUCH smaller 32 by 32 bitmap of only 1024 pixels, which it moves around in the main window. It's no faster, even with a timer setting of 5 ! You might want to check out the mouse handling routine, since it uses onMouse[], ...so it's a little different from screen1.exw.

..and on to the next lesson.

CONTENTS