## Opening a Window using the 'working area' of the desktop.

Here's a bit of code that Brian Broker put on the Euphoria mailing list. This program illustrates a way to size your program's main window so that it fills the entire screen, *except* for the area occupied by the taskbar.

-- full_task.exw

    -- getWorkarea() code originally by Brian K. Broker - APR 2000

    include win32lib.ew
    without warning

    constant
       zSystemParameters = registerw32Function( user32, "SystemParametersInfoA", {C_UINT, C_UINT, C_POINTER, C_UINT}, C_LONG),
       zSPI_SETWORKAREA = 47,
       zSPI_GETWORKAREA = 48

    --

    function getWorkarea()
    -- Returns: sequence containing the coordinates of the work area,
    -- expressed in virtual screen coordinates {x1,y1, x2,y2}
      atom workarea
      sequence wa_out

      -- get pointer for RECT structure to receive coordinates
      workarea = acquire_mem( 0,SIZEOF_RECT )

      -- call C function from user32.dll
      if not w32Func( zSystemParameters, {zSPI_GETWORKAREA, 0, workarea, 0} ) then
          warnErr( "getWorkarea:SystemParametersInfo failed" )
      end if

      -- set return sequence
      wa_out = { fetch( workarea, rectLeft ),  fetch( workarea, rectTop ),
                 fetch( workarea, rectRight ), fetch( workarea, rectBottom ) }

      -- free pointer
      release_mem( workarea )

      return wa_out
    end function

    -- now, for our actual 'window' creation

    sequence area
    atom ok, x, y, cx, cy

    -- get the size and location allowing for the taskbar
    area=getWorkarea()
    x = area[1]
    y = area[2]
    cx = area[3]-area[1]
    cy = area[4] - area[2]

    constant
    Win=create( Window, " ", 0, x, y, cx, cy, 0)

    setText(Win,"total 'working' area = " & sprintf("%d",cx)
              & " by " & sprintf("%d",cy) & " pixels")

    WinMain(Win,Normal)
    -- end of first example --

In this second example,
I've tried to include some extra code that detects if the taskbar has been moved, and if it has, the program's window is re-sized to accomodate the new 'working-area' of the screen, *and* the focus is immediately set back to the program's window

I originally wrote a much simpler version of this, which worked fine in Window's 95, but showed some 'peculiar' behavior in Windows 98.
Apparently, the SetForeGroundWindow() function is no longer 'allowed' to be used this way in Win98. To further confuse the issue, even though the focus was *not* set on the program's window when the window was re-sized, the program's icon sometimes started to 'flash' mysteriously on occasion, ( ..but not with every taskbar-move ! )

I had originally just added the following event handler, which detects a task-bar move:

    -- a simple event handler, which
    -- detects if there are any system-wide changes,
    -- one of these being a new effective work area,
    -- *IF* the taskbar is moved by the user.
    procedure check(atom event,atom wParam,atom lParam)
      if event= zWM_SETTINGCHANGE  and
      wParam = zSPI_SETWORKAREA then
      resize() end if
    end procedure
    --
    onEvent[Win]=routine_id("check")

... and added a simple:

    ok = w32Func( xSetForegroundWindow,{getHandle(Win)})

... to the end of the resize() function, to set the focus back to our program window.

In Win98, it's not that simple.

Since, with every taskbar move, the focus is on the taskbar, you actually have to temporarily 'link' the message queues of the taskbar and your program, so your program 'sees' the SetForegroundWindow() message.

so, here's my updated demo, which does this for Win98.

