views:

40

answers:

2

I want to position a window at the bottom of the screen. If the start menu is present, I want it to lie along the top of the start menu. If it is not (or it is auto-hidden), I still want it to be in the same position as it would be if the start menu was there, meaning there will be a gap of a few pixels.

Currently I get the monitor work area, position the window at the bottom, and always offset by 20 pixels or so. If the start menu isn't there, this works well. If it is, however, the work area also shrinks (as it should), and I end up double-offsetting.

How would I fix the issue?

A: 

Are you are using or have access to .NET in your project?

If so, you can use the Screen.PrimaryScreen.WorkingArea.Height property to determine the bottom of the screen excluding the task bar.

You can also grab the total screen height by getting the Screen.PrimaryScreen.Bounds.Height property (which includes the task bar in the total height value).

Comparing these values, if they're the same, the task bar isn't present. Otherwise, the task bar is and you can adjust accordingly.

George
hmm I don't have .NET, but I might be able to get that info with old-school win32 api calls..
Claudiu
I think the taskbar takes a few pixels even when it's hidden. And when the taskbar isn't present, how do you get its height so you can subtract it?
Mark Ransom
good point.. i was just going to assume standard win98 themed one-unit-high taskbar
Claudiu
+2  A: 

To get the work area of the screen not obscured by the system taskbar or by application desktop toolbars, you can use SystemParametersInfo() with SPI_GETWORKAREA as uiAction parameter. The pvParam parameter must point to a RECT structure that receives the coordinates of the work area, expressed in virtual screen coordinates. For example:

  RECT rectWorkArea;
  SystemParametersInfo(SPI_GETWORKAREA, 0, &rectWorkArea, 0);

As you said in the comment, to get the bounding rectangle of the taskbar, we can call SHAppBarMessage(ABM_GETTASKBARPOS, ...)

To determine the position of the taskbar (whether it is currently at the bottom, top, left, or right of the screen), you could use the following calculation:

  type
    TTaskBarPos = (_TOP, _BOTTOM, _LEFT, _RIGHT);
  var
    iScrW, iScrH: Longint;

  iScrW := GetSystemMetrics(SM_CXSCREEN);
  iScrH := GetSystemMetrics(SM_CXSCREEN);

  if (rectTaskbar.Top > iScrH div 2) and (rectTaskbar.Right >= iScrW) then
    Result := _BOTTOM
  else if (rectTaskbar.Top < iScrH div 2) and (rectTaskbar.Bottom <= iScrW div 2) then
    Result := _TOP
  else if (rectTaskbar.Left < iScrW div 2) and (rectTaskbar.Top <= 0) then
    Result := _LEFT
  else
    Result := _RIGHT;

They should be enough to solve your current problem. However, if you need to know (for another reason) the current taskbar settings of the autohide and always-on-top states, you can use SHAppBarMessage(ABM_GETSTATE, ...).

If you need to be notified that that the taskbar's autohide or always-on-top state has changed, you have to intercept ABN_STATECHANGE message.

Vantomex
Looks like `SHAppBarMessage(ABM_GETTASKBARPOS, ...)` might be the missing piece. http://msdn.microsoft.com/en-us/library/bb762108%28VS.85%29.aspx
Mark Ransom
You're right :-). I've added some missing stuffs.
Vantomex
Sorry, I implement the update using Delphi.
Vantomex