RFBSurface.cs :  » Network-Clients » VNC-Client » VNC » RFBDrawing » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Network Clients » VNC Client 
VNC Client » VNC » RFBDrawing » RFBSurface.cs
using System;
using System.Drawing;
using System.Net.Sockets;
using System.Reflection;
using VNC.RFBProtocolHandling;
using System.Collections;
using System.Threading;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using DrawingSupport;
using VNC.RFBDrawing.UpdateDecoders;
using VNC.RFBDrawing.PixelDecoders;
using VNC.Config;
// Zlib libary  
using NZlib.Compression;
using VNC.zlib;


// author: Dominic Ullmann, dominic_ullmann@swissonline.ch
// Version: 1.03
  
// VNC-Client for .NET
// Copyright (C) 2002  Dominic Ullmann

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.



namespace VNC.RFBDrawing{


  /// <summary>
  /// The RFBSurface class contains the data of the remote frame buffer and handles updates of the
  /// remote frame buffer
  /// </summary>
  public class RFBSurface { 

    /// <summary> reference to protocol-Handler </summary>
    private RFBProtocolHandler protocolHandler;    

    private int bufferWidth, bufferHeight;
    /// <summary> the width of the remote framebuffer </summary>
    public int BufferWidth {
      get { if (!connected) { throw new Exception("not connected"); }
          return bufferWidth; }
    }
    /// <summary> the height of the remote framebuffer </summary>
    public int BufferHeight {
      get { if (!connected) { throw new Exception("not connected"); }
          return bufferHeight; }
    }
    private byte depth;
    /// <summary> the depth selected for usage at client side. The depth is choosable by the client during connection handshake </summary>
    public byte Depth {
      get { if (!connected) { throw new Exception("not connected"); }
          return depth; }
    }

    /// <summary> the vies connected to this surface </summary>
    private ArrayList views = new ArrayList();
    private System.Drawing.Imaging.PixelFormat format;
    /// <summary> decodes pixelvalues from stream </summary>
    private PixelDecoder pixDecod; 
    /// <summary> the drawSupport object: facility for drawing </summary>
    private DrawSupport drawSup;
    
    /// <summary> the decoders for decoding updates, O(1) access in normal case </summary>
    private Hashtable decoders = new Hashtable();
    /// <summary> the decoders sorted by the priority the client wishes to use them </summary>
    private ArrayList decoderPriorities = new ArrayList();
    
    private string serverName;
    /// <summary> the name of the server received during connection establishment </summary>
    public string ServerName {
      get {  if (!connected) { throw new Exception("not connected"); }
          return serverName;   }  
    }
    
    /// <summary> the configuration information </summary>
    private VNCConfiguration config;
    
    // server, port: the information needed for connection to the VNC-Server
    private String server;
    private int port;
    
    private bool connected;
    /// <summary> is this surface has an established connection to a VNC-Server </summary>
    public bool Connected {
      get { return connected; }
    }
          
    /// <summary> constructor for an RFBSurface </summary>
    /// <param name="server">the server to connect to</param>
    /// <param name="port">the port to connect to</param>
    /// <param name="config">the configuration information read from the config-file</param>            
    public RFBSurface(String server, int port, VNCConfiguration config) {
      this.server = server;
      this.port = port;
      this.config = config;
      // create the decoders, after the handshake is complete, the decoders are initalized (before starting listening to regular messages)
      createDecoders();      
    }    

    // ****************************************************************************************************************
    // ************************************ methods for connecting and disconnecting the surface 
    // ****************************************************************************************************************

    /// <summary> Register views to notify
    /// Views displays the content of the RFBSurface
    /// </summary>
    internal void connectSurfaceToView(RFBView view) {
      Monitor.Enter(this);
      if (views.Contains(view)) { Monitor.Exit(this); throw new Exception("surface already connected to view"); }

      if (views.Count == 0) { // first view connected
        views.Add(view);        
        // connecting surface
        establishConnection(server, port);
        
        // creating draw-Support:
        if (config.DrawType == DrawTypes.GDIPlus) {
          // GDI+:
          drawSup = new DrawDotNetSupport(format, bufferWidth, bufferHeight, depth);  
        } else if (config.DrawType == DrawTypes.DirectDraw) {
          // DirectX:
          drawSup = new DirectXDrawSupport(format, bufferWidth, bufferHeight, depth, this);  
        } else {
          // this can only be the case, during development of new drawTypes
          Console.WriteLine("a drawType that is not known encountered in RFBSurface: " + config.DrawType);
          Monitor.Exit(this);
          throw new Exception("drawtype not ok: " + config.DrawType);
        }
      
        view.setRFBSize(bufferWidth, bufferHeight);
        // provide draw-Support Object to get access to drawing facilities
        view.setDrawSupport(drawSup);
        // initalize the decoders
        connectDecoders();

        // start listening for regular server-messages  
        protocolHandler.startMessageProcessing(); // now ready to receive noninitalization-messages from RFBServer!        
        // send update request to server, to get content of the RFB
        getFullUpdate();
      } else { // not the first view: enqueue only
        views.Add(view);
        view.setRFBSize(bufferWidth, bufferHeight);
        // provide draw-Support Object to get access to drawing facilities
        try {
          view.setDrawSupport(drawSup);        
        } catch (Exception e) {
          // Exception: removing the view from the view-List, leaving the monitor! and rethrow exception
          disconnectView(view);
          Monitor.Exit(this);
          throw e;
        }
      }
      
      Monitor.Exit(this);      
    }

