home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / ftes46b5.zip / ftes46b5 / src / con_x11.cpp < prev    next >
Text File  |  1998-01-26  |  37KB  |  1,312 lines

  1. /*    con_x11.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. #include <string.h>
  11. #include <assert.h>
  12. #include <stdarg.h>
  13. #include <unistd.h>
  14. #include <stdio.h>
  15. #include <fcntl.h>
  16. #include <sys/types.h>
  17. #include <sys/time.h>
  18. #include <sys/wait.h>
  19. #include <stdlib.h>
  20. #include <signal.h>
  21. #if defined(AIX)
  22. #include <sys/select.h>
  23. #endif
  24. #include <X11/Xatom.h>
  25. #include <X11/Xlib.h>
  26. #include <X11/Xutil.h>
  27. #include <X11/keysym.h>
  28. #ifdef HPUX
  29. #include </usr/include/X11R5/X11/HPkeysym.h>
  30. #endif
  31. #include "console.h"
  32. #include "gui.h"
  33.  
  34. #ifdef HPUX
  35. #define FD_SET_CAST() (int *)
  36. #else
  37. #define FD_SET_CAST()
  38. #endif
  39.  
  40.  
  41. #define MAX_PIPES 4
  42. //#define PIPE_BUFLEN 4096
  43.  
  44. typedef struct {
  45.     int used;
  46.     int id;
  47.     int fd;
  48.     int pid;
  49.     int stopped;
  50.     EModel *notify;
  51. } GPipe;
  52.  
  53. static GPipe Pipes[MAX_PIPES] = {
  54.     { 0 }, { 0 }, { 0 }, { 0 }
  55. };
  56.  
  57. static long MouseAutoDelay = 40;
  58. static long MouseAutoRepeat = 200;
  59. static long MouseMultiClick = 300;
  60.  
  61. static int setUserPosition = 0;
  62. static int initX = 0, initY = 0;
  63. static unsigned int ScreenCols = 80;
  64. static unsigned int ScreenRows = 40;
  65. static unsigned int CursorX = 0;
  66. static unsigned int CursorY = 0;
  67. static int CursorVisible = 1;
  68. static unsigned char *ScreenBuffer = NULL;
  69. static int Refresh = 0;
  70.  
  71. static Display *display;
  72. static Window root;
  73. static int screen;
  74. static Colormap colormap;
  75. static XWindowAttributes windowAttributes;
  76. static Atom wm_protocols;
  77. static Atom wm_delete_window;
  78. static Window win;
  79. static Atom selection_buffer;
  80. static XSizeHints sizeHints;
  81. static XClassHint classHints;
  82. static XFontStruct *fontStruct;
  83. static int FontCX, FontCY;
  84. static XColor Colors[16];
  85. static GC GCs[256];
  86. static int rc;
  87. static char winTitle[256] = "FTE";
  88. static char winSTitle[256] = "FTE";
  89.  
  90. static char *CurSelectionData = 0;
  91. static int CurSelectionLen = 0;
  92. static int CurSelectionOwn = 0;
  93. static Time now;
  94.  
  95. static int AllocBuffer() {
  96.     unsigned char *p;
  97.     unsigned int i;
  98.     
  99.     ScreenBuffer = (unsigned char *)malloc(2 * ScreenCols * ScreenRows);
  100.     if (ScreenBuffer == NULL) return -1;
  101.     for (i = 0, p = ScreenBuffer; i < ScreenCols * ScreenRows; i++) {
  102.     *p++ = 32;
  103.     *p++ = 0x07;
  104.     }
  105.     return 0;
  106. }
  107.  
  108. static struct {
  109.     int r, g, b;
  110. } dcolors[] =
  111. {
  112.     {   0,   0,   0 },  //     black
  113.     {   0,   0, 128 },  // darkBlue
  114.     {   0, 128,   0 },  // darkGreen
  115.     {   0, 128, 128 },  // darkCyan
  116.     { 128,   0,   0 },  // darkRed
  117.     { 128,   0, 128 },  // darkMagenta
  118.     { 128, 128,   0 },  // darkYellow
  119.     { 192, 192, 192 },  // paleGray
  120.     { 160, 160, 160 },  // darkGray
  121.     {   0,   0, 255 },  //     blue
  122.     {   0, 255,   0 },  //     green
  123.     {   0, 255, 255 },  //     cyan
  124.     { 255,   0,   0 },  //     red
  125.     { 255,   0, 255 },  //     magenta
  126.     { 255, 255,   0 },  //     yellow
  127.     { 255, 255, 255 },  //     white
  128. };
  129.  
  130. static void SetColor(int i) {
  131.     assert (0 <= i && i <= 15);
  132.     Colors[i].blue  = (dcolors[i].b << 8) | dcolors[i].b;
  133.     Colors[i].green = (dcolors[i].g << 8) | dcolors[i].g;
  134.     Colors[i].red   = (dcolors[i].r << 8) | dcolors[i].r;
  135.     Colors[i].flags = DoRed | DoGreen | DoBlue;
  136. }
  137.  
  138. static int InitXColors() {
  139.     int i, j;
  140.     long d = 0x7FFFFFFF, d1;
  141.     XColor clr;
  142.     unsigned long pix;
  143.     int num;
  144.     long d_red, d_green, d_blue;
  145.     long u_red, u_green, u_blue;
  146.     
  147.     for (i = 0; i < 16; i++) {
  148.     SetColor(i);
  149.         if (XAllocColor(display, colormap, &Colors[i]) == 0) {
  150.         SetColor(i);
  151.             pix = 0xFFFFFFFF;
  152.         num = DisplayCells(display, DefaultScreen(display));
  153.             for (j = 0; j < num; j++) {
  154.                 clr.pixel = j;
  155.                 XQueryColor(display, colormap, &clr);
  156.  
  157.                 d_red = (clr.red - Colors[i].red) >> 3;
  158.                 d_green = (clr.green - Colors[i].green) >> 3;
  159.                 d_blue = (clr.blue - Colors[i].blue) >> 3;
  160.  
  161.                 //fprintf(stderr, "%d:%d dr:%d, dg:%d, db:%d\n", i, j, d_red, d_green, d_blue);
  162.  
  163.                 u_red = d_red / 100 * d_red * 3;
  164.                 u_green = d_green / 100 * d_green * 4;
  165.                 u_blue = d_blue / 100 * d_blue * 2;
  166.  
  167.                 //fprintf(stderr, "%d:%d dr:%u, dg:%u, db:%u\n", i, j, u_red, u_green, u_blue);
  168.  
  169.                 d1 = u_red + u_blue + u_green;
  170.                 
  171.         if (d1 < 0)
  172.                 d1 = -d1;
  173.                 if (pix == -1 || d1 < d) {
  174.                     pix = j;
  175.             d = d1;
  176.                 }
  177.             }
  178.             if (pix == 0xFFFFFFFF) {
  179.                 fprintf(stderr, "Color search failed for #%04X%04X%04X\n",
  180.                        Colors[i].red,
  181.                        Colors[i].green,
  182.                        Colors[i].blue);
  183.             } 
  184.             clr.pixel = pix;
  185.             XQueryColor(display, colormap, &clr);
  186.             Colors[i] = clr;
  187.             if (XAllocColor(display, colormap, &Colors[i]) == 0) {
  188.                 fprintf(stderr, "Color alloc failed for #%04X%04X%04X\n",
  189.                         Colors[i].red,
  190.                         Colors[i].green,
  191.                         Colors[i].blue);
  192.             }
  193.         /*colormap = XCreateColormap(display, win, DefaultVisual(display, screen), AllocNone);
  194.         for (i = 0; i < 16; i++) {
  195.         SetColor(i);
  196.         XAllocColor(display, colormap, &Colors[i]);
  197.         }
  198.         XSetWindowColormap(display, win, colormap);
  199.             return 0;*/
  200.     }
  201.     }
  202.     return 0;
  203. }
  204.  
  205. static int InitXGCs() {
  206.     unsigned int i;
  207.     XGCValues gcv;
  208.     
  209.     for (i = 0; i < 256; i++) {
  210.     gcv.foreground = Colors[i % 16].pixel;  
  211.     gcv.background = Colors[(i / 16)].pixel;
  212.     gcv.font = fontStruct->fid;
  213.     GCs[i] = XCreateGC(display, win, GCForeground | GCBackground | GCFont, &gcv);
  214.     }
  215.     return 0;
  216. }
  217.  
  218. static int SetupXWindow() {
  219.     char *fs;
  220.     XSetWindowAttributes setWindowAttributes;
  221.  
  222.     if (getenv("DISPLAY") == 0) {
  223.         DieError(1, "$DISPLAY not set?");
  224.         return -1;
  225.     }
  226.     
  227.     if ((display = XOpenDisplay(getenv("DISPLAY"))) == NULL) {
  228.         DieError(1, "Could not open display: %s", getenv("DISPLAY"));
  229.         return -1;
  230.     }
  231.     root = DefaultRootWindow(display);
  232.     screen = DefaultScreen(display);
  233.     colormap = DefaultColormap(display, screen);
  234.  
  235.     XGetWindowAttributes(display, root, &windowAttributes);
  236.     fs = getenv("VIOFONT");
  237.     if (fs == 0 && WindowFont[0] != 0)
  238.         fs = WindowFont;
  239.     fontStruct = NULL;
  240.     if (fs) 
  241.     fontStruct = XLoadQueryFont(display, fs);
  242.     if (fontStruct == NULL) 
  243.     fontStruct = XLoadQueryFont(display, "8x13");
  244.     if (fontStruct == NULL) 
  245.     fontStruct = XLoadQueryFont(display, "fixed");
  246.     if (fontStruct == NULL) 
  247.     return -1;
  248.     wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False);
  249.     assert(wm_protocols != None);
  250.     wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
  251.     assert(wm_delete_window != None);
  252.     selection_buffer = XInternAtom(display, "fte_clip", False);
  253.     assert(selection_buffer != None);
  254.     FontCX = fontStruct->max_bounds.width;
  255.     FontCY = fontStruct->max_bounds.ascent + fontStruct->max_bounds.descent;
  256.  
  257.  
  258.     setWindowAttributes.bit_gravity = ForgetGravity;
  259.     win = XCreateWindow(display,
  260.                         root,
  261.                         initX, initY,
  262.                         ScreenCols * FontCX, ScreenRows * FontCY, 0,
  263.                         CopyFromParent, InputOutput, CopyFromParent,
  264.                         CWBitGravity, &setWindowAttributes);
  265.     
  266.     sizeHints.flags = PResizeInc | PMinSize | PBaseSize;
  267.     sizeHints.width_inc = FontCX;
  268.     sizeHints.height_inc = FontCY;
  269.     sizeHints.min_width = 20 * FontCX;
  270.     sizeHints.min_height = 6 * FontCY;
  271.     sizeHints.base_width = 0;
  272.     sizeHints.base_height = 0;
  273.     if (setUserPosition)
  274.         sizeHints.flags |= USPosition;
  275.  
  276.     classHints.res_name = "fte";
  277.     classHints.res_class = "Fte";
  278.     XSetClassHint(display, win, &classHints);
  279.     XSetStandardProperties(display, win, winTitle, winTitle, 0, NULL, 0, 0);
  280.     XSetWMNormalHints(display, win, &sizeHints);
  281.     XSetWMProtocols(display, win, &wm_delete_window, 1);
  282.     XSelectInput(display, win, 
  283.          ExposureMask | StructureNotifyMask | VisibilityChangeMask |
  284.          KeyPressMask | KeyReleaseMask |
  285.          ButtonPressMask | ButtonReleaseMask | ButtonMotionMask);
  286.     if (InitXColors() != 0) return -1;
  287.     if (InitXGCs() != 0) return -1;
  288.     XMapRaised(display, win);
  289.     return 0;
  290. }
  291.  
  292. int ConInit(int XSize, int YSize) {
  293.     if (XSize != -1)
  294.         ScreenCols = XSize;
  295.     if (YSize != -1)
  296.         ScreenRows = YSize;
  297.     if (AllocBuffer() == -1) return -1;
  298.     if (SetupXWindow() == -1) return -1;
  299.     signal(SIGALRM, SIG_IGN);
  300.     signal(SIGPIPE, SIG_IGN);
  301.     return 0;
  302. }
  303.  
  304. int ConDone(void) {
  305.     XDestroyWindow(display, win);
  306.     return (XCloseDisplay(display) == 0);
  307. }
  308.  
  309. int ConSuspend(void) {
  310.     return 0;
  311. }
  312.  
  313. int ConContinue(void) {
  314.     return 0;
  315. }
  316.  
  317. int ConClear(void) {
  318.     TDrawBuffer B;
  319.     MoveCh(B, ' ', 0x07, ScreenCols);
  320.     return ConPutLine(0, 0, ScreenCols, ScreenRows, B);
  321. }
  322.  
  323. int ConSetTitle(char *Title, char *STitle) {
  324.     strncpy(winTitle, Title, sizeof(winTitle) - 1);
  325.     winTitle[sizeof(winTitle) - 1] = 0;
  326.     strncpy(winSTitle, STitle, sizeof(winSTitle) - 1);
  327.     winSTitle[sizeof(winSTitle) - 1] = 0;
  328.     XSetStandardProperties(display, win, winTitle, winSTitle, 0, NULL, 0, NULL);
  329.     return 0;
  330. }
  331.  
  332. int ConGetTitle(char *Title, int MaxLen, char *STitle, int SMaxLen) {
  333.     strncpy(Title, winTitle, MaxLen);
  334.     Title[MaxLen - 1] = 0;
  335.     strncpy(STitle, winSTitle, SMaxLen);
  336.     STitle[SMaxLen - 1] = 0;
  337.     return 0;
  338. }
  339.  
  340. #define InRange(x,a,y) (((x) <= (a)) && ((a) < (y)))
  341. #define CursorXYPos(x,y) (ScreenBuffer + ((x) + ((y) * ScreenCols)) * 2)
  342.  
  343. void DrawCursor(int Show) {
  344.     if (CursorVisible) {
  345.     unsigned char *p = CursorXYPos(CursorX, CursorY), attr;
  346.     attr = p[1];
  347.     /*if (Show) attr = ((((attr << 4) & 0xF0)) | (attr >> 4)) ^ 0x77;*/
  348.     if (Show) attr = (attr ^ 0x77);
  349.     rc = XDrawImageString(display, win, GCs[((unsigned)attr) & 0xFF],
  350.                   CursorX * FontCX,
  351.                   fontStruct->max_bounds.ascent + CursorY * FontCY,
  352.                   (char *)p, 1);
  353.     }
  354. }
  355.  
  356. int ConPutBox(int X, int Y, int W, int H, PCell Cell) {
  357.     unsigned int i;
  358.     unsigned char temp[256], attr;
  359.     unsigned char *p, *ps, *c, *ops;
  360.     unsigned int len, x, l, ox, olen, skip;
  361.     
  362.     
  363.     if (X >= ScreenCols || Y >= ScreenRows ||
  364.         X + W > ScreenCols || Y + H > ScreenRows)
  365.     {
  366.         //fprintf(stderr, "%d %d  %d %d %d %d\n", ScreenCols, ScreenRows, X, Y, W, H);
  367.     return -1;
  368.     }
  369.     
  370.     for (i = 0; i < H; i++) {
  371.         len = W;
  372.     p = CursorXYPos(X, Y + i);
  373.     ps = (unsigned char *) Cell;
  374.     x = X;
  375.     while (len > 0) {
  376.         if (!Refresh) {
  377.         c = CursorXYPos(x, Y + i);
  378.         skip = 0;
  379.         ops = ps;
  380.         ox = x;
  381.         olen = len;
  382.         while ((len > 0) && (*(unsigned short *) c == *(unsigned short *)ps)) x++, len--, ps+=2, c+=2, skip++;
  383.         if (len <= 0) break;
  384.         if (skip <= 4) {
  385.             ps = ops;
  386.             x = ox;
  387.             len = olen;
  388.         }
  389.         }
  390.         p = ps;
  391.         l = 1;
  392.         temp[0] = *ps++; attr = *ps++;
  393.         while ((l < len) && ((unsigned char) (ps[1]) == attr)) {
  394.         temp[l++] = *ps++;
  395.         ps++;
  396.         }
  397.         rc = XDrawImageString(display, win, GCs[((unsigned)attr) & 0xFF],
  398.                   x * FontCX,
  399.                   fontStruct->max_bounds.ascent + (Y + i) * FontCY,
  400.                   (char *)temp, l);
  401.         x += l;
  402.         len -= l;
  403.     }
  404.     p = CursorXYPos(X, Y + i);
  405.     memcpy(p, Cell, W * 2);
  406.     if (i + Y == CursorY)
  407.         DrawCursor(1);
  408.     Cell += W;
  409.     }
  410.     return 0;
  411. }
  412.  
  413. int ConGetBox(int X, int Y, int W, int H, PCell Cell) {
  414.     int i;
  415.     
  416.     for (i = 0; i < H; i++) {
  417.     memcpy(Cell, CursorXYPos(X, Y + i), 2 * W);
  418.     Cell += W;
  419.     }
  420.     return 0;
  421. }
  422.  
  423. int ConPutLine(int X, int Y, int W, int H, PCell Cell) {
  424.     int i;
  425.     for (i = 0; i < H; i++) {
  426.     if (ConPutBox(X, Y + i, W, 1, Cell) != 0) return -1;
  427.     }
  428.     return 0;
  429. }
  430.  
  431. int ConSetBox(int X, int Y, int W, int H, TCell Cell) {
  432.     TDrawBuffer B;
  433.     int i;
  434.     
  435.     for (i = 0; i < W; i++) B[i] = Cell;
  436.     ConPutLine(X, Y, W, H, B);
  437.     return 0;
  438. }
  439.  
  440. int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count) {
  441.     TCell Cell;
  442.     int l;
  443.     
  444.     MoveCh(&Cell, ' ', Fill, 1);
  445.     DrawCursor(0);
  446.     if (Way == csUp) {
  447.     XCopyArea(display, win, win, GCs[0], 
  448.           X * FontCX, 
  449.           (Y + Count) * FontCY, 
  450.           W * FontCX, 
  451.           (H - Count) * FontCY, 
  452.           X * FontCX, 
  453.           Y * FontCY
  454.           );
  455.     for (l = 0; l < H - Count; l++) {
  456.         memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l + Count), 2 * W);
  457.     }
  458.     if (ConSetBox(X, Y + H - Count, W, Count, Cell) == -1) return -1;
  459.     } else if (Way == csDown) {
  460.     XCopyArea(display, win, win, GCs[0], 
  461.           X * FontCX, 
  462.           Y * FontCY, 
  463.           W * FontCX, 
  464.           (H - Count) * FontCY, 
  465.           X * FontCX, 
  466.           (Y + Count)* FontCY
  467.           );
  468.     for (l = H - 1; l >= Count; l--) {
  469.         memcpy(CursorXYPos(X, Y + l), CursorXYPos(X, Y + l - Count), 2 * W);
  470.     }
  471.     if (ConSetBox(X, Y, W, Count, Cell) == -1) return -1;
  472.     }
  473.     DrawCursor(1);
  474.     return 0;
  475. }
  476.  
  477. int ConSetSize(int X, int Y) {
  478.     unsigned char *NewBuffer;
  479.     unsigned char *p;
  480.     int i;
  481.     unsigned int MX, MY;
  482.     
  483.     p = NewBuffer = (unsigned char *) malloc(X * Y * 2);
  484.     if (NewBuffer == NULL) return -1;
  485.     for (i = 0; i < X * Y; i++) {
  486.     *p++ = ' ';
  487.     *p++ = 0x07;
  488.     }
  489.     MX = ScreenCols; if (X < MX) MX = X;
  490.     MY = ScreenRows; if (Y < MY) MY = Y;
  491.     if (X < MX) MX = X;
  492.     p = NewBuffer;
  493.     for (i = 0; i < MY; i++) {
  494.     memcpy(p, CursorXYPos(0, i), MX * 2);
  495.     p += X * 2;
  496.     }
  497.     free(ScreenBuffer);
  498.     ScreenBuffer = NewBuffer;
  499.     ScreenCols = X;
  500.     ScreenRows = Y;
  501.     //ConPutBox(0, 0, ScreenCols, ScreenRows, (PCell) ScreenBuffer);
  502.     //if (Refresh == 0)
  503.     //    XResizeWindow(display, win, ScreenCols * FontCX, ScreenRows * FontCY);
  504.     return 0;
  505. }
  506.  
  507. int ConQuerySize(int *X, int *Y) {
  508.     *X = ScreenCols;
  509.     *Y = ScreenRows;
  510.     return 0;
  511. }
  512.  
  513. int ConSetCursorPos(int X, int Y) {
  514.     DrawCursor(0);
  515.     CursorX = X;
  516.     CursorY = Y;
  517.     DrawCursor(1);
  518.     return 0;
  519. }
  520.  
  521. int ConQueryCursorPos(int *X, int *Y) {
  522.     *X = CursorX;
  523.     *Y = CursorY;
  524.     return 0;
  525. }
  526.  
  527. int ConShowCursor(void) {
  528.     CursorVisible = 1;
  529.     DrawCursor(1);
  530.     return 0;
  531. }
  532.  
  533. int ConHideCursor(void) {
  534.     DrawCursor(0);
  535.     CursorVisible = 0;
  536.     return 0;
  537. }
  538.  
  539. int ConCursorVisible(void) {
  540.     return 1;
  541. }
  542. int ConSetCursorSize(int Start, int End) {
  543.     return 1;
  544. }
  545.  
  546. int ConSetMousePos(int X, int Y) {
  547.     return 0;
  548. }
  549.  
  550. static int LastMouseX = -1, LastMouseY = -1;
  551.  
  552. int ConQueryMousePos(int *X, int *Y) {
  553.     if (X) *X = LastMouseX;
  554.     if (Y) *Y = LastMouseY;
  555.     return 0;
  556. }
  557.  
  558. int ConShowMouse(void) {
  559.     return 0;
  560. }
  561.  
  562. int ConHideMouse(void) {
  563.     return 0;
  564. }
  565.  
  566. int ConMouseVisible(void) {
  567.     return 1;
  568. }
  569.  
  570. int ConQueryMouseButtons(int *ButtonCount) {
  571.     *ButtonCount = 3;
  572.     return 0;
  573. }
  574.  
  575. void UpdateWindow(int xx, int yy, int ww, int hh) {
  576.     PCell p;
  577.     int i;
  578.     ww /= FontCX; ww += 2;
  579.     hh /= FontCY; hh += 2;
  580.     xx /= FontCX;
  581.     yy /= FontCY;
  582.     if (xx + ww > ScreenCols) ww = ScreenCols - xx;
  583.     if (yy + hh > ScreenRows) hh = ScreenRows - yy;
  584.     Refresh = 1;
  585.     //frames->Repaint();
  586.     //frames->Update();
  587.     p = (PCell) CursorXYPos(xx, yy);
  588.     for (i = 0; i < hh; i++) {
  589.     ConPutBox(xx, yy + i, ww, 1, p);
  590.     p += ScreenCols;
  591.     }
  592.     //XFlush(display);
  593.     Refresh = 0;
  594. }
  595.  
  596. void ResizeWindow(int ww, int hh) {
  597.     ww /= FontCX; if (ww <= 4) ww = 4;
  598.     hh /= FontCY; if (hh <= 2) hh = 2;
  599.     if (ScreenCols != ww || ScreenRows != hh) {
  600.         Refresh = 0;
  601.         ConSetSize(ww, hh);
  602.         Refresh = 1;
  603.         UpdateWindow(0, 0, ScreenCols * FontCX, ScreenRows * FontCY);
  604.         Refresh = 0;
  605.     }
  606. }
  607.  
  608. static struct {
  609.     long keysym;
  610.     long keycode;
  611. } key_table[] = {
  612. { XK_Escape,         kbEsc },
  613. { XK_Tab,            kbTab },
  614. { XK_Return,         kbEnter },
  615. { XK_Pause,          kbPause },
  616. { XK_BackSpace,      kbBackSp },
  617. { XK_Home,           kbHome },
  618. { XK_Up,             kbUp },
  619. { XK_Prior,          kbPgUp },
  620. { XK_Left,           kbLeft },
  621. { XK_Right,          kbRight },
  622. { XK_End,            kbEnd },
  623. { XK_Down,           kbDown },
  624. { XK_Next,           kbPgDn },
  625. { XK_Select,         kbEnd },
  626. { XK_KP_Enter,       kbEnter | kfGray },
  627. { XK_Insert,         kbIns | kfGray },
  628. { XK_Delete,         kbDel | kfGray },
  629. { XK_KP_Add,         '+' | kfGray },
  630. { XK_KP_Subtract,    '-' | kfGray },
  631. { XK_KP_Multiply,    '*' | kfGray },
  632. { XK_KP_Divide,      '/' | kfGray },
  633. { XK_Num_Lock,       kbNumLock },
  634. { XK_Caps_Lock,      kbCapsLock },
  635. { XK_Print,          kbPrtScr },
  636. { XK_Shift_L,        kbShift },
  637. { XK_Shift_R,        kbShift | kfGray },
  638. { XK_Control_L,      kbCtrl },
  639. { XK_Control_R,      kbCtrl | kfGray },
  640. { XK_Alt_L,          kbAlt },
  641. { XK_Alt_R,          kbAlt | kfGray },
  642. { XK_Meta_L,         kbAlt },
  643. { XK_Meta_R,         kbAlt | kfGray },
  644. { XK_F1,             kbF1 },
  645. { XK_F2,             kbF2 },
  646. { XK_F3,             kbF3 },
  647. { XK_F4,             kbF4 },
  648. { XK_F5,             kbF5 },
  649. { XK_F6,             kbF6 },
  650. { XK_F7,             kbF7 },
  651. { XK_F8,             kbF8 },
  652. { XK_F9,             kbF9 },
  653. { XK_F10,            kbF10 },
  654. { XK_F11,            kbF11 },
  655. { XK_F12,            kbF12 },
  656. { XK_KP_0,           '0' | kfGray },
  657. { XK_KP_1,           '1' | kfGray },
  658. { XK_KP_2,           '2' | kfGray },
  659. { XK_KP_3,           '3' | kfGray },
  660. { XK_KP_4,           '4' | kfGray },
  661. { XK_KP_5,           '5' | kfGray },
  662. { XK_KP_6,           '6' | kfGray },
  663. { XK_KP_7,           '7' | kfGray },
  664. { XK_KP_8,           '8' | kfGray },
  665. { XK_KP_9,           '9' | kfGray },
  666. { XK_KP_Decimal,     '.' | kfGray },
  667. { 0x1000FF6F,        kbDel | kfShift | kfGray },
  668. { 0x1000FF70,        kbIns | kfCtrl | kfGray },
  669. { 0x1000FF71,        kbIns | kfShift | kfGray },
  670. { 0x1000FF72,        kbIns | kfGray },
  671. { 0x1000FF73,        kbDel | kfGray },
  672. { 0x1000FF74,        kbTab | kfShift },
  673. { 0x1000FF75,        kbTab | kfShift },
  674. { 0,                 0 }
  675. };
  676.  
  677. void ConvertKeyToEvent(KeySym key, KeySym key1, char *keyname, char *keyname1, int etype, int state, TEvent *Event) {
  678.     unsigned int myState = 0;
  679.     int i,k;
  680.     
  681.     Event->What = evNone;
  682.     
  683.     switch (etype) {
  684.     case KeyPress:   Event->What = evKeyDown; break;
  685.     case KeyRelease: Event->What = evKeyUp; break;
  686.     default:
  687.         return ;
  688.     }
  689.     
  690.     if (state & ShiftMask) myState |= kfShift;
  691.     if (state & ControlMask) myState |= kfCtrl;
  692.     if (state & Mod1Mask) myState |= kfAlt;
  693.     
  694.     //printf("key: %d ; %d ; %d\n", key, key1, state);
  695.     if (key < 256 || (key1 < 256 && (myState == kfAlt || myState == (kfAlt | kfShift)))) {
  696.         if (myState & kfAlt)
  697.             key = key1;
  698.         if (myState == kfShift)
  699.             myState = 0;
  700.     if (myState & (kfAlt | kfCtrl))
  701.         if ((key >= 'a') && (key < 'z' + 32))
  702.         key &= ~0x20;
  703.     Event->Key.Code = key | myState;
  704.     return;
  705.     } else {
  706.     for (i = 0; i < (sizeof(key_table) / sizeof(key_table[0])); i++) {
  707.         if (key1 == key_table[i].keysym) {
  708.         k = key_table[i].keycode;
  709.         if (k < 256)
  710.                     if (myState == kfShift)
  711.                         myState = 0;
  712.                 Event->Key.Code = k | myState;
  713.         return;
  714.         }
  715.     }
  716.     }
  717.     /*printf("Unknown key: %ld %s %d %d\n", key, keyname, etype, state); */
  718.     Event->What = evNone;
  719. }
  720.  
  721.  
  722. static TEvent LastMouseEvent = { evNone };
  723.  
  724. #define TM_DIFF(x,y) ((long)(((long)(x) < (long)(y)) ? ((long)(y) - (long)(x)) : ((long)(x) - (long)(y))))
  725.  
  726. void ConvertClickToEvent(int type, int xx, int yy, int button, int state, TEvent *Event, Time time) {
  727.     unsigned int myState = 0;
  728.     static unsigned long LastClickTime = 0;
  729.     static unsigned long LastClickCount = 0;
  730.     static unsigned long LastClick = 0;
  731.     unsigned long CurTime = time;
  732.     
  733.     if (type == MotionNotify) Event->What = evMouseMove;
  734.     else if (type == ButtonPress) Event->What = evMouseDown;
  735.     else Event->What = evMouseUp;
  736.     Event->Mouse.X = xx / FontCX;
  737.     Event->Mouse.Y = yy / FontCY;
  738.     if (Event->What == evMouseMove) 
  739.         if (LastMouseX == Event->Mouse.X &&
  740.             LastMouseY == Event->Mouse.Y)
  741.         {
  742.             Event->What = evNone;
  743.             return;
  744.         }
  745.     LastMouseX = Event->Mouse.X;
  746.     LastMouseY = Event->Mouse.Y;
  747.     Event->Mouse.Buttons = 0;
  748.     if (type == MotionNotify) {
  749.     if (state & Button1Mask) Event->Mouse.Buttons |= 1;
  750.     if (state & Button2Mask) Event->Mouse.Buttons |= 4;
  751.     if (state & Button3Mask) Event->Mouse.Buttons |= 2;
  752.     } else {
  753.     switch (button) {
  754.     case Button1: Event->Mouse.Buttons |= 1; break;
  755.     case Button2: Event->Mouse.Buttons |= 4; break;
  756.     case Button3: Event->Mouse.Buttons |= 2; break;
  757.     }
  758.     }
  759.     Event->Mouse.Count = 1;
  760.     if (state & ShiftMask) myState |= kfShift;
  761.     if (state & ControlMask) myState |= kfCtrl;
  762.     if (state & Mod1Mask) myState |= kfAlt;
  763.     if (state & Mod2Mask) myState |= kfAlt;
  764.     if (state & Mod3Mask) myState |= kfAlt;
  765.     if (state & Mod4Mask) myState |= kfAlt;
  766.     Event->Mouse.KeyMask = myState;
  767.     
  768.     if (Event->What == evMouseDown) {
  769.     if (LastClickCount) {
  770.         if (LastClick == Event->Mouse.Buttons) {
  771.         if (TM_DIFF(CurTime, LastClickTime) <= MouseMultiClick) {
  772.             Event->Mouse.Count = ++LastClickCount;
  773.         } else {
  774.             LastClickCount = 0;
  775.         }
  776.         } else {
  777.         LastClick = 0;
  778.         LastClickCount = 0;
  779.         LastClickTime = 0;
  780.         }
  781.     }
  782.  
  783.     LastClick = Event->Mouse.Buttons;
  784.     if (LastClickCount == 0) 
  785.         LastClickCount = 1;
  786.     LastClickTime = CurTime;
  787.     }
  788. /*    if (Event->What == evMouseMove) {
  789.     LastClick = 0;
  790.     LastClickCount = 0;
  791.     LastClickTime = 0;
  792.     }
  793.     */
  794.     LastMouseEvent = *Event;
  795. }
  796.  
  797. void ProcessXEvents(TEvent *Event) {
  798.     XEvent event;
  799.     XAnyEvent *anyEvent = (XAnyEvent *) &event;
  800.     XExposeEvent *exposeEvent = (XExposeEvent *) &event;
  801.     XButtonEvent *buttonEvent = (XButtonEvent *) &event;
  802.     XKeyEvent *keyEvent = (XKeyEvent *) &event;
  803.     XKeyEvent keyEvent1;
  804.     XConfigureEvent *configureEvent = (XConfigureEvent *) &event;
  805.     XGraphicsExposeEvent *gexposeEvent = (XGraphicsExposeEvent *) &event;
  806.     XMotionEvent *motionEvent = (XMotionEvent *) &event;
  807.     KeySym key, key1;
  808.     int state;
  809.     char keyName[32];
  810.     char keyName1[32];
  811.     
  812.     memset((void *)&event, 0, sizeof(event));
  813.     Event->What = evNone;
  814.     rc = XNextEvent(display, &event);
  815.  
  816.     if (event.type == MappingNotify) {
  817.         XRefreshKeyboardMapping(&event.xmapping);
  818.         return ;
  819.     }
  820.  
  821.     if (anyEvent->window != win)
  822.         return ;
  823.     
  824.     switch (event.type) {
  825.     case Expose:
  826.         UpdateWindow(exposeEvent->x,
  827.                      exposeEvent->y,
  828.                      exposeEvent->width,
  829.                      exposeEvent->height);
  830.     break;
  831.     case GraphicsExpose:
  832.         UpdateWindow(gexposeEvent->x,
  833.                      gexposeEvent->y,
  834.                      gexposeEvent->width,
  835.                      gexposeEvent->height);
  836.     break;
  837.     case ConfigureNotify:
  838.         while ((XPending(display) > 0) && 
  839.                XCheckTypedWindowEvent(display, win,
  840.                                       ConfigureNotify, &event)) 
  841.             XSync(display, 0);
  842.     ResizeWindow(configureEvent->width, configureEvent->height);
  843.     Event->What = evCommand;
  844.         Event->Msg.Command = cmResize;
  845.     break;
  846.     case ButtonPress:
  847.     case ButtonRelease:
  848.         now = event.xbutton.time;
  849.     ConvertClickToEvent(event.type, buttonEvent->x, buttonEvent->y, buttonEvent->button, buttonEvent->state, Event, motionEvent->time);
  850.     break;
  851.     case KeyPress:
  852.     case KeyRelease:
  853.         now = event.xkey.time;
  854.         state = keyEvent->state;
  855.         keyEvent1 = *keyEvent;
  856.         keyEvent1.state &= ~(ShiftMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask);
  857.         
  858.         XLookupString(keyEvent, keyName, sizeof(keyName), &key, 0);
  859.         XLookupString(&keyEvent1, keyName1, sizeof(keyName1), &key1, 0);
  860.         //printf("keyEvent->state = %d %s %08X\n", keyEvent->state, keyName, key);
  861.         //printf("keyEvent1.state = %d %s %08X\n", keyEvent1.state, keyName1, key1);
  862.         //key1 = XLookupKeysym(keyEvent, 0);
  863.     ConvertKeyToEvent(key, key1, keyName, keyName1, event.type, state, Event);
  864.     break;
  865.     case MotionNotify:
  866.         now = event.xmotion.time;
  867.     ConvertClickToEvent(event.type, motionEvent->x, motionEvent->y, 0, motionEvent->state, Event, motionEvent->time);
  868.     break;                
  869.     case ClientMessage:
  870.         if (event.xclient.message_type == wm_protocols
  871.             || event.xclient.format == 32
  872.             || event.xclient.data.l[0] == wm_delete_window)
  873.         {
  874.             Event->What = evCommand;
  875.             Event->Msg.Command = cmClose;
  876.         }
  877.         break;
  878.     case SelectionClear:
  879.         {
  880.             Window owner;
  881.  
  882.             owner = XGetSelectionOwner(display, XA_PRIMARY);
  883.             if (owner != win) {
  884.                 if (CurSelectionData != 0)
  885.                     free(CurSelectionData);
  886.                 CurSelectionData = 0;
  887.                 CurSelectionLen = 0;
  888.                 CurSelectionOwn = 0;
  889.             }
  890.         }
  891.         break;
  892.     case SelectionRequest:
  893.         {
  894.             XEvent notify;
  895.  
  896.             notify.type = SelectionNotify;
  897.             notify.xselection.requestor = event.xselectionrequest.requestor;
  898.             notify.xselection.selection = event.xselectionrequest.selection;
  899.             notify.xselection.target = event.xselectionrequest.target;
  900.             notify.xselection.time = event.xselectionrequest.time;
  901.             
  902.             if (event.xselectionrequest.selection == XA_PRIMARY &&
  903.                 event.xselectionrequest.target == XA_STRING)
  904.             {
  905.                 XChangeProperty(display,
  906.                                 event.xselectionrequest.requestor,
  907.                                 event.xselectionrequest.property,
  908.                                 event.xselectionrequest.target,
  909.                                 8, PropModeReplace,
  910.                                 (unsigned char *)(CurSelectionData ? CurSelectionData : ""),
  911.                                 CurSelectionLen);
  912.                 notify.xselection.property = event.xselectionrequest.property;
  913.             } else {
  914.                 notify.xselection.property = None;
  915.             }
  916.             
  917.             XSendEvent(display, notify.xselection.requestor, False, 0L, ¬ify);
  918.         }
  919.         break;
  920.     }
  921. }
  922.  
  923. static TEvent Pending = { evNone };
  924.  
  925. int ConGetEvent(TEventMask EventMask, TEvent *Event, int WaitTime, int Delete) {
  926.     fd_set read_fds;
  927.     struct timeval timeout;
  928.     int rc;
  929.     static TEvent Queued = { evNone };
  930.  
  931.     Event->What = evNone;
  932.     if (Queued.What != evNone) {
  933.     *Event = Queued;
  934.     if (Delete) Queued.What = evNone;
  935.         if (Event->What & EventMask) return 0;
  936.         else Queued.What = evNone;
  937.     }
  938.     
  939.     Event->What = evNone;
  940.     if (Pending.What != evNone) {
  941.     *Event = Pending;
  942.     if (Delete) Pending.What = evNone;
  943.         if (Event->What & EventMask) return 0;
  944.         else
  945.             Pending.What = evNone;
  946.     }
  947.     
  948.     Event->What = evNone;
  949.     while (Event->What == evNone) {
  950.         Event->What = evNone;
  951.         while (XPending(display) > 0) {
  952.             ProcessXEvents(Event);
  953.             if (Event->What != evNone) {
  954.                 while ((Event->What == evMouseMove) && (Queued.What == evNone)) {
  955.                     while ((rc = XPending(display)) > 0) {
  956.                         ProcessXEvents(&Queued);
  957.                         if (Queued.What == evMouseMove) {
  958.                             *Event = Queued;
  959.                             Queued.What = evNone;
  960.                         } else break;
  961.                     }
  962.                     if (rc <= 0) break;
  963.                 }
  964.             }
  965.             if (Delete == 0)
  966.                 Pending = *Event;
  967.             if (Event->What & EventMask) return 0;
  968.             else
  969.                 Pending.What = evNone;
  970.             Event->What = evNone;
  971.         }
  972.  
  973.         Event->What = evNone;
  974.         FD_ZERO(&read_fds);
  975.         FD_SET(ConnectionNumber(display), &read_fds);
  976.         for (int p = 0; p < MAX_PIPES; p++)
  977.             if (Pipes[p].used)
  978.                 if (Pipes[p].fd != -1)
  979.                     FD_SET(Pipes[p].fd, &read_fds);
  980.  
  981.         if ((WaitTime == -1 || WaitTime > MouseAutoDelay) && (LastMouseEvent.What == evMouseAuto) && (EventMask & evMouse)) {
  982.             timeout.tv_sec = 0;
  983.             timeout.tv_usec = MouseAutoDelay * 1000;
  984.             rc = select(sizeof(fd_set) * 8, FD_SET_CAST() &read_fds, NULL, NULL, &timeout);
  985.             if (rc == 0) {
  986.                 *Event = LastMouseEvent;
  987.                 return 0;
  988.             }
  989.         } else if ((WaitTime == -1 || WaitTime > MouseAutoRepeat) && (LastMouseEvent.What == evMouseDown || LastMouseEvent.What == evMouseMove)
  990.                    &&
  991.                    (LastMouseEvent.Mouse.Buttons) && (EventMask & evMouse))
  992.         {
  993.             timeout.tv_sec = 0;
  994.             timeout.tv_usec = MouseAutoRepeat * 1000;
  995.             rc = select(sizeof(fd_set) * 8, FD_SET_CAST() &read_fds, NULL, NULL, &timeout);
  996.             if (rc == 0) {
  997.                 LastMouseEvent.What = evMouseAuto;
  998.                 *Event = LastMouseEvent;
  999.                 return 0;
  1000.             }
  1001.         } else if (WaitTime == -1) {
  1002.             rc = select(sizeof(fd_set) * sizeof(char), FD_SET_CAST() &read_fds, NULL, NULL, NULL);
  1003.         } else {
  1004.         /*        if (WaitTime > 1000) WaitTime = 1000;*/
  1005.             timeout.tv_sec = 0;
  1006.             timeout.tv_usec = WaitTime * 1000 + 1;
  1007.             rc = select(sizeof(fd_set) * sizeof(char), FD_SET_CAST() &read_fds, NULL, NULL, &timeout);
  1008.         }
  1009.  
  1010.         if (rc == 0 || rc == -1) {
  1011.             Event->What = evNone;
  1012.             return -1;
  1013.         }
  1014.         if (FD_ISSET(ConnectionNumber(display), &read_fds)) // X has priority
  1015.             continue;
  1016.         for (int pp = 0; pp < MAX_PIPES; pp++) {
  1017.             if (Pipes[pp].used)
  1018.                 if (Pipes[pp].fd != -1)
  1019.                     if (FD_ISSET(Pipes[pp].fd, &read_fds)) {
  1020.                         if (Pipes[pp].notify) {
  1021.                             Event->What = evNotify;
  1022.                             Event->Msg.View = 0;
  1023.                             Event->Msg.Model = Pipes[pp].notify;
  1024.                             Event->Msg.Command = cmPipeRead;
  1025.                             Event->Msg.Param1 = pp;
  1026.                             Pipes[pp].stopped = 0;
  1027.                         }
  1028.                         //fprintf(stderr, "Pipe %d\n", Pipes[pp].fd);
  1029.                         return 0;
  1030.                     }
  1031.         }
  1032.     }
  1033.     return 0;
  1034. }
  1035.  
  1036. int ConPutEvent(TEvent Event) {
  1037.     Pending = Event;
  1038.     return 0;
  1039. }
  1040.  
  1041. int ConFlush(void) {
  1042.     return XFlush(display) == 0;
  1043. }
  1044.  
  1045. int ConGrabEvents(TEventMask EventMask) {
  1046.     return 0;
  1047. }
  1048.  
  1049. int GetXSelection(int *len, char **data) {
  1050.     if (CurSelectionOwn) {
  1051.         *data = (char *)malloc(CurSelectionLen);
  1052.         if (*data == 0)
  1053.             return -1;
  1054.         memcpy(*data, CurSelectionData, CurSelectionLen);
  1055.         *len = CurSelectionLen;
  1056.         return 0;
  1057.     } else {
  1058.         if (XGetSelectionOwner(display, XA_PRIMARY) == None)
  1059.         {
  1060.         }
  1061.         else
  1062.         {
  1063.             XEvent event;
  1064.             Atom type;
  1065.             long extra;
  1066.             int i;
  1067.             long l;
  1068.         time_t time_started;
  1069.  
  1070.         assert(selection_buffer != None);
  1071.             
  1072.             XConvertSelection(display,
  1073.                               XA_PRIMARY, XA_STRING,
  1074.                               selection_buffer, win, now);
  1075.             
  1076.             time_started = time(NULL);
  1077.  
  1078.             while (1) {
  1079.                 if (XCheckTypedWindowEvent(display,
  1080.                                            win,
  1081.                                            SelectionNotify,
  1082.                                            &event))
  1083.                     break;
  1084.                 
  1085.                 time_t now = time(NULL);
  1086.  
  1087.                 if (time_started > now)
  1088.                     time_started = now;
  1089.  
  1090.                 if (now - time_started > 5000)
  1091.                     return -1;
  1092.             }
  1093.  
  1094.             /*do
  1095.             {
  1096.                 XNextEvent(display, &event);
  1097.             } while (event.type != SelectionNotify &&
  1098.                      event.xselection.property != None &&
  1099.                      event.type != ButtonPress);*/
  1100.  
  1101.             if (event.type == SelectionNotify && event.xselection.property != None)
  1102.             {
  1103.                  XGetWindowProperty(display,
  1104.                                    event.xselection.requestor,
  1105.                                    event.xselection.property,
  1106.                                    0L, 0x10000, True,
  1107.                                    event.xselection.target, &type, &i,
  1108.                                    (unsigned long *)&l,
  1109.                                    (unsigned long *)&extra,
  1110.                                    (unsigned char **)data);
  1111.  
  1112.                 *len = l;
  1113.                 return 0;
  1114.             }
  1115.             return -1;
  1116.         }
  1117.     }
  1118.     *data = XFetchBytes(display, len);
  1119.     if (*data == 0)
  1120.     return -1;
  1121.     else
  1122.     return 0;
  1123. }
  1124.  
  1125. int SetXSelection(int len, char *data) {
  1126.     if (CurSelectionData != 0) {
  1127.         free(CurSelectionData);
  1128.         CurSelectionData = 0;
  1129.         CurSelectionLen = 0;
  1130.     }
  1131.     CurSelectionData = (char *)malloc(len);
  1132.     if (CurSelectionData == 0)
  1133.         return -1;
  1134.     CurSelectionLen = len;
  1135.     memcpy(CurSelectionData, data, CurSelectionLen);
  1136.     if (CurSelectionLen < 64 * 1024) {
  1137.         XStoreBytes(display, data, len);
  1138.         XSetSelectionOwner (display, XA_PRIMARY, win, CurrentTime);
  1139.         if (XGetSelectionOwner(display, XA_PRIMARY) == win)
  1140.             CurSelectionOwn = 1;
  1141.     } else {
  1142.         XSetSelectionOwner (display, XA_PRIMARY, None, CurrentTime);
  1143.     }
  1144.     return 0;
  1145. }
  1146.  
  1147. GUI::GUI(int &argc, char **argv, int XSize, int YSize) {
  1148.     int o = 1;
  1149.     for (int c = 1; c < argc; c++) {
  1150.         if (strcmp(argv[c], "-font") == 0) {
  1151.             if (c + 1 < argc) {
  1152.                 strcpy(WindowFont, argv[c + 1]);
  1153.                 c += 1;
  1154.             }
  1155.         } else if (strcmp(argv[c], "-geometry") == 0) {
  1156.             if (c + 1 < argc) {
  1157.                 
  1158.                 XParseGeometry(argv[c + 1],
  1159.                                &initX, &initY, &ScreenCols, &ScreenRows);
  1160.                 if (ScreenCols > 255)
  1161.                     ScreenCols = 255;
  1162.                 if (ScreenRows > 255)
  1163.                     ScreenRows = 255;
  1164.                 setUserPosition = 1;
  1165.                 c += 1;
  1166.             }
  1167.         } else
  1168.             argv[o++] = argv[c];
  1169.     }
  1170.     argc = o;
  1171.     argv[argc] = 0;
  1172.     
  1173.     fArgc = argc;
  1174.     fArgv = argv;
  1175.  
  1176.     if (::ConInit(XSize, YSize) == 0)
  1177.         gui = this;
  1178.     else
  1179.         gui = 0;
  1180. }
  1181.  
  1182. GUI::~GUI() {
  1183.     ::ConDone();
  1184.     gui = 0;
  1185. }
  1186.  
  1187. int GUI::ConSuspend(void) {
  1188.     return ::ConSuspend();
  1189. }
  1190.  
  1191. int GUI::ConContinue(void) {
  1192.     return ::ConContinue();
  1193. }
  1194.  
  1195. int GUI::ShowEntryScreen() {
  1196.     return 1;
  1197. }
  1198.  
  1199. int GUI::OpenPipe(char *Command, EModel *notify) {
  1200.     int i;
  1201.     
  1202.     for (i = 0; i < MAX_PIPES; i++) {
  1203.         if (Pipes[i].used == 0) {
  1204.             int pfd[2];
  1205.             
  1206.             Pipes[i].id = i;
  1207.             Pipes[i].notify = notify;
  1208.             Pipes[i].stopped = 1;
  1209.             
  1210.             if (pipe((int *)pfd) == -1)
  1211.                 return -1;
  1212.             
  1213.             switch (Pipes[i].pid = fork()) {
  1214.             case -1: /* fail */
  1215.                 return -1;
  1216.             case 0: /* child */
  1217.                 signal(SIGPIPE, SIG_DFL);
  1218.                 close(pfd[0]);
  1219.                 close(0);
  1220.                 assert(open("/dev/null", O_RDONLY) == 0);
  1221.                 dup2(pfd[1], 1);
  1222.                 dup2(pfd[1], 2);
  1223.                 close(pfd[1]);
  1224.                 exit(system(Command));
  1225.             default:
  1226.                 close(pfd[1]);
  1227.                 fcntl(pfd[0], F_SETFL, O_NONBLOCK);
  1228.                 Pipes[i].fd = pfd[0];
  1229.             }
  1230.             Pipes[i].used = 1;
  1231.             //fprintf(stderr, "Pipe Open: %d\n", i);
  1232.             return i;
  1233.         }
  1234.     }
  1235.     return -1;
  1236. }
  1237.  
  1238. int GUI::SetPipeView(int id, EModel *notify) {
  1239.     if (id < 0 || id > MAX_PIPES)
  1240.         return -1;
  1241.     if (Pipes[id].used == 0)
  1242.         return -1;
  1243.     //fprintf(stderr, "Pipe View: %d %08X\n", id, notify);
  1244.     Pipes[id].notify = notify;
  1245.     return 0;
  1246. }
  1247.  
  1248. int GUI::ReadPipe(int id, void *buffer, int len) {
  1249.     int rc;
  1250.     
  1251.     if (id < 0 || id > MAX_PIPES)
  1252.         return -1;
  1253.     if (Pipes[id].used == 0)
  1254.         return -1;
  1255.     //fprintf(stderr, "Pipe Read: Get %d %d\n", id, len);
  1256.     
  1257.     rc = read(Pipes[id].fd, buffer, len);
  1258.     //fprintf(stderr, "Pipe Read: Got %d %d\n", id, len);
  1259.     if (rc == 0) {
  1260.         close(Pipes[id].fd);
  1261.         Pipes[id].fd = -1;
  1262.         return -1;
  1263.     }
  1264.     if (rc == -1) {
  1265.         Pipes[id].stopped = 1;
  1266.         return 0;
  1267.     }
  1268.     return rc;
  1269. }
  1270.  
  1271. int GUI::ClosePipe(int id) {
  1272.     int status;
  1273.     
  1274.     if (id < 0 || id > MAX_PIPES)
  1275.         return -1;
  1276.     if (Pipes[id].used == 0)
  1277.         return -1;
  1278.     if (Pipes[id].fd != -1)
  1279.         close(Pipes[id].fd);
  1280.     kill(Pipes[id].pid, SIGHUP);
  1281.     alarm(2);
  1282.     waitpid(Pipes[id].pid, &status, 0);
  1283.     alarm(0);
  1284.     //fprintf(stderr, "Pipe Close: %d\n", id);
  1285.     Pipes[id].used = 0;
  1286.     return WEXITSTATUS(status);
  1287. }
  1288.  
  1289. int GUI::RunProgram(char *Command) {
  1290.     char Cmd[1024];
  1291.     
  1292.     if (*Command == 0)  // empty string = shell
  1293.         strcpy(Cmd, "xterm");
  1294.     else {
  1295.         strcpy(Cmd, "xterm -e ");
  1296.         strcat(Cmd, Command);
  1297.     }
  1298.     strcat(Cmd, " &");
  1299.     
  1300.     rc = system(Cmd);
  1301.     
  1302.     return rc;
  1303. }
  1304.  
  1305. char ConGetDrawChar(int index) {
  1306.     static char tab[] = "\x0D\x0C\x0E\x0B\x12\x19____+>\x1F\x01\x12 ";
  1307.     
  1308.     assert(index >= 0 && index < strlen(tab));
  1309.     
  1310.     return tab[index];
  1311. }
  1312.