home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c083 / 11.ddi / OWLSRC.PAK / WINDOW.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-02  |  58.8 KB  |  2,311 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1991, 1993 by Borland International
  3. //   source\owl\window.cpp
  4. //   Defines type TWindow.  This defines the basic behavior of all Windows.
  5. //----------------------------------------------------------------------------
  6. #include <owl\owlpch.h>
  7. #include <owl\window.h>
  8. #include <owl\applicat.h>
  9. #include <owl\scroller.h>
  10. #include <owl\gdiobjec.h>
  11. #include <stdlib.h>
  12.  
  13. DIAG_DECLARE_GROUP(OwlMsg);  // diagnostic group for message tracing
  14. DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlWin, 1, 0);
  15.                              // diagnostic group for windows
  16.  
  17. //#define BUILDUP_CLASSNAME  // to build registered classname with modulename
  18.  
  19. //
  20. // Externs defined in owl.cpp
  21. //
  22. extern LRESULT FAR PASCAL _export InitWndProc(HWND, UINT, WPARAM, LPARAM);
  23.  
  24. extern WNDPROC       CreateInstanceThunk(TWindow*);
  25. extern void          FreeInstanceThunk(WNDPROC);
  26. extern void _OWLFUNC SetCreationWindow(TWindow*);
  27. extern UINT _OWLDATA GetWindowPtrMsgId;
  28.  
  29. struct TCurrentEvent {
  30.   TWindow*  win;
  31.   UINT      message;
  32.   WPARAM    wParam;
  33.   LPARAM    lParam;
  34. };
  35. TCurrentEvent CurrentEvent;
  36.  
  37.  
  38. //$---------------------------------------------------------------------------
  39.  
  40. DEFINE_RESPONSE_TABLE(TWindow)
  41.   EV_WM_SETCURSOR,
  42.   EV_WM_SIZE,
  43.   EV_WM_MOVE,
  44.   EV_WM_COMPAREITEM,
  45.   EV_WM_DELETEITEM,
  46.   EV_WM_DRAWITEM,
  47.   EV_WM_MEASUREITEM,
  48.   EV_WM_VSCROLL,
  49.   EV_WM_HSCROLL,
  50.   EV_WM_CHILDINVALID,
  51.   EV_WM_ERASEBKGND,
  52.   EV_WM_PAINT,
  53.   EV_WM_LBUTTONDOWN,
  54.   EV_WM_KILLFOCUS,
  55. #if defined(__WIN32__)
  56.   EV_MESSAGE(WM_CTLCOLORMSGBOX, EvWin32CtlColor),
  57.   EV_MESSAGE(WM_CTLCOLOREDIT, EvWin32CtlColor),
  58.   EV_MESSAGE(WM_CTLCOLORLISTBOX, EvWin32CtlColor),
  59.   EV_MESSAGE(WM_CTLCOLORBTN, EvWin32CtlColor),
  60.   EV_MESSAGE(WM_CTLCOLORDLG, EvWin32CtlColor),
  61.   EV_MESSAGE(WM_CTLCOLORSCROLLBAR, EvWin32CtlColor),
  62.   EV_MESSAGE(WM_CTLCOLORSTATIC, EvWin32CtlColor),
  63. #endif
  64.   EV_WM_CREATE,
  65.   EV_WM_CLOSE,
  66.   EV_WM_DESTROY,
  67.   EV_WM_NCDESTROY,
  68.   EV_COMMAND(CM_EXIT, CmExit),
  69.   EV_WM_QUERYENDSESSION,
  70.   EV_WM_SYSCOLORCHANGE,
  71. END_RESPONSE_TABLE;
  72.  
  73.  
  74. //$---------------------------------------------------------------------------
  75. //
  76. //
  77. TCommandEnabler::TCommandEnabler(UINT id, HWND hWndReceiver)
  78.   : Id(id), HWndReceiver(hWndReceiver)
  79. {
  80.   Handled = FALSE;
  81. }
  82.  
  83. void
  84. TCommandEnabler::Enable(BOOL)
  85. {
  86.   Handled = TRUE;
  87. }
  88.  
  89. //$---------------------------------------------------------------------------
  90.  
  91. //
  92. // constructor for a TWindow.  if a parent window is passed, adds the TWindow
  93. // to its parent's list of children
  94. //
  95. TWindow::TWindow(TWindow*        parent,
  96.                  const char far* title,
  97.                  TModule*        module)
  98. {
  99.   Thunk = 0;  // remember that we still need to initialize
  100.   Init(parent, title, module);
  101. }
  102.  
  103. //$---------------------------------------------------------------------------
  104. //
  105. // constructor for a TWindow which is being used as an alias for a
  106. // non-OWL window.  This ctor is generally not used by derived classes
  107. //
  108. TWindow::TWindow(HWND hWnd, TModule* module)
  109. {
  110.   //
  111.   // perform preliminary initialization
  112.   //
  113.   HWindow = hWnd;
  114.   Title = 0;
  115.   Thunk = 0;  // remember that we still need to initialize
  116.  
  117.   //
  118.   // if the receiver's parent is an OWL window then pass the window to Init()
  119.   // so the receiver can be added to the parent's list of children
  120.   //
  121.   HWND      hParent = GetParent();
  122.   TWindow*  parent = hParent ? GetWindowPtr(hParent) : 0;
  123.   Init(parent, module);
  124.  
  125.   //
  126.   // thunk the window
  127.   //
  128.   SubclassWindowFunction();
  129.  
  130.   //
  131.   // copy over the title, styles, the coordinates & the id
  132.   //
  133.   GetWindowTextTitle();
  134.   GetHWndState();
  135.  
  136.   //
  137.   // Keep track that this is an alias object
  138.   //
  139.   SetFlag(wfAlias);
  140. }
  141.  
  142. //$---------------------------------------------------------------------------
  143. //
  144. // Protected constructor for use by immediate virtually derived classes.
  145. // Immediate derivitives must call Init() before constructions are done.
  146. //
  147. TWindow::TWindow()
  148. {
  149.   Thunk = 0;  // remember that we still need to initialize
  150. }
  151.  
  152. //
  153. // Normal initialization of a default constructed TWindow. Is ignored
  154. // if called more than once.
  155. //
  156. void
  157. TWindow::Init(TWindow*        parent,
  158.               const char far* title,
  159.               TModule*        module)
  160. {
  161.   if (!Thunk) {
  162.     Init(parent, module);
  163.     Title = strnewdup(title);
  164.     DefaultProc = 0;
  165.     HWindow = 0;
  166.     EnableAutoCreate();
  167.  
  168.     //
  169.     // initialize creation attributes
  170.     //
  171.     Attr.Style = WS_CHILD | WS_VISIBLE;
  172.     Attr.X = Attr.Y = Attr.W = Attr.H = 0;
  173.     Attr.ExStyle = 0;
  174.     Attr.Id = 0;
  175.   }
  176. }
  177.  
  178. //
  179. // Private initializer function that does the bulk of the work
  180. //
  181. void
  182. TWindow::Init(TWindow* parent, TModule* module)
  183. {
  184.   ZOrder = 0;
  185.   ChildList = 0;
  186.   Flags = 0;
  187.   TransferBuffer = 0;
  188.   Parent = parent;
  189.   Attr.Param = 0;
  190.   Attr.Menu = 0;
  191.   Attr.AccelTable = 0;
  192.   hAccel = 0;
  193.   Thunk = CreateInstanceThunk(this);
  194.   Application = GetApplicationObject();
  195.   Scroller = 0;
  196.  
  197.   CursorModule = 0;
  198.   CursorResId = 0;
  199.   HCursor = 0;
  200.   BkgndColor = NoColor;
  201.  
  202.   if (Parent)
  203.     Parent->AddChild(this);
  204.  
  205.   else
  206.     SiblingList = 0;
  207.  
  208.   //
  209.   // Use passed module if one, else get parent's. If no parent, get app's
  210.   //
  211.   Module = module ? module : (Parent ? Parent->GetModule() : Application);
  212.   SetUniqueId();
  213.  
  214.   TRACEX(OwlWin, 1, "TWindow constructed @" << (void*)this);
  215. }
  216.  
  217. //
  218. // installs the thunk as the window function and saves the old window function
  219. // in "DefaultProc"
  220. //
  221. void
  222. TWindow::SubclassWindowFunction()
  223. {
  224.   CHECK(HWindow != 0);
  225.   DefaultProc = (WNDPROC)SetWindowLong(GWL_WNDPROC, DWORD(GetThunk()));
  226.   CHECK(DefaultProc != GetThunk());  // can only be called once!
  227. }
  228.  
  229. //
  230. // destructor for a TWindow: disposes of each window in its ChildList
  231. // and removes itself from a non-0 parent's list of children
  232. //
  233. // destroys a still-associated MS-Windows interface element and frees
  234. // the instance thunk used for association of an MS-Windows element
  235. // to the TWindow
  236. //
  237. // disposes of its Scroller if the TScroller object was constructed
  238. //
  239. static void shutDown(TWindow* win, void*) {
  240.   win->Destroy();
  241.   delete win;
  242. }
  243.  
  244. TWindow::~TWindow()
  245. {
  246.   //
  247.   // Flush the cache so that messages dont get dispatched to a
  248.   // already-destructed derived class
  249.   //
  250.   void CacheFlush(uint32 id);
  251.   CacheFlush(UniqueId);
  252.  
  253.   //
  254.   //  ShutDown children first, so the Owl objects get a chance to clean up
  255.   //
  256.   ForEach(shutDown);
  257.  
  258.   //
  259.   // If the HWindow is still around, then destroy it or unlink from it as
  260.   // appropriate.
  261.   //
  262.   if (HWindow) {
  263.     //
  264.     // for aliases:
  265.     //  - we are destructing the C++ object but not destroying the MS window
  266.     //  - restore the original window function
  267.     //
  268.     if (IsFlagSet(wfAlias)) {
  269.       //
  270.       // May want to check WNDPROC against Thunk to see if its still us
  271.       // and not restore if it's not us...
  272.       //
  273.       WARNX(OwlWin, GetWindowLong(GWL_WNDPROC) != (uint32)GetThunk(), 0,
  274.             "Restoring old WndProc after foreign subclass of:" << *this);
  275.       SetWindowLong(GWL_WNDPROC, DWORD(DefaultProc));
  276.  
  277.     //
  278.     // for non-aliases:
  279.     //  - destroy the windows element
  280.     // this is not a normal condition and is a safety net only
  281.     //
  282.     } else {
  283.       WARNX(OwlWin, HWindow, 0, "Destroying from TWindow::~TWindow: " << *this);
  284.       Destroy();
  285.     }
  286.   }
  287.  
  288.   if (Parent)
  289.     Parent->RemoveChild(this);
  290.  
  291.   if (IsFlagSet(wfMainWindow))
  292.     GetApplication()->MainWindow = 0;
  293.  
  294.   //
  295.   // Delete menu id string, scroller, title, cursor & thunk
  296.   //
  297.   if (Attr.Menu.IsString())
  298.     delete (char far*)Attr.Menu;
  299.  
  300.   //
  301.   // delete scroller if there is one, by casting up to base and relying on
  302.   // virtual dtor to avoid pulling in TScroller object code.
  303.   //
  304.   if (Scroller) {
  305.     delete (TStreamableBase*)Scroller;
  306.     Scroller = 0;
  307.   }
  308.  
  309.   if (HIWORD(Title))
  310.     delete Title;
  311.  
  312.   if (HCursor && CursorModule)
  313.     SetCursor(0, 0);
  314.  
  315.   FreeInstanceThunk(Thunk);
  316.   TRACEX(OwlWin, 1, "TWindow destructed @" << (void*)this);
  317. }
  318.  
  319. #if defined(__WIN32__)
  320. //
  321. // overrides TEventHandler::Dispatch() to handle multi-thread synchonization
  322. //
  323. LRESULT TWindow::Dispatch(TEventInfo& info, WPARAM wp, LPARAM lp)
  324. {
  325.   TApplication::TAppLock Lock(*GetApplication());
  326.   return TEventHandler::Dispatch(info, wp, lp);
  327. }
  328.  
  329. #endif
  330.  
  331. //
  332. //
  333. BOOL
  334. TWindow::PreProcessMsg(MSG& msg)
  335. {
  336.   return hAccel ? ::TranslateAccelerator(HWindow, hAccel, &msg) : FALSE;
  337. }
  338.  
  339. BOOL
  340. TWindow::IdleAction(long /*idleCount*/)
  341. {
  342.   return FALSE;  // we don't need any more time for now
  343. }
  344.  
  345. //
  346. // respond to this message by broadcasting it to all children
  347. //
  348. void
  349. TWindow::EvSysColorChange()
  350. {
  351.   ChildBroadcastMessage(WM_SYSCOLORCHANGE);
  352. }
  353.  
  354. //
  355. // removes the passed pointer to a child window from the linked list of
  356. // sibling windows which the TWindow's ChildList points to
  357. //
  358. void
  359. TWindow::RemoveChild(TWindow* child)
  360. {
  361.   if (child && ChildList) {
  362.     TWindow*  lastChild = ChildList;
  363.     TWindow*  nextChild = lastChild;
  364.  
  365.     while (nextChild->SiblingList != lastChild &&
  366.            nextChild->SiblingList != child) {
  367.       nextChild = nextChild->SiblingList;
  368.     }
  369.  
  370.     if (nextChild->SiblingList == child) {
  371.       if (nextChild->SiblingList == nextChild)
  372.         ChildList = 0;
  373.  
  374.       else {
  375.         if (nextChild->SiblingList == ChildList)
  376.           ChildList = nextChild;
  377.  
  378.         nextChild->SiblingList = nextChild->SiblingList->SiblingList;
  379.       }
  380.     }
  381.   }
  382. }
  383.  
  384. //
  385. // reparents "this" to a new parent
  386. //
  387. void
  388. TWindow::SetParent(TWindow* newParent)
  389. {
  390.   if (Parent != newParent) {
  391.     if (Parent)
  392.       Parent->RemoveChild(this);
  393.  
  394.     SiblingList = 0;
  395.  
  396.     if (HWindow) {
  397.       //
  398.       // tell Windows about the change
  399.       //
  400.       if (newParent) {
  401.         CHECK(newParent->HWindow);
  402.         ::SetParent(HWindow, newParent->HWindow);
  403.       } else
  404.         ::SetParent(HWindow, 0);
  405.     }
  406.  
  407.     Parent = newParent;
  408.  
  409.     if (Parent)
  410.       Parent->AddChild(this);
  411.   }
  412. }
  413.  
  414. //
  415. // default behavior for updating document title is to pass it to parent frame
  416. //
  417. BOOL
  418. TWindow::SetDocTitle(LPCSTR docname, int index)
  419. {
  420.   return Parent ? Parent->SetDocTitle(docname, index) : FALSE;
  421. }
  422.  
  423. //
  424. // wildcard check used for child id notifications
  425. //
  426. static BOOL wildcardCheck(TGenericTableEntry __RTFAR& entry,
  427.                           TEventHandler::TEventInfo& info) {
  428.   return entry.Id == info.Id && (entry.Msg == UINT_MAX || entry.Msg == info.Msg);
  429. }
  430.  
  431. //
  432. // handles default processing of events
  433. //
  434. // this includes continued processing of menu/accelerators and child Id
  435. // notifications
  436. //
  437. LRESULT
  438. TWindow::DefaultProcessing()
  439. {
  440.   if (CurrentEvent.message == WM_COMMAND_ENABLE) {
  441.     if (CurrentEvent.win != this) {
  442.       TWindow*          receiver = Parent ? Parent : CurrentEvent.win;
  443.       TCommandEnabler&  commandEnabler = *(TCommandEnabler*)CurrentEvent.lParam;
  444.       TEventInfo        eventInfo(WM_COMMAND_ENABLE, commandEnabler.Id);
  445.  
  446.       if (receiver->Find(eventInfo))
  447.         return receiver->Dispatch(eventInfo, 0, CurrentEvent.lParam);
  448.     }
  449.  
  450.     return 0;
  451.   }
  452.  
  453.   if (CurrentEvent.message != WM_COMMAND)
  454.     return DefWindowProc(CurrentEvent.message, CurrentEvent.wParam, CurrentEvent.lParam);
  455.  
  456.   //
  457.   // CurrentEvent.message == WM_COMMAND
  458.   //
  459. #if defined(__WIN32__)
  460.   UINT    notifyCode = HIWORD(CurrentEvent.wParam);
  461. #else
  462.   UINT    notifyCode = HIWORD(CurrentEvent.lParam);
  463. #endif
  464.   UINT    id = LOWORD(CurrentEvent.wParam);
  465.   HWND    hWndCtl = (HWND)(UINT)CurrentEvent.lParam;
  466.  
  467.   if (CurrentEvent.win == this) {
  468.     //
  469.     // menu command originally destined for the receiver. defer to the app
  470.     //
  471.     if (hWndCtl == 0) {
  472.       TEventInfo     eventInfo(0, id);
  473.       TApplication*  app = GetApplication();
  474.  
  475.       if (app->Find(eventInfo)) {
  476.         app->Dispatch(eventInfo, eventInfo.Id);
  477.         return 0;
  478.       }
  479.       WARNX(OwlMsg, notifyCode<=1, 0, "Unprocessed WM_COMMAND(id=" << id << ")");
  480.     }
  481.     //
  482.     // originally destined for the receiver and the receiver has called us so
  483.     // default processing can occur
  484.     //
  485.     // unpack the original parameters and call DefWindowProc()
  486.     //
  487.     return DefWindowProc(CurrentEvent.message, CurrentEvent.wParam, CurrentEvent.lParam);
  488.  
  489.   } else {
  490.     TWindow*        receiver;
  491.     UINT            wParam;
  492.     TEqualOperator  equal = 0;
  493.  
  494.     if (hWndCtl == 0) {
  495.       //
  496.       // menu/accelerator/push button
  497.       //
  498.       // either give the message to the receiver's parent or the original
  499.       // receiver of the message
  500.       //
  501.       receiver = Parent ? Parent : CurrentEvent.win;
  502.  
  503.       //
  504.       // "notifyCode" is either 0 or 1 depending on whether this is from an
  505.       // accelerator; however, we want to explicitly look for a 0...
  506.       //
  507.       notifyCode = 0;
  508.  
  509.       wParam = id;  // pass along "id" in case the receiver wants it
  510.  
  511.     } else {
  512.       //
  513.       // child id notification sent to the child and the child has called us
  514.       //
  515.       // offer the parent an opportunity to handle the notification
  516.       //
  517.       // NOTE: use equal function that will do a wildcard search
  518.       //
  519.       equal = wildcardCheck;
  520.       receiver = CurrentEvent.win;
  521.  
  522.       //
  523.       // the child window identifier shouldn't be 0, but if it is then it will
  524.       // look like we are searching for a WM_ message with value "notifyCode"
  525.       //
  526.       if (receiver->IsFlagSet(wfAlias) || id == 0)
  527.         return receiver->DefWindowProc(CurrentEvent.message, CurrentEvent.wParam, CurrentEvent.lParam);
  528.  
  529.       wParam = notifyCode;  // pass notification code in case receiver wants it
  530.     }
  531.  
  532.     TEventInfo  eventInfo(notifyCode, id);
  533.  
  534.     if (receiver->Find(eventInfo, equal))
  535.       return receiver->Dispatch(eventInfo, wParam);
  536.  
  537.     else
  538.       return receiver->DefaultProcessing();
  539.   }
  540. }
  541.  
  542. //
  543. // processing for WM_COMMAND
  544. //
  545. LRESULT
  546. TWindow::EvCommand(UINT id, HWND hWndCtl, UINT notifyCode)
  547. {
  548.   TWindow*        receiver = this;
  549.   UINT            wParam;
  550.   TEqualOperator  equal = 0;
  551.  
  552.   if (hWndCtl == 0) {
  553.     //
  554.     // menu/accelerator
  555.     //
  556.     // "notifyCode" is either 0 or 1 depending on whether this is from an
  557.     // accelerator; however, we want to explicitly look for a 0...
  558.     //
  559.     notifyCode = 0;
  560.  
  561.     //
  562.     // pass the "id" along in case the user wants it...
  563.     //
  564.     wParam = id;
  565.  
  566.   } else {
  567.     //
  568.     // child id notification
  569.     //
  570.     TWindow*  child = GetWindowPtr(hWndCtl);
  571.  
  572.     //
  573.     // pass the "notifyCode" along in case the user wants it...
  574.     //
  575.     wParam = notifyCode;
  576.  
  577.     if (child) {
  578.       //
  579.       // give the child first crack at the event
  580.       //
  581.       receiver = child;
  582.       id = UINT_MAX;  // special designator for child Id notifications that are
  583.                       // handled at the child
  584.  
  585.     } else {
  586.       //
  587.       // offer the parent an opportunity to handle the notification
  588.       //
  589.       // NOTE: use equal function that will do a wildcard search
  590.       //
  591.       equal = wildcardCheck;
  592.  
  593.       //
  594.       // the child window identifier shouldn't be 0, but if it is then it will
  595.       // look like we are searching for a WM_ message with value "notifyCode"
  596.       //
  597.       if (id == 0)
  598.         return DefaultProcessing();
  599.     }
  600.   }
  601.  
  602.   TEventInfo  eventInfo(notifyCode, id);
  603.  
  604.   if (receiver->Find(eventInfo, equal))
  605.     return receiver->Dispatch(eventInfo, wParam);
  606.  
  607.   else
  608.     return receiver->DefaultProcessing();
  609. }
  610.  
  611. //
  612. void
  613. TWindow::EvCommandEnable(TCommandEnabler& commandEnabler)
  614. {
  615.   TEventInfo  eventInfo(WM_COMMAND_ENABLE, commandEnabler.Id);
  616.  
  617.   if (Find(eventInfo))
  618.     Dispatch(eventInfo, 0, (LPARAM)&commandEnabler);
  619. }
  620.  
  621. //
  622. // specifies default processing for an incoming message
  623. //
  624. // calls original window proc that we subclassed, using ::CallWindowProc to
  625. // make sure that registers get setup correctly.
  626. //
  627. LRESULT
  628. TWindow::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  629. {
  630.   LRESULT result;
  631.   CHECK(DefaultProc);
  632.   result = ::CallWindowProc(DefaultProc, HWindow, message, wParam, lParam);
  633.   GetApplication()->ResumeThrow();
  634.   return result;
  635. }
  636.  
  637.  
  638. static const int     msgCacheSize = 31;
  639. struct TCacheEntry {
  640.   DWORD                        UniqueId;
  641.   TGenericTableEntry  __RTFAR* Entry;
  642.   UINT                         Msg;
  643.   int                          Delta;  // adjustment to "this" pointer
  644.  
  645.   BOOL  Hit(UINT msg, DWORD uniqueId) {return msg == Msg && uniqueId == UniqueId;}
  646.   static UINT  Key(uint32 id, UINT msg) {return (UINT(id) ^ msg) % msgCacheSize;}
  647. };
  648.  
  649. DWORD TWindow::LastUniqueId = 0;
  650.  
  651. static TCacheEntry  msgCache[msgCacheSize];
  652. static BOOL         cacheEnabled = TRUE;
  653.  
  654. void CacheFlush(uint32 id) {
  655.   for (int i = 0; i < msgCacheSize; i++)
  656.     if (msgCache[i].UniqueId == id)
  657.       msgCache[i].Msg = 0;
  658. }
  659.  
  660. void
  661. TWindow::SetUniqueId()
  662. {
  663.   if (++LastUniqueId == 0) {
  664.     //
  665.     // numbers wrapped around. disable the cache to be safe...
  666.     //
  667.     LastUniqueId = 1;
  668.     cacheEnabled = FALSE;
  669.   }
  670.  
  671.   UniqueId = LastUniqueId;
  672. }
  673.  
  674. //
  675. // if the message is WM_COMMAND calls EvCommand(); otherwise looks for a handler
  676. // in the message response table
  677. //
  678. LRESULT
  679. TWindow::WindowProc(UINT msg, WPARAM wParam, LPARAM lParam)
  680. {
  681.   if (msg == WM_COMMAND_ENABLE) {
  682.     EvCommandEnable(*(TCommandEnabler*)lParam);
  683.     return 0;
  684.  
  685.   } else if (msg == WM_COMMAND) {
  686.   #if defined(__WIN32__)
  687.     return EvCommand(LOWORD(wParam), (HWND)(UINT)lParam, HIWORD(wParam));
  688.   #else
  689.     return EvCommand(LOWORD(wParam), (HWND)(UINT)lParam, HIWORD(lParam));
  690.   #endif
  691.  
  692.   } else {
  693.     UINT        key = TCacheEntry::Key(UniqueId, msg);
  694.     TEventInfo  eventInfo(msg);
  695.  
  696.     //
  697.     // check the cache
  698.     //
  699.     // NOTE: because there isn't necessarily a 1-1 mapping between response
  700.     //       tables and OWL classes we can't do the lookup based on the
  701.     //       response table. when we get RTTI support then we can use the
  702.     //       pointer to the runtime class information, but until then use the
  703.     //       unique Id for the window. this means our caching is instance
  704.     //       based and not class based...
  705.     //
  706.     if (cacheEnabled && msgCache[key].Hit(msg, UniqueId)) {
  707.       TRACEX(OwlMsg, 1, MsgName(msg) << "* => " << *this);
  708.  
  709.       eventInfo.Entry = msgCache[key].Entry;
  710.       eventInfo.Object = (GENERIC*)(((char*)this) + msgCache[key].Delta);
  711.       return Dispatch(eventInfo, wParam, lParam);
  712.  
  713.     } else if (Find(eventInfo)) {
  714.       TRACEX(OwlMsg, 1, MsgName(msg) << " => " << *this);
  715.       msgCache[key].UniqueId = UniqueId;
  716.       msgCache[key].Entry = eventInfo.Entry;
  717.       msgCache[key].Msg = msg;
  718.       msgCache[key].Delta = int(eventInfo.Object) - int(this);
  719.       return Dispatch(eventInfo, wParam, lParam);
  720.  
  721.     } else {
  722.       if (IsFlagSet(wfMainWindow)) {
  723.         TEventInfo cmdEventInfo(msg, wParam);
  724.         if (GetApplication()->Find(cmdEventInfo))
  725.           return GetApplication()->Dispatch(cmdEventInfo, wParam, lParam);
  726.         if (GetApplication()->Find(eventInfo))
  727.           return GetApplication()->Dispatch(eventInfo, wParam, lParam);
  728.       }
  729.       return DefWindowProc(msg, wParam, lParam);
  730.     }
  731.   }
  732. }
  733.  
  734. //
  735. // Save current event and call this window's WindowProc. Handles exceptions,
  736. // error checking, & GetWindowPtr messages.
  737. //
  738.  
  739. LRESULT
  740. TWindow::HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam)
  741. {
  742.   //
  743.   // if it's a "GetWindowPtr" message, then return pointer to this window
  744.   //
  745.   if (msg == GetWindowPtrMsgId)
  746.     return (LRESULT)this;
  747.  
  748.   PRECONDITION(HWindow);
  749.  
  750.   //
  751.   // save event away in "CurrentEvent"
  752.   //
  753.   TCurrentEvent    saveEvent = CurrentEvent;  // for nested calls
  754.   CurrentEvent.win = this;
  755.   CurrentEvent.message = msg;
  756.   CurrentEvent.wParam = wParam;
  757.   CurrentEvent.lParam = lParam;
  758.  
  759.   //
  760.   // call window object's WindowProc virtual function
  761.   //
  762.   LRESULT  result;
  763.   result = WindowProc(msg, wParam, lParam);
  764.   CurrentEvent = saveEvent;  // restore previous event to current event
  765.   return result;
  766. }
  767.  
  768. //
  769. // Window function called for normal, initialized, OWL windows via a
  770. // per-window thunk. 'this' ptr is setup in register(s) by the thunk before
  771. // StdWndProc is called.
  772. //
  773. #if defined(__WIN32__)
  774. LRESULT
  775. FAR PASCAL _stdcall
  776. StdWndProc(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
  777. {
  778.   return ((TWindow*)_EAX)->ReceiveMessage(msg, wParam, lParam);
  779. }
  780. #else
  781. LRESULT
  782. FAR PASCAL __export
  783. StdWndProc(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
  784. {
  785.   return ((TWindow*)MK_FP(_ES,_BX))->ReceiveMessage(msg, wParam, lParam);
  786. }
  787. #endif
  788.  
  789. //
  790. // First member function that receives messages from windows thru the
  791. // thunk & then StdWndProc. Deals with exception suspension for non-NT
  792. // environments.
  793. //
  794. LRESULT
  795. TWindow::ReceiveMessage(UINT msg, WPARAM wParam, LPARAM lParam)
  796. {
  797. #if defined(__WIN32__)
  798.   static BOOL IsNT = ((HIWORD(::GetVersion()) & 0x8000) == 0);
  799.   if (IsNT)
  800.     return HandleMessage(msg, wParam, lParam);
  801. #endif
  802.   TRY {
  803.     return HandleMessage(msg, wParam, lParam);
  804.   }
  805.   CATCH( (TXOwl& x) {
  806.     GetApplication()->SuspendThrow(x);
  807.   })
  808.   CATCH( (xalloc& x) {
  809.     GetApplication()->SuspendThrow(x);
  810.   })
  811.   CATCH( (xmsg& x) {
  812.     GetApplication()->SuspendThrow(x);
  813.   })
  814.   CATCH( (Bad_cast) {
  815.     GetApplication()->SuspendThrow(TApplication::xsBadCast);
  816.   })
  817.   CATCH( (Bad_typeid) {
  818.     GetApplication()->SuspendThrow(TApplication::xsBadTypeid);
  819.   })
  820.   CATCH( (...) {
  821.     GetApplication()->SuspendThrow(TApplication::xsUnknown);
  822.   })
  823.  
  824.   // When we're building small model, exceptions are disabled
  825.   // CATCH is defined as empty, so the only code is the TRY block,
  826.   // making this return unreachable
  827.   #pragma warn -rch
  828.   return msg == WM_CREATE ? -1 : 0;  // default value returned when exception caught
  829.   #pragma warn .rch
  830. }
  831.  
  832. //
  833. // response method for an incoming WM_SIZE message
  834. //
  835. // Call virtual SetupWindow to give derived classes a chance to set things up
  836. // now that we have an HWindow
  837. //
  838. int
  839. TWindow::EvCreate(CREATESTRUCT far&)
  840. {
  841.   SetupWindow();
  842.   return (int)DefaultProcessing();
  843. }
  844.  
  845. //
  846. // regular windows never hold focus child handles
  847. //
  848. BOOL
  849. TWindow::HoldFocusHWnd(HWND /*hWndLose*/, HWND /*hWndGain*/)
  850. {
  851.   return FALSE;
  852. }
  853.  
  854. //
  855. //
  856. void
  857. TWindow::EvKillFocus(HWND getFocus)
  858. {
  859.   //
  860.   // Follow the parent chain back until a window volunteers to hold our handle
  861.   //
  862.   TWindow* holdWin = Parent;
  863.   while (holdWin && !holdWin->HoldFocusHWnd(HWindow, getFocus))
  864.     holdWin = holdWin->Parent;
  865.  
  866.   DefaultProcessing();
  867. }
  868.  
  869. //
  870. // response method for an incoming WM_SIZE message
  871. //
  872. // saves the normal size of the window in Attr
  873. //
  874. // also calls the SetPageSize() and SetBarRange() methods of the TWindow's
  875. // scroller, if it has been constructed
  876. //
  877. void
  878. TWindow::EvSize(UINT sizeType, TSize&)
  879. {
  880.   if (Scroller && sizeType != SIZE_MINIMIZED) {
  881.     Scroller->SetPageSize();
  882.     Scroller->SetSBarRange();
  883.   }
  884.  
  885.   if (sizeType == SIZE_RESTORED) {
  886.     TRect  wndRect;
  887.  
  888.     GetWindowRect(wndRect);
  889.     Attr.W = wndRect.Width();
  890.     Attr.H = wndRect.Height();
  891.   }
  892.  
  893.   // Added owl functionality: notify parent of a resize in case it wants to
  894.   // adust accordingly
  895.   //
  896.   if (Parent && !(GetWindowLong(GWL_EXSTYLE)&WS_EX_NOPARENTNOTIFY))
  897.     Parent->SendMessage(WM_PARENTNOTIFY, WM_SIZE, (UINT)HWindow);
  898.  
  899.   DefaultProcessing();
  900. }
  901.  
  902. //
  903. // save the normal position of the window
  904. //
  905. // if IsIconic() or IsZoomed() ignore the position since it does not reflect the
  906. // normal state
  907. //
  908. void
  909. TWindow::EvMove(TPoint&)
  910. {
  911.   if (!IsIconic() && !IsZoomed()) {
  912.     TRect wndRect;
  913.  
  914.     GetWindowRect(wndRect);
  915.  
  916.     if ((GetWindowLong(GWL_STYLE) & WS_CHILD) == WS_CHILD && Parent &&
  917.          Parent->HWindow)
  918.       Parent->ScreenToClient(wndRect.TopLeft());
  919.  
  920.     Attr.X = wndRect.left;
  921.     Attr.Y = wndRect.top;
  922.   }
  923.  
  924.   DefaultProcessing();
  925. }
  926.  
  927. //
  928. // handles WM_COMPAREITEM message (for owner draw controls) by forwarding
  929. // message to control itself
  930. //
  931. LRESULT
  932. TWindow::EvCompareItem(UINT /*ctrlId*/, COMPAREITEMSTRUCT far& compareInfo)
  933. {
  934.   TWindow* win = GetWindowPtr(compareInfo.hwndItem);
  935.   if (win)
  936.     return win->ForwardMessage();
  937.   return DefaultProcessing();
  938. }
  939.  
  940. //
  941. // handles WM_DELETEITEM message (for owner draw controls) by forwarding
  942. // message to control itself
  943. //
  944. void
  945. TWindow::EvDeleteItem(UINT /*ctrlId*/, DELETEITEMSTRUCT far& deleteInfo)
  946. {
  947.   TWindow* win = GetWindowPtr(deleteInfo.hwndItem);
  948.   if (deleteInfo.hwndItem != HWindow && win)
  949.     win->ForwardMessage();
  950.   else
  951.     DefaultProcessing();
  952. }
  953.  
  954. //
  955. // handles WM_DRAWITEM message (for owner draw controls & menus) by forwarding
  956. // message to control itself
  957. //
  958. void
  959. TWindow::EvDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT far& drawInfo)
  960. {
  961.   if (drawInfo.CtlType == ODT_MENU) {
  962.     // dispatch to menu...
  963.     // TMenu* menu = ...
  964.     // menu->DrawItem(drawInfo);
  965.  
  966.   } else {
  967.     TWindow* win = GetWindowPtr(drawInfo.hwndItem);
  968.     if (drawInfo.hwndItem != HWindow && win) {
  969.       win->ForwardMessage();
  970.       return;
  971.     }
  972.   }
  973.   DefaultProcessing();
  974. }
  975.  
  976. //
  977. // handles WM_MEASUREITEM message (for owner draw controls & menus) by
  978. // forwarding message to control itself
  979. //
  980. void
  981. TWindow::EvMeasureItem(UINT /*ctrlId*/, MEASUREITEMSTRUCT far& measureInfo)
  982. {
  983.   if (measureInfo.CtlType == ODT_MENU) {
  984.     // dispatch to menu...
  985.     // TMenu* menu = ...
  986.     // menu->MeasureItem(measureInfo);
  987.  
  988.   } else {
  989.     HWND hwndCtl = GetDlgItem(measureInfo.CtlID);  // hWnd not in struct, get
  990.     TWindow* win = GetWindowPtr(hwndCtl);
  991.     //
  992.     // If the GetWindowPtr failed, & CreationWindow is non-zero, then this
  993.     // WM_MEASUREITEM is probably for the ctrl which is not yet thunked.
  994.     // route the message directly to creation window.
  995.     //
  996.     extern TWindow* _OWLDATA CreationWindow;
  997.     if (!win && CreationWindow)
  998.       win = CreationWindow; // sometimes this is send before Owl thunks ctl
  999.     if (win) {
  1000.       win->ForwardMessage();
  1001.       return;
  1002.     }
  1003.   }
  1004.   DefaultProcessing();
  1005. }
  1006.  
  1007. //
  1008. //
  1009. #if defined(__WIN32__)
  1010. LRESULT
  1011. TWindow::EvWin32CtlColor(WPARAM wParam, LPARAM lParam)
  1012. {
  1013.   int         ctlType = CurrentEvent.message - WM_CTLCOLORMSGBOX;
  1014.  
  1015.   CHECK(ctlType >= CTLCOLOR_MSGBOX && ctlType <= CTLCOLOR_STATIC);
  1016.  
  1017.   TEventInfo  eventInfo(WM_CTLCOLOR);
  1018.  
  1019.   if (!Find(eventInfo))
  1020.     return DefWindowProc(CurrentEvent.message, wParam, lParam);
  1021.  
  1022.   else {
  1023.     typedef HBRUSH(GENERIC::*CTL_COLOR_PMF)(HDC, HWND, UINT);
  1024.  
  1025.     CTL_COLOR_PMF&  pmf = (CTL_COLOR_PMF&)(eventInfo.Entry->Pmf);
  1026.  
  1027.     return (LRESULT)(eventInfo.Object->*pmf)((HDC)wParam, (HWND)lParam, ctlType);
  1028.   }
  1029. }
  1030. #endif
  1031.  
  1032. //
  1033. // dispatches scroll messages as if they were Command messages.
  1034. //
  1035. void
  1036. TWindow::DispatchScroll(UINT scrollCode, UINT /*thumbPos*/, HWND hWndCtrl)
  1037. {
  1038.   if (hWndCtrl) {
  1039.     TWindow* win = GetWindowPtr(hWndCtrl);
  1040.     if (win)
  1041.       win->ForwardMessage();
  1042.  
  1043.     //
  1044.     // Adjust CurrentEvent to allow DefaultProcessing to work
  1045.     //
  1046.     WORD id = (WORD)::GetDlgCtrlID(hWndCtrl);
  1047.     CurrentEvent.message = WM_COMMAND;
  1048.     #if defined(__WIN32__)
  1049.       CurrentEvent.wParam = MAKEWPARAM(id, scrollCode);
  1050.       CurrentEvent.lParam = LPARAM(hWndCtrl);
  1051.     #else
  1052.       CurrentEvent.wParam = id;
  1053.       CurrentEvent.lParam = MAKELPARAM(hWndCtrl, scrollCode);
  1054.     #endif
  1055.  
  1056.     EvCommand(id, hWndCtrl, scrollCode);
  1057.     return;
  1058.   }
  1059.   DefaultProcessing();
  1060. }
  1061.  
  1062. //
  1063. // response method for an incoming WM_HSCROLL message
  1064. //
  1065. // if the message is from a scrollbar control, calls DispatchScroll()
  1066. // otherwise passes the message to the TWindow's scroller if it has been
  1067. // constructed, else calls DefaultProcessing()
  1068. //
  1069. // assumes, because of a Windows bug, that if the window has the scrollbar
  1070. // style, it will not have scrollbar controls
  1071. //
  1072. void
  1073. TWindow::EvHScroll(UINT scrollCode, UINT thumbPos, HWND hWndCtl)
  1074. {
  1075.   if (!(GetWindowLong(GWL_STYLE) & WS_HSCROLL))
  1076.     DispatchScroll(scrollCode, thumbPos, hWndCtl);  // from scrollbar control
  1077.  
  1078.   else if (Scroller)
  1079.     Scroller->HScroll(scrollCode, thumbPos);
  1080.  
  1081.   else
  1082.     DefaultProcessing();
  1083. }
  1084.  
  1085. //
  1086. // response method for an incoming WM_VSCROLL message
  1087. //
  1088. // if the message is from a scrollbar control, calls DispatchScroll()
  1089. // otherwise passes the message to the TWindow's scroller if it has been
  1090. // constructed, else calls DefaultProcessing()
  1091. //
  1092. // assumes, because of a Windows bug, that if the window has the scrollbar
  1093. // style, it will not have scrollbar controls
  1094. //
  1095. void
  1096. TWindow::EvVScroll(UINT scrollCode, UINT thumbPos, HWND hWndCtl)
  1097. {
  1098.   if (!(GetWindowLong(GWL_STYLE) & WS_VSCROLL))
  1099.     DispatchScroll(scrollCode, thumbPos, hWndCtl);
  1100.  
  1101.   else if (Scroller)
  1102.     Scroller->VScroll(scrollCode, thumbPos);
  1103.  
  1104.   else
  1105.     DefaultProcessing();
  1106. }
  1107.  
  1108. //
  1109. // response method for an incoming WM_ERASEBKGND message
  1110. //
  1111. BOOL
  1112. TWindow::EvEraseBkgnd(HDC hDC)
  1113. {
  1114.   //
  1115.   // color set, we'll handle erasing (or doing nothing) here
  1116.   //
  1117.   if (BkgndColor != NoColor) {
  1118.  
  1119.     //
  1120.     // if a color is set, blt out a rectangle of it, else don't erase & let
  1121.     // paint handle background
  1122.     //
  1123.     if (BkgndColor != NoErase) {
  1124.       SetBkColor(hDC, BkgndColor);
  1125.       ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &GetClientRect(), 0, 0, 0);
  1126.     }
  1127.     return TRUE;
  1128.   }
  1129.  
  1130.   //
  1131.   // no color set, use default class brush
  1132.   //
  1133.   return (BOOL)DefaultProcessing();
  1134. }
  1135.  
  1136. //
  1137. // response method for an incoming WM_PAINT message
  1138. //
  1139. // calls Paint(), performing Windows-required paint setup and cleanup before
  1140. // and after. if the TWindow has a TScroller, also calls its BeginView() and
  1141. // EndView() methods before and after call to Paint()
  1142. //
  1143. void
  1144. TWindow::EvPaint()
  1145. {
  1146.   if (IsFlagSet(wfAlias))
  1147.     DefaultProcessing();  // use application-defined wndproc
  1148.  
  1149.   else {
  1150.     TPaintDC dc(*this);
  1151.     TRect&   rect = *(TRect*)&dc.Ps.rcPaint;
  1152.  
  1153.     if (Scroller)
  1154.       Scroller->BeginView(dc, rect);
  1155.  
  1156.     Paint(dc, dc.Ps.fErase, rect);
  1157.  
  1158.     if (Scroller)
  1159.       Scroller->EndView();
  1160.   }
  1161. }
  1162.  
  1163. //
  1164. // redraws the contents of the TWindow after a WM_PAINT message
  1165. // is received
  1166. //
  1167. // placeholder for descendant object types to redefine
  1168. //
  1169. void
  1170. TWindow::Paint(TDC&, BOOL /*erase*/, TRect&)
  1171. {
  1172. }
  1173.  
  1174. //
  1175. // response method for an incoming WM_SETCURSOR message
  1176. //
  1177. // if a cursor has been set for this window, & the mouse is over the
  1178. // client area, set the cursor
  1179. //
  1180. BOOL
  1181. TWindow::EvSetCursor(HWND hWndCursor, UINT hitTest, UINT /*mouseMsg*/)
  1182. {
  1183.   if (hWndCursor == HWindow && hitTest == HTCLIENT && HCursor) {
  1184.     ::SetCursor(HCursor);
  1185.     return TRUE;
  1186.   }
  1187.   return (BOOL)DefaultProcessing();
  1188. }
  1189.  
  1190. //
  1191. // response method for an incoming WM_LBUTTONDOWN message
  1192. //
  1193. // if the TWindow's Scroller has been constructed and if auto-scrolling
  1194. // has been requested, captures mouse input, loops until a WM_LBUTTONUP
  1195. // message comes in calling the Scroller's AutoScroll method, and then
  1196. // releases capture on mouse input
  1197. // will also break if a WM_MOUSEMOVE comes in without the left button down
  1198. // indicating a lost WM_LBUTTONUP
  1199. //
  1200. void
  1201. TWindow::EvLButtonDown(UINT /*modKeys*/, TPoint& /*pt*/)
  1202. {
  1203.   if (Scroller && Scroller->IsAutoMode()) {
  1204.     MSG  loopMsg;
  1205.  
  1206.     loopMsg.message = 0;
  1207.     SetCapture();
  1208.  
  1209.     while (loopMsg.message != WM_LBUTTONUP &&
  1210.           (loopMsg.message != WM_MOUSEMOVE || (loopMsg.wParam&MK_LBUTTON))) {
  1211.       if (::PeekMessage(&loopMsg, 0, 0, 0, PM_REMOVE)) {
  1212.         ::TranslateMessage(&loopMsg);
  1213.         ::DispatchMessage(&loopMsg);
  1214.       }
  1215.  
  1216.       Scroller->AutoScroll();
  1217.     }
  1218.  
  1219.     ReleaseCapture();
  1220.     GetApplication()->ResumeThrow();
  1221.   }
  1222.  
  1223.   DefaultProcessing();
  1224. }
  1225.  
  1226. //
  1227. void
  1228. DoEnableAutoCreate(TWindow* win, void* /*retVal*/)
  1229. {
  1230.   if (win->HWindow)
  1231.     win->EnableAutoCreate();
  1232. }
  1233.  
  1234. //
  1235. // destroys an MS-Windows element associated with the TWindow
  1236. // after setting the wfAutoCreate flag to ON for each of the windows
  1237. // in the TWindow's ChildList
  1238. //
  1239. void
  1240. TWindow::Destroy(int retVal)
  1241. {
  1242.   if (HWindow) {
  1243.     ForEach(DoEnableAutoCreate, &retVal);
  1244.  
  1245.     if (::DestroyWindow(HWindow))
  1246.       HWindow = 0;
  1247.     GetApplication()->ResumeThrow();
  1248.     WARNX(OwlWin, HWindow, 0, "::DestroyWindow(" << (UINT)HWindow << ") failed");
  1249.   }
  1250. }
  1251.  
  1252. //
  1253. // specifies registration attributes for the MS-Windows window class
  1254. // of the TWindow, allowing instances of TWindow to be registered
  1255. //
  1256. // sets the fields of the passed WNDCLASS parameter to the default
  1257. // attributes appropriate for a TWindow
  1258. //
  1259. void
  1260. TWindow::GetWindowClass(WNDCLASS& wndClass)
  1261. {
  1262.   wndClass.cbClsExtra = 0;
  1263.   wndClass.cbWndExtra = 0;
  1264.   wndClass.hInstance = *GetModule();
  1265.   wndClass.hIcon = 0;
  1266.   wndClass.hCursor = ::LoadCursor(0, IDC_ARROW);
  1267.   wndClass.hbrBackground = HBRUSH(COLOR_WINDOW + 1);
  1268.   wndClass.lpszMenuName = 0;
  1269.   wndClass.lpszClassName = GetClassName();
  1270.   wndClass.style = CS_DBLCLKS;
  1271.   wndClass.lpfnWndProc = InitWndProc;
  1272. }
  1273.  
  1274. //
  1275. // Returns a classname for a generic owl window. Builds the name based on the
  1276. // name part of the current module's filename with "Window" appended.
  1277. //
  1278. char far*
  1279. TWindow::GetClassName()
  1280. {
  1281. #if defined(BUILDUP_CLASSNAME)
  1282.   static char classSuffix[] = "Window";
  1283.   static char className[_MAX_FNAME+sizeof(classSuffix)];
  1284.  
  1285.   if (!*className) {
  1286.     char filePath[_MAX_PATH];
  1287.   #if (__WIN32__)
  1288.     int  len = ::GetModuleFileName(0, filePath, sizeof(filePath));
  1289.   #else
  1290.     int  len = GetModule()->GetModuleFileName(filePath, sizeof(filePath));
  1291.   #endif
  1292.     CHECK(len > 0);
  1293.     _splitpath(filePath, 0, 0, className, 0);
  1294.     strcat(className, classSuffix);
  1295.   }
  1296.   return className;
  1297. #else
  1298.   return "OwlWindow";  // assume application private class
  1299. #endif
  1300. }
  1301.  
  1302. //
  1303. void
  1304. TWindow::LoadAcceleratorTable()
  1305. {
  1306.   if (Attr.AccelTable) {
  1307.     hAccel = GetModule()->LoadAccelerators(Attr.AccelTable);
  1308.     WARNX(OwlWin, !hAccel, 0,
  1309.           "Unable to load accelerators " << Attr.AccelTable
  1310.           << " from " << *GetModule());
  1311.   }
  1312. }
  1313.  
  1314. //
  1315. // Perform MS Windows window creation
  1316. //
  1317. void
  1318. TWindow::PerformCreate(int menuOrId)
  1319. {
  1320.   HWindow = ::CreateWindowEx(Attr.ExStyle,
  1321.                            GetClassName(),
  1322.                            Title,
  1323.                            Attr.Style,
  1324.                            Attr.X, Attr.Y, Attr.W, Attr.H,
  1325.                            Parent ? Parent->HWindow : 0,
  1326.                            (HMENU)menuOrId,
  1327.                            *GetModule(),
  1328.                            Attr.Param);
  1329. }
  1330.  
  1331. //
  1332. // associates an MS-Windows interface element with the TWindow object,
  1333. // after creating the interface element if not already created
  1334. //
  1335. // when creating an element, uses the creation attributes previously set in
  1336. // the Attr data field(simply associates the TWindow with an already
  1337. // created interface element if the "FromResource" flag is set)
  1338. //
  1339. // Since this member function now throw an exception on error, it always
  1340. // returns TRUE.
  1341. //
  1342. BOOL
  1343. TWindow::Create()
  1344. {
  1345.   PRECONDITION(HWindow == 0);
  1346.  
  1347.   int  menuOrId = 0;
  1348.  
  1349.   DisableAutoCreate();
  1350.  
  1351.   if (IsFlagSet(wfFromResource))
  1352.     HWindow = Parent ? Parent->GetDlgItem(Attr.Id) : 0;  // windows already created it
  1353.  
  1354.   else if (Register()) {
  1355.     SetCreationWindow(this);
  1356.  
  1357.     LoadAcceleratorTable();
  1358.  
  1359.     if (Attr.Menu) {
  1360.       menuOrId = (int)GetModule()->LoadMenu(Attr.Menu);
  1361.       WARNX(OwlWin, !menuOrId, 0, "Unable to load menu: " << Attr.Menu <<
  1362.             " from " << *GetModule());
  1363.  
  1364.     } else
  1365.       menuOrId = Attr.Id;
  1366.  
  1367.     PerformCreate(menuOrId);
  1368.     GetApplication()->ResumeThrow();
  1369.  
  1370.   } else
  1371.     THROW( TXWindow(this, IDS_CLASSREGISTERFAIL) );
  1372.  
  1373.   if (!HWindow) {
  1374.     if (Attr.Menu)  // && !IsFlagSet(wfFromResource) ?
  1375.       DestroyMenu(HMENU(menuOrId));
  1376.  
  1377.     THROW( TWindow::TXWindow(this, IDS_WINDOWCREATEFAIL) );
  1378.   }
  1379.  
  1380.   //
  1381.   // predefined (non-owl) class--grab the state info that the class setup,
  1382.   // install the thunk & zero the creation window since InitWndProc never got
  1383.   // called, and set a flag
  1384.   //
  1385.   if (!GetWindowPtr(HWindow)) {
  1386.     GetWindowTextTitle();
  1387.     GetHWndState();
  1388.  
  1389.     SubclassWindowFunction();
  1390.     SetCreationWindow(0);
  1391.     SetFlag(wfPredefinedClass);
  1392.  
  1393.     SetupWindow();
  1394.   }
  1395.  
  1396.   return TRUE;
  1397. }
  1398.  
  1399. //
  1400. // performs setup following creation of an associated MS-Windows window.
  1401. // Iterates through the TWindow's ChildList, attempting to create
  1402. // an associated MS-Windows interface element for each child window
  1403. // object in the list (a child's Create method is not called if its
  1404. // wfAutoCreate flag is not set)
  1405. //
  1406. // calls TransferData to transfer data for its children for whom data transfer
  1407. // is enabled
  1408. //
  1409. // if the receiver has a TScroller object, calls the scroller's SetBarRange()
  1410. // method
  1411. //
  1412. // can be redefined in derived classes to perform additional special
  1413. // initialization that requires an HWND
  1414. //
  1415. void
  1416. TWindow::SetupWindow()
  1417. {
  1418.   if (Scroller)
  1419.     Scroller->SetSBarRange();
  1420.  
  1421.   if (!CreateChildren())
  1422.     THROW( TXWindow(0, IDS_CHILDCREATEFAIL) ); // not us, an unspecified child
  1423.  
  1424.   else
  1425.     TransferData(tdSetData);
  1426. }
  1427.  
  1428. //
  1429. // always called just before HWindow goes away to give derived classes a
  1430. // chance to cleanup HWND related resources.
  1431. //
  1432. void
  1433. TWindow::CleanupWindow()
  1434. {
  1435. }
  1436.  
  1437. //
  1438. // transfer window 'data' to/from the passed data buffer.  Used to initialize
  1439. // windows and get data in or out of them.
  1440. //
  1441. // the direction passed specifies whether data is to be read from or
  1442. // written to the passed buffer, or whether the data element size is simply
  1443. // to be returned
  1444. //
  1445. // the return value is the size (in bytes) of the transfer data.  this method
  1446. // recursively calls transfer on all its children that have wfTransfer set.
  1447. //
  1448.  
  1449. struct TTransferIterInfo {
  1450.   void*               Data;
  1451.   TTransferDirection  Direction;
  1452. };
  1453.  
  1454. static void transferDatchild(TWindow* child, TTransferIterInfo* info) {
  1455.   if (child->IsFlagSet(wfTransfer))
  1456.     (char*)info->Data += child->Transfer(info->Data, info->Direction);
  1457. }
  1458.  
  1459. UINT
  1460. TWindow::Transfer(void* buffer, TTransferDirection direction)
  1461. {
  1462.   if (buffer) {
  1463.     TTransferIterInfo info = { buffer, direction };
  1464.     ForEach((TActionFunc)transferDatchild, &info);
  1465.     return (char near*)info.Data - (char near*)buffer;
  1466.   }
  1467.   return 0;
  1468. }
  1469.  
  1470. //$---------------------------------------------------------------------------
  1471. //
  1472. // transfers data between the TWindow's data buffer and the child
  1473. // windows in its ChildList (data is not transfered between any child
  1474. // windows whose wfTransfer flag is not set)
  1475. //
  1476. void
  1477. TWindow::TransferData(TTransferDirection direction)
  1478. {
  1479.   if (TransferBuffer)
  1480.     Transfer(TransferBuffer, direction);
  1481. }
  1482.  
  1483. //
  1484. // registers the TWindow's MS-Windows, if not already registered
  1485. //
  1486. BOOL
  1487. TWindow::Register()
  1488. {
  1489.   WNDCLASS  windowClass;
  1490.   BOOL gc;
  1491.  
  1492.   //
  1493.   // Only check for globally registered classes if not in an NT WoW box,
  1494.   // since WoW plays nasty games with class registration.
  1495.   //
  1496. #if defined(__WIN32__)
  1497.   gc = ::GetClassInfo(0, GetClassName(), &windowClass);
  1498. #else
  1499.   static BOOL isWoW = BOOL(::GetWinFlags()&0x4000);
  1500.   if (!isWoW)
  1501.     gc = ::GetClassInfo(0, GetClassName(), &windowClass);
  1502.   else
  1503.     gc = 0;
  1504. #endif
  1505.  
  1506.   if (!gc && !GetModule()->GetClassInfo(GetClassName(), &windowClass)) {
  1507.     GetWindowClass(windowClass);
  1508.     return ::RegisterClass(&windowClass);
  1509.   }
  1510.  
  1511.   return TRUE;
  1512. }
  1513.  
  1514. //
  1515. // returns a BOOL indicating whether or not it is Ok to close the TWindow
  1516. //
  1517. // iterates through the TWindow's ChildList, calling the CanClose()
  1518. // method of each
  1519. //
  1520. // returns FALSE if any of the child windows returns FALSE
  1521. //
  1522.  
  1523. static BOOL cannotClose(TWindow* win, void*) {
  1524.   return win->HWindow && !win->CanClose();
  1525. }
  1526.  
  1527. BOOL
  1528. TWindow::CanClose()
  1529. {
  1530.   return !FirstThat(cannotClose);
  1531. }
  1532.  
  1533. //
  1534. // destroys the associated MS-Windows interface element and frees "this"
  1535. // after determining that it is Ok to do so
  1536. //
  1537. // if the TWindow is the main window of the application, calls the CanClose()
  1538. // method of the application, else calls this->CanClose(), before calling
  1539. // Destroy()
  1540. //
  1541. void
  1542. TWindow::CloseWindow(int retVal)
  1543. {
  1544.   BOOL  willClose;
  1545.  
  1546.   if (IsFlagSet(wfMainWindow))
  1547.     willClose = GetApplication()->CanClose();
  1548.  
  1549.   else
  1550.     willClose = CanClose();
  1551.  
  1552.   if (willClose)
  1553.     Destroy(retVal);
  1554. }
  1555.  
  1556. //
  1557. // the default response to a WM_CLOSE message is to call CloseWindow()
  1558. // and then have the window deleted if CloseWindow() did the Destroy().
  1559. //
  1560. void
  1561. TWindow::EvClose()
  1562. {
  1563.   if (IsFlagSet(wfAlias))
  1564.     DefaultProcessing();
  1565.  
  1566.   else {
  1567.     CloseWindow();
  1568.     if (!HWindow)
  1569.       GetApplication()->Condemn(this);  // Assumes delete
  1570.   }
  1571. }
  1572.  
  1573. //
  1574. // responds to an incoming WM_DESTROY message
  1575. //
  1576. // Calls CleanupWindow() to let derived classes cleanup
  1577. //
  1578. // if the TWindow is the application's main window posts a 'quit' message to
  1579. // end the application, unless already in ~TApplication() (MainWindow == 0)
  1580. //
  1581. void
  1582. TWindow::EvDestroy()
  1583. {
  1584.   CleanupWindow();
  1585.  
  1586.   if (!IsFlagSet(wfAlias)) {
  1587.     if (IsFlagSet(wfMainWindow))
  1588.       ::PostQuitMessage(GetApplication()->Status);
  1589.   }
  1590.  
  1591.   DefaultProcessing();
  1592. }
  1593.  
  1594. //
  1595. // responds to an incoming WM_NCDESTROY message, the last message
  1596. // sent to an MS-Windows interface element
  1597. //
  1598. // sets the HWindow data member of the TWindow to zero to indicate that an
  1599. // interface element is no longer associated with the object
  1600. //
  1601. void
  1602. TWindow::EvNCDestroy()
  1603. {
  1604.   DefaultProcessing();
  1605.   HWindow = 0;
  1606. }
  1607.  
  1608. //
  1609. // respond to Windows attempt to close close down
  1610. //
  1611. BOOL
  1612. TWindow::EvQueryEndSession()
  1613. {
  1614.   if (IsFlagSet(wfAlias))
  1615.     return (BOOL)DefaultProcessing();
  1616.  
  1617.   else if (IsFlagSet(wfMainWindow))
  1618.     return GetApplication()->CanClose();
  1619.  
  1620.   else
  1621.     return CanClose();
  1622. }
  1623.  
  1624. //
  1625. // if the window receives an Exit menu choice, it will attempt
  1626. // to close down the window
  1627. //
  1628. void
  1629. TWindow::CmExit()
  1630. {
  1631.   if (IsFlagSet(wfMainWindow))
  1632.     CloseWindow();
  1633.  
  1634.   else
  1635.     DefaultProcessing();
  1636. }
  1637.  
  1638. //
  1639. // Handle message posted to us by a control needing assistance in dealing with
  1640. // invalid inputs
  1641. //
  1642. void
  1643. TWindow::EvChildInvalid(HWND hWnd)
  1644. {
  1645.   ::SendMessage(hWnd, WM_CHILDINVALID, 0, 0);
  1646. }
  1647.  
  1648. //----------------------------------------------------------------------------
  1649. // Non-virtuals
  1650. //----------------------------------------------------------------------------
  1651.  
  1652. //$---------------------------------------------------------------------------
  1653. unsigned
  1654. TWindow::NumChildren()
  1655. {
  1656.   return IndexOf(ChildList) + 1;
  1657. }
  1658.  
  1659. //$---------------------------------------------------------------------------
  1660. //
  1661. //
  1662. void
  1663. TWindow::AssignZOrder()
  1664. {
  1665.   TWindow*  wnd;
  1666.   HWND      curWindow = HWindow;
  1667.  
  1668.   if (curWindow) {
  1669.     curWindow = ::GetWindow(curWindow, GW_CHILD);
  1670.  
  1671.     if (curWindow) {
  1672.       int  i = 1;
  1673.  
  1674.       for (curWindow = ::GetWindow(curWindow, GW_HWNDLAST);
  1675.            curWindow;
  1676.            curWindow = ::GetWindow(curWindow, GW_HWNDPREV))
  1677.       {
  1678.         wnd = GetWindowPtr(curWindow);
  1679.  
  1680.         if (wnd)
  1681.           wnd->ZOrder = (WORD)i++;
  1682.       }
  1683.     }
  1684.   }
  1685. }
  1686.  
  1687. //$---------------------------------------------------------------------------
  1688. //
  1689. // The private field ZOrder is used to ensure the Z-order is
  1690. // consistent through read and write of the object.
  1691. //
  1692. // When the object is written, parent->AssignZOrder will fill in this value
  1693. //
  1694. // ZOrder ranges from 1 to N where N is the number of objects and the top one.
  1695. // A ZOrder value of 0 means that the Z-ordering has not be recoreded.
  1696. //
  1697. BOOL
  1698. TWindow::OrderIsI(TWindow* win, void* position)
  1699. {
  1700.   return win->ZOrder == *(int*)position;
  1701. }
  1702.  
  1703. //$---------------------------------------------------------------------------
  1704. //
  1705. // returns TRUE if the child was supposed to be created but couldn't be
  1706. //
  1707. static BOOL
  1708. cantCreate(TWindow* win, void*)
  1709. {
  1710.   if (win->HWindow)
  1711.     return FALSE;
  1712.  
  1713.   BOOL autoCreate = win->IsFlagSet(wfAutoCreate);
  1714.  
  1715.   WARNX(OwlWin, !autoCreate, 0,
  1716.         "Child window(Id=" << win->GetId() << ") not autocreated");
  1717.   if (!autoCreate)
  1718.     return FALSE;
  1719.  
  1720.   //
  1721.   // this call will only fail if a user-defined Create() returns FALSE. Owl's
  1722.   // Creates always throw exceptions.
  1723.   //
  1724.   if (!win->Create())
  1725.     return TRUE;
  1726.  
  1727.   if (win->IsIconic()) {
  1728.     int    textLen = ::GetWindowTextLength(win->HWindow);
  1729.     char*  text = new char[textLen + 1];
  1730.  
  1731.     ::GetWindowText(win->HWindow, text, textLen + 1);
  1732.     ::SetWindowText(win->HWindow, text);
  1733.     delete text;
  1734.   }
  1735.   return FALSE;
  1736. }
  1737.  
  1738. //
  1739. // create the children of the object.  returns true if all the windows
  1740. // were successfully created
  1741. //
  1742. BOOL
  1743. TWindow::CreateChildren()
  1744. {
  1745.   if (FirstThat(cantCreate)) // create children first to restore created order
  1746.     return FALSE;
  1747.   //  
  1748.   // restore Z-ordering for children that have Z-ordering recorded
  1749.   //  
  1750.   HWND above = HWND_TOP;
  1751.   for (int top = NumChildren(); top; top--) {
  1752.     TWindow* wnd = FirstThat(&TWindow::OrderIsI, &top);
  1753.     if (wnd) {
  1754.       wnd->SetWindowPos(above, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
  1755.       above = wnd->HWindow;
  1756.     }
  1757.   }
  1758.   return TRUE;
  1759. }
  1760.  
  1761. //$---------------------------------------------------------------------------
  1762. //
  1763. // adds the passed pointer to a child window to the linked list
  1764. // of sibling windows which ChildList points to
  1765. //
  1766. void
  1767. TWindow::AddChild(TWindow* child)
  1768. {
  1769.   if (child)
  1770.     if (ChildList) {
  1771.       child->SiblingList = ChildList->SiblingList;
  1772.       ChildList->SiblingList = child;
  1773.       ChildList = child;
  1774.  
  1775.     } else {
  1776.       ChildList = child;
  1777.       child->SiblingList = child;
  1778.     }
  1779. }
  1780.  
  1781. //$---------------------------------------------------------------------------
  1782. //
  1783. // returns a pointer to the TWindow's previous sibling (the
  1784. // window previous to the TWindow in its parent's child window
  1785. // list)
  1786. //
  1787. // returns the sibling which points to the TWindow
  1788. //
  1789. // if the TWindow was the first child added to the list, returns
  1790. // a pointer to the last child added
  1791. //
  1792. TWindow*
  1793. TWindow::Previous()
  1794. {
  1795.   if (!SiblingList)
  1796.     return 0;
  1797.  
  1798.   else {
  1799.     TWindow*  CurrentIndex = this;
  1800.  
  1801.     while (CurrentIndex->Next() != this)
  1802.       CurrentIndex = CurrentIndex->Next();
  1803.  
  1804.     return CurrentIndex;
  1805.   }
  1806. }
  1807.  
  1808. //$---------------------------------------------------------------------------
  1809. //
  1810. // returns a pointer to the first TWindow in the ChildList that meets some
  1811. // specified criteria
  1812. //
  1813. // if no child in the list meets the criteria, 0 is returned
  1814. //
  1815. // the Test parameter which defines the criteria, is a pointer to a
  1816. // function that takes a TWindow pointer & a pointer to void
  1817. //
  1818. // the TWindow* will be used as the pointer to the child window and
  1819. // the void* as a pointer to the Test function's additional parameters
  1820. //
  1821. // the Test function must return a Boolean value indicating whether the
  1822. // child passed meets the criteria
  1823. //
  1824. TWindow*
  1825. TWindow::FirstThat(TCondFunc test, void* paramList)
  1826. {
  1827.   if (ChildList) {
  1828.     TWindow*  nextChild = ChildList->Next();
  1829.     TWindow*  curChild;
  1830.  
  1831.     do {
  1832.       curChild = nextChild;
  1833.       nextChild = nextChild->Next();
  1834.  
  1835.       //
  1836.       // Test curChild for okay
  1837.       //
  1838.       if (test(curChild, paramList))
  1839.         return curChild;
  1840.     } while (curChild != ChildList && ChildList);
  1841.   }
  1842.   return 0;
  1843. }
  1844.  
  1845. //$---------------------------------------------------------------------------
  1846. //
  1847. // iterates over each child window in the TWindow's ChildList,
  1848. // calling the procedure whose pointer is passed as the Action to be
  1849. // performed for each child
  1850. //
  1851. // a pointer to a child is passed as the first parameter to the iteration
  1852. // procedure
  1853. //
  1854. void
  1855. TWindow::ForEach(TActionFunc action, void* paramList)
  1856. {
  1857.   if (ChildList) {
  1858.     TWindow*  curChild;
  1859.     TWindow*  nextChild = ChildList->Next();  // allows ForEach to delete children
  1860.  
  1861.     do {
  1862.       curChild = nextChild;
  1863.       nextChild = nextChild->Next();
  1864.       action(curChild, paramList);
  1865.     } while (curChild != ChildList && ChildList);
  1866.   }
  1867. }
  1868.  
  1869. //$---------------------------------------------------------------------------
  1870. //
  1871. // returns a pointer to the first TWindow in the ChildList that
  1872. // meets some specified criteria
  1873. //
  1874. // if no child in the list meets the criteria, 0 is returned
  1875. //
  1876. // the Test parameter which defines the criteria, is a pointer to a member
  1877. // function (this is how it's different from FirstThat above) that takes a
  1878. // pointer to a TWindow & a pointer to void
  1879. //
  1880. // the TWindow pointer will be used as the pointer to the child window and the
  1881. // void pointer as a pointer to the Test function's additional parameters
  1882. //
  1883. // the Test function must return a Boolean value indicating whether the child
  1884. // passed meets the criteria
  1885. //
  1886. TWindow*
  1887. TWindow::FirstThat(TCondMemFunc test, void* paramList)
  1888. {
  1889.   if (ChildList) {
  1890.     TWindow*  nextChild = ChildList->Next();
  1891.     TWindow*  curChild;
  1892.  
  1893.     do {
  1894.       curChild = nextChild;
  1895.       nextChild = nextChild->Next();
  1896.  
  1897.       if ((this->*test)(curChild, paramList))
  1898.         return curChild;
  1899.     } while (curChild != ChildList && ChildList);
  1900.   }
  1901.   return 0;
  1902. }
  1903.  
  1904. //$---------------------------------------------------------------------------
  1905. //
  1906. // iterates over each child window in the TWindow's ChildList,
  1907. // calling the member function (unlike ForEach above which takes pointer
  1908. // to non-member function) whose pointer is passed as the Action to
  1909. // be performed for each child
  1910. //
  1911. // a pointer to a child is passed as the first parameter to the iteration
  1912. // procedure
  1913. //
  1914. void
  1915. TWindow::ForEach(TActionMemFunc action, void* paramList)
  1916. {
  1917.   if (ChildList) {
  1918.     TWindow*  nextChild = ChildList->Next();
  1919.     TWindow*  curChild;
  1920.  
  1921.     do {
  1922.       curChild = nextChild;
  1923.       nextChild = nextChild->Next();
  1924.       (this->*action)(curChild, paramList);
  1925.     } while (curChild != ChildList && ChildList);
  1926.   }
  1927. }
  1928.  
  1929. //$---------------------------------------------------------------------------
  1930. //
  1931. // returns the position at which the passed child window appears
  1932. // in the TWindow's ChildList
  1933. //
  1934. // if the child does not appear in the list, -1 is returned
  1935. //
  1936. // zero'th position is ChildList->Next
  1937. //
  1938. static int position;
  1939. static BOOL isItThisChild1(TWindow* win, void* child) {
  1940.   ++position;
  1941.   return win == (TWindow*)child;
  1942. }
  1943.  
  1944. int
  1945. TWindow::IndexOf(TWindow* child)
  1946. {
  1947.   position = -1;
  1948.   return FirstThat(isItThisChild1, child) ? position : -1;
  1949. }
  1950.  
  1951. //$---------------------------------------------------------------------------
  1952. //
  1953. // returns the child at the passed position in the TWindow's
  1954. // ChildList
  1955. //
  1956. // the ChildList is circularly-referent so that passing a position
  1957. // larger than the number of children will cause the traversal of the
  1958. // list to wrap
  1959. //
  1960. // zero'th position is ChildList->Next
  1961. //
  1962. TWindow*
  1963. TWindow::At(int position)
  1964. {
  1965.   if (position == -1)
  1966.     return 0;
  1967.  
  1968.   else {
  1969.     TWindow*  currentChild = ChildList;
  1970.  
  1971.     if (currentChild) {
  1972.       currentChild = ChildList->Next();
  1973.  
  1974.       while (position > 0) {
  1975.         currentChild = currentChild->Next();
  1976.         position--;
  1977.       }
  1978.     }
  1979.     return currentChild;
  1980.   }
  1981. }
  1982.  
  1983. //$---------------------------------------------------------------------------
  1984. //
  1985. // returns a pointer to the window in the ChildList with the passed Id
  1986. //
  1987. // if no child in the list has the passed Id, 0 is returned
  1988. //
  1989. static BOOL isItThisChild2(TWindow* win, void* id) {
  1990.   return win->GetId() == *(int*)id;
  1991. }
  1992.  
  1993. TWindow*
  1994. TWindow::ChildWithId(int id) const
  1995. {
  1996.   return ((TWindow*)this)->FirstThat(isItThisChild2, &id);
  1997. }
  1998.  
  1999. //$---------------------------------------------------------------------------
  2000. //
  2001. LRESULT
  2002. TWindow::SendMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
  2003.   LRESULT result = ::SendMessage(HWindow, msg, wParam, lParam);
  2004.   GetApplication()->ResumeThrow();
  2005.   return result;
  2006. }
  2007.  
  2008. //$---------------------------------------------------------------------------
  2009. //
  2010. LRESULT
  2011. TWindow::ForwardMessage(HWND hWnd, BOOL send)
  2012. {
  2013.   if (!hWnd)
  2014.     return 0;
  2015.   if (send) {
  2016.     LRESULT result = ::SendMessage(hWnd, CurrentEvent.message,
  2017.                          CurrentEvent.wParam, CurrentEvent.lParam);
  2018.     GetApplication()->ResumeThrow();
  2019.     return result;
  2020.   }
  2021.   else
  2022.     return ::PostMessage(hWnd, CurrentEvent.message,
  2023.                          CurrentEvent.wParam, CurrentEvent.lParam);
  2024. }
  2025.  
  2026. //$---------------------------------------------------------------------------
  2027. //
  2028. // Forward a message to an Owl window. If send, then bypass windows directly
  2029. // and call the owl window's window proc.
  2030. //
  2031. LRESULT
  2032. TWindow::ForwardMessage(BOOL send)
  2033. {
  2034.   if (send)
  2035.     return HandleMessage(CurrentEvent.message, CurrentEvent.wParam,
  2036.                          CurrentEvent.lParam);
  2037.   return ForwardMessage(HWindow, send);
  2038. }
  2039.  
  2040. //$---------------------------------------------------------------------------
  2041. //
  2042. void
  2043. TWindow::ChildBroadcastMessage(UINT msg, WPARAM wParam, LPARAM lParam)
  2044. {
  2045.   for (HWND hWndChild = GetWindow(GW_CHILD); hWndChild; ) {
  2046.     HWND hWndNext = ::GetWindow(hWndChild, GW_HWNDNEXT);
  2047.     ::SendMessage(hWndChild, msg, wParam, lParam);
  2048.     GetApplication()->ResumeThrow();
  2049.     hWndChild = hWndNext;
  2050.   }
  2051. }
  2052.  
  2053. //$---------------------------------------------------------------------------
  2054. //
  2055. // destroys the associated MS-Windows interface element and frees "this"
  2056. // without calling CanClose()
  2057. //
  2058. // This function is obsolete. Destroy() should be called directly, & then the
  2059. // window destructed (using delete, etc).
  2060. //
  2061. void
  2062. TWindow::ShutDownWindow(int retVal)
  2063. {
  2064.   Destroy(retVal);
  2065.   GetApplication()->Condemn(this);  // Assumes delete
  2066. }
  2067.  
  2068. //$---------------------------------------------------------------------------
  2069. //
  2070. // displays the TWindow, after checking that it has a valid handle
  2071. //
  2072. void
  2073. TWindow::Show(int cmdShow)
  2074. {
  2075.   //
  2076.   // if the window is being minimzed send a WM_SYSCOMMAND; this way the
  2077.   // frame window focus saving works properly
  2078.   //
  2079.   if (HWindow)
  2080.     if (cmdShow == SW_MINIMIZE)
  2081.       HandleMessage(WM_SYSCOMMAND, SC_MINIMIZE);
  2082.  
  2083.     else
  2084.       ::ShowWindow(HWindow, cmdShow);
  2085. }
  2086.  
  2087. //$---------------------------------------------------------------------------
  2088. //
  2089. // sets the Title and caption of the TWindow
  2090. //
  2091. void
  2092. TWindow::SetCaption(const char far* title)
  2093. {
  2094.   if (Title != title) {
  2095.     if (HIWORD(Title))
  2096.       delete Title;
  2097.  
  2098.     Title = strnewdup(title);
  2099.   }
  2100.  
  2101.   if (HWindow)
  2102.     ::SetWindowText(HWindow, Title);
  2103. }
  2104.  
  2105. //$---------------------------------------------------------------------------
  2106. //
  2107. // gets the Title member var from the current window caption or text
  2108. //
  2109. void
  2110. TWindow::GetWindowTextTitle()
  2111. {
  2112.   if (LOWORD(Title) == 0xFFFF)  // ignore "don't-change" titles
  2113.     return;
  2114.  
  2115.   if (HIWORD(Title))
  2116.     delete Title;
  2117.  
  2118.   int titleLength = GetWindowTextLength();
  2119.   if (titleLength < 0)
  2120.     Title = strnewdup((const char far*)"");
  2121.  
  2122.   else {
  2123.     Title = new far char[titleLength + 1];
  2124.     Title[0] = 0;
  2125.     Title[titleLength] = 0;
  2126.     GetWindowText(Title, titleLength + 1);
  2127.   }
  2128. }
  2129.  
  2130. //$---------------------------------------------------------------------------
  2131. //
  2132. // copy over the styles, the coordinates & the id from the existing HWnd into
  2133. // the owl TWindow members.
  2134. // Note: the title is not copied here
  2135. //
  2136. void
  2137. TWindow::GetHWndState()
  2138. {
  2139.   //
  2140.   // retrieve Attr.Style and Attr.ExStyle
  2141.   //
  2142.   // NOTE: some windows controls (e.g. EDIT) change the style bits
  2143.   // (e.g. WS_BORDER) from their original values.  if we always reset
  2144.   // Attr.Style and Attr.ExStyle by extracting their values from
  2145.   // Windows, we will lose some of the style bits we supplied
  2146.   // in the CreateWindowEx call.  in the case of the ResourceId
  2147.   // constructors, of course, we must retrieve these values.
  2148.   //
  2149.   if (IsFlagSet(wfFromResource)) {
  2150.     Attr.Style = GetWindowLong(GWL_STYLE);
  2151.     Attr.ExStyle = GetWindowLong(GWL_EXSTYLE);
  2152.   }
  2153.  
  2154.   //
  2155.   // retrieve Attr.X, Attr.Y, Attr.W and Attr.H
  2156.   //
  2157.   TRect  wndRect;
  2158.  
  2159.   GetWindowRect(wndRect);
  2160.   Attr.H = wndRect.Height();
  2161.   Attr.W = wndRect.Width();
  2162.  
  2163.   HWND      hParent = GetParent();
  2164.   if ((Attr.Style & WS_CHILD) && hParent)
  2165.     ::ScreenToClient(hParent, &wndRect.TopLeft());
  2166.  
  2167.   Attr.X = wndRect.left;
  2168.   Attr.Y = wndRect.top;
  2169.  
  2170. #if defined(__WIN32__)
  2171.   Attr.Id = GetWindowLong(GWL_ID);
  2172. #else
  2173.   Attr.Id = GetWindowWord(GWW_ID);
  2174. #endif
  2175. }
  2176.  
  2177. //$---------------------------------------------------------------------------
  2178. //
  2179. // Set the cursor for this window given a TModule and a resId
  2180. // Updates the current cursor if it is over this window.
  2181. //
  2182. BOOL
  2183. TWindow::SetCursor(TModule* module, TResId resId)
  2184. {
  2185.   if (module == CursorModule && resId == CursorResId)
  2186.     return FALSE;
  2187.  
  2188.   HCURSOR hOldCursor = (HCursor && CursorModule) ? HCursor : 0;
  2189.  
  2190.   CursorModule = module;
  2191.   CursorResId = resId;
  2192.   if (CursorResId)
  2193.     if (CursorModule)
  2194.       HCursor = CursorModule->LoadCursor(CursorResId);
  2195.     else
  2196.       HCursor = ::LoadCursor(0, CursorResId);
  2197.   else
  2198.     HCursor = 0;
  2199.  
  2200.   //
  2201.   // If the cursor is in our client window then set it now
  2202.   //
  2203.   if (HWindow) {
  2204.     TPoint p;
  2205.     GetCursorPos(p);
  2206.     ScreenToClient(p);
  2207.     if (GetClientRect().Contains(p))
  2208.       ::SetCursor(HCursor);
  2209.   }
  2210.  
  2211.   //
  2212.   // Destroy old cursor if there was one & it was not loaded from USER
  2213.   //
  2214.   if (hOldCursor)
  2215.     ::DestroyCursor(hOldCursor);
  2216.   return TRUE;
  2217. }
  2218.  
  2219. //$---------------------------------------------------------------------------
  2220. //
  2221. // not inline to avoid requiring gdiobjec.h by window.h
  2222. //
  2223. BOOL
  2224. TWindow::GetUpdateRgn(TRegion& region, BOOL erase) const
  2225. {
  2226.   return ::GetUpdateRgn(HWindow, region, erase);
  2227. }
  2228.  
  2229. //$---------------------------------------------------------------------------
  2230. //
  2231. //
  2232. int
  2233. TWindow::MessageBox(const char far* text,
  2234.                     const char far* caption,
  2235.                     UINT            type)
  2236. {
  2237.   Application->EnableCtl3dAutosubclass(TRUE);
  2238.   int retValue = ::MessageBox(HWindow, text, caption, type);
  2239.   Application->EnableCtl3dAutosubclass(FALSE);
  2240.   return retValue;
  2241. }
  2242.  
  2243. #if defined(__TRACE) || defined(__WARN)
  2244.   ostream& operator <<(ostream& os, const TWindow& w)
  2245.   {
  2246.     os << '(';
  2247.     #if !defined(BI_NO_RTTI)
  2248.       os << typeid(w).name() << ',';
  2249.     #endif
  2250.     os << "0x" << hex << (unsigned)w.HWindow << ',';
  2251.     if (!w.Parent)
  2252.       os << '\'' << TResId(w.Title) << '\'';
  2253.     else
  2254.       os << "id=" << w.GetId();
  2255.     os << ')';
  2256.     return os;
  2257.   }
  2258. #endif
  2259.  
  2260. //$---------------------------------------------------------------------------
  2261. //
  2262. // static member function to construct base TXOwl object
  2263. //
  2264. string
  2265. TWindow::TXWindow::Msg(TWindow* win, UINT resId)
  2266. {
  2267.   BOOL   found;  // did we locate the string
  2268.   string rscMsg = ResourceIdToString(&found, resId);
  2269.  
  2270.   if (found) {
  2271.     char buf[255];
  2272.  
  2273.     //
  2274.     // supply title of window if we have a valid window
  2275.     //
  2276.     wsprintf(buf, rscMsg.c_str(), win ? win->Title : "");
  2277.     return string(buf);
  2278.  
  2279.   } else
  2280.     return rscMsg;
  2281. }
  2282.  
  2283. //$---------------------------------------------------------------------------
  2284. //
  2285. // InvalidWindow exception constructor
  2286. //
  2287. TWindow::TXWindow::TXWindow(TWindow* win, UINT resId)
  2288.   : TXOwl(Msg(win, resId))
  2289. {
  2290.   Window = win;
  2291. }
  2292.  
  2293. TWindow::TXWindow::TXWindow(const TXWindow& src) : TXOwl(src),Window(src.Window)
  2294. {
  2295. }
  2296.  
  2297. int
  2298. TWindow::TXWindow::Unhandled(TModule* app, unsigned promptResId)
  2299. {
  2300.   delete Window;
  2301.   Window = 0;
  2302.   return TXOwl::Unhandled(app, promptResId);
  2303. }
  2304.  
  2305. TXOwl*
  2306. TWindow::TXWindow::Clone()
  2307. {
  2308.   return new TXWindow(*this);
  2309. }
  2310.  
  2311.