home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / vpbgib2.zip / GRAPHSRV.PAS < prev    next >
Pascal/Delphi Source File  |  1996-11-02  |  14KB  |  480 lines

  1. {█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█}
  2. {█                                                       █}
  3. {█      Virtual Pascal v1.1                              █}
  4. {█      BGI Graphics Server for mixed BGI/Textmode       █}
  5. {█      ─────────────────────────────────────────────────█}
  6. {█      Copyright (C) 1996 fPrint UK Ltd                 █}
  7. {█        Written May-Sep 1996 by Allan Mertner          █}
  8. {█        Pipe interface engineered by Alex Vermeulen    █}
  9. {█                                                       █}
  10. {▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀}
  11.  
  12. program GraphSrv;
  13.  
  14. {&PMTYPE PM}
  15. {$Delphi+}
  16.  
  17. uses Use32, Dos, Os2Def, Os2Base, Strings, Dgraph, BGImsg, SysUtils, VPUtils;
  18.  
  19. const
  20.   Stopping : boolean = false;
  21.  
  22. var
  23.   que  : HQueue;       // Queue used to notify about input
  24.  
  25. {-----[ Graph Server wrappers for Image functions ]-----}
  26.  
  27. function SrvGetImage( x1, y1, x2, y2: Longint; Buffer: Pointer ): uLong;
  28. var
  29.   rc: ApiRet;
  30.  
  31. begin
  32.   // Get access to shared memory
  33.   rc := DosGetSharedMem( Buffer, pag_Write );
  34.   if rc = 0 then
  35.     begin
  36.       GetImage( x1, y1, x2, y2, Buffer^ );
  37.  
  38.       // Release access to shared memory
  39.       DosFreeMem( Buffer );
  40.       SrvGetImage := 0;
  41.     end
  42.   else
  43.     SrvGetImage := rc;
  44. end;
  45.  
  46. function SrvPutImage( x, y: Longint; Buffer: Pointer; Mode: Longint ): uLong;
  47. var
  48.   rc: ApiRet;
  49.  
  50. begin
  51.   // Get access to shared memory
  52.   rc := DosGetSharedMem( Buffer, pag_Read or pag_Write );
  53.   if rc = 0 then
  54.     begin
  55.       PutImage( x, y, Buffer^, Mode );
  56.  
  57.       // Release access to shared memory
  58.       DosFreeMem( Buffer );
  59.       SrvPutImage := 0;
  60.     end
  61.   else
  62.     SrvPutImage := rc;
  63. end;
  64.  
  65. {-----[ Graph Server input handler ]-----}
  66.  
  67. // SendKeyStroke: Send keystroke notification to client
  68. function InputThread( p: Pointer ): ApiRet;
  69. var
  70.   rc: ApiRet;
  71.   data: pInputT;
  72.   Buffer : pInputArrayT;
  73.   M: MouseEventRecT;
  74.   Inx: Word;
  75.  
  76.   function NextData: pInputT;
  77.   begin
  78.     NextData := @Buffer^[Inx];
  79.     Inc(Inx);
  80.     if Inx > MaxInput then
  81.       Inx := 0;
  82.   end;
  83.  
  84. begin
  85.   // Allocate memory buffer for talking to client process
  86.   rc := DosAllocSharedMem( Pointer(Buffer), nil, Sizeof(InputArrayT),
  87.     pag_read or pag_write or pag_commit or obj_gettable );
  88.   Inx := 0;
  89.  
  90.   // Tell client the address of the memory
  91.   Data := NextData;
  92.   rc := DosWriteQueue( que, bgi_Init, Sizeof(Data), Data, 0 );
  93.  
  94.   while not Stopping do
  95.     begin
  96.       if KeyPressed then
  97.         begin
  98.           Data := NextData;
  99.           data^.Ch := ReadKey;
  100.           rc := DosWriteQueue( que, bgi_Key, Sizeof(Data), Data, 0 );
  101.         end
  102.       else if MouseMoved then
  103.         begin
  104.           MouseMoved := False;
  105.           Data := NextData;
  106.           data^.X := CurrentMouseX;
  107.           data^.Y := CurrentMouseY;
  108.           rc := DosWriteQueue( que, bgi_mPos, Sizeof(Data), Data, 0 );
  109.         end
  110.       else if MouseClicked then
  111.         begin
  112.           Data := NextData;
  113.           GetMouseEvent( M );
  114.           data^.EventX := M.X;
  115.           data^.EventY := M.Y;
  116.           data^.EventType := Byte(M.Event);
  117.           rc := DosWriteQueue( que, bgi_Mou, Sizeof(Data), Data, 0 );
  118.         end
  119.       else
  120.         DosSleep( 31 );
  121.     end;
  122.   DosFreeMem( Buffer );
  123. end;
  124.  
  125. {-----[ Graph Server error handlers ]-----}
  126.  
  127. type
  128.   EGraphSrv = class(Exception);
  129.  
  130. procedure Error( No: Integer; s: String; rc: Longint );
  131. begin
  132.   Case No of
  133.     1 : raise EGraphSrv.CreateFmt( 'Cannot open BGI pipe %s. Maybe another instance is already running.', [s] );
  134.     2 : raise EGraphSrv.CreateFmt( 'Cannot create semaphore %s; rc = %d', [s, rc] );
  135.     3 : raise EGraphSrv.CreateFmt( 'Cannot link named pipe and semaphore; rc = %d', [rc] );
  136.     4 : raise EGraphSrv.CreateFmt( 'Cannot read data from pipe; rc = %d', [rc] );
  137.     5 : raise EGraphSrv.CreateFmt( 'Cannot send result to client; rc = %d', [rc] );
  138.     6 : raise EGraphSrv.Create( 'SetTextStyle failed; check BGIPath' );
  139.     7 : raise EGraphSrv.CreateFmt( 'Cannot connect to pipe; rc = %d', [rc] );
  140.     8 : raise EGraphSrv.CreateFmt( 'Cannot open queue %s; rc = %d', [s, rc] );
  141.   else
  142.     raise EGraphSrv.CreateFmt( 'Unknown error occured; rc = %d', [rc] );
  143.   end;
  144.   Halt( No );
  145. end;
  146.  
  147. {-----[ Graph Server pipe handler and message dispatcher ]-----}
  148.  
  149. var
  150.   pip  : HPipe;        // Pipe used to talk to client
  151.   hevn : HEv;          // Event semaphore associated with pipe
  152.  
  153. procedure openpipe( Name: String );
  154. var
  155.   rc: ApiRet;
  156.   MyName: String;
  157.   Pid: ULong;
  158.  
  159. begin
  160.   // Create named pipe for communicating with client
  161.   name[Length(name)+1] := #0;
  162.   rc:=DosCreateNPipe( @Name[1],pip,NP_ACCESS_DUPLEX,  // Duplex pipe
  163.                       NP_WAIT OR
  164.                       NP_WMESG OR                     // Write messages
  165.                       NP_RMESG OR                     // Read messages
  166.                       1,                              // Unique instance of pipe
  167.                       256,                            // Output buffer size
  168.                       4096*sizeof(Word),              // Input buffer size
  169.                       1000);                          // Use default time-out
  170.   if rc <> No_Error then
  171.     Error( 1, Name, rc );
  172.  
  173.   // Create event semaphore to link with pipe
  174.   while pos( '\', Name ) <> 0 do
  175.     Delete( Name, 1, pos( '\', Name ) );
  176.   MyName := '\SEM32\' + name+#0;
  177.   rc := DosCreateEventSem( @Myname[1], hevn, 0, false );
  178.   if rc <> No_Error then
  179.     Error( 2, MyName, rc );
  180.  
  181.   // Link semaphore and pipe together
  182.   rc := DosSetNPipeSem( Pip, hsem(hevn), 1);
  183.   if rc <> No_Error then
  184.     Error( 3, '', rc );
  185.  
  186.   // Connect to the pipe
  187.   rc := DosConnectNPipe(Pip);
  188.   if rc <> No_Error then
  189.     Error( 7, '', rc );
  190.  
  191.   // Create queue for transmitting input events
  192.   MyName := '\QUEUES\' + name+#0;
  193.   rc := DosOpenQueue( Pid, que, @MyName[1] );
  194.   if rc <> No_Error then
  195.     Error( 8, MyName, rc );
  196. end;
  197.  
  198. // WaitForConn: Wait for client to connect to the pipe
  199. procedure WaitForConn;
  200. var
  201.   rc     : ApiRet;
  202.   Buffer : Longint;
  203.   fRead  : Longint;
  204.   fAvail : AvailData;
  205.   fState : Longint;
  206.  
  207. begin
  208.   repeat
  209.     // Have a look at the pipe data
  210.     rc := DosPeekNPipe(pip, Buffer, 0, fRead, fAvail, fState);
  211.     if rc <> 0 then
  212.       Stopping := True;
  213.     if fAvail.cbPipe = 0 then
  214.       begin
  215.         // No data available in pipe
  216.         if fState in [ np_state_Disconnected, np_State_Closing ] then
  217.           begin
  218.             // If exiting, return EOF
  219.             Stopping := True;
  220.             Exit;
  221.           end;
  222.         // No data: Wait a little before retrying
  223.         DosSleep( 31 );
  224.       end;
  225.     // Stay in loop until data received
  226.   until ( rc = No_Error ) and ( fAvail.cbPipe <> 0 );
  227. end;
  228.  
  229. procedure ProcessBGIMessages;
  230. var
  231.   point   : ^CommandListT;
  232.   nrpar   : word;
  233.   len     : word;
  234.   cmd     : word;
  235.   lineS   : LineSettingsType;
  236.   ArcC    : ArcCoordsType;
  237.   Pal     : PaletteType;
  238.   Fill    : FillPatternType;
  239.   FillI   : FillSettingsType;
  240.   textS   : TextSettingsType;
  241.   View    : ViewPortType;
  242.   State   : Ulong;
  243.   rc      : ApiRet;
  244.   Ptr     : word;
  245.   res     : BGIResArT;
  246.   ulBytesR: uLong;
  247.   ulBytes : uLong;
  248.   r       : DisplayListT;
  249.  
  250. begin
  251.   repeat
  252.     repeat
  253.       rc := DosRead(Pip,                  { Handle of pipe }
  254.                     r,                    { Buffer for message read }
  255.                     sizeof(DisplayListT), { Buffer size }
  256.                     ulBytesR);            { Number of bytes actually read }
  257.       if rc = Error_No_Data then
  258.         WaitForConn;
  259.     until (rc <> error_no_Data) or Stopping;
  260.  
  261.     if rc <> No_Error then
  262.       // Error; cannot normally occur, since we know that there are
  263.       // data in the pipe
  264.       Error( 4, '', rc );
  265.  
  266.     // Stop DIVE from refreshing the display while drawing
  267.     SuspendRefresh;
  268.     Ptr    :=0;
  269.     res[0] :=0;
  270.  
  271.     // Process all messages
  272.     while Ptr < ulBytesR div Sizeof(word) do
  273.     begin
  274.       cmd   := r.w[Ptr];      // Command number
  275.       nrpar := r.w[Ptr+1];    // Parameter count
  276.       len   := r.w[Ptr+2];    // Length of expected return value
  277.       point := @r.w[Ptr+3];   // Array of points (x,y)
  278.  
  279.       // Execute one command
  280.       with point^ do
  281.         case cmd of
  282.           1: Arc(x1,y1,w3,w4,w5);
  283.           2: Bar(x1,y1,x2,y2);
  284.           3: Bar3D(x1,y1,x2,y2,w5,w6=1);
  285.           4: Circle(x1,y1,w3);
  286.           5: ClearDevice;
  287.           6: ClearViewPort;
  288.           7: CloseGraph;
  289.           8: DetectGraph(res[0],res[1]);
  290.           9: DrawPoly(nr,pts);
  291.           10: Ellipse(x1,y1,w3,w4,w5,w6);
  292.           11: FillEllipse(x1,y1,w3,w4);
  293.           12: FillPoly(nr,pts);
  294.           13: FloodFill(x1,y1,w3);
  295.           14: begin GetArcCoords(ArcC);move(arcC,res,sizeof(arcC)) end;
  296.           15: GetAspectRatio(res[0],res[1]);
  297.           16: res[0]:=getBkColor;
  298.           17: res[0]:=GetColor;
  299.           18: begin GetDefaultpalette(Pal);move(Pal,res,sizeof(Pal)) end;
  300.           19: begin s:=GetDriverName;move(s,res,sizeof(s)) end;
  301.           20: begin GetFillPattern(Fill);move(fill,res,sizeof(fill)) end;
  302.           21: begin GetFillSettings(FillI);move(fillI,res,sizeof(fillI)) end;
  303.           22: res[0]:=GetGraphMode;
  304.           23: res[0]:=SrvGetImage( x1, y1, x2, y2, Pointer(i[4]) );
  305.           24: begin getlinesettings(lineS);move(lineS,res,sizeof(lineS)) end;
  306.           25: res[0]:=GetMaxColor;
  307.           26: res[0]:=GetMaxX;
  308.           27: res[0]:=GetMaxY;
  309.           28: begin s:=getModeName(w1);move(s,res,sizeof(s)) end;
  310.           29: begin GetPalette(Pal); move(Pal,res,sizeof(Pal)) end;
  311.           30: res[0]:=GetPaletteSize;
  312.           31: res[0]:=GetPixel(x1,y1);
  313.           32: begin gettextsettings(textS);move(texts,res,sizeof(texts)) end;
  314.           33: begin getviewsettings(view);move(view,res,sizeof(view)) end;
  315.           34: res[0]:=GetX;
  316.           35: res[0]:=GetY;
  317.           36: GraphDefaults;
  318.           39: res[0]:=ImageSize(x1,y1,x2,y2);
  319.           41: res[0]:=InstallUserFont(s);
  320.           42: Line(x1,y1,x2,y2);
  321.           43: LineRel(x1,y1);
  322.           44: LineTo(x1,y1);
  323.           45: MoveRel(x1,y1);
  324.           46: MoveTo(x1,y1);
  325.           47: OutText(s);
  326.           48: OutTextXY(x1,y1,s);
  327.           49: PieSlice(x1,y1,w3,w4,w5);
  328.           50: res[0]:=SrvPutImage(x,y,Buffer,m);
  329.           51: PutPixel(x1,y1,w3);
  330.           52: Rectangle(x1,y1,x2,y2);
  331.           53: RegisterBGIFont(i1,pointer(w2));
  332.           54: Sector(x1,y1,w3,w4,w5,w6);
  333.           55: SetAllPalette(PaletteType(i[0]));
  334.           56: SetAspectRatio(w1,w2);
  335.           57: SetBkColor(w1);
  336.           58: SetColor(w1);
  337.           59: SetFillPattern(fillpatterntype(w[1]),w1);
  338.           60: SetFillStyle(w1,w2);
  339.           61: SetLineStyle(w1,w2,w3);
  340.           62: SetPalette(w1,w2);
  341.           63: SetRGBPalette(w1,w2,w3,w4);
  342.           64: SetTextJustify(w1,w2);
  343.           65: SetTextStyle(i1,i2,i3);
  344.           66: SetUserCharSize(w1,w2,w3,w4);
  345.           67: SetViewPort(x1,y1,x2,y2,w5=1);
  346.           68: SetWriteMode(i1);
  347.           69: res[0]:=TextHeight(s);
  348.           70: res[0]:=TextWidth(s);
  349.           71: SetWideFillPattern(newpatterntype(w[1]),w1);
  350.         else
  351.           // Ignore unknown commands
  352.         end;
  353.  
  354.         // Skip command and parameters
  355.         Inc(Ptr,nrpar+3);
  356.       end;
  357.  
  358.     // Re-enable DIVE refreshind the display
  359.     EnableRefresh;
  360.  
  361.     // Always send at least one word of acknowledgment to client
  362.     if len = 0 then
  363.       len := 1;
  364.  
  365.     if ulBytesR > 0 then
  366.       begin
  367.         rc:= DosWrite(Pip,              // Handle of pipe
  368.                       res,              // Buffer containing message to write
  369.                       len*sizeof(word), // Length of message
  370.                       ulBytes);         // Number of bytes actually written
  371.  
  372.         if rc <> No_Error then
  373.           Error( 5, '', rc );
  374.       end
  375.     else
  376.       // Check if connection is broken
  377.       WaitForConn;
  378.  
  379.   until ulBytesR = 0;
  380. end;
  381.  
  382. // Close pipe connection
  383. procedure shutconn;
  384. var
  385.   rc: ApiRet;
  386. begin
  387.   rc := DosCloseEventSem(hevn);
  388.   rc := DosDisConnectNPipe(Pip);
  389. end;
  390.  
  391. procedure ServerProcess;
  392. begin
  393.   // Open pipe for communications with client
  394.   OpenPipe(BGIPipeName);
  395.   // Start thread capturing input events
  396.   VPBeginThread( InputThread, 16384, nil );
  397.  
  398.   try
  399.     try
  400.       ClearDevice;
  401.       GraphDefaults;
  402.  
  403.       // Receive and execute BGI commands
  404.       repeat
  405.         if not Stopping then
  406.           ProcessBGIMessages;
  407.       until Stopping;
  408.  
  409.     except
  410.       // Ignore ^C but terminate.  This is also generated if the
  411.       // parent process is closed
  412.       on EControlC do ;
  413.     else
  414.       // Re-raise all other exceptions to display error message
  415.       raise;
  416.     end;
  417.   finally
  418.     // Close the DIVE window and pipe connection
  419.     CloseGraph;
  420.     ShutConn;
  421.   end;
  422. end;
  423.  
  424. var
  425.   ok          : Integer;
  426.   BGIPath     : String;
  427.  
  428. procedure ParseCmdLine;
  429. var
  430.   s : String;
  431.   x : Integer;
  432.  
  433. begin
  434.   // Set up defaults;
  435.   WaitKeypressed := False;
  436.   BGIPath := '';
  437.   x_Size := 640;
  438.   y_Size := 480;
  439.   // Process command line parameters
  440.   // -P<PipeName> sets the pipe name
  441.   // -X<Number>   sets the horizontal resolution
  442.   // -Y<Number>   sets the vertical resolution
  443.   // -B<Path>     sets the path to BP BGI fonts
  444.   for x:=1 to paramcount do
  445.     begin
  446.       s := ParamStr(x);
  447.       if s[1] IN ['/','-'] then
  448.         case upcase(s[2]) of
  449.           'P': begin
  450.                  BGIPipeName:=copy(s,3,length(s));
  451.                  WindowTitle:=copy(s,3,length(s));
  452.                end;
  453.           'X': Val(copy(s,3,length(s)),X_Size,ok);
  454.           'Y': Val(copy(s,3,length(s)),Y_Size,ok);
  455.           'B': begin
  456.                  BGIPath := s;
  457.                  Delete( BGIPath, 1, 2 );
  458.                end;
  459.         end;
  460.     end;
  461.  
  462.   if BGIPath = '' then
  463.     BGIPath := GetEnv( 'BGIDIR' );
  464. end;
  465.  
  466. begin
  467.   ParseCmdLine;
  468.  
  469.   // Initialise DIVE window
  470.   VPInitGraph( x_Size, y_Size, BGIPath );
  471.   ok := GraphResult;
  472.   if ok <> 0 then
  473.     raise EGraphSrv.CreateFmt( 'Error initialising GRAPH window; rc = %d', [ok] );
  474.  
  475.   ServerProcess;
  476. end.
  477.  
  478.  
  479.  
  480.