Initial prototype for embedded VNC framebuffer

This commit is contained in:
Daniel P. Berrange 2006-06-16 15:22:18 -04:00
parent 6529609d4b
commit 21b7ef51d7
8 changed files with 2028 additions and 11 deletions

View File

@ -2495,29 +2495,119 @@ Inactive virtual machines</property>
</child>
<child>
<widget class="GtkScrolledWindow" id="console-pane">
<widget class="GtkNotebook" id="console-pages">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
<property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
<property name="shadow_type">GTK_SHADOW_NONE</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<property name="show_tabs">True</property>
<property name="show_border">False</property>
<property name="tab_pos">GTK_POS_TOP</property>
<property name="scrollable">False</property>
<property name="enable_popup">False</property>
<child>
<widget class="GtkViewport" id="viewport2">
<widget class="GtkLabel" id="console-unavailable">
<property name="visible">True</property>
<property name="shadow_type">GTK_SHADOW_IN</property>
<property name="label" translatable="yes">&lt;b&gt;The console is currently unavailable&lt;/b&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="tab_expand">False</property>
<property name="tab_fill">True</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label87">
<property name="visible">True</property>
<property name="label" translatable="yes">Unavailable</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="type">tab</property>
</packing>
</child>
<child>
<widget class="GtkImage" id="console-screenshot">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
<packing>
<property name="tab_expand">False</property>
<property name="tab_fill">True</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label88">
<property name="visible">True</property>
<property name="label" translatable="yes">Screenshot</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="type">tab</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table7">
<property name="border_width">3</property>
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">3</property>
<property name="homogeneous">False</property>
<property name="row_spacing">3</property>
<property name="column_spacing">3</property>
<child>
<widget class="GtkLabel" id="label52">
<widget class="GtkLabel" id="label92">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;The console is currently unavailable&lt;/b&gt;</property>
<property name="label" translatable="yes">Password:</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
@ -2526,8 +2616,168 @@ Inactive virtual machines</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="console-auth-remember">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Save this password in your keyring</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="console-auth-password">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">False</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkButton" id="console-auth-login">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_console_auth_login_clicked" last_modification_time="Fri, 16 Jun 2006 17:48:10 GMT"/>
<child>
<widget class="GtkAlignment" id="alignment12">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">0</property>
<property name="yscale">0</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">0</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkHBox" id="hbox13">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">2</property>
<child>
<widget class="GtkImage" id="image29">
<property name="visible">True</property>
<property name="stock">gtk-yes</property>
<property name="icon_size">4</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label93">
<property name="visible">True</property>
<property name="label" translatable="yes">Login</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
<packing>
<property name="tab_expand">False</property>
<property name="tab_fill">True</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label89">
<property name="visible">True</property>
<property name="label" translatable="yes">Auth</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="type">tab</property>
</packing>
</child>
</widget>
<packing>

View File

