home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / owlsrc.pak / FRAMEWIN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-24  |  26.2 KB  |  1,020 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // (C) Copyright 1991, 1994 by Borland International, All Rights Reserved
  4. //
  5. //   Implementation of class TFrameWindow
  6. //----------------------------------------------------------------------------
  7. #pragma hdrignore SECTION
  8. #include <owl/owlpch.h>
  9. #include <owl/framewin.h>
  10. #include <owl/applicat.h>
  11. #include <owl/menu.h>
  12.  
  13. #if !defined(SECTION) || SECTION == 1
  14.  
  15. DEFINE_RESPONSE_TABLE1(TFrameWindow, TWindow)
  16.   EV_WM_PAINT,
  17.   EV_WM_ERASEBKGND,
  18.   EV_WM_QUERYDRAGICON,
  19.   EV_WM_INITMENUPOPUP,
  20.   EV_WM_SETFOCUS,
  21.   EV_WM_SIZE,
  22.   EV_WM_PARENTNOTIFY,
  23.   EV_WM_ENTERIDLE,
  24. END_RESPONSE_TABLE;
  25.  
  26. //
  27. // Enable/disable the command sender, in this case the menu item.
  28. //
  29. void
  30. TMenuItemEnabler::Enable(bool enable)
  31. {
  32.   TCommandEnabler::Enable(enable);
  33.   ::EnableMenuItem(HMenu, Position,
  34.                    MF_BYPOSITION | (enable ? MF_ENABLED : MF_GRAYED));
  35. }
  36.  
  37. //
  38. // Set the text for the command sender, in this case the menu item.
  39. //
  40. void
  41. TMenuItemEnabler::SetText(const char far* str)
  42. {
  43.   ::ModifyMenu(HMenu, Position, MF_BYPOSITION | MF_STRING, Id, str);
  44. }
  45.  
  46. //
  47. // Set the check state of the command sender, in this case the menu item.
  48. //
  49. void
  50. TMenuItemEnabler::SetCheck(int state)
  51. {
  52.   ::CheckMenuItem(HMenu, Position,
  53.                   MF_BYPOSITION | (state == Checked ? MF_CHECKED : MF_UNCHECKED));
  54. }
  55.  
  56. //----------------------------------------------------------------------------
  57.  
  58. //
  59. // constructor for a TFrameWindow
  60. //
  61. TFrameWindow::TFrameWindow(TWindow*        parent,
  62.                            const char far* title,
  63.                            TWindow*        clientWnd,
  64.                            bool            shrinkToClient,
  65.                            TModule*        module)
  66. {
  67.   //
  68.   // Initialize virtual base, in case the derived-most used default ctor
  69.   //
  70.   TWindow::Init(parent, title, module);
  71.  
  72.  
  73.   IconResId = 0;  // remember that we still need to init
  74.   Init(clientWnd, shrinkToClient);
  75. }
  76.  
  77. //
  78. // constructor for a TFrameWindow. This ctor is generally not used by derived
  79. // classes, only as generic alias to a framewindow-like HWND
  80. //
  81. TFrameWindow::TFrameWindow(HWND hWnd, TModule* module)
  82.   : TWindow(hWnd, module)
  83. {
  84.   Init(0);
  85. }
  86.  
  87. //
  88. // Protected constructor for use by immediate virtually derived classes.
  89. // Immediate derivitives must call Init() before constructions are done.
  90. //
  91. TFrameWindow::TFrameWindow()
  92. {
  93.   IconResId = 0;  // Zero this member to remember that we still need to init
  94. }
  95.  
  96. //
  97. // Normal initialization of a default constructed TFrameWindow. Is ignored
  98. // if called more than once.
  99. //
  100. void
  101. TFrameWindow::Init(TWindow* clientWnd, bool shrinkToClient)
  102. {
  103.   if (!IconResId) {
  104.     Attr.Style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
  105.     Attr.X = Attr.W = CW_USEDEFAULT;
  106.  
  107.     if (clientWnd)
  108.       Attr.Style |= WS_CLIPCHILDREN;
  109.  
  110.     if (shrinkToClient)
  111.       SetFlag(wfShrinkToClient);
  112.  
  113.     Init(clientWnd);
  114.   }
  115. }
  116.  
  117. //
  118. // Private initializer does a bulk of the common frame window initialization
  119. //
  120. void
  121. TFrameWindow::Init(TWindow* clientWnd)
  122. {
  123.   HWndRestoreFocus = 0;
  124.   KeyboardHandling = false;
  125.   ClientWnd = clientWnd;
  126.  
  127.   MenuDescr = 0;
  128.   MergeModule = 0;
  129.  
  130.   IconModule = ::Module;
  131.   IconResId = IDI_OWLAPP;
  132.  
  133.   MinimizedPos = TPoint(-1,-1);  // Windows convention for never minimized
  134.  
  135.   if (ClientWnd) {
  136.     ClientWnd->SetParent(this);
  137.     ClientWnd->EnableAutoCreate();  // in case client is a dialog
  138.     SetBkgndColor(NoErase);         // no need to erase client area
  139.   }
  140. }
  141.  
  142. TFrameWindow::~TFrameWindow()
  143. {
  144.   delete MenuDescr;
  145. }
  146.  
  147. static uint32
  148. GetMenuStateBits(HMENU hmenu, int count)
  149. {
  150.   uint32 bit = 1;
  151.   uint32 result = 0;
  152.  
  153.   for (int i=0; i<count; i++) {
  154.     uint state = GetMenuState(hmenu, i, MF_BYPOSITION);
  155.     if (state != (uint)-1) {
  156.       if (!(state  & (MF_DISABLED | MF_GRAYED))) {
  157.         result |= bit;
  158.       }
  159.     }
  160.     bit <<= 1;
  161.   }
  162.  
  163.   return result;
  164. }
  165.  
  166. void
  167. TFrameWindow::EvInitMenuPopup(HMENU hPopupMenu, uint index, bool sysMenu)
  168. {
  169.   if (!sysMenu && hPopupMenu) {
  170.     const int count = ::GetMenuItemCount(hPopupMenu);
  171.  
  172.     // Save current state of visible top level menus
  173.     //
  174.     uint32 preState = 0;
  175.     if (hPopupMenu == GetMenu())
  176.       preState = GetMenuStateBits(hPopupMenu, count);
  177.  
  178.     TWindow::EvInitMenuPopup(hPopupMenu, index, sysMenu);
  179.  
  180.     // If the top level menu state changes, redraw the menu bar
  181.     //
  182.     if (hPopupMenu == GetMenu())
  183.       if (GetMenuStateBits(hPopupMenu, count) != preState)
  184.         DrawMenuBar();
  185.   }
  186. }
  187.  
  188. static void
  189. DoIdleAction(TWindow* win, void* idleCount)
  190. {
  191.   win->IdleAction(*(long*)idleCount);
  192. }
  193.  
  194. //
  195. // TFrameWindow processes idle action occurs once per block of messages
  196. //
  197. bool
  198. TFrameWindow::IdleAction(long idleCount)
  199. {
  200.   if (idleCount == 0) {
  201.     // do command enabling for the menu bar if this is the active task
  202.     //
  203. #if defined(BI_PLAT_WIN32)
  204.     if (GetFocus()) {
  205. #else
  206.     HWND focus = GetFocus();
  207.     if (focus && ::GetWindowTask(focus) == GetCurrentTask()) {
  208. #endif
  209.       long style = ::GetWindowLong(*this, GWL_STYLE);
  210.       if (!(style & WS_CHILD)) {
  211.         HMENU hMenu = ::GetMenu(*this);
  212.         if (IsMenu(hMenu))
  213.           HandleMessage(WM_INITMENUPOPUP, WPARAM(hMenu));
  214.       }
  215.     }
  216.     // give child windows an opportunity to do any idle processing
  217.     //
  218.     ForEach(DoIdleAction, &idleCount);
  219.   }
  220.   return false;  // we don't need any more time for now
  221. }
  222.  
  223. //
  224. // Locate and return the child window that is the target of command and command
  225. // enable messages.
  226. //
  227. HWND
  228. TFrameWindow::GetCommandTarget()
  229. {
  230.   // Start with the focus window
  231.   //
  232.   HWND  hFocus = ::GetFocus();
  233.  
  234.   // If its a child of ours, then return it.
  235.   //
  236.   if (IsChild(hFocus))
  237.     return hFocus;
  238.  
  239.   // The focus is not our descendent, use our most recently active child
  240.   //
  241.   if (HWndRestoreFocus)
  242.     return HWndRestoreFocus;
  243.  
  244.   // If we have a client, fall back on that
  245.   //
  246.   if (GetClientWindow())
  247.     return *GetClientWindow();
  248.  
  249.   // Don't know who else to send it to, return ourselves
  250.   //
  251.   return *this;
  252. }
  253.  
  254. //
  255. // Handle WM_COMMAND to provide extra processing for commands: send the
  256. // command down the command chain
  257. //
  258. LRESULT
  259. TFrameWindow::EvCommand(uint id, HWND hWndCtl, uint notifyCode)
  260. {
  261.   // walk the command chain from the focus child back up to us or until
  262.   // we hit a child that is an owl window. Delegate to owl-child or forward to
  263.   // our base if no child is found.
  264.   //
  265.   if (hWndCtl == 0) {
  266.     HWND  hCmdTarget = GetCommandTarget();
  267.  
  268.     // Check owl parentage too in case the hWnds were reparented
  269.     //
  270.     while (hCmdTarget && hCmdTarget != HWindow) {
  271.       TWindow*  cmdTarget = GetWindowPtr(hCmdTarget);
  272.  
  273.       if (cmdTarget)
  274.         return cmdTarget->EvCommand(id, hWndCtl, notifyCode);
  275.  
  276.       hCmdTarget = ::GetParent(hCmdTarget);
  277.     }
  278.   }
  279.  
  280.   return TWindow::EvCommand(id, hWndCtl, notifyCode);
  281. }
  282.  
  283. //
  284. // Handle WM_COMMAND_ENABLE to provide command enable distribution and default
  285. // support for windows without command enable handlers.
  286. //
  287. void
  288. TFrameWindow::EvCommandEnable(TCommandEnabler& commandEnabler)
  289. {
  290.   // Don't process for windows out of our window tree (esp. other apps)
  291.   //
  292.   RouteCommandEnable(GetCommandTarget(), commandEnabler);
  293. }
  294.  
  295. //
  296. // Preprocess queued messages to handle translation of accelerators on a per
  297. // window basis, and dialog-like keyboard navigation if enabled.
  298. //
  299. bool
  300. TFrameWindow::PreProcessMsg(MSG& msg)
  301. {
  302.   if (TWindow::PreProcessMsg(msg))
  303.     return true;  // process accelerators
  304.  
  305.   if (KeyboardHandling && msg.message >= WM_KEYFIRST &&
  306.                           msg.message <= WM_KEYLAST) {
  307.     HWND parent = ::GetParent(msg.hwnd);
  308.  
  309.     //
  310.     // Retrieve the COMBO handle if we're in the EDIT ctl
  311.     // parented to the combobox
  312.     //
  313.     char szClassName[0x10];
  314.     ::GetClassName(parent, szClassName, sizeof(szClassName));
  315.     if (!strcmpi(szClassName, "COMBOBOX"))
  316.       parent = ::GetParent(parent);
  317.  
  318.     if (parent && ::IsDialogMessage(parent, &msg));
  319.       return true;
  320.   }
  321.  
  322.   return false;
  323. }
  324.  
  325. //
  326. // Overrides TWindow's non-virtual SetMenu to make it virtual. This allows
  327. // derived frame classes to implement this differently
  328. // It also calls the application's PreProcessMenu() if it is the main window
  329. // to let it make any changes just before setting.
  330. //
  331. bool
  332. TFrameWindow::SetMenu(HMENU newMenu)
  333. {
  334.   if (IsFlagSet(wfMainWindow))
  335.     GetApplication()->PreProcessMenu(newMenu);
  336.  
  337.   return TWindow::SetMenu(newMenu);
  338. }
  339.  
  340. //
  341. // Perform a high-level menu assignment either before or after the HWND for the
  342. // window has been created.
  343. //
  344. // returns true if successful; false otherwise
  345. //
  346. bool
  347. TFrameWindow::AssignMenu(TResId menuResId)
  348. {
  349.   if (menuResId != Attr.Menu) {
  350.     if (Attr.Menu.IsString())
  351.       delete (char far*)Attr.Menu;
  352.  
  353.     Attr.Menu = menuResId.IsString() ? strnewdup(menuResId) : (char far*)menuResId;
  354.   }
  355.  
  356.   // if the window has been created then load and set the new menu and destroy
  357.   // the old menu
  358.   //
  359.   if (!HWindow)
  360.     return true;
  361.  
  362.   HMENU curMenu = GetMenu();
  363.   HMENU newMenu = GetModule()->LoadMenu(Attr.Menu);
  364.  
  365.   if (!SetMenu(newMenu))
  366.     return false;
  367.  
  368.   if (curMenu)
  369.     ::DestroyMenu(curMenu);
  370.  
  371.   return true;
  372. }
  373.  
  374. //
  375. // Set the Icon for use when this frame is minimized
  376. //
  377. bool
  378. TFrameWindow::SetIcon(TModule* module, TResId resId)
  379. {
  380.   IconModule = module;
  381.   IconResId = resId;
  382.   return true;
  383. }
  384.  
  385. //
  386. // Return the current client window as a TWindow*
  387. //
  388. TWindow*
  389. TFrameWindow::GetClientWindow()
  390. {
  391.   return ClientWnd;
  392. }
  393.  
  394. //
  395. // Remove the current client (if any) and set a new one.
  396. // Assume clientWnd was parented to us.
  397. //
  398. TWindow*
  399. TFrameWindow::SetClientWindow(TWindow* clientWnd)
  400. {
  401.   TWindow* oldClientWnd = ClientWnd;
  402.   HWND oldHWnd = oldClientWnd ? oldClientWnd->HWindow : (HWND)0;
  403.   RemoveChild(ClientWnd);
  404.  
  405.   if (HWndRestoreFocus == oldHWnd)
  406.     HWndRestoreFocus = 0;
  407.  
  408.   ClientWnd = clientWnd;
  409.  
  410.   if (ClientWnd) {
  411.     ClientWnd->SetParent(this);
  412.     if (!ClientWnd->HWindow)
  413.       ClientWnd->Create();
  414.     ClientWnd->Show(SW_NORMAL);
  415.     SetBkgndColor(NoErase);         // no need to erase client area
  416.     ResizeClientWindow();
  417.   }
  418.   else
  419.     SetBkgndColor(NoColor);         // will need to erase client area
  420.  
  421.   if (ClientWnd && ClientWnd->HWindow)
  422.     ClientWnd->SetFocus();
  423.   else
  424.     SetFocus();
  425.  
  426.   return oldClientWnd;
  427. }
  428.  
  429. //
  430. // If someone removes our client with a RemoveChild() call, update our client
  431. // and restore focus ptrs.
  432. //
  433. void
  434. TFrameWindow::RemoveChild(TWindow* child)
  435. {
  436.   TWindow::RemoveChild(child);
  437.   if (child) {
  438.     if (child == ClientWnd)
  439.       ClientWnd = 0;
  440.     if (child->HWindow == HWndRestoreFocus)
  441.       HWndRestoreFocus = 0;
  442.   }
  443. }
  444.  
  445. //
  446. // Set the document style title for this frame window. Uses SetWindowText to
  447. // modify the caption directly without modifying the Title data member.
  448. // Generates a composite title based on Title if it exists, docname, and index
  449. // if it is > 0.
  450. //  [<Title> - ]<docname>[:<index>]
  451. //
  452. bool
  453. TFrameWindow::SetDocTitle(const char far* docname, int index)
  454. {
  455.   if (index >= 0) {
  456.     string title;
  457.  
  458.     if (Title && *Title) {
  459.       title = Title;
  460.       title += " - ";
  461.     }
  462.     title += docname;
  463.     if (index > 0) {
  464.       title += ':';
  465.       char num[10];
  466.       itoa(index, num, 10);
  467.       title += num;
  468.     }
  469.  
  470.     SetWindowText(title.c_str());
  471.  
  472.   }  // else if index negative, simply acknowledge that title will display
  473.  
  474.   return true;
  475. }
  476.  
  477. //
  478. // Obtain the real windows application icon. The IDI_APPLICATION icon is an
  479. // ugly black & white box, but when a class is registered with this icon it
  480. // gets substituted with a better windows icon. Worse case we end up with the
  481. // ugly box icon.
  482. //
  483. static HICON
  484. getAppIcon()
  485. {
  486.   static HICON hRealAppIcon = 0;
  487.   if (!hRealAppIcon) {
  488.     WNDCLASS wndClass;
  489.     static char className[] = "IconSnarfer";
  490.     memset(&wndClass, 0, sizeof wndClass);
  491.     wndClass.hInstance = *::Module;
  492.     wndClass.hIcon = ::LoadIcon(0, IDI_APPLICATION);
  493.     wndClass.lpszClassName = className;
  494.     wndClass.lpfnWndProc = ::DefWindowProc;
  495.     ::RegisterClass(&wndClass);
  496.     ::GetClassInfo(*::Module, className, &wndClass);
  497.     hRealAppIcon = wndClass.hIcon;
  498.     ::UnregisterClass(className, *::Module);
  499.   }
  500.   return hRealAppIcon ? hRealAppIcon : ::LoadIcon(0, IDI_APPLICATION);
  501. }
  502.  
  503. //
  504. // Response method for an incoming WM_PAINT message
  505. //
  506. // If iconic, and an icon has been defined then draw that.
  507. // Or, if iconic & there is a client window, then call its paint function.
  508. //
  509. // If not iconic, forwards to TWindow for normal paint processing
  510. //
  511. void
  512. TFrameWindow::EvPaint()
  513. {
  514.   if (IsIconic() && (IconResId || ClientWnd)) {
  515.     TPaintDC  dc(HWindow);
  516.  
  517.     if (IconResId) {
  518.       HINSTANCE hInstance = IconModule ? HINSTANCE(*IconModule) : HINSTANCE(0);
  519.       HICON hIcon = ::LoadIcon(hInstance, IconResId);
  520.       ::DrawIcon(dc, 0, 0, hIcon ? hIcon : getAppIcon());
  521.     }
  522.     else
  523.         ClientWnd->Paint(dc, dc.Ps.fErase, *(TRect*)&dc.Ps.rcPaint);
  524.   }
  525.   else
  526.     TWindow::EvPaint();
  527. }
  528.  
  529. //
  530. // Response method for an incoming WM_ERASEBKGND message
  531. //
  532. // If this frame window is iconic, and there is a client window, then give it
  533. // a chance to erase the background since it may want to take over painting.
  534. //
  535. // If not iconic, forward to TWindow for normal erase background processing
  536. //
  537. bool
  538. TFrameWindow::EvEraseBkgnd(HDC hDC)
  539. {
  540.   if (IsIconic()) {
  541.     if (!IconResId && ClientWnd)
  542.       return (bool)ClientWnd->HandleMessage(WM_ERASEBKGND, WPARAM(hDC));
  543.  
  544.     HandleMessage(WM_ICONERASEBKGND, WPARAM(hDC));
  545.     return true;
  546.   }
  547.   else
  548.     return TWindow::EvEraseBkgnd(hDC);
  549. }
  550.  
  551. //
  552. // Response method for an incoming WM_QUERYDRAGICON message
  553. //
  554. // If there is an icon set for this frame, then return it so that windows
  555. // can make a nice cursor out of it when the user drags the icon
  556. //
  557. HANDLE
  558. TFrameWindow::EvQueryDragIcon()
  559. {
  560.   if (IconResId) {
  561.     HINSTANCE hInstance = IconModule ? HINSTANCE(*IconModule) : HINSTANCE(0);
  562.     HICON hIcon = ::LoadIcon(hInstance, IconResId);
  563.     return hIcon ? hIcon : getAppIcon();
  564.   }
  565.   else
  566.     return TWindow::EvQueryDragIcon();
  567. }
  568.  
  569. static inline bool
  570. IsEnabledVisibleChild(long style)
  571. {
  572.   return (style & (WS_CHILD | WS_VISIBLE | WS_DISABLED)) == (WS_CHILD | WS_VISIBLE);
  573. }
  574.  
  575. static TWindow*
  576. SearchForChildWithTab(TWindow* win)
  577. {
  578.   TWindow*  firstChild = win->GetFirstChild();
  579.  
  580.   if (firstChild) {
  581.     TWindow*  child = firstChild;
  582.  
  583.     do {
  584.       if (child->HWindow) {
  585.         long  style = child->GetWindowLong(GWL_STYLE);
  586.  
  587.         if (IsEnabledVisibleChild(style)) {
  588.           if (style & WS_TABSTOP)
  589.             return child;
  590.  
  591.           else {
  592.             TWindow*  result = SearchForChildWithTab(child);
  593.             if (result)
  594.               return result;
  595.           }
  596.         }
  597.       }
  598.       child = child->Next();
  599.     } while (child != firstChild);
  600.   }
  601.  
  602.   return 0;
  603. }
  604.  
  605. static bool
  606. EnabledVisibleChild(TWindow* win, void*)
  607. {
  608.   return win->HWindow ? IsEnabledVisibleChild(win->GetWindowLong(GWL_STYLE)) :
  609.                         false;
  610. }
  611.  
  612. //
  613. // if the receiver doesn't have any children then returns 0. otherwise
  614. // we search for the first child with WS_TABSTOP; if no child has WS_TABSTOP
  615. // then we return the first enabled visible child
  616. //
  617. // does a depth-first search of nested child windows
  618. //
  619. // NOTE: we stop at the first child with WS_TABSTOP and do not search its
  620. //       children...
  621. //
  622. TWindow*
  623. TFrameWindow::FirstChildWithTab()
  624. {
  625.   TWindow*  win = SearchForChildWithTab(this);
  626.  
  627.   return win ? win : FirstThat(EnabledVisibleChild);
  628. }
  629.  
  630. //
  631. // Respond to a request to hold on to the handle of a child window that is
  632. // losing focus, so that we can restore it again later (below).
  633. //
  634. // return true if caller can stop searching for a window to hold its handle.
  635. //
  636. bool
  637. TFrameWindow::HoldFocusHWnd(HWND hWndLose, HWND hWndGain)
  638. {
  639.   if (IsChild(hWndLose)) {
  640.     if (!hWndGain || !IsChild(hWndGain))
  641.       HWndRestoreFocus = hWndLose;
  642.     return true;
  643.   }
  644.   return hWndLose == HWindow;
  645. }
  646.  
  647. //
  648. // Handle WM_SETFOCUS to return focus back to the child that had it most
  649. // recently, or find the best one to give it to otherwise.
  650. //
  651. void
  652. TFrameWindow::EvSetFocus(HWND hWndLostFocus)
  653. {
  654.   TWindow::EvSetFocus(hWndLostFocus);
  655.  
  656.   if (HWndRestoreFocus) {
  657.     //
  658.     // Set focus to the saved HWND as long as it is still a valid window handle
  659.     //
  660.     if (::IsWindow(HWndRestoreFocus))
  661.       ::SetFocus(HWndRestoreFocus);
  662.  
  663.     HWndRestoreFocus = 0;
  664.   }
  665.   else {
  666.     TWindow*  win = FirstChildWithTab();
  667.  
  668.     if (win && win->HWindow != hWndLostFocus)
  669.       win->SetFocus();
  670.   }
  671. }
  672.  
  673. //
  674. // Close this window if the client is destroyed
  675. //
  676. // Clear the wfFullyCreated flag on any child that is destroyed
  677. // Resize this frame if the client changes size & wfShrinkToClient is set
  678. //
  679. void
  680. TFrameWindow::EvParentNotify(uint event,
  681.                              uint childHandleOrX, uint /*childIDOrY*/)
  682. {
  683.   if (event == WM_DESTROY) {
  684.     if (ClientWnd && ClientWnd->HWindow == HWND(childHandleOrX))
  685.       PostMessage(WM_CLOSE);  // using ShutDownWindow() has side effects
  686.  
  687.     TWindow* c = GetWindowPtr(HWND(childHandleOrX));
  688.     if (c)
  689.       c->ClearFlag(wfFullyCreated);
  690.   }
  691.   else if (event == WM_SIZE) {
  692.     if (IsFlagSet(wfShrinkToClient)
  693.         && ClientWnd
  694.         && ClientWnd->HWindow == HWND(childHandleOrX)
  695.         && !IsIconic())
  696.       ResizeClientWindow();
  697.   }
  698. }
  699.  
  700. //
  701. // Watch for WM_ENTERIDLE messages from idling modal dialog boxes so that
  702. // background processing can continue when they are up.
  703. //
  704. void
  705. TFrameWindow::EvEnterIdle(uint source, HWND hWndDlg)
  706. {
  707.   if (source == MSGF_DIALOGBOX && IsFlagSet(wfMainWindow))
  708.     IdleAction(0);  // could call GetApplication()->IdleAction(0)...
  709.   TWindow::EvEnterIdle(source, hWndDlg);
  710. }
  711.  
  712. //
  713. // Resize & reposition the client window to fit in this frames client area
  714. // or resize the frame to fit around the client's client area if
  715. // wfShrinkToClient
  716. // Return true if a client was actualy resized.
  717. // Adjust clients styles & make sure they get set.
  718. //
  719. bool
  720. TFrameWindow::ResizeClientWindow(bool redraw)
  721. {
  722.   if (!ClientWnd)
  723.     return false;
  724.  
  725.   // prevent recursion during resize by ignore calls from EvParentNotify and
  726.   // EvSize when we have already been called
  727.   // do this by disabling notifications while resizing using the
  728.   // wfShrinkToClient flag as a semaphore on the client
  729.   //
  730.   if (ClientWnd->IsFlagSet(wfShrinkToClient))
  731.     return true;
  732.   ClientWnd->SetFlag(wfShrinkToClient);
  733.  
  734.   bool  clientResized = false;
  735.   TSize frameSize = GetClientRect().Size();
  736.   TSize childSize = ClientWnd->GetWindowRect().Size();
  737.  
  738.   // first time through, strip client window of thick borders
  739.   // if shrink-to-client, then must measure the client size first
  740.   // if the client has scrolls bars, we must hide them to obtain the correct
  741.   // size
  742.   // Border style is left on & dealt with by hand below
  743.   //
  744.   const uint32 badClientStyles = WS_DLGFRAME | WS_THICKFRAME | // bad borders
  745.                                  WS_POPUP | WS_OVERLAPPED;     // bad parenting
  746.   const uint32 badClientExStyles = WS_EX_DLGMODALFRAME;
  747.   if ((ClientWnd->Attr.Style & badClientStyles) ||
  748.       (ClientWnd->Attr.ExStyle & badClientExStyles)) {
  749.     if (IsFlagSet(wfShrinkToClient)) {
  750.       TSize tstSize = ClientWnd->GetClientRect().Size();
  751.       ClientWnd->ShowScrollBar(SB_BOTH, false);
  752.       childSize = ClientWnd->GetClientRect().Size();
  753.       if (childSize != tstSize) {
  754.         int restore = SB_BOTH;
  755.         if (childSize.cx == tstSize.cx)
  756.           restore = SB_HORZ;
  757.         if (childSize.cy == tstSize.cy)
  758.           restore = SB_VERT;
  759.         ClientWnd->ShowScrollBar(restore, true);
  760.       }
  761.     }
  762.     if (ClientWnd->Attr.Style & badClientStyles) {
  763.       bool reparent = (ClientWnd->Attr.Style & (WS_POPUP|WS_OVERLAPPED)) != 0;
  764.       ClientWnd->Attr.Style &= ~badClientStyles;
  765.       ClientWnd->Attr.Style |= WS_CHILD | WS_BORDER | WS_VISIBLE;
  766.       ClientWnd->SetWindowLong(GWL_STYLE, ClientWnd->Attr.Style);
  767.       if (reparent)
  768.         ::SetParent(*ClientWnd, *this);
  769.     }
  770.     if (ClientWnd->Attr.ExStyle & badClientExStyles) {
  771.       ClientWnd->Attr.ExStyle &= ~badClientExStyles;
  772.       ClientWnd->SetWindowLong(GWL_EXSTYLE, ClientWnd->Attr.ExStyle);
  773.     }
  774.   }
  775.   if (ClientWnd->Attr.Style & WS_BORDER) {
  776.     childSize = ClientWnd->GetClientRect().Size();
  777.   }
  778.   if (childSize != frameSize) {
  779.     if (IsFlagSet(wfShrinkToClient)) {
  780.       TRect outside = GetWindowRect();
  781.       TPoint outsideOrg(0, 0);
  782.       if (Parent)
  783.         Parent->ClientToScreen(outsideOrg); // adjust our rect by our parent's
  784.  
  785.       TSize border = outside.Size() - frameSize;
  786.       MoveWindow(outside.left - outsideOrg.x, outside.top - outsideOrg.y,
  787.                  childSize.cx + border.cx, childSize.cy + border.cy, redraw);
  788.       frameSize = childSize;     // must move client, will not cause an EvSize
  789.     }
  790.     else {
  791.       clientResized = true;      // client will get resized
  792.     }
  793.   }
  794.   // If frame is sizeable, turn off flag so that user can then resize
  795.   // after initial setup
  796.   //
  797.   if (Attr.Style & WS_THICKFRAME)
  798.     ClearFlag(wfShrinkToClient);
  799.  
  800.   // Handle border style by shoving the client's borders under the frame
  801.   //
  802.   if (ClientWnd->Attr.Style & WS_BORDER) {
  803.     int bx = ::GetSystemMetrics(SM_CXBORDER);
  804.     int by = ::GetSystemMetrics(SM_CYBORDER);
  805.     ClientWnd->MoveWindow(-bx, -by, frameSize.cx+bx+bx, frameSize.cy+by+by, redraw);
  806.   }
  807.   else
  808.     ClientWnd->MoveWindow(0, 0, frameSize.cx, frameSize.cy, redraw);
  809.  
  810.   ClientWnd->ClearFlag(wfShrinkToClient);
  811.   return clientResized;
  812. }
  813.  
  814. //
  815. // called following a successful association between an MS-Windows interface
  816. // element and a TFrameWindow
  817. //
  818. void
  819. TFrameWindow::SetupWindow()
  820. {
  821.   // create windows in child list (this includes the client window)
  822.   //
  823.   TWindow::SetupWindow();
  824.  
  825.   ResizeClientWindow();
  826.  
  827.   if (MinimizedPos != TPoint(-1,-1)) {
  828.     WINDOWPLACEMENT windata;
  829.     windata.length = sizeof(WINDOWPLACEMENT);
  830.     GetWindowPlacement(&windata);
  831.     windata.flags = WPF_SETMINPOSITION;
  832.     windata.showCmd = SW_SHOWNA;
  833.     windata.ptMinPosition = MinimizedPos;
  834.     SetWindowPlacement(&windata);
  835.   }
  836.  
  837.   // if SetMenuDescr() was called before window created, update the menu now
  838.   //
  839.   if (IsFlagSet(wfMainWindow) && MenuDescr) {
  840.     HMENU curMenu = GetMenu();
  841.     TMenu newMenu(*MenuDescr, NoAutoDelete);
  842.     if (SetMenu(newMenu)) {
  843.       if (curMenu)
  844.         ::DestroyMenu(curMenu);
  845.     }
  846.     else
  847.       ::DestroyMenu(newMenu);
  848.   }
  849.  
  850.   // if we haven't set HWndRestoreFocus then pick the first child with tabstop
  851.   //
  852.   if (!HWndRestoreFocus) {
  853.     TWindow*  win = FirstChildWithTab();
  854.  
  855.     HWndRestoreFocus = win ? win->HWindow : HWindow;
  856.   }
  857. }
  858.  
  859. //
  860. // response method for an incoming WM_SIZE message
  861. //
  862. // if not minimizing resizes the client window to be the same size as the
  863. // client rectangle,
  864. // if no WM_SIZE sent, forwards WM_SIZE message to client so it can recalc.
  865. //
  866. void
  867. TFrameWindow::EvSize(uint sizeType, TSize& size)
  868. {
  869.   TWindow::EvSize(sizeType, size);
  870.  
  871.   if (ClientWnd) {
  872.     bool sizeSent = false;
  873.     if (sizeType != SIZE_MINIMIZED) {
  874.       sizeSent = ResizeClientWindow();
  875.       size = ClientWnd->GetClientRect().Size();
  876.     }
  877.     if (!sizeSent)
  878.       ClientWnd->ForwardMessage();
  879.   }
  880. }
  881.  
  882. #endif
  883. #if !defined(SECTION) || SECTION == 2
  884.  
  885. //
  886. // Set the menu descriptor for this frame window
  887. //
  888. void
  889. TFrameWindow::SetMenuDescr(const TMenuDescr& menuDescr)
  890. {
  891.   delete MenuDescr;
  892.   MenuDescr = new TMenuDescr(menuDescr);
  893.  
  894.   if (IsFlagSet(wfMainWindow) && HWindow) {
  895.     HMENU curMenu = GetMenu();
  896.     TMenu newMenu(*MenuDescr, NoAutoDelete);
  897.     if (SetMenu(newMenu))
  898.       ::DestroyMenu(curMenu);
  899.     else
  900.       ::DestroyMenu(newMenu);
  901.   }
  902. }
  903.  
  904. //
  905. // Merge another menu, given its menu descriptor, into our own using our menu
  906. // descriptor.
  907. // optionally use an existing HMENU to merge into & set
  908. //
  909. bool
  910. TFrameWindow::MergeMenu(const TMenuDescr& childMenuDescr)
  911. {
  912.   if (!MenuDescr || !HWindow)
  913.     return false;
  914.  
  915.   MergeModule = childMenuDescr.GetModule();
  916.   TMenu  curMenu(*this, NoAutoDelete);
  917.   TMenu  newMenu(NoAutoDelete);
  918.  
  919.   MenuDescr->Merge(childMenuDescr, newMenu);
  920.  
  921.   if (IsFlagSet(wfMainWindow))
  922.     GetApplication()->PreProcessMenu(newMenu);
  923.  
  924.   if (SetMenu(newMenu)) {
  925.     ::DestroyMenu(curMenu);
  926.     return true;
  927.  
  928.   }
  929.   else {
  930.     ::DestroyMenu(newMenu);
  931.     return false;
  932.   }
  933.  
  934. }
  935.  
  936. //
  937. // Restore our menu to the one described by our menu descriptor
  938. //
  939. bool
  940. TFrameWindow::RestoreMenu()
  941. {
  942.   if (!MenuDescr)
  943.     return false;
  944.  
  945.   HMENU curMenu = GetMenu();
  946.   TMenu newMenu(*MenuDescr, NoAutoDelete);
  947.   if (SetMenu(newMenu)) {
  948.     MergeModule = 0;
  949.     ::DestroyMenu(curMenu);
  950.   }
  951.   else
  952.     ::DestroyMenu(newMenu);
  953.   return true;
  954. }
  955.  
  956. #endif
  957. #if !defined(SECTION) || SECTION == 3
  958.  
  959. IMPLEMENT_STREAMABLE1(TFrameWindow, TWindow);
  960.  
  961. //
  962. // reads data of the uninitialized TFrameWindow from the passed ipstream
  963. //
  964. void*
  965. TFrameWindow::Streamer::Read(ipstream& is, uint32 /*version*/) const
  966. {
  967.   TFrameWindow* o = GetObject();
  968.   ReadVirtualBase((TWindow*)o, is);
  969.   if (o->IsFlagSet(wfMainWindow))
  970.     return o;
  971.  
  972.   is >> o->ClientWnd;
  973.   is >> o->KeyboardHandling;
  974.   o->HWndRestoreFocus = 0;
  975.  
  976.   bool hasMenuDescr = is.readByte();
  977.   if (hasMenuDescr) {
  978.     o->MenuDescr = new TMenuDescr;
  979.     is >> *o->MenuDescr;
  980.   }
  981.   else
  982.     o->MenuDescr = 0;
  983.  
  984.   is >> o->IconModule;
  985.   is >> o->IconResId;
  986.   is >> o->MergeModule;
  987.   is >> o->MinimizedPos;
  988.  
  989.   return o;
  990. }
  991.  
  992. //
  993. // writes data of the TFrameWindow to the passed opstream
  994. //
  995. void
  996. TFrameWindow::Streamer::Write(opstream& os) const
  997. {
  998.   TFrameWindow* o = GetObject();
  999.   WriteVirtualBase((TWindow*)o, os);
  1000.   if (o->IsFlagSet(wfMainWindow))
  1001.     return;
  1002.  
  1003.   os << o->ClientWnd;
  1004.   os << o->KeyboardHandling;
  1005.  
  1006.   os.writeByte(uint8(o->MenuDescr ? 1 : 0));
  1007.   if (o->MenuDescr)
  1008.     os << *o->MenuDescr;
  1009.  
  1010.   os << o->IconModule;
  1011.   os << o->IconResId;
  1012.   os << o->MergeModule;
  1013.   WINDOWPLACEMENT windata;
  1014.   windata.length = sizeof(WINDOWPLACEMENT);
  1015.   o->GetWindowPlacement(&windata);
  1016.   os << TPoint(windata.ptMinPosition);
  1017. }
  1018.  
  1019. #endif  // SECTION
  1020.