Help for Tune Smithy Koch snowflake icon.gif

How to show a dialog full screen

From Tune Smithy

(Difference between revisions)
Jump to: navigation, search
Line 10: Line 10:
<source lang="c">
<source lang="c">
 +
 +
BOOL bFullScreen; // somewhere in the program this gets set when you go to full screen for the dialog
 +
 +
BOOL bIsFullScreenDialog(HWND hDlg)
 +
{
 +
// simple case where you have just the one dialog
 +
// - write your own custom proc here
 +
return bFullScreen;
 +
}
 +
 +
...
  switch(message)
  switch(message)
  {
  {
  case WM_GETMINMAXINFO:
  case WM_GETMINMAXINFO:
-
   // bIsFullScreenDialog(..)
+
   // bIsFullScreenDialog(hDlg)
   // returns TRUE if the  
   // returns TRUE if the  
   // dialog has been set to full screen
   // dialog has been set to full screen
Line 41: Line 52:
<source lang="c">
<source lang="c">
-
char hide_start_menu_for_full_screen=1;
+
BOOL hide_start_menu_for_full_screen=TRUE;
-
char do_full_screen_dialogs_topmost=1;
+
BOOL do_full_screen_dialogs_topmost=TRUE;
 +
BOOL clip_to_monitor_for_full_screen_dialog=TRUE;
 +
 
 +
BOOL bHideMenuForFullScreenDialog(hDlg)
 +
{
 +
return TRUE;// Whatever
 +
}
 +
 
...
...
  switch(message)
  switch(message)
Line 61: Line 79:
   }
   }
   // What you have here depends on the style of dialog.
   // What you have here depends on the style of dialog.
 +
  // But not to worry, will check it is okay and resize a second
 +
  // time if nec.
   rcNewWin.top-=GetSystemMetrics(SM_CYSIZEFRAME);
   rcNewWin.top-=GetSystemMetrics(SM_CYSIZEFRAME);
   rcNewWin.bottom+=GetSystemMetrics(SM_CYSIZEFRAME);
   rcNewWin.bottom+=GetSystemMetrics(SM_CYSIZEFRAME);