@ -3,6 +3,8 @@ import gobject
import gtk.glade
import libvirt
from vncViewer.vnc import GRFBViewer
class vmmConsole(gobject.GObject):
__gsignals__ = {
"action-show-details": (gobject.SIGNAL_RUN_FIRST,
@ -37,6 +39,16 @@ class vmmConsole(gobject.GObject):
self.window.get_widget("control-snapshot").set_icon_widget(gtk.Image())
self.window.get_widget("control-snapshot").get_icon_widget().set_from_file(config.get_icon_dir() + "/icon_snapshot.png")
self.vncViewer = GRFBViewer()
scrolledWin = gtk.ScrolledWindow()
scrolledWin.add_with_viewport(self.vncViewer)
self.window.get_widget("console-pages").set_show_tabs(False)
self.window.get_widget("console-pages").append_page(scrolledWin, gtk.Label("VNC"))
scrolledWin.show()
self.vncViewer.show()
self.ignorePause = False
self.window.signal_autoconnect({
@ -49,11 +61,18 @@ class vmmConsole(gobject.GObject):
"on_control_terminal_clicked": self.control_vm_terminal,
"on_control_snapshot_clicked": self.control_vm_snapshot,
"on_control_details_clicked": self.control_vm_details,
"on_console_auth_login_clicked": self.try_login,
})
self.vm.connect("status-changed", self.update_widget_states)
self.update_widget_states(vm, vm.status())
self.vncViewer.connect("disconnected", self._vnc_disconnected)
self.try_login()
def show(self):
dialog = self.window.get_widget("vmm-console")
dialog.show_all()
@ -61,11 +80,36 @@ class vmmConsole(gobject.GObject):
def close(self,ignore1=None,ignore2=None):
self.window.get_widget("vmm-console").hide()
if self.vncViewer.is_connected():
self.vncViewer.disconnect()
return 1
def control_vm_run(self, src):
return 0
def _vnc_disconnected(self, src):
self.window.get_widget("console-auth-password").set_text("")
self.window.get_widget("console-pages").set_current_page(2)
def try_login(self, src=None):
password = self.window.get_widget("console-auth-password").get_text()
protocol, host, port = self.vm.get_console_info()
if protocol != "vnc" or self.vm.get_id() == 0:
self.window.get_widget("console-pages").set_curent_page(0)
return
if not(self.vncViewer.is_connected()):
self.vncViewer.connect_to_host(host, port)
if password and self.vncViewer.authenticate(password) == 1:
self.window.get_widget("console-pages").set_current_page(3)
self.vncViewer.activate()
else:
self.window.get_widget("console-auth-password").set_text("")
self.window.get_widget("console-pages").set_current_page(2)
def control_vm_shutdown(self, src):
status = self.vm.status()
if not(status in [ libvirt.VIR_DOMAIN_SHUTDOWN, libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_CRASHED ]):

View File

@ -24,6 +24,9 @@ class vmmDomain(gobject.GObject):
def get_connection(self):
return self.connection
def get_id(self):
return self.vm.ID()
def get_name(self):
return self.vm.name()
@ -222,5 +225,11 @@ class vmmDomain(gobject.GObject):
status = self.run_status()
return self.config.get_vm_status_icon(status.lower())
def get_console_info(self):
# XXX don't hardcode me! need to really extract info from
# the libvirt XML as & when the display device info gets
# added
return ["vnc", "localhost", 5900 + self.get_id()]
gobject.type_register(vmmDomain)

View File

View File

@ -0,0 +1,482 @@
#!/usr/bin/env python
##
## pyvnc2swf - crippled_des.py
##
## $Id: crippled_des.py,v 1.3 2005/08/25 20:01:59 euske Exp $
##
## Copyright (C) 2005 by Yusuke Shinyama (yusuke at cs . nyu . edu)
## All Rights Reserved.
##
## This 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 software 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 software; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
## USA.
##
## The following part of this file is taken from
## pyvncviewer by Chris Liechti.
## URL: http://homepage.hispeed.ch/py430/python/
# Modified DES encryption for VNC password authentication.
# Ported from realvnc's java viewer by <cliechti@gmx.net>
# I chose this package name because it is not compatible with the
# original DES algorithm, e.g. found pycrypto.
# Original notice following:
# This DES class has been extracted from package Acme.Crypto for use in VNC.
# The bytebit[] array has been reversed so that the most significant bit
# in each byte of the key is ignored, not the least significant. Also the
# unnecessary odd parity code has been removed.
#
# These changes are:
# Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
#
# This software 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.
#
# DesCipher - the DES encryption method
#
# The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is:
#
# Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
# without fee is hereby granted, provided that this copyright notice is kept
# intact.
#
# WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
# OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
# DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
#
# THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
# CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
# PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
# NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
# SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
# SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
# PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP
# SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
# HIGH RISK ACTIVITIES.
#
#
# The rest is:
#
# Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Visit the ACME Labs Java page for up-to-date versions of this and other
# fine Java utilities: http://www.acme.com/java/
#/ The DES encryption method.
# <P>
# This is surprisingly fast, for pure Java. On a SPARC 20, wrapped
# in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream,
# it does around 7000 bytes/second.
# <P>
# Most of this code is by Dave Zimmerman <dzimm@widget.com>, and is
# Copyright (c) 1996 Widget Workshop, Inc. See the source file for details.
# <P>
# <A HREF="/resources/classes/Acme/Crypto/DesCipher.java">Fetch the software.</A><BR>
# <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
# <P>
# @see Des3Cipher
# @see EncryptedOutputStream
# @see EncryptedInputStream
import struct
class DesCipher:
# Constructor, byte-array key.
def __init__(self, key):
self.setKey(key)
#/ Set the key.
def setKey(self, key):
self.encryptKeys = self.deskey([ord(x) for x in key], 1)
self.decryptKeys = self.deskey([ord(x) for x in key], 0)
# Turn an 8-byte key into internal keys.
def deskey(self, keyBlock, encrypting):
#~ int i, j, l, m, n;
pc1m = [0]*56 #new int[56];
pcr = [0]*56 #new int[56];
kn = [0]*32 #new int[32];
for j in range(56):
l = pc1[j]
m = l & 07
pc1m[j] = ((keyBlock[l >> 3] & bytebit[m]) != 0)
for i in range(16):
if encrypting:
m = i << 1
else:
m = (15-i) << 1
n = m + 1
kn[m] = kn[n] = 0
for j in range(28):
l = j + totrot[i]
if l < 28:
pcr[j] = pc1m[l]
else:
pcr[j] = pc1m[l - 28]
for j in range(28, 56):
l = j + totrot[i]
if l < 56:
pcr[j] = pc1m[l]
else:
pcr[j] = pc1m[l - 28]
for j in range(24):
if pcr[pc2[j]] != 0:
kn[m] |= bigbyte[j]
if pcr[pc2[j+24]] != 0:
kn[n] |= bigbyte[j]
return self.cookey(kn)
def cookey(self, raw):
#~ int raw0, raw1;
#~ int rawi, KnLi;
#~ int i;
KnL = [0]*32
rawi = 0
KnLi = 0
for i in range(16):
raw0 = raw[rawi]
rawi += 1
raw1 = raw[rawi]
rawi += 1
KnL[KnLi] = (raw0 & 0x00fc0000L) << 6
KnL[KnLi] |= (raw0 & 0x00000fc0L) << 10
KnL[KnLi] |= (raw1 & 0x00fc0000L) >> 10
KnL[KnLi] |= (raw1 & 0x00000fc0L) >> 6
KnLi += 1
KnL[KnLi] = (raw0 & 0x0003f000L) << 12
KnL[KnLi] |= (raw0 & 0x0000003fL) << 16
KnL[KnLi] |= (raw1 & 0x0003f000L) >> 4
KnL[KnLi] |= (raw1 & 0x0000003fL)
KnLi += 1
return KnL
# Block encryption routines.
#/ Encrypt a block of eight bytes.
def encrypt(self, clearText):
if len(clearText) != 8:
raise TypeError, "length must be eight bytes"
return struct.pack(">LL",
*self.des(struct.unpack(">LL", clearText), self.encryptKeys)
)
#/ Decrypt a block of eight bytes.
def decrypt(self, cipherText):
if len(cipherText) != 8:
raise TypeError, "length must be eight bytes"
return struct.pack(">LL",
*self.des(struct.unpack(">LL", cipherText), self.decryptKeys)
)
# The DES function.
def des(self, (leftt, right), keys):
#~ int fval, work, right, leftt;
#~ int round
keysi = 0
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL
right ^= work
leftt ^= (work << 4) & 0xffffffffL
work = ((leftt >> 16) ^ right) & 0x0000ffffL
right ^= work
leftt ^= (work << 16) & 0xffffffffL
work = ((right >> 2) ^ leftt) & 0x33333333L
leftt ^= work
right ^= (work << 2) & 0xffffffffL
work = ((right >> 8) ^ leftt) & 0x00ff00ffL
leftt ^= work
right ^= (work << 8) & 0xffffffffL
right = ((right << 1) | ((right >> 31) & 1)) & 0xffffffffL
work = (leftt ^ right) & 0xaaaaaaaaL
leftt ^= work
right ^= work
leftt = ((leftt << 1) | ((leftt >> 31) & 1)) & 0xffffffffL
for round in range(8):
work = ((right << 28) | (right >> 4)) & 0xffffffffL
work ^= keys[keysi]
keysi += 1
fval = SP7[ work & 0x0000003fL ]
fval |= SP5[(work >> 8) & 0x0000003fL ]
fval |= SP3[(work >> 16) & 0x0000003fL ]
fval |= SP1[(work >> 24) & 0x0000003fL ]
work = right ^ keys[keysi]
keysi += 1
fval |= SP8[ work & 0x0000003fL ]
fval |= SP6[(work >> 8) & 0x0000003fL ]
fval |= SP4[(work >> 16) & 0x0000003fL ]
fval |= SP2[(work >> 24) & 0x0000003fL ]
leftt ^= fval
work = ((leftt << 28) | (leftt >> 4)) & 0xffffffffL
work ^= keys[keysi]
keysi += 1
fval = SP7[ work & 0x0000003fL ]
fval |= SP5[(work >> 8) & 0x0000003fL ]
fval |= SP3[(work >> 16) & 0x0000003fL ]
fval |= SP1[(work >> 24) & 0x0000003fL ]
work = leftt ^ keys[keysi]
keysi += 1
fval |= SP8[ work & 0x0000003fL ]
fval |= SP6[(work >> 8) & 0x0000003fL ]
fval |= SP4[(work >> 16) & 0x0000003fL ]
fval |= SP2[(work >> 24) & 0x0000003fL ]
right ^= fval
right = ((right << 31) | (right >> 1)) & 0xffffffffL
work = (leftt ^ right) & 0xaaaaaaaaL
leftt ^= work
right ^= work
leftt = ((leftt << 31) | (leftt >> 1)) & 0xffffffffL
work = ((leftt >> 8) ^ right) & 0x00ff00ffL
right ^= work
leftt ^= (work << 8) & 0xffffffffL
work = ((leftt >> 2) ^ right) & 0x33333333L
right ^= work
leftt ^= (work << 2) & 0xffffffffL
work = ((right >> 16) ^ leftt) & 0x0000ffffL
leftt ^= work
right ^= (work << 16) & 0xffffffffL
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL
leftt ^= work
right ^= (work << 4) & 0xffffffffL
return right, leftt
# Tables, permutations, S-boxes, etc.
bytebit = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]
bigbyte = [
0x800000, 0x400000, 0x200000, 0x100000,
0x080000, 0x040000, 0x020000, 0x010000,
0x008000, 0x004000, 0x002000, 0x001000,
0x000800, 0x000400, 0x000200, 0x000100,
0x000080, 0x000040, 0x000020, 0x000010,
0x000008, 0x000004, 0x000002, 0x000001
]
pc1 = [
56, 48, 40, 32, 24, 16, 8,
0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26,
18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14,
6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28,
20, 12, 4, 27, 19, 11, 3
]
totrot = [
1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
]
pc2 = [
13, 16, 10, 23, 0, 4,
2, 27, 14, 5, 20, 9,
22, 18, 11, 3 , 25, 7,
15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54,
29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52,
45, 41, 49, 35, 28, 31,
]
SP1 = [
0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L
]
SP2 = [
0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L
]
SP3 = [
0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L
]
SP4 = [
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L
]
SP5 = [
0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L
]
SP6 = [
0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L
]
SP7 = [
0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L
]
SP8 = [
0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L
]
#test only:
if __name__ == '__main__':
des = DesCipher('test1234')
print repr(des.encrypt("hello321"))
print des.decrypt(des.encrypt("hello321"))
print des.encrypt(des.decrypt("hello321"))

122
src/vncViewer/image.py Normal file
View File

@ -0,0 +1,122 @@
#!/usr/bin/env python
##
## pyvnc2swf - image.py
##
## $Id: image.py,v 1.9 2005/11/21 04:12:39 euske Exp $
##
## Copyright (C) 2005 by Yusuke Shinyama (yusuke at cs . nyu . edu)
## All Rights Reserved.
##
## This 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 software 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 software; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
## USA.
##
import sys
lowerbound = max
upperbound = min
# format: 1: solid,
# 2: raw (uncompressed)
# 3: DefineBitLossless
# 4: SCREENVIDEOPACKET
IMG_SOLID = 1
IMG_RAW = 2
IMG_LOSSLESS = 3
IMG_VIDEOPACKET = 4
try:
# try to pygame 1.6 or newer.
import pygame
print >>sys.stderr, 'Using pygame', pygame.ver
pygame.init()
def imgsize(img):
return img.get_size()
def create_image(w, h):
return pygame.Surface((w, h), 0, 32)
def create_image_from_string_rgb(w, h, data):
return pygame.image.fromstring(data, (w, h), 'RGB')
def create_image_from_string_rgbx(w, h, data):
return pygame.image.fromstring(data, (w, h), 'RGBX')
def create_image_from_string_xrgb(w, h, data):
return pygame.image.fromstring(data[1:]+'x', (w, h), 'RGBX')
def create_image_from_string_bgr_flipped(w, h, data):
data = ''.join([ data[i+2]+data[i+1]+data[i] for i in xrange(0, len(data), 3) ])
return pygame.transform.flip(pygame.image.fromstring(data, (w, h), 'RGB'), 0, 1)
def crop_image(img, (x,y,w,h)):
(wm,hm) = img.get_size()
return img.subsurface((x,y,upperbound(wm-x,w),upperbound(hm-y,h)))
def paste_image(dest, src, (x0, y0)):
return dest.blit(src, (x0, y0))
def save_image(img, fname):
if not fname.endswith('.bmp'):
print >>sys.stderr, 'Warning: this format not supported by pygame, raw rgb is used instead.'
return pygame.image.save(img, fname)
def convert_image_to_string_rgb_flipped(img):
return pygame.image.tostring(img, 'RGB', 1)
def convert_image_to_string_rgb(img):
return pygame.image.tostring(img, 'RGB')
def convert_image_to_string_xrgb(img):
return pygame.image.tostring(img, 'ARGB')
def solid_fill(dest, rect, color):
return dest.fill(color, rect)
def scale_image(img, scaling):
# this might cause segmentation faults sometimes :(
# In that case, use the following instead:
# (w,h) = img.get_size()
# return pygame.transform.scale(img, (int(w*scaling), int(h*scaling)))
return pygame.transform.rotozoom(img, 0, scaling)
except ImportError:
# use PIL instead
pygame = None
try:
import Image
except ImportError:
print >>sys.stderr, 'Either Pygame or Python Imaging Library is required.'
sys.exit(1)
print >>sys.stderr, 'Using PIL', Image.VERSION
def imgsize(img):
return img.size
def create_image(w, h):
return Image.new('RGB', (w, h))
def create_image_from_string_rgb(w, h, data):
return Image.fromstring('RGB', (w, h), data, 'raw', 'RGB')
def create_image_from_string_rgbx(w, h, data):
return Image.fromstring('RGB', (w, h), data, 'raw', 'RGBX')
def create_image_from_string_xrgb(w, h, data):
return Image.fromstring('RGB', (w, h), data[1:]+'x', 'raw', 'RGBX')
def create_image_from_string_bgr_flipped(w, h, data):
return Image.fromstring('RGB', (w, h), data, 'raw', 'BGR').transpose(Image.FLIP_TOP_BOTTOM)
def crop_image(img, (x0,y0,w,h)):
(wm,hm) = img.size
return img.crop((x0, y0, upperbound(x0+w,wm), upperbound(y0+h,hm)))
def paste_image(dest, src, (x0, y0)):
return dest.paste(src, (x0, y0))
def save_image(img, fname):
return img.save(fname)
def convert_image_to_string_rgb_flipped(img):
return img.transpose(Image.FLIP_TOP_BOTTOM).tostring('raw', 'RGB')
def convert_image_to_string_rgb(img):
return img.tostring('raw', 'RGB')
def convert_image_to_string_xrgb(img):
return img.tostring('raw', 'XRGB')
def solid_fill(dest, (x0,y0,w,h), color):
return dest.paste(color, (x0, y0, x0+w, y0+h))
def scale_image(img, scaling):
img = img.copy()
(w,h) = img.size
img.thumbnail((int(w*scaling), int(h*scaling)), resample=1)
return img

811
src/vncViewer/rfb.py Normal file
View File

@ -0,0 +1,811 @@
#!/usr/bin/env python
##
## pyvnc2swf - rfb.py
##
## $Id: rfb.py,v 1.25 2005/11/27 00:04:18 euske Exp $
##
## Copyright (C) 2005 by Yusuke Shinyama (yusuke at cs . nyu . edu)
## All Rights Reserved.
##
## This 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 software 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 software; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
## USA.
##
import sys, time, socket
from struct import pack, unpack
from crippled_des import DesCipher
from image import IMG_SOLID, IMG_RAW
stderr = sys.stderr
lowerbound = max
def byte2bit(s):
return ''.join([ chr((ord(s[i>>3]) >> (7 - i&7)) & 1) for i in xrange(len(s)*8) ])
# Exceptions
class RFBError(Exception): pass
class RFBAuthError(RFBError): pass
class RFBProtocolError(RFBError): pass
## RFBFrameBuffer
##
class RFBFrameBuffer:
def init_screen(self, width, height, name):
#print >>stderr, 'init_screen: %dx%d, name=%r' % (width, height, name)
raise NotImplementedError
def set_converter(self, convert_pixels, convert_color1):
self.convert_pixels = convert_pixels
self.convert_color1 = convert_color1
return
def process_pixels(self, x, y, width, height, data):
#print >>stderr, 'process_pixels: %dx%d at (%d,%d)' % (width,height,x,y)
raise NotImplementedError
def process_solid(self, x, y, width, height, data):
#print >>stderr, 'process_solid: %dx%d at (%d,%d), color=%r' % (width,height,x,y, color)
raise NotImplementedError
def update_screen(self, t):
#print >>stderr, 'update_screen'
raise NotImplementedError
# data is given as ARGB
def change_cursor(self, width, height, data):
#print >>stderr, 'change_cursor'
raise NotImplementedError
def move_cursor(self, x, y):
#print >>stderr, 'move_cursor'
raise NotImplementedError
def close(self):
return
## RFBProxy
##
class RFBProxy:
"Abstract class of RFB clients."
def __init__(self, fb=None, preferred_encoding=(5,0), debug=0):
self.fb = fb
self.debug = debug
self.preferred_encoding = preferred_encoding
return
FASTEST_FORMAT = (32, 8, 1, 1, 255, 255, 255, 24, 16, 8)
def preferred_format(self, bitsperpixel, depth, bigendian, truecolour,
red_max, green_max, blue_max,
red_shift, green_shift, blue_shift):
# should return 10-tuple (bitsperpixel, depth, bigendian, truecolour,
# red_max, green_max, blue_max, red_shift, green_shift, blue_shift)
if self.fb:
self.fb.set_converter(lambda data: data,
lambda data: unpack('BBBx', data))
return self.FASTEST_FORMAT
def send(self, s):
"Send data s to the server."
raise NotImplementedError
def recv(self, n):
"Receive n-bytes data from the server."
raise NotImplementedError
def recv_relay(self, n):
"Same as recv() except the received data is also passed to self.relay.recv_framedata."
return self.recv(n)
def recv_byte_with_timeout(self):
return self.recv_relay(1)
def write(self, n):
return
def request_update(self):
"Send a request to the server."
raise NotImplementedError
def finish_update(self):
if self.fb:
self.fb.update_screen(time.time())
return
def init(self):
# recv: server protocol version
server_version = self.recv(12)
# send: client protocol version
self.protocol_version = 3
if server_version.startswith('RFB 003.007'):
self.protocol_version = 7
elif server_version.startswith('RFB 003.008'):
self.protocol_version = 8
self.send('RFB 003.%03d\x0a' % self.protocol_version)
if self.debug:
print >>stderr, 'protocol_version: 3.%d' % self.protocol_version
return self
def getpass(self):
raise NotImplementedError
def auth(self):
# vnc challange & response auth
def crauth():
p = self.getpass()
if not p:
raise RFBError('Auth cancelled')
# from pyvncviewer
des = DesCipher((p+'\x00'*8)[:8])
challange = self.recv(16)
if self.debug:
print >>stderr, 'challange: %r' % challange
response = des.encrypt(challange[:8]) + des.encrypt(challange[8:])
if self.debug:
print >>stderr, 'response: %r' % response
self.send(response)
# recv: security result
(result,) = unpack('>L', self.recv(4))
return result
server_result = 0
if self.protocol_version == 3:
# protocol 3.3 (or 3.6)
# recv: server security
(server_security,) = unpack('>L', self.recv(4))
if self.debug:
print >>stderr, 'server_security: %r' % server_security
# server_security might be 0, 1 or 2.
if server_security == 0:
(reason_length,) = unpack('>L', self.recv(4))
reason = self.recv(reason_length)
raise RFBAuthError('Auth Error: %s' % reason)
elif server_security == 1:
pass
else:
server_result = crauth()
else:
# protocol 3.7 or 3.8
# recv: multiple server securities
(nsecurities,) = unpack('>B', self.recv(1))
server_securities = self.recv(nsecurities)
if self.debug:
print >>stderr, 'server_securities: %r' % server_securities
# must include None or VNCAuth
if '\x01' in server_securities:
# None
self.send('\x01')
if self.protocol_version == 8:
# Protocol 3.8: must recv security result
(server_result,) = unpack('>L', self.recv(4))
else:
server_result = 0
elif '\x02' in server_securities:
# VNCAuth
self.send('\x02')
server_result = crauth()
# result returned.
if self.debug:
print >>stderr, 'server_result: %r' % server_result
if server_result != 0:
# auth failed.
if self.protocol_version != 3:
(reason_length,) = unpack('>L', self.recv(4))
reason = self.recv(reason_length)
else:
reason = server_result
raise RFBAuthError('Auth Error: %s' % reason)
# negotiation ok.
# send: always shared.
self.send('\x01')
return self
def start(self):
# server info.
server_init = self.recv(24)
(width, height, pixelformat, namelen) = unpack('>HH16sL', server_init)
self.name = self.recv(namelen)
(bitsperpixel, depth, bigendian, truecolour,
red_max, green_max, blue_max,
red_shift, green_shift, blue_shift) = unpack('>BBBBHHHBBBxxx', pixelformat)
if self.debug:
print >>stderr, 'Server Encoding:'
print >>stderr, ' width=%d, height=%d, name=%r' % (width, height, self.name)
print >>stderr, ' pixelformat=', (bitsperpixel, depth, bigendian, truecolour)
print >>stderr, ' rgbmax=', (red_max, green_max, blue_max)
print >>stderr, ' rgbshift=', (red_shift, green_shift, blue_shift)
# setformat
self.send('\x00\x00\x00\x00')
# 32bit, 8bit-depth, big-endian(RGBX), truecolour, 255max
(bitsperpixel, depth, bigendian, truecolour,
red_max, green_max, blue_max,
red_shift, green_shift, blue_shift) = self.preferred_format(bitsperpixel, depth, bigendian, truecolour,
red_max, green_max, blue_max,
red_shift, green_shift, blue_shift)
self.bytesperpixel = bitsperpixel/8
pixelformat = pack('>BBBBHHHBBBxxx', bitsperpixel, depth, bigendian, truecolour,
red_max, green_max, blue_max,
red_shift, green_shift, blue_shift)
self.send(pixelformat)
self.write(pack('>HH16sL', width, height, pixelformat, namelen))
self.write(self.name)
if self.fb:
self.clipping = self.fb.init_screen(width, height, self.name)
else:
self.clipping = (0,0, width, height)
self.send('\x02\x00' + pack('>H', len(self.preferred_encoding)))
for e in self.preferred_encoding:
self.send(pack('>l', e))
return self
def loop1(self):
self.request_update()
c = self.recv_byte_with_timeout()
if c == '':
return False
elif c == None:
# timeout
pass
elif c == '\x00':
(nrects,) = unpack('>xH', self.recv_relay(3))
if self.debug:
print >>stderr, 'FrameBufferUpdate: nrects=%d' % nrects
for rectindex in xrange(nrects):
(x0, y0, width, height, t) = unpack('>HHHHl', self.recv_relay(12))
if self.debug:
print >>stderr, ' %d: %d x %d at (%d,%d), type=%d' % (rectindex, width, height, x0, y0, t)
# RawEncoding
if t == 0:
l = width*height*self.bytesperpixel
data = self.recv_relay(l)
if self.debug:
print >>stderr, ' RawEncoding: len=%d, received=%d' % (l, len(data))
if self.fb:
self.fb.process_pixels(x0, y0, width, height, data)
# CopyRectEncoding
elif t == 1:
raise RFBProtocolError('unsupported: CopyRectEncoding')
# RREEncoding
elif t == 2:
(nsubrects,) = unpack('>L', self.recv_relay(4))
bgcolor = self.recv_relay(self.bytesperpixel)
if self.debug:
print >>stderr, ' RREEncoding: subrects=%d, bgcolor=%r' % (nsubrects, bgcolor)
if self.fb:
self.fb.process_solid(x0, y0, width, height, bgcolor)
for i in xrange(nsubrects):
fgcolor = self.recv_relay(self.bytesperpixel)
(x,y,w,h) = unpack('>HHHH', self.recv_relay(8))
if self.fb:
self.fb.process_solid(x0+x, y0+y, w, h, fgcolor)
if 2 <= self.debug:
print >>stderr, ' RREEncoding: ', (x,y,w,h,fgcolor)
# CoRREEncoding
elif t == 4:
(nsubrects,) = unpack('>L', self.recv_relay(4))
bgcolor = self.recv_relay(self.bytesperpixel)
if self.debug:
print >>stderr, ' CoRREEncoding: subrects=%d, bgcolor=%r' % (nsubrects, bgcolor)
if self.fb:
self.fb.process_solid(x0, y0, width, height, bgcolor)
for i in xrange(nsubrects):
fgcolor = self.recv_relay(self.bytesperpixel)
(x,y,w,h) = unpack('>BBBB', self.recv_relay(4))
if self.fb:
self.fb.process_solid(x0+x, y0+y, w, h, fgcolor)
if 2 <= self.debug:
print >>stderr, ' CoRREEncoding: ', (x,y,w,h,fgcolor)
# HextileEncoding
elif t == 5:
if self.debug:
print >>stderr, ' HextileEncoding'
(fgcolor, bgcolor) = (None, None)
for y in xrange(0, height, 16):
for x in xrange(0, width, 16):
w = min(width-x, 16)
h = min(height-y, 16)
c = ord(self.recv_relay(1))
assert c < 32
# Raw
if c & 1:
l = w*h*self.bytesperpixel
data = self.recv_relay(l)
if self.fb:
self.fb.process_pixels(x0+x, y0+y, w, h, data)
if 2 <= self.debug:
print >>stderr, ' Raw:', l
continue
if c & 2:
bgcolor = self.recv_relay(self.bytesperpixel)
if c & 4:
fgcolor = self.recv_relay(self.bytesperpixel)
if self.fb:
self.fb.process_solid(x0+x, y0+y, w, h, bgcolor)
# Solid
if not c & 8:
if 2 <= self.debug:
print >>stderr, ' Solid:', repr(bgcolor)
continue
nsubrects = ord(self.recv_relay(1))
# SubrectsColoured
if c & 16:
if 2 <= self.debug:
print >>stderr, ' SubrectsColoured:', nsubrects, repr(bgcolor)
for i in xrange(nsubrects):
color = self.recv_relay(self.bytesperpixel)
(xy,wh) = unpack('>BB', self.recv_relay(2))
if self.fb:
self.fb.process_solid(x0+x+(xy>>4), y0+y+(xy&15), (wh>>4)+1, (wh&15)+1, color)
if 3 <= self.debug:
print >>stderr, ' ', repr(color), (xy,wh)
# NoSubrectsColoured
else:
if 2 <= self.debug:
print >>stderr, ' NoSubrectsColoured:', nsubrects, repr(bgcolor)
for i in xrange(nsubrects):
(xy,wh) = unpack('>BB', self.recv_relay(2))
if self.fb:
self.fb.process_solid(x0+x+(xy>>4), y0+y+(xy&15), (wh>>4)+1, (wh&15)+1, fgcolor)
if 3 <= self.debug:
print >>stderr, ' ', (xy,wh)
# ZRLEEncoding
elif t == 16:
raise RFBProtocolError('unsupported: ZRLEEncoding')
# RichCursor
elif t == -239:
if width and height:
rowbytes = (width + 7) / 8;
# Cursor image RGB
data = self.recv_relay(width * height * self.bytesperpixel)
# Cursor mask -> 1 bit/pixel (1 -> image; 0 -> transparent)
mask = self.recv_relay(rowbytes * height)
# Set the alpha channel with maskData where bit=1 -> alpha = 255, bit=0 -> alpha=255
if self.debug:
print >>stderr, 'RichCursor: %dx%d at %d,%d' % (width,height,x0,y0)
if self.fb:
data = self.fb.convert_pixels(data)
mask = ''.join([ byte2bit(mask[p:p+rowbytes]) for p in xrange(0, height*rowbytes, rowbytes) ])
def conv1(i):
if mask[i/4] == '\x01':
return '\xff'+data[i]+data[i+1]+data[i+2]
else:
return '\x00\x00\x00\x00'
data = ''.join([ conv1(i) for i in xrange(0, len(data), 4) ])
self.fb.change_cursor(width, height, x0, y0, data)
# XCursor
elif t == -240:
if width and height:
rowbytes = (width + 7) / 8;
# Foreground RGB
fgcolor = self.recv_relay(3)
# Background RGB
bgcolor = self.recv_relay(3)
# Cursor Data -> 1 bit/pixel
data = self.recv_relay(rowbytes * height)
# Cursor Mask -> 1 bit/pixel
mask = self.recv_relay(rowbytes * height)
# Create the image from cursordata and maskdata.
print >>stderr, 'XCursor: %dx%d at %d,%d' % (width,height,x0,y0)
if self.fb:
data = byte2bit(data)
mask = byte2bit(mask)
def conv1(i):
if mask[i] == '\x01':
if data[i] == '\x01':
return '\xff'+fgcolor
else:
return '\xff'+bgcolor
else:
return '\x00\x00\x00\x00'
data = ''.join([ conv1(i) for i in xrange(len(data)) ])
self.fb.change_cursor(width, height, x0, y0, data)
# CursorPos -> only change the cursor position
elif t == -232:
if self.debug:
print >>stderr, 'CursorPos: %d,%d' % (x0,y0)
if self.fb:
self.fb.move_cursor(x0, y0)
else:
raise RFBProtocolError('Illegal encoding: 0x%02x' % t)
self.finish_update()
elif c == '\x01':
(first, ncolours) = unpack('>xHH', self.recv_relay(11))
if self.debug:
print >>stderr, 'SetColourMapEntries: first=%d, ncolours=%d' % (first, ncolours)
for i in ncolours:
self.recv_relay(6)
elif c == '\x02':
if self.debug:
print >>stderr, 'Bell'
elif c == '\x03':
(length, ) = unpack('>3xL', self.recv_relay(7))
data = self.recv_relay(length)
if self.debug:
print >>stderr, 'ServerCutText: %r' % data
else:
raise RFBProtocolError('Unsupported msg: %d' % ord(c))
return True
def loop(self):
while self.loop1():
pass
self.finish_update()
return self
def close(self):
if self.fb:
self.fb.close()
return
## RFBNetworkClient
##
class RFBNetworkClient(RFBProxy):
def __init__(self, host, port, fb=None, pwdfile=None,
preferred_encoding=(0,5), debug=0):
RFBProxy.__init__(self, fb=fb, preferred_encoding=preferred_encoding, debug=debug)
self.host = host
self.port = port
self.pwdfile = pwdfile
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
return
def init(self):
self.sock.connect((self.host, self.port))
x = RFBProxy.init(self)
print >>stderr, 'Connected: %s:%d, protocol_version=3.%d, preferred_encoding=%s' % \
(self.host, self.port, self.protocol_version, self.preferred_encoding)
return x
def recv(self, n):
# MS-Windows doesn't have MSG_WAITALL, so we emulate it.
buf = ''
while n:
x = self.sock.recv(n)
if not x: break
buf += x
n -= len(x)
return buf
def recv_byte_with_timeout(self):
self.sock.settimeout(0.05)
try:
c = self.recv_relay(1)
except socket.timeout:
c = None
self.sock.settimeout(None)
return c
def send(self, s):
return self.sock.send(s)
def getpass(self):
import getpass
if self.pwdfile:
fp = file(self.pwdfile)
s = fp.read().rstrip()
fp.close()
return s
return getpass.getpass('Password for %s:%d: ' % (self.host, self.port))
def request_update(self):
if self.debug:
print >>stderr, 'FrameBufferUpdateRequest'
self.send('\x03\x01' + pack('>HHHH', *self.clipping))
return
def close(self):
RFBProxy.close(self)
self.sock.close()
return
## RFBNetworkClientForRecording (vncrec equivalent)
##
class RFBNetworkClientForRecording(RFBNetworkClient):
def __init__(self, host, port, fname, pwdfile=None,
preferred_encoding=(5,0), debug=0):
RFBNetworkClient.__init__(self, host, port, fb=None, pwdfile=pwdfile,
preferred_encoding=preferred_encoding, debug=debug)
print >>stderr, 'Creating vncrec: %r: vncLog0.0' % fname
self.fp = file(fname, 'wb')
self.write('vncLog0.0')
# disguise data (security=none)
self.write('RFB 003.003\x0a')
self.write('\x00\x00\x00\x01')
self.updated = True
return
def write(self, x):
self.fp.write(x)
return
def request_update(self):
if self.updated:
self.updated = False
t = time.time()
self.write(pack('>LL', int(t), (t-int(t))*1000000))
RFBNetworkClient.request_update(self)
return
def finish_update(self):
self.updated = True
return
def recv_relay(self, n):
data = self.recv(n)
self.write(data)
return data
def close(self):
RFBNetworkClient.close(self)
self.fp.close()
return
## RFBFileParser
##
class RFBFileParser(RFBProxy):
def __init__(self, fname, fb=None, debug=0):
RFBProxy.__init__(self, fb=fb, debug=debug)
if self.fb:
self.fb.change_format = False
self.fp = file(fname, 'rb')
self.fname = fname
return
def preferred_format(self, bitsperpixel, depth, bigendian, truecolour,
red_max, green_max, blue_max,
red_shift, green_shift, blue_shift):
if (bitsperpixel, depth, bigendian, truecolour,
red_max, green_max, blue_max,
red_shift, green_shift, blue_shift) == self.FASTEST_FORMAT:
return RFBProxy.preferred_format(self, bitsperpixel, depth, bigendian, truecolour,
red_max, green_max, blue_max,
red_shift, green_shift, blue_shift)
elif self.fb:
if bigendian:
endian = '>'
else:
endian = '<'
try:
length = {8:'B', 16:'H', 32:'L'}[bitsperpixel]
except KeyError:
raise 'invalid bitsperpixel: %d' % bitsperpixel
unpackstr = endian + length
nbytes = bitsperpixel / 8
bits = {1:1, 3:2, 7:3, 15:4, 31:5, 63:6, 127:7, 255:8}
try:
e = 'lambda p: (((p>>%d)&%d)<<%d, ((p>>%d)&%d)<<%d, ((p>>%d)&%d)<<%d)' % \
(red_shift, red_max, 8-bits[red_max],
green_shift, green_max, 8-bits[green_max],
blue_shift, blue_max, 8-bits[blue_max])
except KeyError:
raise 'invalid {red,green,blue}_max: %d, %d or %d' % (red_max, green_max, blue_max)
getrgb = eval(e)
unpack_pixels = eval('lambda data: unpack("%s%%d%s" %% (len(data)/%d), data)' % (endian, length, nbytes))
unpack_color1 = eval('lambda data: unpack("%s", data)' % unpackstr)
self.fb.set_converter(lambda data: ''.join([ pack('>BBB', *getrgb(p)) for p in unpack_pixels(data) ]),
lambda data: getrgb(unpack_color1(data)[0]))
return (bitsperpixel, depth, bigendian, truecolour,
red_max, green_max, blue_max,
red_shift, green_shift, blue_shift)
def seek(self, pos):
self.fp.seek(pos)
return
def tell(self):
return self.fp.tell()
def init(self):
self.curtime = 0
version = self.fp.read(9)
print >>stderr, 'Reading vncrec file: %s, version=%r...' % (self.fname, version)
if version != 'vncLog0.0':
raise RFBProtocolError('Unsupported vncrec version: %r' % version)
return RFBProxy.init(self)
def recv(self, n):
x = self.fp.read(n)
if len(x) != n:
raise EOFError
return x
def send(self, s):
return
def auth(self):
if self.protocol_version == 3:
# protocol 3.3
# recv: server security
(server_security,) = unpack('>L', self.recv(4))
if self.debug:
print >>stderr, 'server_security=%r' % server_security
if server_security == 2:
# skip challenge+result (dummy)
self.recv(20)
else:
RFBProxy.auth(self)
return self
def request_update(self):
(sec, usec) = unpack('>LL', self.recv(8))
self.curtime = sec+usec/1000000.0
return
def finish_update(self):
if self.fb:
self.fb.update_screen(self.curtime) # use the file time instead
return
def loop(self, endpos=0):
try:
while self.loop1():
if endpos and endpos <= self.tell(): break
except EOFError:
self.finish_update()
return self
def close(self):
RFBProxy.close(self)
self.fp.close()
return
## RFBConverter
##
class RFBConverter(RFBFrameBuffer):
def __init__(self, info, debug=0):
self.debug = debug
self.info = info
return
def init_screen(self, width, height, name):
print >>stderr, 'VNC Screen: size=%dx%d, name=%r' % (width, height, name)
self.info.set_defaults(width, height)
self.images = []
self.cursor_image = None
self.cursor_pos = None
self.t0 = 0
return self.info.clipping
def process_pixels(self, x, y, width, height, data):
self.images.append( ((x, y), (width, height, (IMG_RAW, self.convert_pixels(data)))) )
return
def process_solid(self, x, y, width, height, data):
self.images.append( ((x, y), (width, height, (IMG_SOLID, self.convert_color1(data)))) )
return
def move_cursor(self, x, y):
self.cursor_pos = (x, y)
return
def change_cursor(self, width, height, dx, dy, data):
if width and height:
self.cursor_image = (width, height, dx, dy, data)
return
def calc_frames(self, t):
if not self.t0:
self.t0 = t
return int((t - self.t0) * self.info.framerate)+1
## RFBMovieConverter
##
class RFBMovieConverter(RFBConverter):
def __init__(self, movie, debug=0):
RFBConverter.__init__(self, movie.info, debug)
self.movie = movie
self.frameinfo = []
return
def process_pixels(self, x, y, width, height, data):
if self.processing:
RFBConverter.process_pixels(self, x, y, width, height, data)
return
def process_solid(self, x, y, width, height, data):
if self.processing:
RFBConverter.process_solid(self, x, y, width, height, data)
return
def update_screen(self, t):
if not self.processing:
frames = RFBConverter.calc_frames(self, t)
done = False
while len(self.frameinfo) < frames:
if done:
self.frameinfo.append((self.beginpos, -1))
else:
endpos = self.rfbparser.tell()
self.frameinfo.append((self.beginpos, endpos))
if self.debug:
print >>stderr, 'scan:', self.beginpos, endpos
self.beginpos = endpos
done = True
return
def open(self, fname, debug=0):
self.processing = False
self.rfbparser = RFBFileParser(fname, self, debug)
self.rfbparser.init().auth().start()
self.beginpos = self.rfbparser.tell()
self.rfbparser.loop()
return
def parse_frame(self, i):
(pos, endpos) = self.frameinfo[i]
if self.debug:
print >>stderr, 'seek:', i, pos, endpos
self.rfbparser.seek(pos)
self.images = []
self.processing = True
self.cursor_image = None
self.cursor_pos = None
self.rfbparser.loop(endpos)
return (self.images, [], (self.cursor_image, self.cursor_pos))
## RFBStreamConverter
##
class RFBStreamConverter(RFBConverter):
def __init__(self, info, stream, debug=0):
RFBConverter.__init__(self, info, debug)
self.stream = stream
return
def init_screen(self, width, height, name):
clipping = RFBConverter.init_screen(self, width, height, name)
self.stream.open()
self.nframes = 0
return clipping
def update_screen(self, t):
frames = RFBConverter.calc_frames(self, t)
if self.nframes < frames:
# First we should create the frames up to now
while self.nframes < frames-1:
self.stream.next_frame()
self.nframes += 1
# And only after that we should paint the frame with the updates
self.stream.paint_frame((self.images, [], (self.cursor_image, self.cursor_pos)))
self.images = []
self.cursor_image = None
self.cursor_pos = None
self.stream.next_frame()
self.nframes += 1
return
def close(self):
self.stream.close()
return

299
src/vncViewer/vnc.py Executable file
View File

@ -0,0 +1,299 @@
#!/usr/bin/python
#
# Copyright (C) 2006 Daniel Berrange
# Copyright (C) 2006 Red Hat
#
## This 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 software 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 software; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
## USA.
import gobject
import rfb
import sys
from struct import pack
import pygtk
import gtk
stderr = sys.stderr
from time import time
#host = "courgette"
host = "localhost"
port = 5901
class GRFBFrameBuffer(rfb.RFBFrameBuffer, gobject.GObject):
__gsignals__= {
"resize": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [int,int]),
"invalidate": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [int,int,int,int])
}
def __init__(self, canvas):
self.__gobject_init__()
self.canvas = canvas
self.pixmap = None
def get_pixmap(self):
return self.pixmap
def init_screen(self, width, height, name):
self.pixmap = gtk.gdk.Pixmap(self.canvas.window, width, height)
self.emit("resize", width, height)
return (0, 0, width, height)
def process_pixels(self, x, y, width, height, data):
if self.pixmap == None:
return
gc = self.pixmap.new_gc()
self.pixmap.draw_rgb_32_image(gc, x, y, width, height, gtk.gdk.RGB_DITHER_NONE, data)
self.emit("invalidate", x, y, width, height)
def process_solid(self, x, y, width, height, color):
print >>stderr, 'process_solid: %dx%d at (%d,%d), color=%r' % (width,height,x,y, color)
def update_screen(self, t):
#print >>stderr, 'update_screen'
pass
def change_cursor(self, width, height, data):
print >>stderr, 'change_cursor'
def move_cursor(self, x, y):
print >>stderr, 'move_cursor'
gobject.type_register(GRFBFrameBuffer)
class GRFBNetworkClient(rfb.RFBNetworkClient, gobject.GObject):
__gsignals__= {
"disconnected": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [])
}
def __init__(self, host, port, converter):
rfb.RFBNetworkClient.__init__(self, host, port, converter)
self.__gobject_init__()
self.watch = None
self.password = None
def init(self):
rfb.RFBNetworkClient.init(self)
def start(self):
rfb.RFBNetworkClient.start(self)
self.watch = gobject.io_add_watch(self.sock.fileno(), gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP, self.handle_io)
def handle_io(self, src, condition):
if self.watch == None:
return 0
try:
self.loop1()
except:
self.close()
self.emit("disconnected")
return 0
return 1
def close(self):
rfb.RFBNetworkClient.close(self)
if self.watch != None:
gobject.source_remove(self.watch)
self.watch = None
def setpass(self, password):
self.password = password
def getpass(self):
return self.password
def update_key(self, down, key):
self.send(pack('>BBHI', 4, down, 0, key))
def update_pointer(self, mask, x, y):
self.send(pack('>BBHH', 5, mask, x, y))
gobject.type_register(GRFBNetworkClient)
class GRFBViewer(gtk.DrawingArea):
__gsignals__= {
"connected": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [str, int]),
"authenticated": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []),
"activated": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, []),
"disconnected": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, [])
}
def __init__(self):
gtk.DrawingArea.__init__(self)
self.fb = GRFBFrameBuffer(self)
self.client = None
self.fb.connect("resize", self.resize_display)
self.fb.connect("invalidate", self.repaint_region)
self.connect("expose-event", self.expose_region)
self.connect("motion-notify-event", self.update_pointer)
self.connect("button-press-event", self.update_pointer)
self.connect("button-release-event", self.update_pointer)
self.connect("key-press-event", self.key_press)
self.connect("key-release-event", self.key_release)
self.set_events(gtk.gdk.EXPOSURE_MASK |
gtk.gdk.LEAVE_NOTIFY_MASK |
gtk.gdk.ENTER_NOTIFY_MASK |
gtk.gdk.KEY_RELEASE_MASK |
gtk.gdk.KEY_PRESS_MASK |
gtk.gdk.BUTTON_RELEASE_MASK |
gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.POINTER_MOTION_MASK |
gtk.gdk.POINTER_MOTION_HINT_MASK)
self.set_property("can-focus", True)
def connect_to_host(self, host, port):
if self.client != None:
self.disconnect_from_host()
self.client = GRFBNetworkClient(host, port, self.fb)
self.client.connect("disconnected", self._client_disconnected)
self.client.init()
self.emit("connected", host, port)
def _client_disconnected(self, src):
self.client = None
self.emit("disconnected")
def disconnect_from_host(self):
if self.client == None:
return
self.client.close()
self.client = None
self.emit("disconnected")
def authenticate(self, password):
self.client.setpass(password)
try:
self.client.auth()
except:
return 0
self.emit("authenticated")
return 1
def activate(self):
self.client.start()
self.client.request_update()
self.emit("activated")
def is_connected(self):
if self.client == None:
return False
return True
def state_to_mask(self, state):
mask = 0
if state & gtk.gdk.BUTTON1_MASK:
mask = mask + 1
if state & gtk.gdk.BUTTON2_MASK:
mask = mask + 2
if state & gtk.gdk.BUTTON3_MASK:
mask = mask + 4
if state & gtk.gdk.BUTTON4_MASK:
mask = mask + 8
if state & gtk.gdk.BUTTON5_MASK:
mask = mask + 16
return mask
def update_pointer(self, win, event):
x, y, state = event.window.get_pointer()
self.client.update_pointer(self.state_to_mask(state), x, y)
return True
def key_press(self, win, event):
self.client.update_key(1, event.keyval)
return True
def key_release(self, win, event):
self.client.update_key(0, event.keyval)
return True
def get_frame_buffer(self):
return self.fb
def resize_display(self, fb, width, height):
self.set_size_request(width, height)
def repaint_region(self,fb, x, y, width, height):
if self.fb.get_pixmap() == None:
return
gc = self.window.new_gc()
self.window.draw_drawable(gc, self.fb.get_pixmap(), x, y, x, y, width, height)
def expose_region(self, win, event):
if self.fb.get_pixmap() == None:
return
gc = self.window.new_gc()
self.window.draw_drawable(gc, self.fb.get_pixmap(), event.area.x, event.area.y, event.area.x, event.area.y, event.area.width, event.area.height)
gobject.type_register(GRFBViewer)
def main():
win = gtk.Window()
win.set_name("VNC")
win.connect("destroy", lambda w: gtk.main_quit())
pane = gtk.ScrolledWindow()
pane.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
win.add(pane)
pane.show()
vp = gtk.Viewport()
pane.add(vp)
vp.show()
vnc = GRFBWidget()
vp.add(vnc)
vnc.show()
win.present()
vnc.connect_to_host(host, port)
rootWidth = gtk.gdk.screen_width()
rootHeight = gtk.gdk.screen_height()
vncWidth, vncHeight = vnc.get_size_request()
if vncWidth > (rootWidth-200):
vncWidth = rootWidth - 200
if vncHeight > (rootHeight-200):
vncHeight = rootHeight - 200
vp.set_size_request(vncWidth+2, vncHeight+2)
gtk.main()
vnc.disconnect_from_host()
if __name__ == '__main__':
main()