-- full_task2.exw

    -- originally by Brian K. Broker.
    -- this modified program will re-size the
    -- main window when the taskbar is moved.
    -- Wolf Oct 2001

    include win32lib.ew
    without warning

    constant
    zSystemParameters = registerw32Function(user32, "SystemParametersInfoA",
                     {C_UINT, C_UINT, C_POINTER, C_UINT}, C_LONG),
    zSPI_SETWORKAREA = 47,
    zSPI_GETWORKAREA = 48,
    zWM_SETTINGCHANGE = 26,

    -- more new DLL calls for Win98 functionality.
    zAttachThreadInput = registerw32Function(user32,
        "AttachThreadInput",{C_INT, C_INT, C_INT}, C_INT ),
    zGetWindowThreadProcessId = registerw32Function(user32,
        "GetWindowThreadProcessId",{C_INT, C_POINTER}, C_INT),
    zGetForegroundWindow = registerw32Function(user32,
        "GetForegroundWindow", {}, C_INT)
    ----

    function getWorkarea()
    atom workarea
    sequence wa_out

    workarea = acquire_mem( 0,SIZEOF_RECT )

    if not w32Func( zSystemParameters, {zSPI_GETWORKAREA,
                   0, workarea, 0} ) then
      warnErr( "getWorkarea:SystemParametersInfo failed" )
    end if

    wa_out = { fetch( workarea, rectLeft ),  fetch( workarea, rectTop ),
               fetch( workarea, rectRight ), fetch( workarea, rectBottom ) }

    release_mem( workarea )

    return wa_out
    end function

    sequence area
    atom ok, x, y, cx, cy

    area=getWorkarea()
    x = area[1]
    y = area[2]
    cx = area[3]-area[1]
    cy = area[4] - area[2]

    constant
    Win=create(Window," ", 0, x, y, cx, cy,0),
    TheText=create(LText,"...move or re-size the taskbar.",
                   Win, 10, 10, 200, 25, 0)

    setText(Win,"total 'working' area = " & sprintf("%d",cx)
              & " by " & sprintf("%d",cy) & " pixels")

    -- re-size/re-locate the window if the taskbar has been moved,
    -- * and * set the focus back to the program's window.
    procedure resize()
    atom this_win, id_1, id_2, id_3, pid_ptr

    this_win = getHandle(Win) -- get our main window's handle.

    area=getWorkarea()
    x = area[1]
    y = area[2]
    cx = area[3]-area[1]
    cy = area[4]-area[2]
    setText(Win,"total 'working' area = " & sprintf("%d",cx )
            & " by " & sprintf("%d",cy ) & " pixels")
    ok = w32Func( xMoveWindow, {this_win, x, y, cx, cy, 1} )

    -- our new code to accomodate Win98.
    pid_ptr = acquire_mem(0,1)

    id_1 = w32Func(zGetForegroundWindow,{})
    id_2 = w32Func(zGetWindowThreadProcessId,{id_1, pid_ptr })
    id_3 = w32Func(zGetWindowThreadProcessId,{this_win, pid_ptr })

    if id_2 != id_3 then
      ok = w32Func( zAttachThreadInput,{id_2, id_3, True })
      ok = w32Func( xSetForegroundWindow,{this_win})
      ok = w32Func( zAttachThreadInput,{id_2, id_3, False })
    else
      ok = w32Func( xSetForegroundWindow,{this_win})
    end if

    release_mem(pid_ptr)
    end procedure

    -- check to see if the taskbar has been moved.
    procedure check(atom event,atom wParam,atom lParam)
      if event= zWM_SETTINGCHANGE  and
      wParam = zSPI_SETWORKAREA then
      resize() end if
    end procedure
    --
    onEvent[Win]=routine_id("check")

    WinMain(Win,Normal)
    --------

Even using this code has some peculiar side-effects, which is perhaps why Microsoft made it so difficult !
Try this:
Run this program, then bring any other program, like this tutorial to the foreground, by clicking on it's icon.
Now, just move or re-size the taskbar. Presto!

Since the WM_SETTINGCHANGE message is sent to 'all' windows, our program arrogantly 'assumes' it's the most important. It's no wonder that I've seen many programs that use the re-size code illustrated here, and none that bother with trying to set the focus as well. However, the SetForegroundWindow() code *can* be useful if you're trying to make sure a user never misses a 'critical' warning message.

I should mention that the pid_ptr variable/memory is not actually required by this demo. You could just pass a NULL as the second parameter when you call GetWindowThreadProcessId().

..end of lesson.

CONTENTS