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