home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / ftes46b5.zip / ftes46b5 / src / g_pm.cpp < prev    next >
C/C++ Source or Header  |  1997-07-27  |  119KB  |  3,871 lines

  1. /*    g_pm.cpp
  2.  *
  3.  *    Copyright (c) 1994-1996, Marko Macek
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  */
  9.  
  10. /*
  11.  * here's how it works:
  12.  * there's one visible and one object window per view
  13.  * events are forwarded from the visible on to object window and pulled
  14.  * into the editor from the worker thread (there's only one, FTE
  15.  * editor core is single-threaded).
  16.  * SIQ is never blocked.
  17.  * the only problem is that window doesn't repaint correctly after resize,
  18.  * until the worker thread finishes processing, but we can't really
  19.  * do anything with this as the editor core is not thread-safe.
  20.  */
  21.  
  22. #define INCL_WIN
  23. #define INCL_GPI
  24. #define INCL_VIO
  25. #define INCL_AVIO
  26. #define INCL_DOS
  27. #define INCL_DOSERRORS
  28.  
  29. #include <os2.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include <process.h>
  34. #include <assert.h>
  35. #include <stdarg.h>
  36. #include <ctype.h>
  37. #include "ftever.h"
  38. #include "sysdep.h"
  39. #include "feature.h"
  40. #include "console.h"
  41. #include "gui.h"
  42. #include "c_history.h"
  43. #include "c_commands.h"
  44. #include "c_config.h"
  45. #include "c_mode.h"
  46. #include "c_color.h"
  47.  
  48. #define PM_STACK_SIZE (96 * 1024)
  49.  
  50. #define UWM_NOTIFY (WM_USER + 1)
  51. #define UWM_DESTROY (WM_USER + 2)
  52. #define UWM_DESTROYHWND (WM_USER + 3)
  53. #define UWM_DROPPEDFILE (WM_USER + 4)
  54. #define UWM_FILEDIALOG (WM_USER + 5)
  55. #define UWM_DLGBOX (WM_USER + 6)
  56. #define UWM_PROCESSDLG (WM_USER + 7)
  57. #define UWM_CHOICE (WM_USER + 8)
  58. #define UWM_CREATECHILD (WM_USER + 9)
  59. #define UWM_CREATEWORKER (WM_USER + 10)
  60. #define UWM_CREATEFRAME (WM_USER + 11)
  61. #define UWM_CREATEMAINMENU (WM_USER + 12)
  62. #define UWM_CREATEPOPUPMENU (WM_USER + 13)
  63.  
  64. #define CURSOR_TYPE (CURSOR_FLASH | CURSOR_SOLID)
  65.  
  66. //#define SIZER_HEIGHT  4
  67.  
  68. #define FID_MTOOLBAR  10001
  69.  
  70. #define MAXXSIZE  160
  71. #define MAXYSIZE  96
  72.  
  73. #define MAX_PIPES 4
  74. #define PIPE_BUFLEN 4096
  75.  
  76. typedef struct {
  77.     int used;
  78.     int id;
  79.     int reading, stopped;
  80.     TID tid;
  81.     HMTX Access;
  82.     HEV ResumeRead;
  83.     char *buffer;
  84.     int buflen;
  85.     int bufused;
  86.     int bufpos;
  87.     EModel *notify;
  88.     char *Command;
  89.     int RetCode;
  90.     int DoTerm;
  91. } GPipe;
  92.  
  93. static GPipe Pipes[MAX_PIPES] = {
  94.     { 0 }, { 0 }, { 0 }, { 0 }
  95. };
  96.  
  97. #define sfFocus   1
  98.  
  99. typedef struct _PMPTR { // for passing pointers to winprocs
  100.     USHORT len;
  101.     void *p;
  102. } PMPTR;
  103.  
  104. class GViewPeer;
  105.  
  106. struct PMData {
  107.     GViewPeer *Peer;
  108.     HVPS hvps;
  109.     HPS hps;
  110.     SHORT cxChar;
  111.     SHORT cyChar;
  112.     HWND hwndWorker;
  113. };
  114.  
  115. class GViewPeer {
  116. public:
  117.     GView *View;
  118. //    int wX, wY;
  119.     int wW, wH, wState;
  120.     int cX, cY, cVisible, cStart, cEnd;
  121.     int sbVstart, sbVamount, sbVtotal;
  122.     int sbHstart, sbHamount, sbHtotal;
  123.     
  124.     HWND hwndView;
  125.     HWND hwndVscroll, hwndHscroll;
  126.     HWND hwndWorker;
  127.     PMData *pmData;
  128.     int OldMouseX, OldMouseY;
  129.     
  130.     GViewPeer(GView *view, int XSize, int YSize);
  131.     ~GViewPeer();
  132.  
  133.     int ConPutBox(int X, int Y, int W, int H, PCell Cell);
  134.     int ConGetBox(int X, int Y, int W, int H, PCell Cell);
  135.     int ConPutLine(int X, int Y, int W, int H, PCell Cell);
  136.     int ConSetBox(int X, int Y, int W, int H, TCell Cell);
  137.     int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count);
  138.  
  139.     int ConSetSize(int X, int Y);
  140.     int ConQuerySize(int *X, int *Y);
  141.     
  142.     int ConSetCursorPos(int X, int Y);
  143.     int ConQueryCursorPos(int *X, int *Y);
  144.     int ConShowCursor();
  145.     int ConHideCursor();
  146.     int ConCursorVisible();
  147.     int ConSetCursorSize(int Start, int End);
  148.     
  149.     int QuerySbVPos();
  150.     int SetSbVPos(int Start, int Amount, int Total);
  151.     int SetSbHPos(int Start, int Amount, int Total);
  152.     int ExpandHeight(int DeltaY);
  153.  
  154.     int UpdateCursor();
  155.     int PMShowCursor();
  156.     int PMHideCursor();
  157.     int PMSetCursorPos();
  158. };
  159.  
  160. class GFramePeer {
  161. public:
  162.     GFrame *Frame;
  163.     HWND hwndFrame;
  164.     HWND menuBar;
  165.     HWND hwndToolBar;
  166.     PFNWP oldFrameProc;
  167.     
  168.     GFramePeer(GFrame *aFrame, int Width, int Height);
  169.     ~GFramePeer();
  170.     
  171.     int ConSetTitle(char *Title, char *STitle);
  172.     int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen);
  173.     
  174.     int ConSetSize(int X, int Y);
  175.     int ConQuerySize(int *X, int *Y);
  176.     void MapFrame();
  177.     void ShowFrame();
  178.     void SizeFrame();
  179. };
  180.  
  181. int ShowVScroll = 1;
  182. int ShowHScroll = 0;
  183. int ShowMenuBar = 1;
  184. int ShowToolBar = 1;
  185. unsigned long HaveGUIDialogs =
  186.     GUIDLG_FILE |
  187.     GUIDLG_CHOICE |
  188.     GUIDLG_FIND |
  189.     GUIDLG_FINDREPLACE |
  190.     GUIDLG_PROMPT;
  191. extern int PMDisableAccel;
  192.  
  193. GFrame *frames = 0;
  194. GUI *gui = 0;
  195.  
  196. GView *MouseCapture = 0;
  197. GView *FocusCapture = 0;
  198.  
  199. static HEV WorkerStarted, StartInterface;
  200.  
  201. HWND CreatePMMainMenu(HWND parent, HWND owner, char *Name);
  202. HWND CreatePMMenu(HWND parent, HWND owner, int menu, int id, int style);
  203. HWND CreateToolBar(HWND parent, HWND owner, int id);
  204.  
  205. MRESULT EXPENTRY FrameWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  206. //MRESULT EXPENTRY SizerWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  207. MRESULT EXPENTRY AVIOWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  208. MRESULT EXPENTRY ObjectWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  209. MRESULT EXPENTRY CreatorWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  210.  
  211. HAB hab = 0;
  212. HAB habW = 0;
  213. static char szClient[] = "EViewer";
  214. static char szObject[] = "EWorker";
  215. static char szCreator[] = "ECreator";
  216. //static char szSizeBar[] = "ESizeBar" // TODO
  217. static ULONG flFrame =
  218.     FCF_TITLEBAR      | FCF_SYSMENU  |
  219.     FCF_SIZEBORDER    | FCF_MAXBUTTON | FCF_HIDEBUTTON |
  220.     FCF_SHELLPOSITION | FCF_TASKLIST |
  221. //    FCF_VERTSCROLL    | FCF_HORZSCROLL |
  222.     FCF_MENU          | FCF_ICON;
  223.  
  224. SWP swp;
  225. HMQ hmq = 0;
  226. HMQ hmqW = 0;
  227. HMTX hmtxPMData = 0;
  228. ULONG cxScreen, cyScreen,
  229.       cyTitleBar, //cyMenuBar,
  230.       cxBorder, cyBorder,
  231.       cxScrollBar, cyScrollBar;
  232. SHORT reportSize = 1;
  233. TEvent EventBuf = { evNone };
  234. HWND hwndCreatorUser, hwndCreatorWorker;
  235. char dragname[CCHMAXPATH];
  236.  
  237. #ifdef OLD_PMMENUTOOLBAR  /* implemented using menus */
  238.  
  239. struct {
  240.     int id;
  241.     HBITMAP handle;
  242.     int cmd;
  243.     int flags;
  244. } tools[] =
  245. {
  246. //    { 101, 0, ExExitEditor, MIS_BITMAP },
  247. //    { 0, 0, 0, MIS_SEPARATOR },
  248.     { 102, 0, ExFileOpen, MIS_BITMAP },
  249.     { 103, 0, ExFileSave, MIS_BITMAP },
  250.     { 104, 0, ExFileClose, MIS_BITMAP },
  251.     { 0, 0, 0, MIS_SEPARATOR },
  252.     { 105, 0, ExFilePrev, MIS_BITMAP },
  253.     { 106, 0, ExFileLast, MIS_BITMAP },
  254.     { 107, 0, ExFileNext, MIS_BITMAP },
  255.     { 0, 0, 0, MIS_SEPARATOR },
  256.     { 108, 0, ExUndo, MIS_BITMAP },
  257.     { 109, 0, ExRedo, MIS_BITMAP },
  258.     { 0, 0, 0, MIS_SEPARATOR },
  259.     { 110, 0, ExBlockCut, MIS_BITMAP },
  260.     { 111, 0, ExBlockCopy, MIS_BITMAP },
  261.     { 112, 0, ExBlockPasteStream, MIS_BITMAP },
  262.     { 113, 0, ExBlockPasteColumn, MIS_BITMAP },
  263.     { 0, 0, 0, MIS_SEPARATOR },
  264.     { 114, 0, ExCompilePrevError, MIS_BITMAP },
  265.     { 115, 0, ExCompileNextError, MIS_BITMAP },
  266.     { 0, 0, 0, MIS_SEPARATOR },
  267.     { 116, 0, ExTagFindWord, MIS_BITMAP },
  268.     { 119, 0, ExTagPop, MIS_BITMAP },
  269.     { 117, 0, ExTagNext, MIS_BITMAP },
  270.     { 118, 0, ExTagPrev, MIS_BITMAP },
  271. };
  272.  
  273. HWND CreateToolBar(HWND parent, HWND owner, int id) {
  274.     HWND menu;
  275.     int i;
  276.     MENUITEM item;
  277.     HPS ps;
  278.     
  279.     menu = WinCreateWindow(parent,
  280.                            WC_MENU, "menu", WS_VISIBLE | MS_ACTIONBAR,
  281.                            0, 0, 0, 0,
  282.                            owner, HWND_TOP, id, 0, 0);
  283.  
  284.     //WinEnableWindowUpdate(hmenu, FALSE);
  285.     
  286.     ps = WinGetPS(menu);
  287.     for (i = 0; i < sizeof(tools)/sizeof(tools[0]); i++) {
  288.         if (tools[i].handle == 0 && (tools[i].flags & MIS_BITMAP)) {
  289.             tools[i].handle = GpiLoadBitmap(ps, NULLHANDLE, tools[i].id, 0, 0);
  290.         }
  291.         memset((void *)&item, 0, sizeof(item));
  292.         item.iPosition = i;
  293.         item.hwndSubMenu = 0;
  294.         item.afStyle = tools[i].flags;
  295.         item.id = tools[i].cmd + 16384 + 8192;
  296.         item.afAttribute = 0;
  297.         item.hItem = tools[i].handle;
  298.         WinSendMsg(menu, MM_INSERTITEM, MPFROMP(&item), MPFROMP(0));
  299.     }
  300.     WinReleasePS(ps);
  301.  
  302.     return menu;
  303. }
  304. #else
  305. #include "pm_tool.h"
  306. #include "pm_tool.cpp"
  307.  
  308. #define CMD(x) ((x) + 16384 + 8192)
  309.  
  310. ToolBarItem tools[] =
  311. {
  312.     //   { tiBITMAP, 101, CMD(ExExitEditor), 0, 0 },
  313.     { tiBITMAP, 102, CMD(ExFileOpen), 0, 0 },
  314.     { tiBITMAP, 103, CMD(ExFileSave), 0, 0 },
  315.     { tiBITMAP, 104, CMD(ExFileClose), 0, 0 },
  316.     { tiSEPARATOR, 0, 0, 0, 0},
  317.     { tiBITMAP, 105, CMD(ExFilePrev), 0, 0 },
  318.     { tiBITMAP, 106, CMD(ExFileLast), 0, 0 },
  319.     { tiBITMAP, 107, CMD(ExFileNext), 0, 0 },
  320.     { tiSEPARATOR, 0, 0, 0, 0},
  321.     { tiBITMAP, 108, CMD(ExUndo), 0, 0 },
  322.     { tiBITMAP, 109, CMD(ExRedo), 0, 0 },
  323.     { tiSEPARATOR, 0, 0, 0, 0},
  324.     { tiBITMAP, 110, CMD(ExBlockCut), 0, 0 },
  325.     { tiBITMAP, 111, CMD(ExBlockCopy), 0, 0 },
  326.     { tiBITMAP, 112, CMD(ExBlockPasteStream), 0, 0 },
  327.     { tiBITMAP, 113, CMD(ExBlockPasteColumn), 0, 0 },
  328.     { tiSEPARATOR, 0, 0, 0, 0},
  329.     { tiBITMAP, 114, CMD(ExCompilePrevError), 0, 0 },
  330.     { tiBITMAP, 115, CMD(ExCompileNextError), 0, 0 },
  331.     { tiSEPARATOR, 0, 0, 0, 0},
  332.     { tiBITMAP, 116, CMD(ExTagFindWord), 0, 0 },
  333.     { tiBITMAP, 119, CMD(ExTagPop), 0, 0 },
  334.     { tiBITMAP, 117, CMD(ExTagNext), 0, 0 },
  335.     { tiBITMAP, 118, CMD(ExTagPrev), 0, 0 },
  336. };
  337.  
  338. HWND CreateToolBar(HWND parent, HWND owner, int id) {
  339.     static int reged = 0;
  340.     HPS hps;
  341.     int i;
  342.  
  343.     if (!reged) {
  344.         RegisterToolBarClass(hab);
  345.         reged = 1;
  346.     }
  347.  
  348.     hps = WinGetPS(parent);
  349.     
  350.     for (i = 0; i < sizeof(tools)/sizeof(tools[0]); i++)
  351.         if (tools[i].hBitmap == 0 && (tools[i].ulType == tiBITMAP))
  352.             tools[i].hBitmap = GpiLoadBitmap(hps, NULLHANDLE, tools[i].ulId, 0, 0);
  353.     
  354.     WinReleasePS(hps);
  355.     
  356.     return CreateToolBar(parent, owner, id,
  357.                          sizeof(tools)/sizeof(tools[0]),
  358.                          tools);
  359. }
  360.  
  361. #endif
  362.  
  363. HWND CreatePMMenu(HWND parent, HWND owner, int menu, int id, int style) {
  364.     HWND hmenu;
  365.     int i;
  366.     MENUITEM item;
  367.     char s[256];
  368.     char *p;
  369.     
  370.     hmenu = WinCreateWindow(parent, 
  371.                             WC_MENU, "menu", style & ~MS_CONDITIONALCASCADE,
  372.                             0, 0, 0, 0, 
  373.                             owner, HWND_TOP, id, 0, 0);
  374.     
  375.     //WinEnableWindowUpdate(hmenu, FALSE);
  376.     
  377.     for (i = 0; i < Menus[menu].Count; i++) {
  378.         memset((void *)&item, 0, sizeof(item));
  379.         item.iPosition = i;
  380.         item.hwndSubMenu = 0;
  381.         if (Menus[menu].Items[i].Name) {
  382.             if (Menus[menu].Items[i].SubMenu != -1) {
  383.                 item.afStyle = MIS_SUBMENU | MIS_TEXT;
  384.                 item.hwndSubMenu = CreatePMMenu(HWND_DESKTOP, owner,
  385.                                                 Menus[menu].Items[i].SubMenu, 0,
  386.                                                 (Menus[menu].Items[i].Cmd == SUBMENU_CONDITIONAL) ? MS_CONDITIONALCASCADE : 0);
  387.                 {
  388.                     static ids = 1000;
  389.                     item.id = ids++;
  390.                     if (ids == 7000) {
  391.                         ids = 1000;
  392.                     }
  393.                 }
  394.             } else {
  395.                 item.afStyle = MIS_TEXT;
  396.                 item.id = (Menus[menu].Items[i].Cmd & 0xFFFF) + 8192; // ?
  397.             }
  398.         } else {
  399.             item.afStyle = MIS_SEPARATOR;
  400.             item.id = 0;
  401.         }
  402.         item.afAttribute = 0;
  403.         item.hItem = 0;
  404.         if (Menus[menu].Items[i].Name) {
  405.             strcpy(s, Menus[menu].Items[i].Name);
  406.             p = strchr(s, '&');
  407.             if (p) 
  408.                 (*p) = '~';
  409.             p = (char *)&s;
  410.         } else {
  411.             p = 0;
  412.         }
  413.         WinSendMsg(hmenu, MM_INSERTITEM, MPFROMP(&item), MPFROMP(p));
  414.         if (i == 0 && style == MS_CONDITIONALCASCADE) {
  415.             WinSetWindowBits(hmenu, QWL_STYLE,
  416.                              MS_CONDITIONALCASCADE, MS_CONDITIONALCASCADE);
  417.             WinSendMsg(hmenu, MM_SETDEFAULTITEMID, MPFROMSHORT(item.id), 0);
  418.         }
  419.     }
  420.     //WinEnableWindowUpdate(hmenu, TRUE);
  421.     return hmenu;
  422. }
  423.  
  424. HWND CreatePMMainMenu(HWND parent, HWND owner, char *Name) {
  425.     int id = GetMenuId(Name);
  426.     HWND main;
  427.  
  428.     assert (id != -1);
  429.  
  430.     main = CreatePMMenu(parent, owner, id, FID_MENU, MS_ACTIONBAR);
  431.     return main;
  432. }
  433.  
  434. #include "pmdlg.h"
  435.  
  436. void InsertHistory(HWND hwnd, int id, int maxlen) {
  437.     int i, count;
  438.     char *str;
  439.     count = CountInputHistory(id);
  440.     
  441.     str = (char *)malloc(maxlen + 1);
  442.     if (str == 0)
  443.         return;
  444.     
  445.     for (i = 0; i < count; i++) {
  446.         if (GetInputHistory(id, str, maxlen, i + 1) == 1)
  447.             WinInsertLboxItem(hwnd, LIT_END, str);
  448.     }
  449.     free(str);
  450. }
  451.  
  452. MRESULT EXPENTRY FileDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  453.     FILEDLG *dlg;
  454.  
  455.     dlg = (FILEDLG *)WinQueryWindowULong(hwnd, QWL_USER);
  456.     
  457.     switch (msg) {
  458.     case WM_INITDLG:
  459.         WinSendMsg(hwnd, WM_SETICON,
  460.                    MPFROMLONG(WinLoadPointer(HWND_DESKTOP, 0, 1)), 0);
  461.         
  462.         InsertHistory(WinWindowFromID(hwnd, DID_FILENAME_ED), HIST_PATH, MAXPATH);
  463.         WinInvalidateRect(hwnd, 0, TRUE);
  464.         WinRestoreWindowPos("FTEPM",
  465.                             (dlg->fl & FDS_SAVEAS_DIALOG) ? "FileSaveDlg" : "FileOpenDlg",
  466.                             hwnd);
  467.         break;
  468.     case WM_COMMAND:
  469.         switch (SHORT1FROMMP(mp1)) {
  470.         case DID_OK:
  471.             WinShowWindow(hwnd, FALSE);
  472.             WinStoreWindowPos("FTEPM",
  473.                               (dlg->fl & FDS_SAVEAS_DIALOG) ? "FileSaveDlg" : "FileOpenDlg",
  474.                               hwnd);
  475.             break;
  476.             
  477.         case DID_CANCEL:
  478.             WinShowWindow(hwnd, FALSE);
  479.             WinStoreWindowPos("FTEPM",
  480.                               (dlg->fl & FDS_SAVEAS_DIALOG) ? "FileSaveDlg" : "FileOpenDlg",
  481.                               hwnd);
  482.             break;
  483.         }
  484.         break;
  485.     case WM_CLOSE:
  486.         WinShowWindow(hwnd, FALSE);
  487.         WinStoreWindowPos("FTEPM",
  488.                           (dlg->fl & FDS_SAVEAS_DIALOG) ? "FileSaveDlg" : "FileOpenDlg",
  489.                           hwnd);
  490.         break;
  491.     }
  492.     return WinDefFileDlgProc(hwnd, msg, mp1, mp2);
  493. }
  494.  
  495. int DLGGetFile(GView *View, char *Prompt, unsigned int BufLen, char *FileName, int Flags) {
  496.     FILEDLG dlg;
  497.     
  498.     memset((void *)&dlg, 0, sizeof(dlg));
  499.     
  500.     dlg.cbSize = sizeof(dlg);
  501.     dlg.fl =
  502.         /*FDS_CENTER |*/ FDS_CUSTOM |
  503.         ((Flags & GF_SAVEAS) ? FDS_SAVEAS_DIALOG : FDS_OPEN_DIALOG);
  504.     dlg.pszTitle = Prompt;
  505.     strcpy(dlg.szFullFile, FileName);
  506.     dlg.hMod = NULLHANDLE;
  507.     dlg.usDlgId = IDD_FILEDLG;
  508.     dlg.pfnDlgProc = FileDlgProc;
  509.  
  510.     if (!LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame,
  511.                                UWM_FILEDIALOG, MPFROMP(&dlg), 0)))
  512.         return 0;
  513.     
  514.     if (dlg.lReturn == DID_OK) {
  515.         strncpy(FileName, dlg.szFullFile, BufLen);
  516.         FileName[BufLen - 1] = 0;
  517.         AddInputHistory(HIST_PATH, FileName);
  518.         return 1;
  519.     }
  520.     return 0;
  521. }
  522.  
  523. typedef struct {
  524.     char *Title;
  525.     int NSel;
  526.     va_list ap;
  527.     int Flags;
  528. } ChoiceInfo;
  529.  
  530. static int DoChoice(HWND hwndFrame, ChoiceInfo *choice) {
  531.     char msg[1024];
  532.     char Prompt[1024];
  533.     char *fmt;
  534.     char *p;
  535.     int rc;
  536.     HWND hwndDlg;
  537.     HWND hwndStatic;
  538.     HWND hwndButton[40];
  539.     int cyBorder, cxBorder;
  540.     SWP swp, swp1;
  541.     int i, x, y;
  542.     ULONG flFrame = FCF_TITLEBAR | FCF_SYSMENU | FCF_DLGBORDER;
  543.     HPS ps;
  544.     int xw, yw, nx, ny;
  545.     RECTL tr;
  546.     int cp, cd;
  547.     char msgbox[100];
  548.     int SPC = 4;
  549.     
  550.     sprintf(msgbox, "MsgBox: %s", choice->Title);
  551.     
  552.     cxBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXDLGFRAME);
  553.     cyBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYDLGFRAME);
  554.     
  555.     hwndDlg = WinCreateStdWindow(HWND_DESKTOP,
  556.                                  WS_VISIBLE,
  557.                                  &flFrame,
  558.                                  0,
  559.                                  choice->Title,
  560.                                  0,
  561.                                  0,
  562.                                  0, 0);
  563.     
  564.     WinSendMsg(hwndDlg, WM_SETICON,
  565.                MPFROMLONG(WinLoadPointer(HWND_DESKTOP, 0, 1)), 0);
  566.     
  567.     WinSetOwner(hwndDlg, hwndFrame);
  568.     
  569.     x = SPC;
  570.     for (i = 0; i < choice->NSel; i++) {
  571.         char button[60];
  572.         strcpy(button, va_arg(choice->ap, char *));
  573.         p = strchr(button, '&');
  574.         if (p)
  575.             *p = '~';
  576.         
  577.         hwndButton[i] =
  578.             WinCreateWindow(hwndDlg,
  579.                             WC_BUTTON,
  580.                             button,
  581.                             WS_VISIBLE | BS_PUSHBUTTON | BS_AUTOSIZE | ((i == 0) ? BS_DEFAULT | WS_TABSTOP | WS_GROUP: 0),
  582.                             cxBorder + x, SPC + cyBorder, 0, 0,
  583.                             hwndDlg, ((i == 0) ? HWND_TOP: hwndButton[i - 1]),
  584.                             200 + i,
  585.                             NULL, NULL);
  586.         
  587.         WinQueryWindowPos(hwndButton[i], &swp);
  588.         x += SPC + swp.cx;
  589.     }
  590.     
  591.     fmt = va_arg(choice->ap, char *);
  592.     vsprintf(msg, fmt, choice->ap);
  593.     strncpy(Prompt, msg, sizeof(Prompt));
  594.     Prompt[sizeof(Prompt) - 1] = 0;
  595.     
  596.     hwndStatic = WinCreateWindow(hwndDlg,
  597.                                  WC_STATIC,
  598.                                  Prompt,
  599.                                  WS_VISIBLE | SS_TEXT | DT_TOP | DT_LEFT | DT_WORDBREAK,
  600.                                  0, 0, 0, 0,
  601.                                  hwndDlg, HWND_TOP,
  602.                                  100,
  603.                                  NULL, NULL);
  604.     
  605.     WinRestoreWindowPos("FTEPM", msgbox, hwndDlg);
  606.     
  607.     xw = cxScreen / 2;
  608.     if (x - SPC > xw)
  609.         xw = x - SPC;
  610.     
  611.     yw = 0;
  612.     ps = WinGetPS(hwndStatic);
  613.     
  614.     cp = 0;
  615.     for (;;) {
  616.         tr.xLeft = 0;
  617.         tr.xRight = xw;
  618.         tr.yTop = cyScreen / 2;
  619.         tr.yBottom = 0;
  620.         
  621.         cd = WinDrawText(ps, -1, Prompt + cp,
  622.                          &tr,
  623.                          0, 0,
  624.                          DT_LEFT | DT_TOP | DT_WORDBREAK | DT_TEXTATTRS |
  625.                          DT_QUERYEXTENT | DT_EXTERNALLEADING);
  626.         if (!cd)
  627.             break;
  628.         cp += cd;
  629.         yw += tr.yTop - tr.yBottom;
  630.     }
  631.     
  632.     WinReleasePS(ps);
  633.     
  634.     WinSetWindowPos(hwndStatic, 0,
  635.                     cxBorder + SPC,
  636.                     cyBorder + SPC + swp.cy + SPC,
  637.                     xw, yw, SWP_MOVE | SWP_SIZE);
  638.     
  639.     WinQueryWindowPos(hwndStatic, &swp1);
  640.     WinQueryWindowPos(hwndButton[0], &swp);
  641.     
  642.     nx = cxBorder + SPC + xw + SPC + cxBorder;
  643.     ny = cyBorder + SPC + swp.cy + SPC + swp1.cy + SPC + cyTitleBar + cyBorder;
  644.     
  645.     WinQueryWindowPos(hwndDlg, &swp);
  646.     
  647.     x = swp.x;
  648.     y = swp.y + swp.cy - ny;
  649.     
  650.     if (y < cyBorder) y = - cyBorder;
  651.     if (y + ny >= cyScreen + cyBorder) y = cyScreen - ny + cyBorder;
  652.     if (x + nx >= cxScreen + cxBorder) x = cxScreen - nx + cxBorder;
  653.     if (x < -cxBorder) x = -cxBorder;
  654.     
  655.     WinSetWindowPos(hwndDlg, 0,
  656.                     x, y,
  657.                     nx, ny,
  658.                     SWP_SIZE | SWP_SHOW | SWP_MOVE | SWP_ACTIVATE);
  659.     
  660.     WinSubclassWindow(hwndDlg, (PFNWP) WinDefDlgProc);
  661.     
  662.     if (choice->Flags & (GPC_ERROR | GPC_FATAL))
  663.         WinAlarm(HWND_DESKTOP, WA_ERROR);
  664.     else if (choice->Flags & (GPC_CONFIRM))
  665.         WinAlarm(HWND_DESKTOP, WA_NOTE);
  666.     else if (choice->Flags & (GPC_WARNING))
  667.         WinAlarm(HWND_DESKTOP, WA_WARNING);
  668.     
  669.     rc = LONGFROMMR(WinSendMsg(hwndFrame, UWM_PROCESSDLG,
  670.                                MPFROMLONG(hwndDlg), 0));
  671.     
  672.     WinStoreWindowPos("FTEPM", msgbox, hwndDlg);
  673.     
  674.     WinSendMsg(hwndFrame, UWM_DESTROYHWND, MPFROMLONG(hwndDlg), 0);
  675.     if (rc == DID_CANCEL || rc == DID_ERROR)
  676.         return choice->NSel - 1;
  677.     
  678.     if (rc >= 200 && rc < choice->NSel + 200)
  679.         return rc - 200;
  680.     
  681.     return 0;
  682. }
  683.  
  684. /* reimplemented most of the WinMessageBox code to get store/restore position to work */
  685. int DLGPickChoice(GView *View, char *ATitle, int NSel, va_list ap, int Flags) {
  686.     ChoiceInfo choice;
  687.  
  688.     choice.Title = ATitle;
  689.     choice.NSel = NSel;
  690.     choice.ap = ap;
  691.     choice.Flags = Flags;
  692.     return LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame, UWM_CHOICE, MPFROMP(&choice), 0));
  693. }
  694.  
  695. static struct {
  696.     char *Title;
  697.     char *Entry;
  698.     int MaxLen;
  699.     int HistId;
  700. } PromptInfo;
  701.  
  702. MRESULT EXPENTRY PromptDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  703.     switch (msg) {
  704.     case WM_INITDLG:
  705.         WinSendMsg(hwnd, WM_SETICON,
  706.                    MPFROMLONG(WinLoadPointer(HWND_DESKTOP, 0, 1)), 0);
  707.         
  708.         WinSendDlgItemMsg(hwnd, IDE_FIELD, EM_SETTEXTLIMIT, MPFROMLONG(PromptInfo.MaxLen), 0);
  709.         WinSetDlgItemText(hwnd, IDE_FIELD, PromptInfo.Entry);
  710.         InsertHistory(WinWindowFromID(hwnd, IDE_FIELD), PromptInfo.HistId, PromptInfo.MaxLen);
  711.         WinSetDlgItemText(hwnd, IDS_PROMPT, PromptInfo.Title);
  712.         WinSetWindowText(hwnd, PromptInfo.Title);
  713.         WinInvalidateRect(hwnd, 0, TRUE);
  714.         WinRestoreWindowPos("FTEPM", "PromptDlg", hwnd);
  715.         return WinDefDlgProc(hwnd, msg, mp1, mp2);
  716.         
  717.     case WM_COMMAND:
  718.         switch (SHORT1FROMMP(mp1)) {
  719.         case DID_OK:
  720.             WinQueryDlgItemText(hwnd, IDE_FIELD, PromptInfo.MaxLen, PromptInfo.Entry);
  721.             PromptInfo.Entry[PromptInfo.MaxLen - 1] = 0;
  722.             AddInputHistory(PromptInfo.HistId, PromptInfo.Entry);
  723.             
  724.             WinShowWindow(hwnd, FALSE);
  725.             WinStoreWindowPos("FTEPM", "PromptDlg", hwnd);
  726.             WinDismissDlg(hwnd, TRUE);
  727.             return (MRESULT)FALSE;
  728.             
  729.         case DID_CANCEL:
  730.             WinShowWindow(hwnd, FALSE);
  731.             WinStoreWindowPos("FTEPM", "PromptDlg", hwnd);
  732.             WinDismissDlg(hwnd, FALSE);
  733.             return (MRESULT)FALSE;
  734.         }
  735.         break;
  736.     case WM_CLOSE:
  737.         WinShowWindow(hwnd, FALSE);
  738.         WinStoreWindowPos("FTEPM", "PromptDlg", hwnd);
  739.         /* passthru */
  740.     default:
  741.         return WinDefDlgProc(hwnd, msg, mp1, mp2);
  742.     }
  743.     return (MRESULT)FALSE;
  744. }
  745.  
  746. int DLGGetStr(GView *View, char *Prompt, unsigned int BufLen, char *Str, int HistId, int Flags) {
  747.     assert(BufLen > 0);
  748.     PromptInfo.MaxLen = BufLen - 1;
  749.     PromptInfo.Title = Prompt;
  750.     PromptInfo.Entry = Str;
  751.     PromptInfo.HistId = HistId;
  752.  
  753.     if (LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame,
  754.                    UWM_DLGBOX, MPFROMP(PFNWP(PromptDlgProc)), MPFROMLONG(IDD_PROMPT))) != DID_OK)
  755.         return 0;
  756.     
  757.     return 1;
  758. }
  759.  
  760. static SearchReplaceOptions SearchOpt;
  761. static int ReplaceDlg = 0;
  762.  
  763. MRESULT EXPENTRY FindDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  764.     switch (msg) {
  765.     case WM_INITDLG:
  766.         WinSendMsg(hwnd, WM_SETICON,
  767.                    MPFROMLONG(WinLoadPointer(HWND_DESKTOP, 0, 1)), 0);
  768.         
  769.         WinSendDlgItemMsg(hwnd, IDE_FIND, EM_SETTEXTLIMIT, MPFROMLONG(MAXSEARCH), 0);
  770.         WinSetDlgItemText(hwnd, IDE_FIND, SearchOpt.strSearch);
  771.         InsertHistory(WinWindowFromID(hwnd, IDE_FIND), HIST_SEARCH, MAXSEARCH);
  772.         WinCheckButton(hwnd, IDC_IGNORECASE, (SearchOpt.Options & SEARCH_NCASE) ? 1 : 0);
  773.         WinCheckButton(hwnd, IDC_REGEXPS, (SearchOpt.Options & SEARCH_RE) ? 1 : 0);
  774.         WinCheckButton(hwnd, IDC_WORDS, (SearchOpt.Options & SEARCH_WORD) ? 1 : 0);
  775.         WinCheckButton(hwnd, IDC_BLOCK, (SearchOpt.Options & SEARCH_BLOCK) ? 1 : 0);
  776.         WinCheckButton(hwnd, IDC_GLOBAL, (SearchOpt.Options & SEARCH_GLOBAL) ? 1 : 0);
  777.         WinCheckButton(hwnd, IDC_REVERSE, (SearchOpt.Options & SEARCH_BACK) ? 1 : 0);
  778.         WinCheckButton(hwnd, IDC_ALLOCCURENCES, (SearchOpt.Options & SEARCH_ALL) ? 1 : 0);
  779.         WinCheckButton(hwnd, IDC_JOINLINE, (SearchOpt.Options & SEARCH_JOIN) ? 1: 0);
  780.         if (ReplaceDlg) {
  781.             WinSendDlgItemMsg(hwnd, IDE_REPLACE, EM_SETTEXTLIMIT, MPFROMLONG(MAXSEARCH), 0);
  782.             WinSetDlgItemText(hwnd, IDE_REPLACE, SearchOpt.strReplace);
  783.             InsertHistory(WinWindowFromID(hwnd, IDE_REPLACE), HIST_SEARCH, MAXSEARCH);
  784.             WinCheckButton(hwnd, IDC_NOPROMPTING, (SearchOpt.Options & SEARCH_NASK) ? 1 : 0);
  785.         } else {
  786.             WinCheckButton(hwnd, IDC_DELETELINE, (SearchOpt.Options & SEARCH_DELETE) ? 1 : 0);
  787.         }
  788.         WinInvalidateRect(hwnd, 0, TRUE);
  789.         WinRestoreWindowPos("FTEPM", ReplaceDlg ? "ReplaceDlg" : "FindDlg", hwnd);
  790.         return WinDefDlgProc(hwnd, msg, mp1, mp2);
  791.         
  792.     case WM_COMMAND:
  793.         switch (SHORT1FROMMP(mp1)) {
  794.         case DID_OK:
  795.             SearchOpt.ok = 1;
  796.             SearchOpt.resCount = 0;
  797.             SearchOpt.Options = 0;
  798.             strcpy(SearchOpt.strReplace, "");
  799.             WinQueryDlgItemText(hwnd, IDE_FIND, MAXSEARCH, SearchOpt.strSearch);
  800.             SearchOpt.strSearch[MAXSEARCH - 1] = 0;
  801.             AddInputHistory(HIST_SEARCH, SearchOpt.strSearch);
  802.             
  803.             if (WinQueryButtonCheckstate(hwnd, IDC_IGNORECASE))
  804.                 SearchOpt.Options |= SEARCH_NCASE;
  805.             if (WinQueryButtonCheckstate(hwnd, IDC_REGEXPS))
  806.                 SearchOpt.Options |= SEARCH_RE;
  807.             if (WinQueryButtonCheckstate(hwnd, IDC_WORDS))
  808.                 SearchOpt.Options |= SEARCH_WORD;
  809.             if (WinQueryButtonCheckstate(hwnd, IDC_BLOCK))
  810.                 SearchOpt.Options |= SEARCH_BLOCK;
  811.             if (WinQueryButtonCheckstate(hwnd, IDC_GLOBAL))
  812.                 SearchOpt.Options |= SEARCH_GLOBAL;
  813.             if (WinQueryButtonCheckstate(hwnd, IDC_REVERSE))
  814.                 SearchOpt.Options |= SEARCH_BACK;
  815.             if (WinQueryButtonCheckstate(hwnd, IDC_ALLOCCURENCES))
  816.                 SearchOpt.Options |= SEARCH_ALL;
  817.             if (WinQueryButtonCheckstate(hwnd, IDC_JOINLINE))
  818.                 SearchOpt.Options |= SEARCH_JOIN;
  819.             
  820.             if (ReplaceDlg) {
  821.                 WinQueryDlgItemText(hwnd, IDE_REPLACE, MAXSEARCH, SearchOpt.strReplace);
  822.                 SearchOpt.strReplace[MAXSEARCH - 1] = 0;
  823.                 AddInputHistory(HIST_SEARCH, SearchOpt.strReplace);
  824.                 SearchOpt.Options |= SEARCH_REPLACE;
  825.                 if (WinQueryButtonCheckstate(hwnd, IDC_NOPROMPTING))
  826.                     SearchOpt.Options |= SEARCH_NASK;
  827.             } else {
  828.                 if (WinQueryButtonCheckstate(hwnd, IDC_DELETELINE))
  829.                     SearchOpt.Options |= SEARCH_DELETE;
  830.             }
  831.             
  832.             WinShowWindow(hwnd, FALSE);
  833.             WinStoreWindowPos("FTEPM", ReplaceDlg ? "ReplaceDlg" : "FindDlg", hwnd);
  834.             WinDismissDlg(hwnd, TRUE);
  835.             return (MRESULT)FALSE;
  836.             
  837.         case DID_CANCEL:
  838.             WinShowWindow(hwnd, FALSE);
  839.             WinStoreWindowPos("FTEPM", ReplaceDlg ? "ReplaceDlg" : "FindDlg", hwnd);
  840.             WinDismissDlg(hwnd, FALSE);
  841.             return (MRESULT)FALSE;
  842.         }
  843.         break;
  844.     case WM_CLOSE:
  845.         WinShowWindow(hwnd, FALSE);
  846.         WinStoreWindowPos("FTEPM", ReplaceDlg ? "ReplaceDlg" : "FindDlg", hwnd);
  847.         /* passthru */
  848.     default:
  849.         return WinDefDlgProc(hwnd, msg, mp1, mp2);
  850.     }
  851.     return (MRESULT)FALSE;
  852. }
  853.  
  854. int DLGGetFind(GView *View, SearchReplaceOptions &sr) {
  855.     SearchOpt = sr;
  856.     ReplaceDlg = 0;
  857.  
  858.     if (LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame, UWM_DLGBOX,
  859.                    PVOIDFROMMP(PFNWP(FindDlgProc)), MPFROMLONG(IDD_FIND))) != DID_OK)
  860.         return 0;
  861.     
  862.     sr = SearchOpt;
  863.     
  864.     return 1;
  865. }
  866.  
  867. int DLGGetFindReplace(GView *View, SearchReplaceOptions &sr) {
  868.     SearchOpt = sr;
  869.     ReplaceDlg = 1;
  870.     
  871.     if (LONGFROMMR(WinSendMsg(View->Parent->Peer->hwndFrame, UWM_DLGBOX,
  872.                    PVOIDFROMMP(PFNWP(FindDlgProc)), MPFROMLONG(IDD_FINDREPLACE))) != DID_OK)
  873.         return 0;
  874.     
  875.     sr = SearchOpt;
  876.     
  877.     return 1;
  878. }
  879.  
  880. struct {
  881.     int vk;
  882.     TKeyCode kc;
  883.     char *name;
  884. } lvirt[] = {
  885. { VK_F1, kbF1, "F1" },
  886. { VK_F2, kbF2, "F2" },
  887. { VK_F3, kbF3, "F3" },
  888. { VK_F4, kbF4, "F4" },
  889. { VK_F5, kbF5, "F5" },
  890. { VK_F6, kbF6, "F6" },
  891. { VK_F7, kbF7, "F7" },
  892. { VK_F8, kbF8, "F8" },
  893. { VK_F9, kbF9, "F9" },
  894. { VK_F10, kbF10, "F10" },
  895. { VK_F11, kbF11, "F11" },
  896. { VK_F12, kbF12, "F12" },
  897.  
  898. { VK_ESC, kbEsc, "Esc" },
  899. { VK_ENTER, kbEnter | kfGray, "Enter" },
  900. { VK_NEWLINE, kbEnter, "Enter" },
  901. { VK_BACKSPACE, kbBackSp, "BackSp" },
  902. { VK_SPACE, kbSpace, "Space" },
  903. { VK_TAB, kbTab, "Tab" },
  904. { VK_BACKTAB, kbTab | kfShift, "Tab" },
  905.  
  906. { VK_UP, kbUp, "Up" },
  907. { VK_DOWN, kbDown, "Down" },
  908. { VK_LEFT, kbLeft, "Left" },
  909. { VK_RIGHT, kbRight, "Right" },
  910. { VK_HOME, kbHome, "Home" },
  911. { VK_END, kbEnd, "End" },
  912. { VK_PAGEDOWN, kbPgDn, "PgDn" },
  913. { VK_PAGEUP, kbPgUp, "PgUp" },
  914. { VK_INSERT, kbIns, "Ins" },
  915. { VK_DELETE, kbDel, "Del" },
  916.  
  917. { VK_CTRL, kbCtrl | kfModifier, "Ctrl" },
  918. { VK_ALT, kbAlt | kfModifier, "Alt" },
  919. { VK_ALTGRAF, kbAlt | kfModifier, "Alt" },
  920. { VK_SHIFT, kbShift | kfModifier, "Shift" },
  921. { VK_CAPSLOCK, kbCapsLock | kfModifier, "CapsLock" },
  922. { VK_NUMLOCK, kbNumLock | kfModifier, "NumLock" },
  923. { VK_SCRLLOCK, kbScrollLock | kfModifier, "ScrollLock" },
  924. { VK_BREAK, kbBreak, "Break" },
  925. { VK_PAUSE, kbPause, "Pause" },
  926. { VK_PRINTSCRN, kbPrtScr, "PrtScr" },
  927. { VK_SYSRQ, kbSysReq, "SysReq", },
  928. };
  929.  
  930. char *ConvertKey(int ch, int virt, int flags, int scan, TEvent &Event) {
  931.     int keyFlags = 0;
  932.     static char name[40];
  933.     char keyname[40];
  934.     TKeyCode keyCode = 0;
  935.     
  936.     strcpy(keyname, "UNKNOWN");
  937.     
  938.     //printf("ch:%d, virt:%d, flags:%d, scan:%d\n", ch, virt, flags, scan);
  939.     
  940.     name[0] = 0;
  941.     
  942.     if (flags & KC_CTRL)
  943.         keyFlags |= kfCtrl;
  944.     if (flags & KC_ALT)
  945.         keyFlags |= kfAlt;
  946.     if (flags & KC_SHIFT)
  947.         keyFlags |= kfShift;
  948.     if ((ch != 0xE0) && ((ch & 0xFF) == 0xE0))
  949.         keyFlags |= kfGray;
  950.     
  951.     if (keyFlags == kfAlt) {// do not produce anything on alt+XXX
  952.         switch (scan) {
  953.         case 71: case 72: case 73:
  954.         case 75: case 76: case 77:
  955.         case 79: case 80: case 81:
  956.         case 82: case 83:
  957.             return name;
  958.         }
  959.     }
  960.     if (ch != 0 && (flags & KC_CHAR)) {
  961.         switch (scan) {
  962.         case 71: case 72: case 73:
  963.         case 75: case 76: case 77:
  964.         case 79: case 80: case 81:
  965.         case 82: case 83:
  966.             virt = 0;
  967.         }
  968.     }
  969.     {
  970.         int i;
  971.  
  972.         for (i = 0; i < (sizeof(lvirt)/sizeof(lvirt[0])); i++)
  973.             if (lvirt[i].vk == virt) {
  974.                 keyCode = lvirt[i].kc;
  975.                 strcpy(keyname, lvirt[i].name);
  976.                 break;
  977.             }
  978.     }
  979.     if (keyCode == 0) {
  980.         char c[2];
  981.         
  982.         c[0] = char(ch);
  983.         c[1] = 0;
  984.         
  985.         if (ch == '+' && scan == 78)
  986.             keyCode = '+' | kfGray;
  987.         else if (ch == '-' && scan == 74)
  988.             keyCode = '-' | kfGray;
  989.         else if (ch == '*' && scan == 55)
  990.             keyCode = '*' | kfGray;
  991.         else if (ch == '/' && scan == 92)
  992.             keyCode = '/' | kfGray;
  993.         else {
  994.             keyCode = ch;
  995.             //if (keyFlags == kfShift)
  996.             //    keyFlags = 0;
  997.         }
  998.         
  999.         keyname[0] = 0;
  1000.         
  1001.         if (keyCode & kfGray)
  1002.             strcpy(keyname, "G+");
  1003.         
  1004.         strcat(keyname, c);
  1005.     }
  1006.     
  1007.     if ((keyFlags & (kfAlt | kfSpecial | kfGray)) == kfAlt) {
  1008.         if (keyCode >= 'a' && keyCode <= 'z')
  1009.             keyCode -= 'a' - 'A';
  1010.     }
  1011.     
  1012.     if ((keyFlags & (kfCtrl | kfAlt | kfSpecial | kfGray)) == kfCtrl) {
  1013.         if (keyCode >= 'a' && keyCode < 'a' + 32)
  1014.             keyCode -= 'a' - 1;
  1015.         else if (keyCode >= 'A' && keyCode < 'A' + 32)
  1016.             keyCode -= 'A' - 1;
  1017.     }
  1018.  
  1019.     if (keyFlags & kfCtrl)
  1020.         if (keyCode < 32)
  1021.             keyCode += 64;
  1022.     
  1023.     keyCode |= keyFlags;
  1024.     
  1025.     if (keyCode & kfKeyUp)
  1026.         strcat(name, "UP ");
  1027.     else
  1028.         strcat(name, "DN ");
  1029.     if (keyCode & kfAlt)
  1030.         strcat(name, "A+");
  1031.     if (keyCode & kfCtrl)
  1032.         strcat(name, "C+");
  1033.     if (keyCode & kfGray)
  1034.         strcat(name, "G+");
  1035.     if (keyCode & kfShift)
  1036.         strcat(name, "S+");
  1037.     strcat(name, keyname);
  1038.     
  1039.     Event.What = evKeyDown;
  1040.     if (flags & KC_KEYUP) {
  1041.         keyFlags |= kfKeyUp;
  1042.         Event.What = evKeyUp;
  1043.     }
  1044.     Event.Key.Code = keyCode;
  1045.     return name;
  1046. }
  1047.  
  1048. MRESULT CreateChild(HWND parent, GViewPeer *peer, PMData *pmData) {
  1049.     PMPTR ptr;
  1050.  
  1051.     ptr.len = sizeof(PMPTR);
  1052.     ptr.p = pmData;
  1053.  
  1054.     peer->hwndView = WinCreateWindow(parent,
  1055.                                      szClient, "FTE",
  1056.                                      WS_VISIBLE, 0, 0, 0, 0,
  1057.                                      NULLHANDLE, HWND_TOP, FID_CLIENT,
  1058.                                      (void *)&ptr, NULL);
  1059.  
  1060.     assert(peer->hwndView != NULLHANDLE);
  1061.     
  1062.     peer->hwndVscroll = WinCreateWindow(parent,
  1063.                                         WC_SCROLLBAR, "",
  1064.                                         WS_VISIBLE | SBS_VERT | SBS_AUTOTRACK, 0, 0, 0, 0,
  1065.                                         peer->hwndView, HWND_TOP, 0,
  1066.                                         (void *)&ptr, NULL);
  1067.  
  1068.     assert(peer->hwndVscroll != NULLHANDLE);
  1069.  
  1070.     peer->hwndHscroll = WinCreateWindow(parent,
  1071.                                         WC_SCROLLBAR, "",
  1072.                                         WS_VISIBLE | SBS_HORZ | SBS_AUTOTRACK, 0, 0, 0, 0,
  1073.                                         peer->hwndView, HWND_TOP, 0,
  1074.                                         (void *)&ptr, NULL);
  1075.  
  1076.     assert(peer->hwndHscroll != NULLHANDLE);
  1077.     
  1078.     return (MRESULT)TRUE;
  1079. }
  1080.  
  1081. BOOL CalcFrameSWP(HWND hwnd, PSWP pswp, BOOL bFrame) {
  1082.     BOOL bSuccess;
  1083.     RECTL rcl;
  1084.     
  1085.     rcl.xLeft = pswp->x;
  1086.     rcl.yBottom = pswp->y;
  1087.     rcl.xRight = pswp->x + pswp->cx;
  1088.     rcl.yTop = pswp->y + pswp->cy;
  1089.     
  1090.     bSuccess = WinCalcFrameRect(hwnd, &rcl, bFrame);
  1091.     
  1092.     pswp->x = rcl.xLeft;
  1093.     pswp->y = rcl.yBottom;
  1094.     pswp->cx = rcl.xRight - rcl.xLeft;
  1095.     pswp->cy = rcl.yTop - rcl.yBottom;
  1096.     
  1097.     return bSuccess;
  1098. }
  1099.  
  1100. MRESULT EXPENTRY FrameWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  1101.     GFramePeer *peer = (GFramePeer *) WinQueryWindowULong(hwnd, QWL_USER);
  1102.     
  1103.     if (peer) switch (msg) {
  1104.     case UWM_DESTROY:
  1105.         WinDestroyWindow(hwnd);
  1106.         return 0;
  1107.     
  1108.     case UWM_DESTROYHWND:
  1109.         WinDestroyWindow(LONGFROMMP(mp1));
  1110.         return 0;
  1111.  
  1112.     case UWM_FILEDIALOG:
  1113.         return MRFROMLONG(WinFileDlg(HWND_DESKTOP, hwnd, (FILEDLG *)PVOIDFROMMP(mp1)));
  1114.  
  1115.     case UWM_DLGBOX:
  1116.         return MRFROMLONG(WinDlgBox(HWND_DESKTOP, hwnd,
  1117.                                     PFNWP(PVOIDFROMMP(mp1)), 0, LONGFROMMP(mp2), NULL));
  1118.  
  1119.     case UWM_PROCESSDLG:
  1120.         return MRFROMLONG(WinProcessDlg(HWNDFROMMP(mp1)));
  1121.  
  1122.     case UWM_CHOICE:
  1123.         return MRFROMLONG(DoChoice(hwnd, (ChoiceInfo *)PVOIDFROMMP(mp1)));
  1124.  
  1125.     case UWM_CREATECHILD:
  1126.         //DosBeep(2500, 1000);
  1127.         return CreateChild(hwnd, (GViewPeer *)PVOIDFROMMP(mp1), (PMData *)PVOIDFROMMP(mp2));
  1128.             
  1129.     case WM_TRANSLATEACCEL:
  1130.         // check for keys not to be translated
  1131.         {
  1132.             QMSG *qmsg = (QMSG *)mp1;
  1133.             USHORT vk = SHORT2FROMMP((qmsg->mp2));
  1134.             USHORT fl = (USHORT)(SHORT1FROMMP((qmsg->mp1)) & (KC_ALT | KC_SHIFT | KC_CTRL | KC_KEYUP));
  1135.             USHORT ch = SHORT1FROMMP((qmsg->mp2));
  1136.  
  1137.             if ((vk == VK_MENU || vk == VK_F1) && fl == 0 ||
  1138.                 vk == VK_NEWLINE && fl == KC_ALT ||
  1139.                 vk == VK_ENTER && fl == KC_ALT ||
  1140.                 vk == VK_SPACE && fl == KC_ALT)
  1141.                 return (MRESULT)FALSE;
  1142.  
  1143.             if ((ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') &&
  1144.                 (fl & KC_ALT))
  1145.                     return (MRESULT)FALSE;
  1146.  
  1147.             if (PMDisableAccel)
  1148.                 if (fl & KC_ALT)
  1149.                     if (vk >= VK_F1 && vk <= VK_F24)
  1150.                         return (MRESULT)FALSE;
  1151.  
  1152.         }
  1153.         break;
  1154.  
  1155.     /*case WM_CALCFRAMERECT:
  1156.         {
  1157.             PRECTL rcl = (PRECTL)PVOIDFROMMP(mp1);
  1158.             USHORT isFrame = SHORT1FROMMP(mp2);
  1159.             BOOL fSuccess = LONGFROMMR(peer->oldFrameProc(hwnd, msg, mp1, mp2));
  1160.  
  1161.             if (ShowToolBar && fSuccess) {
  1162.                 SWP swpToolBar;
  1163.                 HWND hwndToolBar = WinWindowFromID(hwnd, FID_MTOOLBAR);
  1164.  
  1165.                 WinQueryWindowPos(hwndToolBar, &swpToolBar);
  1166.                 WinSendMsg(hwndToolBar,
  1167.                            WM_ADJUSTWINDOWPOS,
  1168.                            MPFROMP(&swpToolBar),
  1169.                            MPARAM(0));
  1170.  
  1171.                 if (isFrame)
  1172.                     rcl->yTop -= swpToolBar.cy;
  1173.                 else
  1174.                     rcl->yTop += swpToolBar.cy;
  1175.             }
  1176.  
  1177.             return MRFROMLONG(fSuccess);
  1178.         }*/
  1179.         
  1180.     case WM_QUERYTRACKINFO:
  1181.         {
  1182.             MRESULT mr;
  1183.             
  1184.             mr = peer->oldFrameProc(hwnd, msg, mp1, mp2);
  1185.             
  1186.             if (mr == (MRESULT)FALSE)
  1187.                 return mr;
  1188.             
  1189.             DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  1190.             if ((SHORT1FROMMP(mp1) & TF_MOVE) != TF_MOVE) {
  1191.                 PTRACKINFO pti;
  1192.                 
  1193.                 pti = (PTRACKINFO) PVOIDFROMMP(mp2);
  1194.                 pti->cxGrid = peer->Frame->Top->Peer->pmData->cxChar;
  1195.                 pti->cyGrid = peer->Frame->Top->Peer->pmData->cyChar;
  1196.                 pti->cxKeyboard = peer->Frame->Top->Peer->pmData->cxChar;
  1197.                 pti->cyKeyboard = peer->Frame->Top->Peer->pmData->cyChar;
  1198.                 pti->fs |= TF_GRID;
  1199.             }
  1200.             DosReleaseMutexSem(hmtxPMData);
  1201.             return mr;
  1202.         }
  1203.  
  1204.     case WM_MINMAXFRAME:
  1205.         {
  1206.             PSWP pswp = (PSWP) PVOIDFROMMP(mp1);
  1207.  
  1208.             if (pswp->fl & SWP_MAXIMIZE) {
  1209.                 GView *v;
  1210.                 int cnt;
  1211.                 SWP swpMenu;
  1212.                 SWP swpToolBar;
  1213.                 HWND hwndMenu = WinWindowFromID(hwnd, FID_MENU);
  1214.                 HWND hwndToolBar = WinWindowFromID(hwnd, FID_MTOOLBAR);
  1215.  
  1216.                 WinQueryWindowPos(hwndMenu, &swpMenu);
  1217.                 swpMenu.x = 0;
  1218.                 swpMenu.y = 0;
  1219.                 swpMenu.cx = cxScreen - 2 * cxBorder;
  1220.                 swpMenu.cy = cyScreen;
  1221.                 WinSendMsg(hwndMenu,
  1222.                            WM_ADJUSTWINDOWPOS,
  1223.                            MPFROMP(&swpMenu),
  1224.                            MPARAM(0));
  1225.  
  1226.                 if (ShowToolBar) {
  1227.                     WinQueryWindowPos(hwndToolBar, &swpToolBar);
  1228.                     swpToolBar.x = 0;
  1229.                     swpToolBar.y = 0;
  1230.                     swpToolBar.cx = cxScreen - 2 * cxBorder;
  1231.                     swpToolBar.cy = cyScreen;
  1232.                     WinSendMsg(hwndToolBar,
  1233.                                WM_ADJUSTWINDOWPOS,
  1234.                                MPFROMP(&swpToolBar),
  1235.                                MPARAM(0));
  1236.                 } else {
  1237.                     swpToolBar.cy = 0;
  1238.                 }
  1239.                 
  1240.                 DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  1241.  
  1242.                 pswp->cx = cxScreen - cxScrollBar;
  1243.                 pswp->cy = cyScreen - cyTitleBar - swpMenu.cy - swpToolBar.cy;
  1244.  
  1245.                 cnt = 0;
  1246.                 v = peer->Frame->Top;
  1247.                 while (v) {
  1248.                     cnt++;
  1249.                     v = v->Prev;
  1250.                     if (v == peer->Frame->Top) break;
  1251.                 }
  1252.             
  1253.                 pswp->cy -= cnt * cyScrollBar;
  1254.                 
  1255.                 if (pswp->cy < 0) pswp->cy = 0;
  1256.                 
  1257.                 if (v) {
  1258.                     pswp->cx /= v->Peer->pmData->cxChar;
  1259.                     if (pswp->cx > MAXXSIZE)
  1260.                         pswp->cx = MAXXSIZE;
  1261.                     pswp->cx *= v->Peer->pmData->cxChar;
  1262.  
  1263.                     pswp->cy /= v->Peer->pmData->cyChar;
  1264.                     if (pswp->cy > MAXYSIZE)
  1265.                         pswp->cy = MAXYSIZE;
  1266.                     pswp->cy *= v->Peer->pmData->cyChar;
  1267.                 }
  1268.                 
  1269.                 pswp->cy += cnt * cyScrollBar;
  1270.  
  1271.                 pswp->cx += cxBorder * 2 + cxScrollBar;
  1272.                 pswp->cy += cyBorder * 2 + cyTitleBar + swpMenu.cy + swpToolBar.cy;
  1273.                 
  1274.                 pswp->y = cyScreen - pswp->cy + cyBorder;
  1275.  
  1276.                 DosReleaseMutexSem(hmtxPMData);
  1277.                 return (MRESULT)FALSE;
  1278.             }
  1279.         }
  1280.         break;
  1281.  
  1282.     case WM_ADJUSTWINDOWPOS:
  1283.         {
  1284.             PSWP pswp = (PSWP) PVOIDFROMMP(mp1);
  1285.             
  1286.             if (pswp->fl & (SWP_SIZE | SWP_MOVE | SWP_MAXIMIZE)) {
  1287.                 GView *v;
  1288.                 int cnt;
  1289.                 SWP swpToolBar;
  1290.  
  1291.                 if (pswp->cx < 0 || pswp->cy <= cyTitleBar + 2 * cyBorder)
  1292.                     break;
  1293.                 
  1294.                 DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  1295.                 //printf("Before 1: %d %d | %d %d\n", pswp->cx, pswp->x, pswp->cy, pswp->y);
  1296.                 CalcFrameSWP(hwnd, pswp, TRUE);
  1297.  
  1298.                 if (ShowToolBar) {
  1299.                     HWND hwndToolBar = WinWindowFromID(hwnd, FID_MTOOLBAR);
  1300.                     
  1301.                     WinQueryWindowPos(hwndToolBar, &swpToolBar);
  1302.                     swpToolBar.x = 0;
  1303.                     swpToolBar.y = 0;
  1304.                     swpToolBar.cx = pswp->cx;
  1305.                     swpToolBar.cy = pswp->cy;
  1306.                     WinSendMsg(hwndToolBar,
  1307.                                WM_ADJUSTWINDOWPOS,
  1308.                                MPFROMP(&swpToolBar),
  1309.                                MPARAM(0));
  1310.                 } else {
  1311.                     swpToolBar.cy = 0;
  1312.                 }
  1313.                 
  1314.                 pswp->cy -= swpToolBar.cy;
  1315.                 
  1316.                 pswp->cx -= cxScrollBar;
  1317.                 
  1318.                 cnt = 0;
  1319.                 v = peer->Frame->Top;
  1320.                 while (v) {
  1321.                     cnt++;
  1322.                     v = v->Prev;
  1323.                     if (v == peer->Frame->Top) break;
  1324.                 }
  1325.                 
  1326.                 pswp->cy -= cnt * cyScrollBar;
  1327.                 //if (pswp->cy < 0) pswp->cy = 0;
  1328.                 
  1329.                 if (v) {
  1330.                     pswp->cx /= v->Peer->pmData->cxChar;
  1331.                     //if (pswp->cx < 8) pswp->cx = 8;
  1332.                     if (pswp->cx > MAXXSIZE)
  1333.                         pswp->cx = MAXXSIZE;
  1334.                     pswp->cx *= v->Peer->pmData->cxChar;
  1335.                     
  1336.                     pswp->cy /= v->Peer->pmData->cyChar;
  1337.                     //if (pswp->cy < cnt * 2) pswp->cy = cnt * 2;
  1338.                     if (pswp->cy > MAXYSIZE)
  1339.                         pswp->cy = MAXYSIZE;
  1340.                     pswp->cy *= v->Peer->pmData->cyChar;
  1341.                 }
  1342.                 
  1343.                 pswp->cy += cnt * cyScrollBar;
  1344.                 
  1345.                 pswp->cx += cxScrollBar;
  1346.                 pswp->cy += swpToolBar.cy;
  1347.                 CalcFrameSWP(hwnd, pswp, FALSE);
  1348.                 DosReleaseMutexSem(hmtxPMData);
  1349.             }
  1350.         }
  1351.         break;
  1352.     
  1353.     case WM_QUERYFRAMECTLCOUNT:
  1354.         {
  1355.             SHORT sCount = SHORT1FROMMR(peer->oldFrameProc(hwnd, msg, mp1, mp2));
  1356.             GView *v;
  1357.             
  1358.             DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  1359.             v = peer->Frame->Top;
  1360.             while (v) {
  1361.                 sCount += (SHORT)3;
  1362.                 v = v->Prev;
  1363.                 if (v == peer->Frame->Top) break;
  1364.             }
  1365.             if (ShowToolBar)
  1366.                 sCount++;
  1367.             DosReleaseMutexSem(hmtxPMData);
  1368.             return MRESULT(sCount - 1);
  1369.         }
  1370.     
  1371.     case WM_FORMATFRAME:
  1372.         {
  1373.             SHORT sCount = SHORT1FROMMR(peer->oldFrameProc(hwnd, msg, mp1, mp2));
  1374.             PSWP pswp;
  1375.             HWND Bhwnd;
  1376.             GView *v;
  1377.             int x, w, h, fl, y;
  1378.             int ctl, cnt;
  1379.             int Hy, H1, yPos;
  1380.             HWND hwndToolBar = WinWindowFromID(hwnd, FID_MTOOLBAR);
  1381.             SWP swpToolBar;
  1382.             PRECTL prcl;
  1383.  
  1384.             pswp = (PSWP) mp1;
  1385.             prcl = (PRECTL) mp2;
  1386.  
  1387.             DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  1388.             sCount--;
  1389.  
  1390.             cnt = 0;
  1391.             v = peer->Frame->Top;
  1392.             while (v) {
  1393.                 cnt++;
  1394.                 v = v->Prev;
  1395.                 if (v == peer->Frame->Top) break;
  1396.             }
  1397.             
  1398.             if (cnt == 0) {
  1399.                 DosReleaseMutexSem(hmtxPMData);
  1400.                 return MRFROMSHORT(sCount);
  1401.             }
  1402.  
  1403.             fl = pswp[sCount].fl;
  1404.             x = pswp[sCount].x;
  1405.             y = pswp[sCount].y;
  1406.             w = pswp[sCount].cx;
  1407.             h = pswp[sCount].cy;
  1408.             Bhwnd = pswp[sCount].hwndInsertBehind;
  1409.  
  1410.             if (ShowToolBar) {
  1411.                 swpToolBar = pswp[sCount];
  1412.                 WinSendMsg(hwndToolBar,
  1413.                            WM_ADJUSTWINDOWPOS,
  1414.                            MPFROMP(&swpToolBar),
  1415.                            MPARAM(0));
  1416.  
  1417.  
  1418.                 pswp[sCount].hwndInsertBehind = Bhwnd;
  1419.                 Bhwnd = pswp[sCount].hwnd = hwndToolBar;
  1420.                 pswp[sCount].fl = fl;
  1421.                 pswp[sCount].x = cxBorder;
  1422.                 pswp[sCount].cx = w;
  1423.  
  1424.                 if (ShowToolBar == 1) {
  1425.                     pswp[sCount].y = y + h - swpToolBar.cy;
  1426.                     pswp[sCount].cy = swpToolBar.cy;
  1427.  
  1428.                     h -= swpToolBar.cy;
  1429.                     if (prcl)
  1430.                         prcl->yTop -= swpToolBar.cy;
  1431.                 } else if (ShowToolBar == 2) {
  1432.                     pswp[sCount].y = y;
  1433.                     pswp[sCount].cy = swpToolBar.cy;
  1434.                     
  1435.                     y += swpToolBar.cy;
  1436.                     h -= swpToolBar.cy;
  1437.                     if (prcl)
  1438.                         prcl->yBottom += swpToolBar.cy;
  1439.                 }
  1440.                 sCount++;
  1441.             }
  1442.             
  1443.             ctl = 0;
  1444.             v = peer->Frame->Top;
  1445.  
  1446.             H1 = (h - cyScrollBar * cnt) / cnt;
  1447.             H1 /= v->Peer->pmData->cyChar;
  1448.             H1 *= v->Peer->pmData->cyChar;
  1449.  
  1450.             yPos = 0;
  1451.  
  1452.             while (v) {
  1453.                 v = v->Prev;
  1454.                 if (ctl == cnt - 1) {
  1455.                     Hy = h - yPos - cyScrollBar;
  1456.                     Hy /= v->Peer->pmData->cyChar;
  1457.                     Hy *= v->Peer->pmData->cyChar;
  1458.                 } else {
  1459.                     Hy = H1;
  1460.                 }
  1461.  
  1462.                 pswp[sCount].fl = fl;
  1463.                 pswp[sCount].hwndInsertBehind = Bhwnd;
  1464.                 Bhwnd = pswp[sCount].hwnd = v->Peer->hwndView;
  1465.                 pswp[sCount].x = x;
  1466.                 pswp[sCount].cx = w - cxScrollBar;
  1467.                 pswp[sCount].y = yPos + y + cyScrollBar;
  1468.                 pswp[sCount].cy = Hy;
  1469.  
  1470.                 sCount++;
  1471.  
  1472.                 pswp[sCount].fl = fl;
  1473.                 pswp[sCount].hwndInsertBehind = Bhwnd;
  1474.                 Bhwnd = pswp[sCount].hwnd = v->Peer->hwndHscroll;
  1475.                 pswp[sCount].x = x;
  1476.                 pswp[sCount].cx = w - cxScrollBar;
  1477.                 pswp[sCount].y = yPos + y;
  1478.                 pswp[sCount].cy = cyScrollBar;
  1479.  
  1480.                 yPos += cyScrollBar;
  1481.  
  1482.                 sCount++;
  1483.  
  1484.                 pswp[sCount].fl = fl;
  1485.                 pswp[sCount].hwndInsertBehind = Bhwnd;
  1486.                 Bhwnd = pswp[sCount].hwnd = v->Peer->hwndVscroll;
  1487.                 pswp[sCount].x = x + w - cxScrollBar;
  1488.                 pswp[sCount].cx = cxScrollBar;
  1489.                 pswp[sCount].y = yPos - cyScrollBar + y;
  1490.                 pswp[sCount].cy = Hy + cyScrollBar;
  1491.  
  1492.                 yPos += Hy;
  1493.  
  1494.                 sCount++;
  1495.  
  1496.                 ctl++;
  1497.                 if (v == peer->Frame->Top) break;
  1498.             }
  1499.             DosReleaseMutexSem(hmtxPMData);
  1500.             return MRFROMSHORT(sCount);
  1501.         }
  1502.     }
  1503.     return peer->oldFrameProc(hwnd, msg, mp1, mp2);
  1504. }
  1505.  
  1506. /*MRESULT EXPENTRY SizerWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  1507.     switch (msg) {
  1508.     case WM_CREATE:
  1509.         break;
  1510.     case WM_DESTROY:
  1511.         break;
  1512.         
  1513.     case WM_BUTTON1DOWN:
  1514.     case WM_BUTTON1UP:
  1515.     case WM_MOUSEMOVE:
  1516.         break;
  1517.  
  1518.     case WM_PAINT:
  1519.         {
  1520.             SWP    swp;
  1521.             HPS    hps;
  1522.             RECTL  rc;
  1523.             POINTL pt;
  1524.  
  1525.  
  1526.             WinQueryWindowPos(hwnd, &swp);
  1527.             hps = WinBeginPaint(hwnd, (HPS)NULL, &rc);
  1528.             GpiSetColor(hps, CLR_GRAY);
  1529.             GpiSetBackColor(hps, CLR_PALEGRAY);
  1530.             if (swp.cy > 2 && swp.cx > 2) {
  1531.                 ptl.x = 1;
  1532.                 ptl.y = 1;
  1533.                 GpiMove(hps, &ptl);
  1534.                 ptl.x += swp.cx - 2;
  1535.                 ptl.y += swp.cy - 2;
  1536.                 GpiBox(hps, DRO_FILL, &ptl, 0, 0);
  1537.             }
  1538.             GpiSetColor(hps, CLR_WHITE);
  1539.             ptl.x = 0;
  1540.             ptl.y = 0;
  1541.             GpiMove(hps, &ptl);
  1542.             ptl.y += swp.cy;
  1543.             GpiLine(hps, &ptl);
  1544.             ptl.x += swp.cx;
  1545.             GpiLine(hps, &ptl);
  1546.             GpiSetColor(hps, CLR_GRAY);
  1547.             ptl.y = 0;
  1548.             GpiLine(hps, &ptl);
  1549.             ptl.x = 0;
  1550.             GpiLine(hps, &ptl);
  1551.  
  1552.             WinEndPaint(hps);
  1553.         }
  1554.         break;
  1555.     }
  1556.     return WinDefWndProc(hwnd, msg, mp1, mp2);
  1557. }
  1558. */
  1559. MRESULT EXPENTRY AVIOWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  1560.     PMPTR *ptr = 0;
  1561.     PMData *pmData = (PMData *)WinQueryWindowULong(hwnd, QWL_USER);
  1562.     BYTE bBlank[2] = " ";
  1563.     SHORT cxClient, cyClient;
  1564.     HDC    hdc;
  1565.     SIZEL  sizl;
  1566.     PDRAGINFO pDragInfo;
  1567.     PDRAGITEM pDragItem;
  1568.     
  1569.     switch (msg) {
  1570.     case WM_CREATE:
  1571.         ptr = (PMPTR *)mp1;
  1572.         pmData = ptr ? (PMData *)ptr->p : 0;
  1573.         assert(pmData != 0);
  1574.         assert(WinSetWindowULong(hwnd, QWL_USER, (ULONG)pmData) == TRUE);
  1575.         
  1576.         hdc = WinOpenWindowDC(hwnd);
  1577.         VioCreatePS(&pmData->hvps, MAXYSIZE, MAXXSIZE, 0, 1, 0);
  1578.         sizl.cx = sizl.cy = 0;
  1579.         pmData->hps = GpiCreatePS(hab, hdc, &sizl,
  1580.                           PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
  1581.         VioAssociate(hdc, pmData->hvps);
  1582.         if (WindowFont[0] != 0) {
  1583.             int x, y;
  1584.  
  1585.             if (sscanf(WindowFont, "%dx%d", &x, &y) == 2)
  1586.                 VioSetDeviceCellSize((SHORT)y, (SHORT)x, pmData->hvps);
  1587.         }
  1588.         VioGetDeviceCellSize(&pmData->cyChar, &pmData->cxChar, pmData->hvps);
  1589.         bBlank[1] = hcPlain_Background;
  1590.         VioScrollUp(0, 0, -1, -1, -1, bBlank, pmData->hvps);
  1591.         return 0;
  1592.  
  1593.     case WM_DESTROY:
  1594.         VioAssociate(NULLHANDLE, pmData->hvps);
  1595.         VioDestroyPS(pmData->hvps);
  1596.         GpiDestroyPS(pmData->hps);
  1597.         pmData->Peer->pmData = 0;
  1598.         return 0;
  1599.     
  1600.     case UWM_DESTROY:
  1601.         {
  1602.             GViewPeer *Peer = pmData->Peer;
  1603.             WinDestroyWindow(Peer->hwndVscroll);
  1604.             WinDestroyWindow(Peer->hwndHscroll);
  1605.             WinDestroyWindow(Peer->hwndView);
  1606.         }
  1607.         return 0;
  1608.         
  1609.     case WM_ERASEBACKGROUND:
  1610.         return (MRESULT) FALSE;
  1611.         
  1612.     case WM_CLOSE:
  1613.         if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) {
  1614.             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1615.                           "WinPostMsg failed, WM_CLOSE", "FTE/PM",
  1616.                           0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
  1617.         }
  1618.         return (MRESULT) FALSE;
  1619.  
  1620.     case WM_SIZE:
  1621.         DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  1622.         {
  1623.             GViewPeer *Peer = pmData->Peer;
  1624.  
  1625.             cxClient = SHORT1FROMMP(mp2);
  1626.             cyClient = SHORT2FROMMP(mp2);
  1627.             WinDefAVioWindowProc(hwnd, (USHORT)msg, (ULONG)mp1, (ULONG)mp2);
  1628.  
  1629.             if (cxClient <= pmData->cxChar || cyClient <= pmData->cyChar || reportSize == 0) {
  1630.                 DosReleaseMutexSem(hmtxPMData);
  1631.                 break;
  1632.             }
  1633.             
  1634.             Peer->wW = cxClient / pmData->cxChar;
  1635.             Peer->wH = cyClient / pmData->cyChar;
  1636.             if (hwnd == WinQueryFocus(HWND_DESKTOP)) {
  1637.                 WinDestroyCursor(hwnd);
  1638.                 WinCreateCursor(hwnd, 
  1639.                                 pmData->cxChar * Peer->cX,
  1640.                                 pmData->cyChar * (Peer->wH - Peer->cY - 1) +
  1641.                                 pmData->cyChar * (100 - Peer->cEnd) / 100,
  1642.                                 pmData->cxChar, pmData->cyChar * (Peer->cEnd - Peer->cStart) / 100,
  1643.                                 CURSOR_TYPE,
  1644.                                 NULL);
  1645.                 WinShowCursor(hwnd, TRUE);
  1646.             }
  1647.             //DosBeep(500, 100);
  1648.             if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) {
  1649.                 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1650.                               "WinPostMsg failed, WM_SIZE", "FTE/PM",
  1651.                               0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
  1652.             }
  1653.         }
  1654.         DosReleaseMutexSem(hmtxPMData);
  1655.         break;
  1656.  
  1657.     case WM_ACTIVATE:
  1658.     case WM_SETSELECTION:
  1659.         if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) {
  1660.             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1661.                           "WinPostMsg failed, WM_SETFOCUS", "FTE/PM",
  1662.                           0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
  1663.         }
  1664.         break;
  1665.     
  1666.     case WM_SETFOCUS:
  1667.         DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  1668.         {
  1669.             GViewPeer *Peer = pmData->Peer;
  1670.             
  1671.             if (SHORT1FROMMP(mp2)) {
  1672.                 WinCreateCursor(hwnd,
  1673.                                 pmData->cxChar * Peer->cX,
  1674.                                 pmData->cyChar * (Peer->wH - Peer->cY - 1) +
  1675.                                 pmData->cyChar * (100 - Peer->cEnd) / 100,
  1676.                                 pmData->cxChar, pmData->cyChar * (Peer->cEnd - Peer->cStart) / 100,
  1677.                                 CURSOR_TYPE,
  1678.                                 NULL);
  1679.                 WinShowCursor(hwnd, TRUE);
  1680.                 Peer->wState |= sfFocus;
  1681.             } else {
  1682.                 WinDestroyCursor(hwnd);
  1683.                 Peer->wState &= ~sfFocus;
  1684.             }
  1685.         }
  1686.         DosReleaseMutexSem(hmtxPMData);
  1687.         if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) {
  1688.             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1689.                           "WinPostMsg failed, WM_SETFOCUS", "FTE/PM",
  1690.                           0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
  1691.         }
  1692.         break;
  1693.         
  1694.     case WM_VSCROLL:
  1695.         if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) {
  1696.             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1697.                           "WinPostMsg failed, WM_VSCROLL", "ftePM",
  1698.                           0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
  1699.         }
  1700.         return 0;
  1701.         
  1702.     case WM_HSCROLL:
  1703.         if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) {
  1704.             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1705.                           "WinPostMsg failed, WM_HSCROLL", "ftePM",
  1706.                           0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
  1707.         }
  1708.         return 0;
  1709.         
  1710.     case WM_COMMAND:
  1711.         if (SHORT1FROMMP(mp1) >= 8192) {
  1712.             if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) {
  1713.                 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1714.                               "WinPostMsg failed, WM_COMMAND", "ftePM",
  1715.                               0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
  1716.             }
  1717.         }
  1718.         break;
  1719.  
  1720.     case WM_CHAR:
  1721.         if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) {
  1722.             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1723.                           "WinPostMsg failed, WM_CHAR", "ftePM",
  1724.                           0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
  1725.         }
  1726.         return (MRESULT) TRUE;
  1727.  
  1728.     case WM_MOUSEMOVE:
  1729.         {
  1730.             long b;
  1731.             b = 0;
  1732.             if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)
  1733.                 b |= 1;
  1734.             if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000)
  1735.                 b |= 2;
  1736.             if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000)
  1737.                 b |= 4;
  1738.             if (b == 0)
  1739.                 break;
  1740.         }
  1741.     case WM_BUTTON1DOWN:
  1742.     case WM_BUTTON1DBLCLK:
  1743.     case WM_BUTTON1UP:
  1744.     case WM_BUTTON2DOWN:
  1745.     case WM_BUTTON2DBLCLK:
  1746.     case WM_BUTTON2UP:
  1747.     case WM_BUTTON3DOWN:
  1748.     case WM_BUTTON3DBLCLK:
  1749.     case WM_BUTTON3UP:
  1750.         if (WinPostMsg(pmData->hwndWorker, msg, mp1, mp2) == FALSE) {
  1751.             WinMessageBox(HWND_DESKTOP, HWND_DESKTOP,
  1752.                           "WinPostMsg failed, WM_MOUSE", "ftePM",
  1753.                           0, MB_OK | MB_ERROR | MB_APPLMODAL | MB_MOVEABLE);
  1754.         }
  1755.         break;
  1756.  
  1757.     case WM_PAINT:
  1758.         DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  1759.         {
  1760.             GViewPeer *Peer = pmData->Peer;
  1761.             
  1762.             WinBeginPaint(hwnd, pmData->hps, NULL);
  1763.             if (Peer->wH > 0 && Peer->wH <= MAXYSIZE &&
  1764.                 Peer->wW > 0 && Peer->wW <= MAXXSIZE)
  1765.                 VioShowBuf(0, (SHORT)(MAXXSIZE * Peer->wH * 2), pmData->hvps);
  1766.             WinEndPaint(pmData->hps);
  1767.         }
  1768.         DosReleaseMutexSem(hmtxPMData);
  1769.         return 0;
  1770.  
  1771.     case DM_DRAGOVER:
  1772.         {
  1773.             char buf[1024] = "";
  1774.             pDragInfo = (PDRAGINFO) mp1;
  1775.             DrgAccessDraginfo( pDragInfo );
  1776.             pDragItem = DrgQueryDragitemPtr( pDragInfo, 0 );
  1777.  
  1778.             // Don't accept multi select and non-file
  1779.             DrgQueryNativeRMF(pDragItem, sizeof(buf), buf);
  1780.  
  1781.             if (pDragInfo->cditem > 1 || strstr(buf, "DRM_OS2FILE") == 0)
  1782.                 return (MRFROM2SHORT((DOR_NEVERDROP), (DO_UNKNOWN)));
  1783.             else
  1784.                 return (MRFROM2SHORT((DOR_DROP), (DO_UNKNOWN)));
  1785.         }
  1786.         
  1787.     case DM_DROP:
  1788.         {
  1789.             pDragInfo = (PDRAGINFO)mp1;
  1790.             DrgAccessDraginfo(pDragInfo);
  1791.             pDragItem = DrgQueryDragitemPtr(pDragInfo, 0);
  1792.  
  1793.             DrgQueryStrName(pDragItem->hstrContainerName,100,dragname);
  1794.             DrgQueryStrName(pDragItem->hstrSourceName,100,dragname+strlen(dragname));
  1795.             WinPostMsg(pmData->hwndWorker, UWM_DROPPEDFILE, 0, 0);
  1796.         }
  1797.         break;
  1798.     }
  1799.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  1800. }
  1801.  
  1802. MRESULT EXPENTRY ObjectWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  1803.     switch (msg) {
  1804.     case WM_CREATE:
  1805.         PMPTR *ptr = (PMPTR *)mp1;
  1806.         GViewPeer *peer = ptr ? (GViewPeer *)ptr->p : 0;
  1807.         assert(WinSetWindowULong(hwnd, QWL_USER, (ULONG)peer) == TRUE);
  1808.         break;
  1809.     }
  1810.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  1811. }
  1812.  
  1813. MRESULT EXPENTRY CreatorWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  1814.     switch (msg) {
  1815.     case UWM_CREATEWORKER:
  1816.         {
  1817.             GViewPeer *peer = (GViewPeer *)mp1;
  1818.             PMData *pmData = (PMData *)mp2;
  1819.             PMPTR ptr;
  1820.  
  1821.             ptr.len = sizeof(ptr);
  1822.             ptr.p = peer;
  1823.  
  1824.             //DosBeep(2500, 1000);
  1825.             
  1826.             peer->hwndWorker = pmData->hwndWorker =
  1827.                 WinCreateWindow(HWND_OBJECT,
  1828.                                 szObject,
  1829.                                 "Worker",
  1830.                                 0,
  1831.                                 0, 0, 0, 0,
  1832.                                 HWND_OBJECT, HWND_TOP,
  1833.                                 0, (void *)&ptr, NULL);
  1834.  
  1835.             assert(peer->hwndWorker != NULLHANDLE);
  1836.             
  1837.             return (MRESULT)TRUE;
  1838.         }
  1839.         
  1840.     case UWM_CREATEFRAME:
  1841.         {
  1842.             GFramePeer *peer = (GFramePeer *)PVOIDFROMMP(mp1);
  1843.             FRAMECDATA fcdata;
  1844.  
  1845.             fcdata.cb = sizeof(FRAMECDATA);
  1846.             fcdata.flCreateFlags = flFrame;
  1847.             fcdata.hmodResources = 0;
  1848.             fcdata.idResources   = 1;
  1849.             
  1850.             //DosBeep(2500, 1000);
  1851.             
  1852.             peer->hwndFrame = WinCreateWindow(HWND_DESKTOP,
  1853.                                               WC_FRAME, NULL, 0, 0, 0, 0, 0,
  1854.                                               hwndCreatorUser, HWND_TOP, 1,
  1855.                                               &fcdata, NULL);
  1856.  
  1857.             assert(peer->hwndFrame != NULLHANDLE);
  1858.  
  1859.             WinSetWindowULong(peer->hwndFrame, QWL_USER, (ULONG)peer);
  1860.             
  1861.             peer->oldFrameProc = WinSubclassWindow(peer->hwndFrame, (PFNWP) FrameWndProc);
  1862.             
  1863.             if (ShowToolBar) {
  1864.                 peer->hwndToolBar = CreateToolBar(peer->hwndFrame, peer->hwndFrame, FID_MTOOLBAR);
  1865.                 assert(peer->hwndToolBar != NULLHANDLE);
  1866.             }
  1867.  
  1868.             
  1869.             return (MRESULT)TRUE;
  1870.         }
  1871.  
  1872.     case UWM_CREATEMAINMENU:
  1873.         {
  1874.             GFramePeer *peer = (GFramePeer *)mp1;
  1875.             char *Menu = (char *)PVOIDFROMMP(mp2);
  1876.             HWND hwnd, hwndMenu;
  1877.             char font[256];
  1878.             ULONG AttrFound = 0;
  1879.             LONG len = -1;
  1880.             
  1881.             hwnd = WinWindowFromID(peer->hwndFrame, FID_MENU);
  1882.             if (hwnd != NULLHANDLE) {
  1883.                 if (len == -1) {
  1884.                     AttrFound = 0;
  1885.                     len = WinQueryPresParam(hwnd, PP_FONTNAMESIZE, PP_FONTHANDLE, &AttrFound, sizeof(font), font, 0);
  1886.                 }
  1887.                 WinDestroyWindow(hwnd);
  1888.             }
  1889.             
  1890.             hwndMenu = CreatePMMainMenu(peer->hwndFrame, peer->hwndFrame, Menu);
  1891.             
  1892.             if (len > 0)
  1893.                 WinSetPresParam(hwndMenu, AttrFound, len, font);
  1894.             WinSendMsg(peer->hwndFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_MENU), 0);
  1895.  
  1896.             return (MRESULT)hwndMenu;
  1897.         }
  1898.  
  1899.     case UWM_CREATEPOPUPMENU:
  1900.         {
  1901.             GFramePeer *peer = (GFramePeer *)mp1;
  1902.             int MenuId = LONGFROMMP(mp2);
  1903.             
  1904.             static HWND hwnd = 0;
  1905.             POINTL ptl;
  1906.             char font[256];
  1907.             ULONG AttrFound = 0;
  1908.             ULONG len;
  1909.             
  1910.             if (hwnd != 0) {
  1911.                 WinDestroyWindow(hwnd);
  1912.                 hwnd = 0;
  1913.             }
  1914.             
  1915.             hwnd = CreatePMMenu(HWND_DESKTOP, peer->hwndFrame, MenuId, 0, 0);
  1916.             
  1917.             WinQueryMsgPos(hab, &ptl);
  1918.             
  1919.             len = WinQueryPresParam(peer->menuBar, PP_FONTNAMESIZE, PP_FONTHANDLE, &AttrFound, sizeof(font), font, 0);
  1920.             if (len > 0)
  1921.                 WinSetPresParam(hwnd, AttrFound, len, font);
  1922.             
  1923.             WinPopupMenu(HWND_DESKTOP, peer->Frame->Active->Peer->hwndView, hwnd,
  1924.                          ptl.x, ptl.y,
  1925.                          0,
  1926.                          PU_HCONSTRAIN  | PU_VCONSTRAIN |
  1927.                          PU_NONE | PU_KEYBOARD |
  1928.                          PU_MOUSEBUTTON1 | PU_MOUSEBUTTON2 | PU_MOUSEBUTTON3);
  1929.  
  1930.             return (MRESULT)TRUE;
  1931.         }
  1932.     }
  1933.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  1934. }
  1935.  
  1936. int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete, GView **view) {
  1937.     QMSG qmsg;
  1938.     GFrame *f;
  1939.     GView *v;
  1940.     
  1941.     if (view) 
  1942.         *view = 0;
  1943.     
  1944.     if (EventBuf.What != evNone) {
  1945.         *Event = EventBuf;
  1946.         if (Delete) EventBuf.What = evNone;
  1947.         return 0;
  1948.     }
  1949.     EventBuf.What = evNone;
  1950.     Event->What = evNone;
  1951.     
  1952.     //DosBeep(800, 10);
  1953.  
  1954.     if (WaitTime != -1) {
  1955.         if (WinPeekMsg(hab, &qmsg, NULLHANDLE, 0, 0, PM_NOREMOVE) == FALSE)
  1956.             return 0;
  1957.     }
  1958.     if (WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0) == FALSE)
  1959.         return -1;
  1960.     
  1961.     //DosBeep(800, 10);
  1962.     
  1963.     f = frames;
  1964.     while (f) {
  1965.         v = f->Top;
  1966.         while (frames && v) {
  1967.             if (v->Peer->hwndWorker == qmsg.hwnd) {
  1968.                 if (FocusCapture && v != FocusCapture) {
  1969.                     WinSetFocus(HWND_DESKTOP, FocusCapture->Peer->hwndView);
  1970.                     frames = f;
  1971.                     break;
  1972.                 }
  1973.                 if (view)
  1974.                     *view = v;
  1975.                 switch (qmsg.msg) {
  1976.                 /*case WM_ACTIVATE:
  1977.                 case WM_SETSELECTION:
  1978.                     if (SHORT1FROMMP(qmsg.mp1) == TRUE) {
  1979.                         if (!v->IsActive())
  1980.                             v->Parent->SelectView(v);
  1981.                         DosBeep(800, 10);
  1982.                         return 0;
  1983.                     }
  1984.                     break;*/
  1985.                 case WM_SETFOCUS:
  1986.                     if (SHORT1FROMMP(qmsg.mp2) == TRUE) {
  1987.                         if (!v->IsActive())
  1988.                             v->Parent->SelectView(v);
  1989.                         //DosBeep(800, 10);
  1990.                         return 0;
  1991.                     }
  1992.                     break;
  1993.                     
  1994.                 case UWM_NOTIFY:
  1995.                     //DosBeep(200, 200);
  1996.                     Event->What = evNotify;
  1997.                     Event->Msg.View = v;
  1998.                     Event->Msg.Model = (EModel *)qmsg.mp1;
  1999.                     Event->Msg.Command = cmPipeRead;
  2000.                     Event->Msg.Param1 = (long)qmsg.mp2;
  2001.                     frames = f;
  2002.                     return 0;
  2003.  
  2004.                 case UWM_DROPPEDFILE:
  2005.                     if (!v->IsActive())
  2006.                         v->Parent->SelectView(v);
  2007.                     Event->What = evCommand;
  2008.                     Event->Msg.View = v;
  2009.                     Event->Msg.Command = cmDroppedFile;
  2010.                     Event->Msg.Param1 = 0;
  2011.                     Event->Msg.Param2 = &dragname;
  2012.                     frames = f;
  2013.                     return 0;
  2014.                     
  2015.                 case WM_SIZE:
  2016.                     frames = f;
  2017.                     //DosBeep(500, 500);
  2018.                     v->Resize(v->Peer->wW, v->Peer->wH);
  2019.                     return 0;
  2020.                     
  2021.                 case WM_VSCROLL:
  2022.                     //DosBeep(200, 2000);
  2023.                     if (!v->IsActive())
  2024.                         v->Parent->SelectView(v);
  2025.                     Event->What = evNone;
  2026.                     Event->Msg.View = v;
  2027.                     Event->Msg.Param1 = 0;
  2028.                     Event->Msg.Param2 = 0;
  2029.                     switch (SHORT2FROMMP(qmsg.mp2)) {
  2030.                     case SB_LINEUP:
  2031.                         Event->What = evCommand;
  2032.                         Event->Msg.Command = cmVScrollUp;
  2033.                         break;
  2034.                         
  2035.                     case SB_LINEDOWN:
  2036.                         Event->What = evCommand;
  2037.                         Event->Msg.Command = cmVScrollDown;
  2038.                         break;
  2039.                         
  2040.                     case SB_PAGEUP:
  2041.                         Event->What = evCommand;
  2042.                         Event->Msg.Command = cmVScrollPgUp;
  2043.                         break;
  2044.                         
  2045.                     case SB_PAGEDOWN:
  2046.                         Event->What = evCommand;
  2047.                         Event->Msg.Command = cmVScrollPgDn;
  2048.                         break;
  2049.                         
  2050.                     case SB_ENDSCROLL:
  2051.                         WinSetFocus(HWND_DESKTOP, v->Parent->Active->Peer->hwndView);
  2052.                         /* no break */
  2053.                     case SB_SLIDERPOSITION:
  2054.                     case SB_SLIDERTRACK:
  2055.                         {
  2056.                             SHORT x = SHORT1FROMMP(qmsg.mp2);
  2057.                             
  2058.                             if (x != 0) {
  2059.                                 Event->What = evCommand;
  2060.                                 Event->Msg.Command = cmVScrollMove;
  2061.                                 if (v->Peer->sbVtotal > 32000)
  2062.                                     Event->Msg.Param1 = (x - 1) * v->Peer->sbVtotal / 32000;
  2063.                                 else
  2064.                                     Event->Msg.Param1 = x - 1;
  2065.                             }
  2066.                         }
  2067.                         break;
  2068.                     }
  2069.                     return 0;
  2070.                     
  2071.                 case WM_HSCROLL:
  2072.                     //DosBeep(800, 2000);
  2073.                     if (!v->IsActive())
  2074.                         v->Parent->SelectView(v);
  2075.                     Event->What = evNone;
  2076.                     Event->Msg.View = v;
  2077.                     Event->Msg.Param1 = 0;
  2078.                     Event->Msg.Param2 = 0;
  2079.                     switch (SHORT2FROMMP(qmsg.mp2)) {
  2080.                     case SB_LINEUP:
  2081.                         Event->What = evCommand;
  2082.                         Event->Msg.Command = cmHScrollLeft;
  2083.                         break;
  2084.                         
  2085.                     case SB_LINEDOWN:
  2086.                         Event->What = evCommand;
  2087.                         Event->Msg.Command = cmHScrollRight;
  2088.                         break;
  2089.                         
  2090.                     case SB_PAGEUP:
  2091.                         Event->What = evCommand;
  2092.                         Event->Msg.Command = cmHScrollPgLt;
  2093.                         break;
  2094.                         
  2095.                     case SB_PAGEDOWN:
  2096.                         Event->What = evCommand;
  2097.                         Event->Msg.Command = cmHScrollPgRt;
  2098.                         break;
  2099.                         
  2100.                     case SB_ENDSCROLL:
  2101.                         WinSetFocus(HWND_DESKTOP, v->Parent->Active->Peer->hwndView);
  2102.                         /* no break */
  2103.                     case SB_SLIDERPOSITION:
  2104.                     case SB_SLIDERTRACK:
  2105.                         {
  2106.                             SHORT x = SHORT1FROMMP(qmsg.mp2);
  2107.                             
  2108.                             if (x != 0) {
  2109.                                 Event->What = evCommand;
  2110.                                 Event->Msg.Command = cmHScrollMove;
  2111.                                 if (v->Peer->sbHtotal > 32000)
  2112.                                     Event->Msg.Param1 = (x - 1) * v->Peer->sbHtotal / 32000;
  2113.                                 else
  2114.                                     Event->Msg.Param1 = x - 1;
  2115.                             }
  2116.                         }
  2117.                         break;
  2118.                     }
  2119.                     return 0;
  2120.                 
  2121.                 case WM_CLOSE:
  2122.                     //DosBeep(500, 1500);
  2123.                     frames = f;
  2124.                     Event->What = evCommand;
  2125.                     Event->Msg.View = v->Parent->Active;
  2126.                     Event->Msg.Command = cmClose;
  2127.                     return 0;
  2128.                     
  2129.                 case WM_COMMAND:
  2130.                     //DosBeep(50, 2500);
  2131.                     if (SHORT1FROMMP(qmsg.mp1) >= 8192) {
  2132.                         Event->What = evCommand;
  2133.                         Event->Msg.View = v->Parent->Active;
  2134.                         Event->Msg.Command = (SHORT1FROMMP(qmsg.mp1) - 8192) + 65536;
  2135.                         frames = f;
  2136.                         return 0;
  2137.                     }
  2138.                     break;
  2139.                     
  2140.                 case WM_CHAR:
  2141.                     //DosBeep(50, 500);
  2142.                     Event->What = evNone;
  2143.                     Event->Msg.View = v;
  2144.                     ConvertKey(SHORT1FROMMP(qmsg.mp2), /* char */
  2145.                                SHORT2FROMMP(qmsg.mp2), /* virtual */
  2146.                                SHORT1FROMMP(qmsg.mp1), /* flags */
  2147.                                CHAR4FROMMP(qmsg.mp1), /* scan */
  2148.                                *Event);
  2149.                     frames = f;
  2150.                     return 0;
  2151.                 
  2152.                 case WM_BUTTON1DOWN:
  2153.                 case WM_BUTTON2DOWN:
  2154.                 case WM_BUTTON3DOWN:
  2155.                 case WM_BUTTON1DBLCLK:
  2156.                 case WM_BUTTON2DBLCLK:
  2157.                 case WM_BUTTON3DBLCLK:
  2158.                     if (!v->IsActive()) 
  2159.                         v->Parent->SelectView(v);
  2160.                 case WM_BUTTON1UP:
  2161.                 case WM_BUTTON2UP:
  2162.                 case WM_BUTTON3UP:
  2163.                 case WM_MOUSEMOVE:
  2164.                     Event->Mouse.What = evNone;
  2165.                     Event->Msg.View = v;
  2166.                     Event->Mouse.X = ((SHORT)SHORT1FROMMP(qmsg.mp1)) / v->Peer->pmData->cxChar;
  2167.                     Event->Mouse.Y = v->Peer->wH - ((SHORT)SHORT2FROMMP(qmsg.mp1)) / v->Peer->pmData->cyChar - 1;
  2168.                     Event->Mouse.Buttons = 1;
  2169.                     Event->Mouse.Count = 1;
  2170.                     Event->Mouse.KeyMask = 0;
  2171.                     if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
  2172.                         Event->Mouse.KeyMask |= kfCtrl;
  2173.                     if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000)
  2174.                         Event->Mouse.KeyMask |= kfAlt;
  2175.                     if (WinGetKeyState(HWND_DESKTOP, VK_SHIFT) & 0x8000)
  2176.                         Event->Mouse.KeyMask |= kfShift;
  2177. //                    printf("KeyFlags: %d\n", Event->Mouse.KeyMask);
  2178.                     //DosBeep(2000, 50);
  2179.                     frames = f;
  2180.                 
  2181.                     switch (qmsg.msg) {
  2182.                     case WM_BUTTON1DOWN:
  2183.                         Event->What = evMouseDown;
  2184.                         v->Peer->OldMouseX = Event->Mouse.X;
  2185.                         v->Peer->OldMouseY = Event->Mouse.Y;
  2186.                         return 0;
  2187.                     
  2188.                     case WM_BUTTON1DBLCLK:
  2189.                         Event->What = evMouseDown;
  2190.                         Event->Mouse.Count = 2;
  2191.                         v->Peer->OldMouseX = Event->Mouse.X;
  2192.                         v->Peer->OldMouseY = Event->Mouse.Y;
  2193.                         return 0;
  2194.                     
  2195.                     case WM_BUTTON1UP:
  2196.                         Event->What = evMouseUp;
  2197.                         v->Peer->OldMouseX = Event->Mouse.X;
  2198.                         v->Peer->OldMouseY = Event->Mouse.Y;
  2199.                         return 0;
  2200.                 
  2201.                     case WM_BUTTON2DOWN:
  2202.                         Event->What = evMouseDown;
  2203.                         Event->Mouse.Buttons = 2;
  2204.                         v->Peer->OldMouseX = Event->Mouse.X;
  2205.                         v->Peer->OldMouseY = Event->Mouse.Y;
  2206.                         return 0;
  2207.                     
  2208.                     case WM_BUTTON2DBLCLK:
  2209.                         Event->What = evMouseDown;
  2210.                         Event->Mouse.Buttons = 2;
  2211.                         Event->Mouse.Count = 2;
  2212.                         v->Peer->OldMouseX = Event->Mouse.X;
  2213.                         v->Peer->OldMouseY = Event->Mouse.Y;
  2214.                         return 0;
  2215.                 
  2216.                     case WM_BUTTON2UP:
  2217.                         Event->What = evMouseUp;
  2218.                         Event->Mouse.Buttons = 2;
  2219.                         v->Peer->OldMouseX = Event->Mouse.X;
  2220.                         v->Peer->OldMouseY = Event->Mouse.Y;
  2221.                         return 0;
  2222.                 
  2223.                     case WM_BUTTON3DOWN:
  2224.                         Event->What = evMouseDown;
  2225.                         Event->Mouse.Buttons = 4;
  2226.                         v->Peer->OldMouseX = Event->Mouse.X;
  2227.                         v->Peer->OldMouseY = Event->Mouse.Y;
  2228.                         return 0;
  2229.                 
  2230.                     case WM_BUTTON3DBLCLK:
  2231.                         Event->What = evMouseDown;
  2232.                         Event->Mouse.Buttons = 4;
  2233.                         Event->Mouse.Count = 2;
  2234.                         v->Peer->OldMouseX = Event->Mouse.X;
  2235.                         v->Peer->OldMouseY = Event->Mouse.Y;
  2236.                         return 0;
  2237.                 
  2238.                     case WM_BUTTON3UP:
  2239.                         Event->What = evMouseUp;
  2240.                         Event->Mouse.Buttons = 4;
  2241.                         v->Peer->OldMouseX = Event->Mouse.X;
  2242.                         v->Peer->OldMouseY = Event->Mouse.Y;
  2243.                         return 0;
  2244.                 
  2245.                     case WM_MOUSEMOVE:
  2246.                         Event->What = evMouseMove;
  2247.                         Event->Mouse.Buttons = 0;
  2248.                         if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) & 0x8000)
  2249.                             Event->Mouse.Buttons |= 1;
  2250.                         if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON2) & 0x8000)
  2251.                             Event->Mouse.Buttons |= 2;
  2252.                         if (WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) & 0x8000)
  2253.                             Event->Mouse.Buttons |= 4;
  2254.                         
  2255.                         if (Event->Mouse.Buttons != 0) {
  2256.                             if (Event->Mouse.X != v->Peer->OldMouseX ||
  2257.                                 Event->Mouse.Y != v->Peer->OldMouseY) 
  2258.                             {
  2259.                                 v->Peer->OldMouseX = Event->Mouse.X;
  2260.                                 v->Peer->OldMouseY = Event->Mouse.Y;
  2261.                                 return 0;
  2262.                             } else  if (Event->Mouse.X >= 0 &&
  2263.                                         Event->Mouse.Y >= 0 &&
  2264.                                         Event->Mouse.X < v->Peer->wW &&
  2265.                                         Event->Mouse.Y < v->Peer->wH)
  2266.                             {
  2267.                                 Event->What = evNone;
  2268.                             }
  2269.                         }
  2270.                     }
  2271.                     break;
  2272.  
  2273.                 default:
  2274.                     WinDispatchMsg(hab, &qmsg);
  2275.                     return 0;
  2276.                 }
  2277.             }
  2278.             v = v->Next;
  2279.             if (v == f->Top) break;
  2280.         }
  2281.         f = f->Next;
  2282.         if (f == frames) break;
  2283.     }
  2284.     WinDispatchMsg(hab, &qmsg);
  2285.     return 0;
  2286. }
  2287.  
  2288. static void WorkThread(void *) {
  2289.     habW = WinInitialize(0);
  2290.     hmqW = WinCreateMsgQueue(hab, 0);
  2291.     
  2292.     hwndCreatorWorker = WinCreateWindow(HWND_OBJECT,
  2293.                                         szCreator,
  2294.                                         "Creator",
  2295.                                         0,
  2296.                                         0, 0, 0, 0,
  2297.                                         HWND_OBJECT, HWND_TOP,
  2298.                                         0, NULL, NULL);
  2299.  
  2300.     assert(hwndCreatorWorker != 0);
  2301.     
  2302.     // work thread started
  2303.     DosPostEventSem(WorkerStarted);
  2304.  
  2305.     ULONG ulPostCount;
  2306.     DosWaitEventSem(StartInterface, SEM_INDEFINITE_WAIT);
  2307.     DosResetEventSem(StartInterface, &ulPostCount);
  2308.         
  2309.     //DosBeep(200, 200);
  2310.     if (gui->Start(gui->fArgc, gui->fArgv) == 0) {
  2311.         gui->doLoop = 1;
  2312.         //DosBeep(500, 500);
  2313.         while (gui->doLoop)
  2314.             gui->ProcessEvent();
  2315.         
  2316.         gui->Stop();
  2317.     }
  2318.     
  2319.     WinDestroyMsgQueue(hmqW);
  2320.     WinTerminate(habW);
  2321.     //DosBeep(500, 500);
  2322.     WinPostQueueMsg(hmq, WM_QUIT, 0, 0);
  2323.     _endthread();
  2324. }
  2325.  
  2326. ///////////////////////////////////////////////////////////////////////////
  2327.  
  2328. GViewPeer::GViewPeer(GView *view, int XSize, int YSize) {
  2329.     HWND parent;
  2330.     
  2331.     View = view;
  2332. //    wX = 0;
  2333. //    wY = 0;
  2334.     wW = XSize;
  2335.     wH = YSize;
  2336.     sbVtotal = 0;
  2337.     sbVstart = 0;
  2338.     sbVamount = 0;
  2339.     sbHtotal = 0;
  2340.     sbHstart = 0;
  2341.     sbHamount = 0;
  2342.     wState = 0;
  2343.     cVisible = 1;
  2344.     cStart = 0; // %
  2345.     cEnd = 100;
  2346.     OldMouseX = OldMouseY = 0xFFFF;
  2347.     
  2348.     pmData = (PMData *)malloc(sizeof(PMData));
  2349.     
  2350.     pmData->Peer = this;
  2351.     pmData->hvps = 0;
  2352.     pmData->cxChar = 8;
  2353.     pmData->cyChar = 14;
  2354.     pmData->hwndWorker = 0;
  2355.         
  2356.     parent = View->Parent->Peer->hwndFrame;
  2357.     
  2358.     WinSendMsg(hwndCreatorWorker, UWM_CREATEWORKER, MPFROMP(this), MPFROMP(pmData));
  2359.     
  2360.     WinSendMsg(parent, UWM_CREATECHILD, MPFROMP(this), MPFROMP(pmData));
  2361. }
  2362.  
  2363. GViewPeer::~GViewPeer() {
  2364.     WinSendMsg(hwndView, UWM_DESTROY, 0, 0);
  2365.     WinDestroyWindow(hwndWorker);
  2366.     free(pmData);
  2367. }
  2368.  
  2369. int GViewPeer::ConPutBox(int X, int Y, int W, int H, PCell Cell) {
  2370.     int I;
  2371.     char *p = (char *) Cell;
  2372.     int Hidden = 0;
  2373.  
  2374.     DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  2375.     if (Y < 0 || Y >= wH || X < 0 || X >= wW ||
  2376.         Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW)
  2377.     {
  2378.         //fprintf(stderr,
  2379.         //       "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n",
  2380.         //        X, Y, W, H, wW, wH);
  2381.         DosReleaseMutexSem(hmtxPMData);
  2382.         return -1;
  2383.     }
  2384.     for (I = 0; I < H; I++) {
  2385.         if (I + Y == cY)
  2386.             Hidden = PMHideCursor();
  2387.         VioWrtCellStr(p, (USHORT)(W << 1), (USHORT)(Y + I), (USHORT)X, pmData->hvps);
  2388.         if (Hidden)
  2389.             PMShowCursor();
  2390.         p += W << 1;
  2391.     }
  2392.     DosReleaseMutexSem(hmtxPMData);
  2393.     return 0;
  2394. }
  2395.  
  2396. int GViewPeer::ConGetBox(int X, int Y, int W, int H, PCell Cell) {
  2397.     int I;
  2398.     USHORT WW = (USHORT)(W << 1);
  2399.     char *p = (char *) Cell;
  2400.     
  2401.     DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  2402.     if (Y < 0 || Y >= wH || X < 0 || X >= wW ||
  2403.         Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW)
  2404.     {
  2405.         //fprintf(stderr,
  2406.         //       "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n",
  2407.         //       X, Y, W, H, wW, wH);
  2408.         DosReleaseMutexSem(hmtxPMData);
  2409.         return -1;
  2410.     }
  2411.     for (I = 0; I < H; I++) {
  2412.         VioReadCellStr((char *)p, &WW, (USHORT)(Y + I), (USHORT)X, pmData->hvps);
  2413.         p += W << 1;
  2414.     }
  2415.     DosReleaseMutexSem(hmtxPMData);
  2416.     return 0;
  2417. }
  2418.  
  2419. int GViewPeer::ConPutLine(int X, int Y, int W, int H, PCell Cell) {
  2420.     int I;
  2421.     char *p = (char *) Cell;
  2422.     int Hidden = 0;
  2423.     
  2424.     DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  2425.     if (Y < 0 || Y >= wH || X < 0 || X >= wW ||
  2426.         Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW)
  2427.     {
  2428.         //fprintf(stderr,
  2429.         //        "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n",
  2430.         //        X, Y, W, H, wW, wH);
  2431.         DosReleaseMutexSem(hmtxPMData);
  2432.         return -1;
  2433.     }
  2434.     for (I = 0; I < H; I++) {
  2435.         if (I + Y == cY)
  2436.             Hidden = PMHideCursor();
  2437.         VioWrtCellStr(p, (USHORT)(W << 1), (USHORT)(Y + I), (USHORT)X, pmData->hvps);
  2438.         if (Hidden)
  2439.             PMShowCursor();
  2440.     }
  2441.     DosReleaseMutexSem(hmtxPMData);
  2442.     return 0;
  2443. }
  2444.  
  2445. int GViewPeer::ConSetBox(int X, int Y, int W, int H, TCell Cell) {
  2446.     int I;
  2447.     char *p = (char *) &Cell;
  2448.     int Hidden = 0;
  2449.     
  2450.     DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  2451.     if (Y < 0 || Y >= wH || X < 0 || X >= wW ||
  2452.         Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW)
  2453.     {
  2454.         //fprintf(stderr,
  2455.         //        "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n",
  2456.         //        X, Y, W, H, wW, wH);
  2457.         DosReleaseMutexSem(hmtxPMData);
  2458.         return -1;
  2459.     }
  2460.     for (I = 0; I < H; I++) {
  2461.         if (I + Y == cY)
  2462.             Hidden = PMHideCursor();
  2463.         VioWrtNCell(p, (USHORT)(W), (USHORT)(Y + I), (USHORT)X, pmData->hvps);
  2464.         if (Hidden)
  2465.             PMShowCursor();
  2466.     }
  2467.     DosReleaseMutexSem(hmtxPMData);
  2468.     return 0;
  2469. }
  2470.  
  2471. int GViewPeer::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) {
  2472.     TCell FillCell = (TCell)(Fill << 8);
  2473.     int Hidden = 0;
  2474.     
  2475.     DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  2476.     if (Y < 0 || Y >= wH || X < 0 || X >= wW ||
  2477.         Y + H < 0 || Y + H > wH || X + W < 0 || X + W > wW)
  2478.     {
  2479.         //fprintf(stderr,
  2480.         //        "X:%d, Y:%d, W:%d, H:%d, wW:%d, wH:%d\n",
  2481.         //        X, Y, W, H, wW, wH);
  2482.         DosReleaseMutexSem(hmtxPMData);
  2483.         return -1;
  2484.     }
  2485.     Hidden = PMHideCursor();
  2486.     switch (Way) {
  2487.     case csUp:
  2488.         VioScrollUp((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, pmData->hvps);
  2489.         break;
  2490.     case csDown:
  2491.         VioScrollDn((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, pmData->hvps);
  2492.         break;
  2493.     case csLeft:
  2494.         VioScrollLf((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, pmData->hvps);
  2495.         break;
  2496.     case csRight:
  2497.         VioScrollRt((USHORT)Y, (USHORT)X, (USHORT)(Y + H - 1), (USHORT)(X + W - 1), (USHORT)Count, (PBYTE)&FillCell, pmData->hvps);
  2498.         break;
  2499.     }
  2500.     if (Hidden)
  2501.         PMShowCursor();
  2502.     DosReleaseMutexSem(hmtxPMData);
  2503.     return 0;
  2504. }
  2505.  
  2506. int GViewPeer::ConSetSize(int X, int Y) {
  2507.     wW = X;
  2508.     wH = Y;
  2509.     return 1;
  2510. }
  2511.  
  2512. int GViewPeer::ConQuerySize(int *X, int *Y) {
  2513.     if (X) *X = wW;
  2514.     if (Y) *Y = wH;
  2515.     return 1;
  2516. }
  2517.  
  2518. int GViewPeer::ConSetCursorPos(int X, int Y) {
  2519.     if (X < 0) X = 0;
  2520.     if (X >= wW) X = wW - 1;
  2521.     if (Y < 0) Y = 0;
  2522.     if (Y >= wH) Y = wH - 1;
  2523.     cX = X;
  2524.     cY = Y;
  2525.     if (wState & sfFocus)
  2526.         return PMSetCursorPos();
  2527.     else
  2528.         return 1;
  2529. }
  2530.  
  2531. int GViewPeer::ConQueryCursorPos(int *X, int *Y) {
  2532.     if (X) *X = cX;
  2533.     if (Y) *Y = cY;
  2534.     return 1;
  2535. }
  2536.  
  2537. int GViewPeer::ConShowCursor() {
  2538.     cVisible = 1;
  2539.     if (wState & sfFocus)
  2540.         return PMShowCursor();
  2541.     else
  2542.         return 1;
  2543. }
  2544.  
  2545. int GViewPeer::ConHideCursor() {
  2546.     cVisible = 0;
  2547.     if (wState & sfFocus)
  2548.         return PMHideCursor();
  2549.     else
  2550.         return 1;
  2551. }
  2552.  
  2553. int GViewPeer::ConCursorVisible() {
  2554.     return cVisible;
  2555. }
  2556.  
  2557. int GViewPeer::ConSetCursorSize(int Start, int End) {
  2558.     cStart = Start;
  2559.     cEnd = End;
  2560.     if (wState & sfFocus)
  2561.         return PMSetCursorPos();
  2562.     else
  2563.         return 1;
  2564. }
  2565.  
  2566. int GViewPeer::ExpandHeight(int DeltaY) {
  2567.     if (View->Parent->Top == View->Next)
  2568.         return -1;
  2569.     if (DeltaY + wH < 3)
  2570.         return -1;
  2571.     if (View->Next->Peer->wH - DeltaY < 3)
  2572.         return -1;
  2573.     ConSetSize(wW, wH + DeltaY);
  2574.     //View->Next->Peer->wY += DeltaY;
  2575.     View->Next->ConSetSize(View->Next->Peer->wW, View->Next->Peer->wH - DeltaY);
  2576.     View->Parent->Peer->SizeFrame();
  2577.     return 0;
  2578. }
  2579.  
  2580. int GViewPeer::QuerySbVPos() {
  2581.     return sbVstart;
  2582. }
  2583.  
  2584. int GViewPeer::SetSbVPos(int Start, int Amount, int Total) {
  2585.     if (sbVstart != Start ||
  2586.         sbVamount != Amount ||
  2587.         sbVtotal != Total)
  2588.     {
  2589.         sbVstart = Start;
  2590.         sbVamount = Amount;
  2591.         sbVtotal = Total;
  2592.         
  2593.         if (View->Parent == 0)
  2594.             return 0;
  2595.         
  2596.         WinEnableWindowUpdate(hwndVscroll, FALSE);
  2597.         if (sbVamount < sbVtotal) {
  2598.             if (sbVtotal > 32000) {
  2599.                 int total = 32000;
  2600.                 int start = total * sbVstart / sbVtotal;
  2601.                 int amount = total * sbVamount / sbVtotal;
  2602.  
  2603.                 WinSendMsg(hwndVscroll, SBM_SETTHUMBSIZE,
  2604.                            (MPFROM2SHORT((amount), (total))), 0);
  2605.                 WinSendMsg(hwndVscroll, SBM_SETSCROLLBAR,
  2606.                            (MPFROMSHORT((start + 1))),
  2607.                            (MPFROM2SHORT((1), (total - amount + 2))));
  2608.             } else {
  2609.                 WinSendMsg(hwndVscroll, SBM_SETTHUMBSIZE,
  2610.                            (MPFROM2SHORT((sbVamount), (sbVtotal))), 0);
  2611.                 WinSendMsg(hwndVscroll, SBM_SETSCROLLBAR,
  2612.                            (MPFROMSHORT((sbVstart + 1))),
  2613.                            (MPFROM2SHORT((1), (sbVtotal - sbVamount + 2))));
  2614.             }
  2615.         } else {
  2616.             WinSendMsg(hwndVscroll, SBM_SETTHUMBSIZE,
  2617.                        MPFROM2SHORT(0, 0), 0);
  2618.             WinSendMsg(hwndVscroll, SBM_SETSCROLLBAR,
  2619.                        MPFROMSHORT(0),
  2620.                        MPFROM2SHORT(0, 0));
  2621.         }
  2622.         WinEnableWindowUpdate(hwndVscroll, TRUE);
  2623.     }
  2624.     return 1;
  2625. }
  2626.  
  2627. int GViewPeer::SetSbHPos(int Start, int Amount, int Total) {
  2628.     if (sbHstart != Start ||
  2629.         sbHamount != Amount ||
  2630.         sbHtotal != Total)
  2631.     {
  2632.         sbHstart = Start;
  2633.         sbHamount = Amount;
  2634.         sbHtotal = Total;
  2635.         
  2636.         if (View->Parent == 0)
  2637.             return 0;
  2638.         
  2639.         WinEnableWindowUpdate(hwndHscroll, FALSE);
  2640.         if (sbHtotal > sbHamount) {
  2641.             if (sbHtotal > 32000) {
  2642.                 int total = 32000;
  2643.                 int start = total * sbVstart / sbVtotal;
  2644.                 int amount = total * sbVamount / sbVtotal;
  2645.  
  2646.                 WinSendMsg(hwndHscroll, SBM_SETTHUMBSIZE,
  2647.                            (MPFROM2SHORT(amount, total)), 0);
  2648.                 WinSendMsg(hwndHscroll, SBM_SETSCROLLBAR,
  2649.                            (MPFROMSHORT(start + 1)),
  2650.                            (MPFROM2SHORT(1, total - amount + 2)));
  2651.             } else {
  2652.                 WinSendMsg(hwndHscroll, SBM_SETTHUMBSIZE,
  2653.                            (MPFROM2SHORT(sbHamount, sbHtotal)), 0);
  2654.                 WinSendMsg(hwndHscroll, SBM_SETSCROLLBAR,
  2655.                            (MPFROMSHORT(sbHstart + 1)),
  2656.                            (MPFROM2SHORT(1, sbHtotal - sbHamount + 2)));
  2657.             }
  2658.         } else {
  2659.             WinSendMsg(hwndHscroll, SBM_SETTHUMBSIZE,
  2660.                        (MPFROM2SHORT(0, 0)), 0);
  2661.             WinSendMsg(hwndHscroll, SBM_SETSCROLLBAR,
  2662.                        (MPFROMSHORT(0)),
  2663.                        (MPFROM2SHORT(0, 0)));
  2664.         }
  2665.         WinEnableWindowUpdate(hwndHscroll, TRUE);
  2666.     }
  2667.     return 1;
  2668. }
  2669.  
  2670. int GViewPeer::UpdateCursor() {
  2671.     ConSetCursorPos(cX, cY);
  2672.     ConSetCursorSize(cStart, cEnd);
  2673.     if (cVisible)
  2674.         ConShowCursor();
  2675.     else
  2676.         ConHideCursor();
  2677.     return 1;
  2678. }
  2679.  
  2680. int GViewPeer::PMShowCursor() {
  2681.     if (wState & sfFocus)
  2682.         WinShowCursor(hwndView, TRUE);
  2683.     return 1;
  2684. }
  2685.  
  2686. int GViewPeer::PMHideCursor() {
  2687.     if (wState & sfFocus)
  2688.         WinShowCursor(hwndView, FALSE);
  2689.     return 1;
  2690. }
  2691.  
  2692. int GViewPeer::PMSetCursorPos() {
  2693.     if (wState & sfFocus) {
  2694.         WinDestroyCursor(hwndView);
  2695.         WinCreateCursor(hwndView,
  2696.                         pmData->cxChar * cX,
  2697.                         pmData->cyChar * (wH - cY - 1) +
  2698.                         pmData->cyChar * (100 - cEnd) / 100,
  2699.                         pmData->cxChar, pmData->cyChar * (cEnd - cStart) / 100,
  2700.                         CURSOR_TYPE,
  2701.                         NULL);
  2702.         WinShowCursor(hwndView, TRUE);
  2703.     }
  2704.     return 1;
  2705. }
  2706.  
  2707. ///////////////////////////////////////////////////////////////////////////
  2708.  
  2709. GView::GView(GFrame *parent, int XSize, int YSize) {
  2710.     Parent = parent;
  2711.     Prev = Next = 0;
  2712.     Peer = new GViewPeer(this, XSize, YSize);
  2713.     if (Parent)
  2714.         Parent->AddView(this);
  2715. }
  2716.  
  2717. GView::~GView() {
  2718.     if (FocusCapture == this)
  2719.         CaptureFocus(0);
  2720.     if (MouseCapture == this)
  2721.         CaptureMouse(0);
  2722.     if (Parent)
  2723.         Parent->RemoveView(this);
  2724.     if (Peer) {
  2725.         Peer->View = 0;
  2726.         delete Peer;
  2727.         Peer = 0;
  2728.     }
  2729. }
  2730.  
  2731. int GView::ConClear() {
  2732.     int W, H;
  2733.     TDrawBuffer B;
  2734.     
  2735.     ConQuerySize(&W, &H);
  2736.     MoveChar(B, 0, W, ' ', 0x07, 1);
  2737.     ConSetBox(0, 0, W, H, B[0]);
  2738.     return 1;
  2739. }
  2740.  
  2741. int GView::ConPutBox(int X, int Y, int W, int H, PCell Cell) {
  2742.     return Peer->ConPutBox(X, Y, W, H, Cell);
  2743. }
  2744.  
  2745. int GView::ConGetBox(int X, int Y, int W, int H, PCell Cell) {
  2746.     return Peer->ConGetBox(X, Y, W, H, Cell);
  2747. }
  2748.  
  2749. int GView::ConPutLine(int X, int Y, int W, int H, PCell Cell) {
  2750.     return Peer->ConPutLine(X, Y, W, H, Cell);
  2751. }
  2752.  
  2753. int GView::ConSetBox(int X, int Y, int W, int H, TCell Cell) {
  2754.     return Peer->ConSetBox(X, Y, W, H, Cell);
  2755. }
  2756.  
  2757. int GView::ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) {
  2758.     return Peer->ConScroll(Way, X, Y, W, H, Fill, Count);
  2759. }
  2760.  
  2761. int GView::ConSetSize(int X, int Y) {
  2762.     if (Peer->ConSetSize(X, Y))
  2763.         Resize(X, Y);
  2764.     else
  2765.         return 0;
  2766.     return 1;
  2767. }
  2768.  
  2769. int GView::ConQuerySize(int *X, int *Y) {
  2770.     return Peer->ConQuerySize(X, Y);
  2771. }
  2772.  
  2773. int GView::ConSetCursorPos(int X, int Y) {
  2774.     return Peer->ConSetCursorPos(X, Y);
  2775. }
  2776.  
  2777. int GView::ConQueryCursorPos(int *X, int *Y) {
  2778.     return Peer->ConQueryCursorPos(X, Y);
  2779. }
  2780.  
  2781. int GView::ConShowCursor() {
  2782.     return Peer->ConShowCursor();
  2783. }
  2784.  
  2785. int GView::ConHideCursor() {
  2786.     return Peer->ConHideCursor();
  2787. }
  2788.  
  2789. int GView::ConCursorVisible() {
  2790.     return Peer->ConCursorVisible(); 
  2791. }
  2792.  
  2793. int GView::ConSetCursorSize(int Start, int End) {
  2794.     return Peer->ConSetCursorSize(Start, End);
  2795. }
  2796.  
  2797. int GView::QuerySbVPos() {
  2798.     return Peer->QuerySbVPos();
  2799. }
  2800.  
  2801. int GView::SetSbVPos(int Start, int Amount, int Total) {
  2802.     return Peer->SetSbVPos(Start, Amount, Total);
  2803. }
  2804.  
  2805. int GView::SetSbHPos(int Start, int Amount, int Total) {
  2806.     return Peer->SetSbHPos(Start, Amount, Total);
  2807. }
  2808.  
  2809. int GView::ExpandHeight(int DeltaY) {
  2810.     return Peer->ExpandHeight(DeltaY);
  2811. }
  2812.  
  2813. void GView::Update() {
  2814. }
  2815.  
  2816. void GView::Repaint() {
  2817. }
  2818.  
  2819. void GView::HandleEvent(TEvent &Event) {
  2820. }
  2821.  
  2822. void GView::Resize(int width, int height) {
  2823.     Repaint();
  2824. }
  2825.  
  2826. void GView::EndExec(int NewResult) {
  2827.     Result = NewResult;
  2828. }
  2829.  
  2830. int GView::Execute() {
  2831.     int SaveRc = Result;
  2832.     int NewResult;
  2833.     int didFocus = 0;
  2834.     
  2835.     if (FocusCapture == 0) {
  2836.         if (CaptureFocus(1) == 0) return -1;
  2837.         didFocus = 1;
  2838.     } else
  2839.         if (FocusCapture != this)
  2840.             return -1;
  2841.     Result = -2;
  2842.     while (Result == -2 && frames != 0)
  2843.         gui->ProcessEvent();
  2844.     NewResult = Result;
  2845.     Result = SaveRc;
  2846.     if (didFocus)
  2847.         CaptureFocus(0);
  2848.     return NewResult;
  2849. }
  2850.  
  2851. int GView::IsActive() {
  2852.     return (Parent->Active == this && Parent == frames);
  2853. }
  2854.  
  2855. void GView::Activate(int gotfocus) {
  2856.     if (gotfocus) {
  2857.         Peer->wState |= sfFocus;
  2858.         Peer->UpdateCursor();
  2859.     } else {
  2860.         Peer->wState &= ~sfFocus;
  2861.     }
  2862.     Repaint();
  2863. }
  2864.  
  2865. int GView::CaptureMouse(int grab) {
  2866.     if (MouseCapture == 0) {
  2867.         if (grab) {
  2868.             MouseCapture = this;
  2869.             WinSetCapture(HWND_DESKTOP, Peer->hwndView);
  2870.         } else
  2871.             return 0;
  2872.     } else {
  2873.         if (grab || MouseCapture != this)
  2874.             return 0;
  2875.         else {
  2876.             MouseCapture = 0;
  2877.             WinSetCapture(HWND_DESKTOP, NULLHANDLE);
  2878.         }
  2879.     }
  2880.     return 1;
  2881. }
  2882.  
  2883. int GView::CaptureFocus(int grab) {
  2884.     if (FocusCapture == 0) {
  2885.         if (grab) {
  2886.             FocusCapture = this;
  2887.             WinSetFocus(HWND_DESKTOP, Peer->hwndView);
  2888.         } else
  2889.             return 0;
  2890.     } else {
  2891.         if (grab || FocusCapture != this)
  2892.             return 0;
  2893.         else
  2894.             FocusCapture = 0;
  2895.     }
  2896.     return 1;
  2897. }
  2898.  
  2899. ///////////////////////////////////////////////////////////////////////////
  2900.  
  2901. GFramePeer::GFramePeer(GFrame *aFrame, int Width, int Height) {
  2902.     Frame = aFrame;
  2903.  
  2904.     WinSendMsg(hwndCreatorUser, UWM_CREATEFRAME, MPFROMP(this), MPFROMLONG(0));
  2905.  
  2906.     if (Width != -1 && Height != -1)
  2907.         ConSetSize(Width, Height);
  2908. }
  2909.  
  2910. GFramePeer::~GFramePeer() {
  2911.     WinStoreWindowPos("FTEPM", "Frame1", hwndFrame);
  2912.     WinSendMsg(hwndFrame, UWM_DESTROY, 0, 0);
  2913. }
  2914.  
  2915. int GFramePeer::ConSetSize(int X, int Y) {
  2916.     //return ::ConSetSize(X, Y);
  2917.     return 0;
  2918. }
  2919.  
  2920. int GFramePeer::ConQuerySize(int *X, int *Y) {
  2921. //    ::ConQuerySize(&fW, &fH);
  2922. //    if (X) *X = fW;
  2923. //    if (Y) *Y = fH;
  2924.     return 1;
  2925. }   
  2926.  
  2927. int GFramePeer::ConSetTitle(char *Title, char *STitle) {
  2928.     WinSetWindowText(hwndFrame, Title);
  2929.     return 1;
  2930. }
  2931.  
  2932. int GFramePeer::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) {
  2933.     WinQueryWindowText(hwndFrame, MaxLen, Title);
  2934.     WinQueryWindowText(hwndFrame, SMaxLen, STitle);
  2935.     return 1;
  2936. }
  2937.  
  2938. void GFramePeer::MapFrame() {
  2939.     if (frames != frames->Next || WinRestoreWindowPos("FTEPM", "Frame1", hwndFrame) == FALSE) {
  2940.         WinQueryTaskSizePos(hab, 0, &swp);
  2941.         
  2942.         WinSetWindowPos(hwndFrame, HWND_TOP,
  2943.                         swp.x,
  2944.                         swp.y,
  2945.                         swp.cx,
  2946.                         swp.cy,
  2947.                         SWP_MOVE | SWP_SIZE);
  2948.     }
  2949.     //    WinSendMsg(Peer->hwndFrame, WM_UPDATEFRAME, 0, 0);
  2950.     SizeFrame();
  2951.     ShowFrame();
  2952. }
  2953.  
  2954. void GFramePeer::ShowFrame() {
  2955.     WinSetWindowPos(hwndFrame, HWND_TOP, 0, 0, 0, 0,
  2956.                     SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE);
  2957. }
  2958.  
  2959. void GFramePeer::SizeFrame() {
  2960.     POINTL ptl;
  2961.     GView *v = Frame->Top;
  2962.     SWP swp;
  2963.     SWP swpMenu;
  2964.     HWND hwndMenu = WinWindowFromID(hwndFrame, FID_MENU);
  2965.     SWP swpToolBar;
  2966.  
  2967.     if (ShowToolBar) {
  2968.         HWND hwndToolBar = WinWindowFromID(hwndFrame, FID_MTOOLBAR);
  2969.  
  2970.         WinQueryWindowPos(hwndToolBar, &swpToolBar);
  2971.         WinSendMsg(hwndToolBar,
  2972.                    WM_ADJUSTWINDOWPOS,
  2973.                    MPFROMP(&swpToolBar),
  2974.                    MPARAM(0));
  2975.     } else {
  2976.         swpToolBar.cy = 0;
  2977.     }
  2978.     
  2979.     WinQueryWindowPos(hwndMenu, &swpMenu);
  2980.     WinSendMsg(hwndMenu,
  2981.                WM_ADJUSTWINDOWPOS,
  2982.                MPFROMP(&swpMenu),
  2983.                MPARAM(0));
  2984.  
  2985.     //WinEnableWindowUpdate(hwndFrame, FALSE);
  2986.     DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  2987.     ptl.x = v->Peer->wW * v->Peer->pmData->cxChar + cxScrollBar + 2 * cxBorder;
  2988.     ptl.y = 2 * cyBorder + cyTitleBar + swpMenu.cy + swpToolBar.cy;
  2989.  
  2990.     while (v) {
  2991.         v = v->Prev;
  2992.         ptl.y += v->Peer->wH * v->Peer->pmData->cyChar + cyScrollBar;
  2993.         if (v == Frame->Top) break;
  2994.     }
  2995.     
  2996.     reportSize = 0;
  2997.     DosReleaseMutexSem(hmtxPMData);
  2998.     WinQueryWindowPos(hwndFrame, &swp);
  2999.     swp.y = swp.y + swp.cy - ptl.y;
  3000.     swp.cx = ptl.x;
  3001.     swp.cy = ptl.y;
  3002.     WinSendMsg(hwndFrame,
  3003.                WM_ADJUSTWINDOWPOS,
  3004.                MPFROMP(&swp),
  3005.                MPARAM(0));
  3006.     WinSetWindowPos(hwndFrame, HWND_TOP, swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE);
  3007.     DosRequestMutexSem(hmtxPMData, SEM_INDEFINITE_WAIT);
  3008.     reportSize = 1;
  3009.     DosReleaseMutexSem(hmtxPMData);
  3010.     swp.x = cxBorder;
  3011.     swp.y = cyBorder;
  3012.     if (ShowToolBar == 2) {
  3013.         swp.y += swpToolBar.cy;
  3014.     }
  3015.     v = Frame->Top;
  3016.     while (v) {
  3017.         v = v->Prev;
  3018.         swp.cx = v->Peer->wW * v->Peer->pmData->cxChar;
  3019.         swp.cy = cyScrollBar;
  3020.         WinSetWindowPos(v->Peer->hwndHscroll, 0,
  3021.                         swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE);
  3022.         swp.y += cyScrollBar;
  3023.         swp.cy = v->Peer->wH * v->Peer->pmData->cyChar;
  3024.         WinSetWindowPos(v->Peer->hwndView, 0,
  3025.                         swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE);
  3026.         swp.x = v->Peer->wW * v->Peer->pmData->cxChar + cxBorder;
  3027.         swp.y -= cyScrollBar;
  3028.         swp.cx = cxScrollBar;
  3029.         swp.cy = cyScrollBar + v->Peer->wH * v->Peer->pmData->cyChar;
  3030.         WinSetWindowPos(v->Peer->hwndVscroll, 0,
  3031.                         swp.x, swp.y, swp.cx, swp.cy, SWP_SIZE | SWP_MOVE);
  3032.         swp.y += cyScrollBar + v->Peer->wH * v->Peer->pmData->cyChar;
  3033.         swp.x = cxBorder;
  3034.         if (v == Frame->Top)
  3035.             break;
  3036.     }
  3037.     //WinEnableWindowUpdate(hwndFrame, TRUE);
  3038. }
  3039.  
  3040. ///////////////////////////////////////////////////////////////////////////
  3041.  
  3042. GFrame::GFrame(int XSize, int YSize) {
  3043.     Menu = 0;
  3044.     if (frames == 0) {
  3045.         frames = Prev = Next = this;
  3046.     } else {
  3047.         Next = frames->Next;
  3048.         Prev = frames;
  3049.         frames->Next->Prev = this;
  3050.         frames->Next = this;
  3051.         frames = this;
  3052.     }
  3053.     Top = Active = 0;
  3054.     Peer = new GFramePeer(this, XSize, YSize);
  3055. }
  3056.  
  3057. GFrame::~GFrame() {
  3058.     GView *P = Top, *Q;
  3059.     if (P) do {
  3060.         Q = P;
  3061.         P = Q->Next;
  3062.         Q->Parent = 0;
  3063.         delete Q;
  3064.     } while (P != Top);
  3065.     
  3066.     Top = Active = 0;
  3067.     if (Peer) {
  3068.         delete Peer;
  3069.         Peer = 0;
  3070.     }
  3071.     if (Next == this) {
  3072.         frames = 0;
  3073.         //DosBeep(500, 500);
  3074. //        printf("No more frames\x7\x7\n");
  3075.     } else {
  3076.         Next->Prev = Prev;
  3077.         Prev->Next = Next;
  3078.         frames = Next;
  3079.         frames->Activate();
  3080.     }
  3081.     Next = Prev = 0;
  3082. }
  3083.  
  3084. int GFrame::ConSetTitle(char *Title, char *STitle) {
  3085.     return Peer->ConSetTitle(Title, STitle);
  3086. }
  3087.  
  3088. int GFrame::ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) {
  3089.     return Peer->ConGetTitle(Title, MaxLen, STitle, SMaxLen);
  3090. }
  3091.  
  3092. int GFrame::ConSetSize(int X, int Y) {
  3093.     return Peer->ConSetSize(X, Y);
  3094. }
  3095.  
  3096. int GFrame::ConQuerySize(int *X, int *Y) {
  3097.     return Peer->ConQuerySize(X, Y);
  3098. }
  3099.  
  3100. int GFrame::ConSplitView(GView *view, GView *newview) {
  3101.     int dmy;
  3102.  
  3103.     newview->Parent = this;
  3104.     view->ConQuerySize(&newview->Peer->wW, &dmy);
  3105.     newview->Peer->wH = view->Peer->wH - view->Peer->wH / 2 - 1;
  3106.     view->Peer->wH /= 2;
  3107.     InsertView(view, newview);
  3108.     view->ConSetSize(view->Peer->wW, view->Peer->wH);
  3109.     newview->ConSetSize(newview->Peer->wW, newview->Peer->wH);
  3110.     Peer->SizeFrame();
  3111.     return 0;
  3112. }
  3113.  
  3114. int GFrame::ConCloseView(GView *view) {
  3115.     return 0;
  3116. }
  3117.  
  3118. int GFrame::ConResizeView(GView *view, int DeltaY) {
  3119.     return 0;
  3120. }
  3121.  
  3122. int GFrame::AddView(GView *view) {
  3123.     if (Active != 0) {
  3124.         return ConSplitView(Active, view);
  3125.     } else {
  3126. //        int W, H;
  3127.         
  3128.         view->Parent = this;
  3129.         view->Prev = view->Next = 0;
  3130.         
  3131. //        view->Peer->wX = 0;
  3132. //        view->Peer->wY = 0;
  3133. //        ConQuerySize(&W, &H);
  3134. //        view->ConSetSize(W, H);
  3135.         InsertView(Top, view);
  3136.         return 0;
  3137.     }
  3138. }
  3139.  
  3140. void GFrame::Update() {
  3141.     GView *v = Active;
  3142.     
  3143.     UpdateMenu();
  3144.     while (v) {
  3145.         v->Update();
  3146.         v = v->Next;
  3147.         if (v == Active) 
  3148.             break;
  3149.     }
  3150. }
  3151.  
  3152. void GFrame::UpdateMenu() {
  3153. }
  3154.  
  3155. void GFrame::Repaint() {
  3156.     GView *v = Active;
  3157.     
  3158.     while (v) {
  3159.         v->Repaint();
  3160.         v = v->Next;
  3161.         if (v == Active) 
  3162.             break;
  3163.     }
  3164. }
  3165.  
  3166. void GFrame::InsertView(GView *Prev, GView *view) {
  3167.     if (!view) return ;
  3168.     if (Prev) {
  3169.         view->Prev = Prev;
  3170.         view->Next = Prev->Next;
  3171.         Prev->Next = view;
  3172.         view->Next->Prev = view;
  3173.     } else {
  3174.         view->Prev = view->Next = view;
  3175.         Top = view;
  3176.     }
  3177.     if (Active == 0) {
  3178.         Active = view;
  3179.         Active->Activate(1);
  3180.     }
  3181. }
  3182.  
  3183. void GFrame::RemoveView(GView *view) {
  3184.     if (!view) return ;
  3185.     
  3186.     if (Active == view)
  3187.         Active->Activate(0);
  3188.     if (view->Next == view) {
  3189.         Top = Active = 0;
  3190.         delete this;
  3191.     } else {
  3192.         view->Next->Prev = view->Prev;
  3193.         view->Prev->Next = view->Next;
  3194.         
  3195.         if (Top == view) {
  3196.             Top = view->Next;
  3197.             Top->ConSetSize(Top->Peer->wW, Top->Peer->wH + view->Peer->wH + 1);
  3198.         } else {
  3199.             view->Prev->ConSetSize(view->Prev->Peer->wW,
  3200.                                    view->Prev->Peer->wH + view->Peer->wH + 1);
  3201.         }
  3202.         
  3203.         if (Active == view) {
  3204.             Active = view->Prev;
  3205.             WinSetFocus(HWND_DESKTOP, Active->Peer->hwndView);
  3206.             Active->Activate(1);
  3207.         }
  3208.     }
  3209.     Peer->SizeFrame();
  3210. }
  3211.  
  3212. void GFrame::SelectNext(int back) {
  3213.     GView *c = Active;
  3214.     
  3215.     if (c == 0 && Top == 0)
  3216.         return;
  3217.     else if (c == 0)
  3218.         c = Active = Top;
  3219.     else
  3220.         if (back) {
  3221.             Active = Active->Prev;
  3222.         } else {
  3223.             Active = Active->Next;
  3224.         }
  3225.     if (c != Active) {
  3226.         c->Activate(0);
  3227.         Active->Activate(1);
  3228.         WinSetFocus(HWND_DESKTOP, Active->Peer->hwndView);
  3229.     }
  3230. }
  3231.  
  3232. int GFrame::SelectView(GView *view) {
  3233.     if (Top == 0)
  3234.         return 0;
  3235.     
  3236.     if (FocusCapture != 0 || MouseCapture != 0)
  3237.         return 0;
  3238.     
  3239.     if (Active)
  3240.         Active->Activate(0);
  3241.     Active = view;
  3242.     if (Active) {
  3243.         Active->Activate(1);
  3244.     }
  3245.     //DosBeep(50, 500);
  3246.     frames = this;
  3247.     return 1;
  3248. }
  3249.  
  3250. void GFrame::Resize(int width, int height) {
  3251.     if (!Top)
  3252.         return;
  3253.     
  3254.     if (width < 8 || height < 2)
  3255.         return;
  3256.     
  3257.     if (Top == Top->Next) {
  3258.         Top->ConSetSize(width, height);
  3259.     } else {
  3260.     }
  3261. }
  3262.  
  3263. int GFrame::SetMenu(char *Name) {
  3264.     //WinAlarm(HWND_DESKTOP, WA_NOTE);
  3265.     if (Menu && Name && strcmp(Name, Menu) == 0)
  3266.         return 1;
  3267.     
  3268.     free(Menu);
  3269.     Menu = strdup(Name);
  3270.  
  3271.     Peer->menuBar = (HWND)WinSendMsg(hwndCreatorUser,
  3272.                                      UWM_CREATEMAINMENU,
  3273.                                      MPFROMP(Peer),
  3274.                                      MPFROMP(Menu));
  3275.  
  3276.     return 1;
  3277. }
  3278.  
  3279. int GFrame::ExecMainMenu(char Sub) {
  3280.     HWND hwnd;
  3281.     
  3282.     hwnd = WinWindowFromID(Peer->hwndFrame, FID_MENU);
  3283.     if (Sub != 0) {
  3284.         int count = LONGFROMMR(WinSendMsg(hwnd, MM_QUERYITEMCOUNT, 0, 0));
  3285.         SHORT id;
  3286.         char buf[256];
  3287.         int len;
  3288.         char srch[3] = "~x";
  3289.  
  3290.         srch[1] = (char)toupper(Sub);
  3291.         
  3292.         //puts("mainmenu");
  3293.         for (SHORT i = 0; i < count; i++) {
  3294.             id = SHORT1FROMMR(WinSendMsg(hwnd, MM_ITEMIDFROMPOSITION, MPFROMSHORT(i), 0));
  3295.             if (id == MIT_ERROR) {
  3296.                 puts("error");
  3297.             } else {
  3298.                 //printf("got %d %d\n", i, id);
  3299.                 len = SHORT1FROMMR(WinSendMsg(hwnd, MM_QUERYITEMTEXT, MPFROM2SHORT((id), (sizeof(buf) - 1)), MPFROMP(buf)));
  3300.                 buf[len] = 0;
  3301.                 //puts(buf);
  3302.                 srch[1] = (char)toupper(Sub);
  3303.                 if (strstr(buf, srch) != 0) {
  3304.                     WinSendMsg(hwnd, MM_SELECTITEM, (MPFROM2SHORT(id, 0)), 0);
  3305.                     //printf("select %d %d\n", i, id);
  3306.                 } else {
  3307.                     srch[1] = (char)tolower(Sub);
  3308.                     if (strstr(buf, srch) != 0) {
  3309.                         WinSendMsg(hwnd, MM_SELECTITEM, (MPFROM2SHORT(id, 0)), 0);
  3310.                         //printf("select %d %d\n", i, id);
  3311.                     }
  3312.                 }
  3313.             }
  3314.         }
  3315.     } else {
  3316.         WinPostMsg(hwnd, MM_STARTMENUMODE, MPFROM2SHORT((Sub ? TRUE : FALSE), FALSE), 0);
  3317.     }
  3318.     return 0;
  3319. }
  3320.  
  3321. int GFrame::PopupMenu(char *Name) {
  3322.     int id = GetMenuId(Name);
  3323.  
  3324.     if (id == -1)
  3325.         return 0;
  3326.             
  3327.  
  3328.     WinSendMsg(hwndCreatorUser,
  3329.                UWM_CREATEPOPUPMENU,
  3330.                MPFROMP(Peer),
  3331.                MPFROMLONG(id));
  3332.     return 0;
  3333. }
  3334.  
  3335. void GFrame::Show() {
  3336.     Update();
  3337.     Peer->MapFrame();
  3338. }
  3339.  
  3340. void GFrame::Activate() {
  3341.     frames = this;
  3342.     Update();
  3343.     Peer->ShowFrame();
  3344. }
  3345.  
  3346. // GUI
  3347.  
  3348. GUI::GUI(int &argc, char **argv, int XSize, int YSize) {
  3349.     fArgc = argc;
  3350.     fArgv = argv;
  3351.     hab = WinInitialize(0);
  3352.     hmq = WinCreateMsgQueue(hab, 0);
  3353.     assert(0 == DosCreateMutexSem(0, &hmtxPMData, 0, 0));
  3354.  
  3355.     cxBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER);
  3356.     cyBorder = WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER);
  3357.     cxScrollBar = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL);
  3358.     cyScrollBar = WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL);
  3359.     cxScreen = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  3360.     cyScreen = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  3361.     cyTitleBar = WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR);
  3362.  
  3363.     // edit window class
  3364.     WinRegisterClass(hab, szClient, (PFNWP)AVIOWndProc, CS_SIZEREDRAW, 4);
  3365.     //WinRegisterClass(hab, szSizer, (PFNWP)SizerWndProc, CS_SIZEREDRAW, 4);
  3366.  
  3367.     // worker object-window class
  3368.     WinRegisterClass(hab, szObject, (PFNWP)ObjectWndProc, 0, 4);
  3369.  
  3370.     // window that created windows in thr 1 for thr 2
  3371.     WinRegisterClass(hab, szCreator, (PFNWP)CreatorWndProc, 0, 0);
  3372.  
  3373.     hwndCreatorUser = WinCreateWindow(HWND_DESKTOP,
  3374.                                       szCreator,
  3375.                                       "FTEPM",
  3376.                                       0,
  3377.                                       0, 0, 0, 0,
  3378.                                       HWND_DESKTOP, HWND_TOP,
  3379.                                       0, NULL, NULL);
  3380.  
  3381.     assert(0 == DosCreateEventSem(0, &WorkerStarted, 0, 0));
  3382.     assert(0 == DosCreateEventSem(0, &StartInterface, 0, 0));
  3383.  
  3384.     _beginthread(WorkThread, FAKE_BEGINTHREAD_NULL PM_STACK_SIZE, 0);
  3385.  
  3386.     ULONG ulPostCount;
  3387.     DosWaitEventSem(WorkerStarted, SEM_INDEFINITE_WAIT);
  3388.     DosResetEventSem(WorkerStarted, &ulPostCount);
  3389.     
  3390.     gui = this;
  3391. }
  3392.  
  3393. GUI::~GUI() {
  3394.     WinDestroyMsgQueue(hmq);
  3395.     WinTerminate(hab);
  3396.     gui = 0;
  3397. }
  3398.  
  3399. int GUI::ConGrabEvents(TEventMask EventMask) {
  3400.     return 0;
  3401. }
  3402.  
  3403. void GUI::DispatchEvent(GFrame *frame, GView *view, TEvent &Event) {
  3404.     if (Event.What != evNone) {
  3405.         if (view)
  3406.             view->HandleEvent(Event);
  3407.     }
  3408. }
  3409.  
  3410. int GUI::ConSuspend(void) { return 0; }
  3411.  
  3412. int GUI::ConContinue(void) { return 0; }
  3413.  
  3414. int GUI::ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete, GView **view) {
  3415.     return ::ConGetEvent(EventMask, Event, WaitTime, Delete, view);
  3416. }
  3417.  
  3418. int GUI::ConPutEvent(TEvent Event) {
  3419.     EventBuf = Event;
  3420.     return 0;
  3421. }
  3422.  
  3423. int GUI::ConFlush(void) {
  3424.     return 0;
  3425. }
  3426.  
  3427. void GUI::ProcessEvent() {
  3428.     TEvent E;
  3429.     GView *v;
  3430.  
  3431.     if (frames == 0)
  3432.         return ;
  3433.  
  3434.     E.What = evNone;
  3435.     if (E.What == evNone) {
  3436.         if (ConGetEvent(evMouseDown | evCommand | evKeyDown, &E, 0, 1, &v) == -1)
  3437.             ;
  3438.     }
  3439.     if (E.What == evNone) {
  3440.         //DosBeep(500, 100);
  3441.         frames->Update();
  3442.         //DosBeep(1000, 100);
  3443.         if (ConGetEvent(evMouseDown | evCommand | evKeyDown, &E, -1, 1, &v) == -1)
  3444.             ;
  3445.     }
  3446.     if (E.What != evNone) {
  3447.         v = E.Msg.View;
  3448.         DispatchEvent(v->Parent, v, E);
  3449.     }
  3450. }
  3451.  
  3452. int GUI::Run() {
  3453.     QMSG qmsg;
  3454.     doLoop = 1;
  3455.     DosPostEventSem(StartInterface);
  3456.     while (doLoop != 0 && WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0))
  3457.         WinDispatchMsg(hab, &qmsg);
  3458.     return 0;
  3459. }
  3460.  
  3461. int GUI::ShowEntryScreen() {
  3462.     return 1;
  3463. }
  3464.  
  3465. int GUI::RunProgram(char *Command) {
  3466.     char FailBuf[256];
  3467.     char *Args;
  3468.     char *Prog;
  3469.     int rc;
  3470.     PID pid;
  3471.     ULONG sid;
  3472.     
  3473.     Prog = getenv("COMSPEC");
  3474.     
  3475.     Args = (char *)malloc(3 + strlen(Command) + 1);
  3476.     if (Args == NULL) {
  3477.         return -1;
  3478.     }
  3479.     
  3480.     if (*Command != 0) {
  3481.         strcpy(Args, "/c ");
  3482.         strcat(Args, Command);
  3483.     } else {
  3484.         Args[0] = 0;
  3485.     }
  3486.     
  3487.     {
  3488.         STARTDATA sd;
  3489.         
  3490.         memset((void *)&sd, 0, sizeof(sd));
  3491.         sd.Length = sizeof(sd);
  3492.         sd.Related = SSF_RELATED_INDEPENDENT;
  3493.         sd.FgBg = SSF_FGBG_FORE;
  3494.         sd.TraceOpt = SSF_TRACEOPT_NONE;
  3495.         sd.PgmTitle = (Command && Command[0] != 0) ? Command : 0;
  3496.         sd.PgmName = Prog;
  3497.         sd.PgmInputs = Args;
  3498.         sd.TermQ = 0;
  3499.         sd.Environment = 0;
  3500.         sd.InheritOpt = SSF_INHERTOPT_PARENT;
  3501.         sd.SessionType = SSF_TYPE_DEFAULT;
  3502.         sd.IconFile = 0;
  3503.         sd.PgmHandle = 0;
  3504.         sd.PgmControl = SSF_CONTROL_VISIBLE;// | ((Command && Command[0] != 0) ? SSF_CONTROL_NOAUTOCLOSE : 0);
  3505.         sd.ObjectBuffer = FailBuf;
  3506.         sd.ObjectBuffLen = sizeof(FailBuf);
  3507.         rc = DosStartSession(&sd, &sid, &pid);
  3508.     }
  3509.     
  3510.     free(Args);
  3511.     
  3512.     return rc;
  3513. }
  3514.  
  3515. static int CreatePipeChild(ULONG *sid, PID *pid, HPIPE &hfPipe, char *Command) {
  3516.     static int PCount = 0;
  3517.     char szPipe[32];
  3518.     char FailBuf[256];
  3519.     char *Args;
  3520.     char *Prog;
  3521. #if 0
  3522.     int arglen = 0;
  3523.     RESULTCODES rc_code;
  3524. #endif
  3525.     ULONG ulAction;
  3526.     //ULONG ulNew;
  3527.     HPIPE hfChildPipe;
  3528.     HFILE hfNewStdOut = -1, hfNewStdErr = -1;
  3529.     HFILE hfStdOut = 1, hfStdErr = 2;
  3530.     int rc;
  3531.     
  3532.     sprintf(szPipe, "\\PIPE\\FTE%d\\CHILD%d", getpid(), PCount);
  3533.     PCount++;
  3534.     
  3535.     rc = DosCreateNPipe(szPipe, &hfPipe,
  3536.                         NP_NOINHERIT | NP_ACCESS_INBOUND,
  3537.                         NP_NOWAIT | NP_TYPE_BYTE | NP_READMODE_BYTE | 1,
  3538.                         0, 4096, 0);
  3539.     if (rc != 0)
  3540.         return -1;
  3541.     
  3542.     rc = DosConnectNPipe (hfPipe);
  3543.     if (rc != 0 && rc != ERROR_PIPE_NOT_CONNECTED) {
  3544.         DosClose(hfPipe);
  3545.         return -1;
  3546.     }
  3547.     
  3548.     rc = DosSetNPHState (hfPipe, NP_WAIT | NP_READMODE_BYTE);
  3549.     if (rc != 0) {
  3550.         DosClose(hfPipe);
  3551.         return -1;
  3552.     }
  3553.     
  3554.     rc = DosOpen (szPipe, &hfChildPipe, &ulAction, 0,
  3555.                   FILE_NORMAL,
  3556.                   OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
  3557.                   OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE,
  3558.                   NULL);
  3559.     if (rc != 0) {
  3560.         DosClose (hfPipe);
  3561.         return -1;
  3562.     }
  3563.     
  3564.     // Duplicate handles
  3565.     DosDupHandle(hfStdOut, &hfNewStdOut);
  3566.     DosDupHandle(hfStdErr, &hfNewStdErr);
  3567.     // Close existing handles for current process
  3568.     DosClose(hfStdOut);
  3569.     DosClose(hfStdErr);
  3570.     // Redirect existing handles to new file
  3571.     DosDupHandle(hfChildPipe, &hfStdOut);
  3572.     DosDupHandle(hfChildPipe, &hfStdErr);
  3573.     // Let started program inherit handles from parent
  3574.     
  3575.     Prog = getenv("COMSPEC");
  3576.     
  3577. #if 0
  3578.     Args = (char *)malloc(strlen(Prog) + 1
  3579.                           + 3 + strlen(Command) + 1
  3580.                           + 1);
  3581.     if (Args == NULL) {
  3582.         DosClose(hfPipe);
  3583.         return -1;
  3584.     }
  3585.     
  3586.     strcpy(Args, Prog);
  3587.     arglen = strlen(Args) + 1;
  3588.     strcpy(Args + arglen, "/c ");
  3589.     arglen += 3;
  3590.     strcpy(Args + arglen, Command);
  3591.     arglen += strlen(Command) + 1;
  3592.     Args[arglen] = '\0';
  3593. #else
  3594.     Args = (char *)malloc(3 + strlen(Command) + 1);
  3595.     if (Args == NULL) {
  3596.         DosClose(hfPipe);
  3597.         return -1;
  3598.     }
  3599.     
  3600.     strcpy(Args, "/c ");
  3601.     strcat(Args, Command);
  3602. #endif
  3603.     
  3604.     
  3605. #if 0
  3606.     rc = DosExecPgm(FailBuf, sizeof(FailBuf),
  3607.                     EXEC_ASYNCRESULT, // | EXEC_BACKGROUND,
  3608.                     Args,
  3609.                     0,
  3610.                     &rc_code,
  3611.                     Prog);
  3612. #else
  3613.     {
  3614.         STARTDATA sd;
  3615.  
  3616.         memset((void *)&sd, 0, sizeof(sd));
  3617.         sd.Length = sizeof(sd);
  3618.         sd.Related = SSF_RELATED_INDEPENDENT;
  3619.         sd.FgBg = SSF_FGBG_BACK;
  3620.         sd.TraceOpt = SSF_TRACEOPT_NONE;
  3621.         sd.PgmTitle = 0;
  3622.         sd.PgmName = Prog;
  3623.         sd.PgmInputs = Args;
  3624.         sd.TermQ = 0;
  3625.         sd.Environment = 0;
  3626.         sd.InheritOpt = SSF_INHERTOPT_PARENT;
  3627.         sd.SessionType = SSF_TYPE_DEFAULT;
  3628.         sd.IconFile = 0;
  3629.         sd.PgmHandle = 0;
  3630.         sd.PgmControl = SSF_CONTROL_INVISIBLE;
  3631.         sd.ObjectBuffer = FailBuf;
  3632.         sd.ObjectBuffLen = sizeof(FailBuf);
  3633.         rc = DosStartSession(&sd, sid, pid);
  3634.     }
  3635. #endif
  3636.     
  3637.     free(Args);
  3638.     
  3639.     // Get back original handles
  3640.     DosDupHandle(hfNewStdOut, &hfStdOut);
  3641.     DosDupHandle(hfNewStdErr, &hfStdErr);
  3642.     // Close the duplicated handles - no longer needed
  3643.     DosClose(hfNewStdOut);
  3644.     DosClose(hfNewStdErr);
  3645.     
  3646.     DosClose(hfChildPipe); // pipe one way, close out write end
  3647.     
  3648.     if (rc != 0) {
  3649.         DosClose(hfPipe);
  3650.         return -1;
  3651.     }
  3652.     
  3653. #if 0
  3654.     pid = rc_code.codeTerminate; // get pid when successful
  3655.     sid = 0;
  3656. #endif
  3657.     
  3658.     return 0;
  3659. }
  3660.  
  3661. static void _LNK_CONV PipeThread(void *p) {
  3662.     GPipe *pipe = (GPipe *)p;
  3663.     HAB hab;
  3664.     ULONG ulPostCount;
  3665.     ULONG used;
  3666.     PID pid;
  3667.     ULONG sid;
  3668.     HPIPE hfPipe;
  3669. #if 0
  3670.     RESULTCODES rc_code;
  3671. #endif
  3672.     int rc;
  3673.     
  3674.     hab = WinInitialize(0);
  3675.     
  3676.     rc = CreatePipeChild(&sid, &pid, hfPipe, pipe->Command);
  3677.     
  3678.     if (rc != 0) {
  3679.         DosRequestMutexSem(pipe->Access, SEM_INDEFINITE_WAIT);
  3680.         pipe->reading = 0;
  3681.         if (pipe->notify)
  3682.             WinPostMsg(frames->Active->Peer->hwndWorker, UWM_NOTIFY, MPFROMLONG(pipe->notify), MPFROMLONG(pipe->id));
  3683.         DosReleaseMutexSem(pipe->Access);
  3684.         WinTerminate(hab);
  3685.         return;
  3686.     }
  3687. //    fprintf(stderr, "Pipe: Begin: %d\n", pipe->id);
  3688.     while (1) {
  3689.         rc = DosRead(hfPipe, pipe->buffer, pipe->buflen, &used);
  3690.         if (rc < 0)
  3691.             used = 0;
  3692.  
  3693.         DosRequestMutexSem(pipe->Access, SEM_INDEFINITE_WAIT);
  3694.         pipe->bufused = used;
  3695. //        fprintf(stderr, "Pipe: fread: %d %d\n", pipe->id, pipe->bufused);
  3696.         DosResetEventSem(pipe->ResumeRead, &ulPostCount);
  3697.         if (pipe->bufused == 0)
  3698.             break;
  3699.         if (pipe->notify && pipe->stopped) {
  3700.             WinPostMsg(frames->Active->Peer->hwndWorker, UWM_NOTIFY, MPFROMLONG(pipe->notify), MPFROMLONG(pipe->id));
  3701.             pipe->stopped = 0;
  3702.         }
  3703.         DosReleaseMutexSem(pipe->Access);
  3704.         if (pipe->DoTerm)
  3705.             break;
  3706.         DosWaitEventSem(pipe->ResumeRead, SEM_INDEFINITE_WAIT);
  3707.         if (pipe->DoTerm)
  3708.             break;
  3709.     }
  3710. //    fprintf(stderr, "Pipe: pClose: %d\n", pipe->id);
  3711.     DosClose(hfPipe);
  3712.     //fprintf(stderr, "Pipe: pClose: %d\n", pipe->id);
  3713. #if 0
  3714.     rc = DosWaitChild(DCWA_PROCESS, DCWW_WAIT,
  3715.                       &rc_code,
  3716.                       &pid,
  3717.                       pid);
  3718.     pipe->RetCode = rc_code.codeResult;
  3719. #else
  3720.     //DosStopSession(STOP_SESSION_SPECIFIED, sid);
  3721.     pipe->RetCode = 0;
  3722. #endif
  3723.     pipe->reading = 0;
  3724.     if (pipe->notify)
  3725.         WinPostMsg(frames->Active->Peer->hwndWorker, UWM_NOTIFY, MPFROMLONG(pipe->notify), MPFROMLONG(pipe->id));
  3726.     DosReleaseMutexSem(pipe->Access);
  3727.     WinTerminate(hab);
  3728. }
  3729.  
  3730. int GUI::OpenPipe(char *Command, EModel *notify) {
  3731.     int i;
  3732.     
  3733.     for (i = 0; i < MAX_PIPES; i++) {
  3734.         if (Pipes[i].used == 0) {
  3735.             Pipes[i].reading = 1;
  3736.             Pipes[i].stopped = 1;
  3737.             Pipes[i].id = i;
  3738.             Pipes[i].bufused = 0;
  3739.             Pipes[i].bufpos = 0;
  3740.             Pipes[i].buflen = PIPE_BUFLEN;
  3741.             Pipes[i].Command = strdup(Command);
  3742.             Pipes[i].notify = notify;
  3743.             Pipes[i].DoTerm = 0;
  3744.             if ((Pipes[i].buffer = (char *)malloc(PIPE_BUFLEN)) == 0)
  3745.                 return -1;
  3746.             
  3747.             if (0 != DosCreateMutexSem(0, &Pipes[i].Access, 0, 0)) {
  3748.                 free(Pipes[i].Command);
  3749.                 free(Pipes[i].buffer);
  3750.                 return -1;
  3751.             }
  3752.             
  3753.             if (0 != DosCreateEventSem(0, &Pipes[i].ResumeRead, 0, 0)) {
  3754.                 free(Pipes[i].Command);
  3755.                 free(Pipes[i].buffer);
  3756.                 DosCloseMutexSem(Pipes[i].Access);
  3757.                 return -1;
  3758.             }
  3759.             
  3760.             Pipes[i].tid = _beginthread(PipeThread,
  3761.                                         FAKE_BEGINTHREAD_NULL
  3762.                                         16384, &Pipes[i]);
  3763.  
  3764.             Pipes[i].used = 1;
  3765. //            fprintf(stderr, "Pipe Open: %d\n", i);
  3766.             return i;
  3767.         }
  3768.     }
  3769.     return -1;
  3770. }
  3771.  
  3772. int GUI::SetPipeView(int id, EModel *notify) {
  3773.     if (id < 0 || id > MAX_PIPES)
  3774.         return -1;
  3775.     if (Pipes[id].used == 0)
  3776.         return -1;
  3777.     DosRequestMutexSem(Pipes[id].Access, SEM_INDEFINITE_WAIT);
  3778. //    fprintf(stderr, "Pipe View: %d %08X\n", id, notify);
  3779.     Pipes[id].notify = notify;
  3780.     DosReleaseMutexSem(Pipes[id].Access);
  3781.     return 0;
  3782. }
  3783.  
  3784. int GUI::ReadPipe(int id, void *buffer, int len) {
  3785.     int l;
  3786.     //ULONG ulPostCount;
  3787.     
  3788.     if (id < 0 || id > MAX_PIPES)
  3789.         return -1;
  3790.     if (Pipes[id].used == 0)
  3791.         return -1;
  3792. //    DosQueryEventSem(Pipes[id].ResumeRead, &ulPostCount);
  3793. //    if (ulPostCount != 0)
  3794. //        return 0;
  3795.     DosRequestMutexSem(Pipes[id].Access, SEM_INDEFINITE_WAIT);
  3796. //    fprintf(stderr, "Pipe Read: Get %d %d\n", id, len);
  3797.     if (Pipes[id].bufused - Pipes[id].bufpos > 0) {
  3798.         l = len;
  3799.         if (l > Pipes[id].bufused - Pipes[id].bufpos) {
  3800.             l = Pipes[id].bufused - Pipes[id].bufpos;
  3801.         }
  3802.         memcpy(buffer, 
  3803.                Pipes[id].buffer + Pipes[id].bufpos,
  3804.                l);
  3805.         Pipes[id].bufpos += l;
  3806.         if (Pipes[id].bufpos == Pipes[id].bufused) {
  3807.             Pipes[id].bufused = 0;
  3808.             Pipes[id].bufpos = 0;
  3809. //            fprintf(stderr, "Pipe Resume Read: %d\n", id);
  3810.             Pipes[id].stopped = 1;
  3811.             DosPostEventSem(Pipes[id].ResumeRead);
  3812.         }
  3813.     } else if (Pipes[id].reading == 0)
  3814.         l = -1;
  3815.     else {
  3816.         l = 0;
  3817.         //DosBeep(200, 200);
  3818.     }
  3819. //    fprintf(stderr, "Pipe Read: Got %d %d\n", id, l);
  3820.     DosReleaseMutexSem(Pipes[id].Access);
  3821.     return l;
  3822. }
  3823.  
  3824. int GUI::ClosePipe(int id) {
  3825.     if (id < 0 || id > MAX_PIPES)
  3826.         return -1;
  3827.     if (Pipes[id].used == 0)
  3828.         return -1;
  3829.     if (Pipes[id].reading == 1) {
  3830.         Pipes[id].DoTerm = 1;
  3831.         DosPostEventSem(Pipes[id].ResumeRead);
  3832.         DosWaitThread(&Pipes[id].tid, DCWW_WAIT);
  3833.     }
  3834.     free(Pipes[id].buffer);
  3835.     free(Pipes[id].Command);
  3836.     DosCloseEventSem(Pipes[id].ResumeRead);
  3837.     DosCloseMutexSem(Pipes[id].Access);
  3838. //    fprintf(stderr, "Pipe Close: %d\n", id);
  3839.     Pipes[id].used = 0;
  3840.     return Pipes[id].RetCode;
  3841. }
  3842.  
  3843. int GUI::multiFrame() {
  3844.     return 1;
  3845. }
  3846.  
  3847. void DieError(int rc, char *msg, ...) {
  3848.     va_list ap;
  3849.     char str[1024];
  3850.     
  3851.     va_start(ap, msg);
  3852.     vsprintf(str, msg, ap);
  3853.     va_end(ap);
  3854.     if (hab == 0)
  3855.         hab = WinInitialize(0);
  3856.     if (hmq == 0)
  3857.         hmq = WinCreateMsgQueue(hab, 0);
  3858.     WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, str, "FTE", 0, MB_OK | MB_ERROR);
  3859.     WinDestroyMsgQueue(hmq);
  3860.     WinTerminate(hab);
  3861.     exit(rc);
  3862. }
  3863.  
  3864. char ConGetDrawChar(int index) {
  3865.     static char tab[] = "┌┐└┘─│┬├┤┴┼\x1A·─▒░\x1B\x1A";
  3866.     
  3867.     assert(index >= 0 && index < strlen(tab));
  3868.     
  3869.     return tab[index];
  3870. }
  3871.