    /// <summary> disconnect a view from the surface </summary>
    internal void disconnectView(RFBView view) {
      Monitor.Enter(this); /* synchronize with adding/notification */
      views.Remove(view);
      if (views.Count == 0) {
        // last view disconnected: closing connection
        closeConnection();
      }
      Monitor.Exit(this);
    }
    
    /// <summary> is called, when last view gets disconnected </summary>
    public void closeConnection() {
      protocolHandler.closeConnection();
      drawSup.Dispose();
    }

    /// <summary> connects this RFBSurface to the RFBServer,
    /// afterwards this surface stores pixeldata and informs the server of
    /// events
    /// </summary>
    private void establishConnection(string server, int port) {
      // creating Connection-Handler for Connection to the RFB-Server
      
      protocolHandler = new RFBProtocolHandler(server, port, this);
      ServerData data = protocolHandler.handshake();

      bufferWidth = data.fbWidth;
      bufferHeight = data.fbHeight;
      serverName = data.serverName;
      depth = data.pixForm.depth;

      // creating buffer and decoder
      // chooses the format I like and sending setFormat to Server
      // decoder: strategy-pattern for short decoding routines
      switch (depth) {
        case 8:  // bitsPerPixel = 8;
           // 8bit not supported, use 16bit
           depth = 16;
           goto case 16;
        case 16: // bitsPerPixel = 16;
           // inputBuffer = new byte[bufferWidth * bufferHeight * 2]; // creating reading buffer
           format = System.Drawing.Imaging.PixelFormat.Format16bppRgb565;
           pixDecod = new Pixel16bitDecoder(); 
           Console.WriteLine("16 bit modus selected");
           break;
        case 24: // bitsPerPixel = 32;
           // inputBuffer = new byte[bufferWidth*bufferHeight * 3]; // creating reading buffer
           format = System.Drawing.Imaging.PixelFormat.Format24bppRgb;
           pixDecod = new Pixel24bitDecoder();
            Console.WriteLine("24 bit modus selected");
           break;
        case 32: // bitsPerPixel = 32;
          //  inputBuffer = new byte[bufferWidth*bufferHeight * 4]; // creating reading buffer
           format = System.Drawing.Imaging.PixelFormat.Format32bppRgb;
           pixDecod = new Pixel32bitDecoder();
            Console.WriteLine("32 bit modus selected");
           break;
        default:
          // error
          throw new Exception("Server-Depth not supported!");
      }  
    
      // sending setPixelFormat-Message:
      // the format is defined by the choosen decoder
      protocolHandler.sendSetPixelFormat(pixDecod.getFormatDescription());
      // sends supported encodings
      protocolHandler.sendSetEncodings(decoderPriorities);
      // listening is started, when surface is connected to a View
      connected = true; // here the connection handshake is completed, connection to the server is ok
      Console.WriteLine("framebuffer size: " + bufferWidth + " " + bufferHeight);        
    }
    
    /// <summary> create the configured Decoders. </summary>
    /// <remarks> for extending the RFB-Protocol by an own decoder, add it to the decoder section
    /// in the VNCClient.Config.xml file.
    /// Use the fully qualified name of the decoder in the config-file.
    /// If the decoder is in a separate dll, append the name of the dll to the name after a comma,
    /// eg. VNC.RFBDrawing.UpdateDecoders.MyOwnDecoder,decoder for MyOwnDecoder in decoder.dll
    /// A decoder which should be usable here, must provide a no-argument constructor.
    /// </remarks>
    private void createDecoders() {  
      // use the decoders from the config
      int nrOfDecodersWorking = 0;
      foreach (String dec in config.Decoders) {
        // try to instantiate the decoder
        try {
          Type decoderType = Type.GetType(dec, true);
          Decoder decoder = (Decoder) decoderType.Assembly.CreateInstance(decoderType.FullName);
          registerDecoder(decoder);
          nrOfDecodersWorking++;
          // Console.WriteLine("created decoder " + dec + ": " + decoder);  
        } catch (Exception e) {
          Console.WriteLine("WARNING: error instantiating decoder " + dec + ": " + e);
        }
      }
      if (nrOfDecodersWorking == 0) { throw new Exception("no decoders could be instantiated!"); }
    }
    
    /// <summary> registers a Decoder in the order the client wishes to use it, highest priority decoder
    /// must be registered first
    /// </summary>
    private void registerDecoder(Decoder decoder) {
      // add in list, sorted by priority the client wishes to use decoder
      decoderPriorities.Add(decoder);
    }
    