Line 76: Line 96:
   }
   }
   MoveWindow(hDlg,rcNewWin.left,rcNewWin.top,rcNewWin.right-rcNewWin.left,rcNewWin.bottom-rcNewWin.top,bTF);
   MoveWindow(hDlg,rcNewWin.left,rcNewWin.top,rcNewWin.right-rcNewWin.left,rcNewWin.bottom-rcNewWin.top,bTF);
 +
  // Check that it is as expected, with the client area filling the monitor.
 +
  // - you don't need to do this bit normally, but it may help in some rare situations such as
 +
  // menu wrapping over several lines - or if unsure of the size of the dialog borders
 +
  {
 +
  int menu_height=GetSystemMetrics(SM_CYMENU);
 +
  // check the menu height now that the window has been made
 +
  // - needs to be done after the MoveWindow(..)
 +
  // The previous GetSystemMetrics(SM_CYMENU);
 +
  // will give wrong height if the menu wraps over more than one line
 +
  MENUBARINFO mbi;
 +
  mbi.cbSize=sizeof(mbi);
 +
  get_pGetMenuBarInfo_if_nec();
 +
  if(pGetMenuBarInfo)
 +
  {
 +
    pGetMenuBarInfo(hDlg,OBJID_MENU,0/*menu itself*/,&mbi);
 +
    menu_height=mbi.rcBar.bottom-mbi.rcBar.top;
 +
  }
 +
  }
 +
  {
 +
  RECT rcClient,rcWin;
 +
  GetWindowRect(hDlg,&rcWin);
 +
  GetClientRect(hDlg,&rcClient);
 +
  ClientToScreenRect(hDlg,&rcClient);
 +
  if(GetMenu(hDlg)&&!full_screen_dialog_hide_menu[sw_window])
 +
    rcClient.top-=menu_height;
 +
  if(!SameRect(&rcmon,&rcClient))
 +
  {
 +
    int left_margin=rcClient.left-rcWin.left;
 +
    int top_margin=rcClient.top-rcWin.top;
 +
    int right_margin=rcWin.right-rcClient.right;
 +
    int bottom_margin=rcWin.bottom-rcClient.bottom;
 +
    rcNewWin.left=rcmon.left-left_margin;
 +
    rcNewWin.top=rcmon.top-top_margin;
 +
    rcNewWin.right=rcmon.right+right_margin;
 +
    rcNewWin.bottom=rcmon.bottom+bottom_margin;
 +
    if(GetMenu(hDlg)&&bHideMenuForFullScreenDialog(hDlg))
 +
    rcNewWin.top-=menu_height;
 +
    MoveWindow(hDlg,rcNewWin.left,rcNewWin.top,rcNewWin.right-rcNewWin.left,rcNewWin.bottom-rcNewWin.top,bTF);
 +
  }
 +
  }
 +
  // Now clip to the monitor
   if(clip_to_monitor_for_full_screen_dialog)
   if(clip_to_monitor_for_full_screen_dialog)
   {
   {

Revision as of 10:35, 23 February 2010

C-code

First, the problem. It is easy to show a normal window full screen, in various ways. But for a dialog created using e.g. CreateDialog, then the problem is that it normally gets created with a border and title bar. So how to show it full screen without them?

The idea is to resize the dialog so that its edges and title bar go outside the monitor. Then - so that you can't see the extra bits of it on a multiple monitor setup - clip the window to the client area.

First of all, we need to tell Windows that our dialog can be resized larger than the screen, otherwise it will helpfully resize it to fit the screen whenever we try.

So - in the dialog proc for the window use:

BOOL bFullScreen; // somewhere in the program this gets set when you go to full screen for the dialog
 
BOOL bIsFullScreenDialog(HWND hDlg)
{
 // simple case where you have just the one dialog
 // - write your own custom proc here
 return bFullScreen;
}
 
...
 switch(message)
 {
 case WM_GETMINMAXINFO:
  // bIsFullScreenDialog(hDlg)
  // returns TRUE if the 
  // dialog has been set to full screen
  if(!bIsFullScreenDialog(hDlg))
   break;
  {
   // http://msdn.microsoft.com/en-us/library/ms632626%28VS.85%29.aspx
   // see also http://msdn.microsoft.com/en-us/magazine/cc188910.aspx
   MINMAXINFO *pmmi=(MINMAXINFO *)lParam;
   // Pointer to a MINMAXINFO structure that contains the default maximized position and dimensions, and the default minimum and maximum tracking sizes. An application can override the defaults by setting the members of this structure.
   // Now work out the border size - this will depend on your dialog - and you can over estimate
   // since this is only for situation bIsFullScreenDialog(hDlg);
   int xborder=GetSystemMetrics(SM_CXEDGE)+GetSystemMetrics(SM_CXSIZEFRAME);
   int yborder=GetSystemMetrics(SM_CYEDGE)+GetSystemMetrics(SM_CYSIZEFRAME);
   int ytitle_bar=GetSystemMetrics(SM_CYCAPTION)+(GetMenu(hDlg)?GetSystemMetrics(SM_CYMENU):0);
   // The maximum tracking size is the largest window size that can be produced by using the borders to size the window. The minimum tracking size is the smallest window size that can be produced by using the borders to size the window.
   pmmi->ptMaxTrackSize.x=GetSystemMetrics(SM_CXVIRTUALSCREEN)+xborder*2;
   pmmi->ptMaxTrackSize.y=GetSystemMetrics(SM_CYVIRTUALSCREEN)+yborder*2+ytitle_bar;
   pmmi->ptMaxPosition.x=-xborder;
   pmmi->ptMaxPosition.y=-yborder;
  }
  break;
 }

Now resize the dialog so that it is larger than the screen. To take account of multiple monitors, detect which monitor the dialog is in first

BOOL hide_start_menu_for_full_screen=TRUE;
BOOL do_full_screen_dialogs_topmost=TRUE;
BOOL clip_to_monitor_for_full_screen_dialog=TRUE;
 
BOOL bHideMenuForFullScreenDialog(hDlg)
{
 return TRUE;// Whatever
}
 
...
 switch(message)
 {
 case WM_INITDIALOG:
  if(bIsFullScreenDialog(hDlg))
  {
   RECT rcmon;
   char do_topmost=0;
   RECT rcNewWin;
   rcNewWin=rcmon=rcRectMonitorForRect(&rcWas,MONITOR_WORKAREA);
   if(hide_start_menu_for_full_screen)
   {
    rcmon=rcRectMonitorForRect(&rcWas,MONITOR_AREA);
    if(!SameRect(&rcmon,&rcNewWin))
     do_topmost=1;// Must be topmost anyway to hide the start menu
    rcNewWin=rcmon;
   }
   // What you have here depends on the style of dialog.
   // But not to worry, will check it is okay and resize a second
   // time if nec.
   rcNewWin.top-=GetSystemMetrics(SM_CYSIZEFRAME);
   rcNewWin.bottom+=GetSystemMetrics(SM_CYSIZEFRAME);
   rcNewWin.left-=GetSystemMetrics(SM_CXSIZEFRAME);
   rcNewWin.right+=GetSystemMetrics(SM_CXSIZEFRAME);
   rcNewWin.top-=GetSystemMetrics(SM_CYEDGE);
   rcNewWin.bottom+=GetSystemMetrics(SM_CYEDGE);
   rcNewWin.left-=GetSystemMetrics(SM_CXEDGE);
   rcNewWin.right+=GetSystemMetrics(SM_CXEDGE);
   rcNewWin.top-=GetSystemMetrics(SM_CYCAPTION);
   if(GetMenu(hDlg)&&bHideMenuForFullScreenDialog(hDlg))
   {
    int cy_menu=GetSystemMetrics(SM_CYMENU);
    rcNewWin.top-=cy_menu;
   }
   MoveWindow(hDlg,rcNewWin.left,rcNewWin.top,rcNewWin.right-rcNewWin.left,rcNewWin.bottom-rcNewWin.top,bTF);
  // Check that it is as expected, with the client area filling the monitor.
  // - you don't need to do this bit normally, but it may help in some rare situations such as
  // menu wrapping over several lines - or if unsure of the size of the dialog borders
  {
   int menu_height=GetSystemMetrics(SM_CYMENU);
   // check the menu height now that the window has been made
   // - needs to be done after the MoveWindow(..)
   // The previous GetSystemMetrics(SM_CYMENU);
   // will give wrong height if the menu wraps over more than one line
   MENUBARINFO mbi;
   mbi.cbSize=sizeof(mbi);
   get_pGetMenuBarInfo_if_nec();
   if(pGetMenuBarInfo)
   {
    pGetMenuBarInfo(hDlg,OBJID_MENU,0/*menu itself*/,&mbi);
    menu_height=mbi.rcBar.bottom-mbi.rcBar.top;
   }
  }
  {
   RECT rcClient,rcWin;
   GetWindowRect(hDlg,&rcWin);
   GetClientRect(hDlg,&rcClient);
   ClientToScreenRect(hDlg,&rcClient);
   if(GetMenu(hDlg)&&!full_screen_dialog_hide_menu[sw_window])
    rcClient.top-=menu_height;
   if(!SameRect(&rcmon,&rcClient))
   {
    int left_margin=rcClient.left-rcWin.left;
    int top_margin=rcClient.top-rcWin.top;
    int right_margin=rcWin.right-rcClient.right;
    int bottom_margin=rcWin.bottom-rcClient.bottom;
    rcNewWin.left=rcmon.left-left_margin;
    rcNewWin.top=rcmon.top-top_margin;
    rcNewWin.right=rcmon.right+right_margin;
    rcNewWin.bottom=rcmon.bottom+bottom_margin;
    if(GetMenu(hDlg)&&bHideMenuForFullScreenDialog(hDlg))
     rcNewWin.top-=menu_height;
    MoveWindow(hDlg,rcNewWin.left,rcNewWin.top,rcNewWin.right-rcNewWin.left,rcNewWin.bottom-rcNewWin.top,bTF);
   }
  }
  // Now clip to the monitor
   if(clip_to_monitor_for_full_screen_dialog)
   {
    // Clip by edges showing outside the window
    HRGN hRgn=CreateRectRgn(rcmon.left-rcNewWin.left,rcmon.top-rcNewWin.top,rcmon.right-rcNewWin.left
     ,rcmon.bottom-rcNewWin.top);
    SetWindowRgn(hDlg,hRgn,FALSE);
   }
   if(do_topmost&&do_full_screen_dialogs_topmost)
    SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
   break;
  }
 }

Now just need to supply the extra routines we need for boilerplate type stuff - there's only one, to detect the size and position of the monitor nearest to the dialog:

#include <multimon.h>
#define MONITOR_WORKAREA 0x0002        // use monitor work area
#define MONITOR_AREA     0x0000        // use monitor entire area
 
RECT rcRectMonitorForRect(RECT *prc,DWORD flags)
{
 HMONITOR hMonitor;
 MONITORINFO mi;
 RECT        rc;
 // get the nearest monitor to the passed rect.
 //
 hMonitor = MonitorFromRect(prc, MONITOR_DEFAULTTONEAREST);
 
 //
 // get the work area or entire monitor rect.
 //
 mi.cbSize = sizeof(mi);
 GetMonitorInfo(hMonitor, &mi);
 
 if (flags & MONITOR_WORKAREA)
     rc = mi.rcWork;
 else
     rc = mi.rcMonitor;
 return rc;
}

If you want to do this in C++ then Full Screen Display and Implementing Drag to Move Dialogs may be helpful. That's where I learnt about WM_GETMINMAXINFO in fact.

The clip to window technique used here can also be used to make a dialog that is draggable without a title bar - clip in the same way, and make it draggable using the HTCAPTION trick - see How to make any part of a window or dialog draggable

Personal tools
Namespaces
Variants
Actions
Navigation
How to use the wiki
More
Toolbox