    /// <summary> connect the decoders to the DrawSupport instance; after completion of this method, the decoders are usable </summary>
    private void connectDecoders() {
      foreach (Decoder decoder in decoderPriorities) {
        decoder.initalize(this, protocolHandler.Stream, pixDecod, drawSup);
        // add for accessing decoder
        decoders[decoder.getEncodingNr()] = decoder;
      }
    }
    
    // *******************************************************************************
    // ****************** methods used during regular rfb-protocol message exchange
    // *******************************************************************************
    
    /// <summary> gets a full update from the server </summary>
    public void getFullUpdate() {
      // send update request to server, to get content of the RFB
      protocolHandler.sendFBNonIncrementalUpdateRequest(0, 0, (ushort)bufferWidth, (ushort)bufferHeight);
    }
        
    /// <summary> notify interested views, changement discribed by x,y,width,height </summary>
    private void notifyView(int x, int y, int width, int height) {
      Monitor.Enter(this); /* synchronize with adding/removing of views */
         IEnumerator enumerator = views.GetEnumerator();
         while (enumerator.MoveNext()) {
           ((RFBView)enumerator.Current).notifyUpdate(x,y,width,height);
         }
         Monitor.Exit(this);
    }
    
    /// <summary>
    /// decodes a received update with the encoding encoding
    /// </summary>
    public void decodeUpdate(uint encoding, ushort xpos, ushort ypos, ushort width, ushort height) {
      // get the decoder for this update
      Decoder dec = (Decoder)decoders[encoding];
      if (dec == null) {
        Console.WriteLine("encoding not supported: " + encoding + "; check the VNCClient.config.xml if a decoder should be present!");  
        throw new Exception("encoding not Supported: " + encoding);
      }
      // update is decoded and drawn by the Decoder
      dec.decode(xpos, ypos, width, height);
    }

    /// <summary>
    /// this method decides what to do on an update receiving
    /// </summary>
    public void gotRFBUpdate() {
      // sending network-events as early as possible to reduce delay
      
      // sending a new update request to stay informed of changes of the remote frame buffer
      // incremental updated are ok, because the buffer contains a probably old, but valid content
      protocolHandler.sendFBIncrementalUpdateRequest(0, 0, (ushort)bufferWidth, (ushort)bufferHeight);
    }
        
    /// <summary>
    /// this method decides how to proceed after a successful update of the framebuffer
    /// </summary>
    public void updateDone(int minX, int minY, int maxX, int maxY) {
      // draw the update to the screen!
      notifyView(minX, minY, maxX-minX, maxY-minY);
    }
    
    /// <summary>
    /// new cutbuffer content at the server
    /// </summary>
    public void serverCutText(RFBNetworkStream stream) {
      // the server has new date in its cutBuffer
      for (int i = 0; i < 3; i++) {
        stream.ReadByte();
      }
      uint length = stream.ReadCard32();
      String buf = stream.ReadString(length);
      // Insert data into Clipboard:
      Clipboard.SetDataObject(buf, true);
    }
    /// <summary>
    /// handling a beep received from server, dummy implementation at the moment
    /// (how to play sound using only safe code)
    /// </summary>    
    public void beep() {
      // handling a beep received from Server
      Console.WriteLine("beep");
    }
    
    /// <summary> reading a color-Map: unsopperted by this client </summary>
    public void setColorMapEntries(RFBNetworkStream stream) {
      ushort firstColor = stream.ReadCard16();
      ushort numberOfColors = stream.ReadCard16();
      for (int i = 0; i < numberOfColors; i++) {
        ushort red = stream.ReadCard16();
        ushort green = stream.ReadCard16();
        ushort blue = stream.ReadCard16();
      }
      Console.WriteLine("Ignoring setColormap-Entry because of Client-specified colors!");
    }

    // --------------
    // Event-Handling
    // --------------
    /// <summary> handles a pointer event, used by the connected views to inform the surface </summary>
    public void handlePointerEvent(byte buttonMask, ushort x, ushort y) {
      // for slow connections: it would be possible to drop some events, but this slows down faster
      // connections
      protocolHandler.sendPointerEvent(buttonMask, x, y);
    }
    
    /// <summary> handles a key event, used by the connected views to inform the surface </summary>
    public void handleKeyEvent(uint keySym, bool pressed) {
      protocolHandler.sendKeyEvent(keySym, pressed);
    }
    
    /// <summary> user wants to paste CutBuffer-Contents to server </summary>
    public void sendClientCutText() {
      IDataObject data = Clipboard.GetDataObject();
      if(data.GetDataPresent(DataFormats.Text)) {
             String text = (String)data.GetData(DataFormats.Text); 
             // sending to server cut buffer
          protocolHandler.setClientCutText(text);
        } else {
          Console.WriteLine("no Text data in Clipboard present!)");
        }
    }
        
  }

}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.