Re: [gtk-vnc-devel] VNC sessions on a 3-d spinning cube
- From: "Daniel P. Berrange" <berrange redhat com>
- To: gtk-vnc-devel <gtk-vnc-devel lists sourceforge net>
- Subject: Re: [gtk-vnc-devel] VNC sessions on a 3-d spinning cube
- Date: Mon, 5 Nov 2007 01:31:10 +0000
And with the code attached this time....
On Mon, Nov 05, 2007 at 01:17:01AM +0000, Daniel P. Berrange wrote:
> One evil thought, led to another even more evil thought, and thus I ended
> up writing a VNC viewer program which displays multiple VNC sessions on a
> spinning cube....
>
> http://berrange.com/personal/diary/2007/11/vnc-sessions-on-3-d-spinning-cube
>
> It doesn't work with the current version of GTK-VNC. I needed to add a
> couple of Anthony's patches to propagate mouse events. I also need to add
> an API for sending fake mouse events, and a nnew signal to get notices of
> the VNC region updates so I could refresh the textures. I don't claim it
> is fast/efficient. It is fun though. I think its probably better to write
> it to interact directly with the GVNC class, rather than hooking into the
> VNC DIsplay frontend, since Clutter doesn't technically need to use GTK
> at all - it talks OpenGL & X11 directly. I used the Clutter<->GTK bridge
> for this hack though.
Dan.
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules: http://search.cpan.org/~danberr/ -=|
|=- Projects: http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
diff -r 4a821c404746 examples/gvncviewer.c
--- a/examples/gvncviewer.c Fri Oct 26 09:59:54 2007 -0400
+++ b/examples/gvncviewer.c Sun Nov 04 20:26:51 2007 -0500
@@ -80,28 +80,28 @@ static void send_caf1(GtkWidget *menu G_
{
guint keys[] = { GDK_Control_L, GDK_Alt_L, GDK_F1 };
printf("Sending Ctrl+Alt+F1\n");
- vnc_display_send_keys(VNC_DISPLAY(vnc), keys, sizeof(keys)/sizeof(keys[0]));
+ vnc_display_send_keys(VNC_DISPLAY(vnc), keys, sizeof(keys)/sizeof(keys[0]), 3);
}
static void send_caf7(GtkWidget *menu G_GNUC_UNUSED, GtkWidget *vnc)
{
guint keys[] = { GDK_Control_L, GDK_Alt_L, GDK_F7 };
printf("Sending Ctrl+Alt+F7\n");
- vnc_display_send_keys(VNC_DISPLAY(vnc), keys, sizeof(keys)/sizeof(keys[0]));
+ vnc_display_send_keys(VNC_DISPLAY(vnc), keys, sizeof(keys)/sizeof(keys[0]), 3);
}
static void send_cad(GtkWidget *menu G_GNUC_UNUSED, GtkWidget *vnc)
{
guint keys[] = { GDK_Control_L, GDK_Alt_L, GDK_Delete };
printf("Sending Ctrl+Alt+Delete\n");
- vnc_display_send_keys(VNC_DISPLAY(vnc), keys, sizeof(keys)/sizeof(keys[0]));
+ vnc_display_send_keys(VNC_DISPLAY(vnc), keys, sizeof(keys)/sizeof(keys[0]), 3);
}
static void send_cab(GtkWidget *menu G_GNUC_UNUSED, GtkWidget *vnc)
{
guint keys[] = { GDK_Control_L, GDK_Alt_L, GDK_BackSpace };
printf("Sending Ctrl+Alt+Backspace\n");
- vnc_display_send_keys(VNC_DISPLAY(vnc), keys, sizeof(keys)/sizeof(keys[0]));
+ vnc_display_send_keys(VNC_DISPLAY(vnc), keys, sizeof(keys)/sizeof(keys[0]), 3);
}
static void vnc_credential(GtkWidget *vnc, GValueArray *credList)
diff -r 4a821c404746 examples/gvncviewer.py
--- a/examples/gvncviewer.py Fri Oct 26 09:59:54 2007 -0400
+++ b/examples/gvncviewer.py Sun Nov 04 20:26:51 2007 -0500
@@ -45,15 +45,15 @@ def vnc_disconnected(src):
def send_caf1(src, vnc):
print "Send Ctrl+Alt+F1"
- vnc.send_keys(["Control_L", "Alt_L", "F1"])
+ vnc.send_keys(["Control_L", "Alt_L", "F1"], 3)
def send_caf7(src, vnc):
print "Send Ctrl+Alt+F7"
- vnc.send_keys(["Control_L", "Alt_L", "F7"])
+ vnc.send_keys(["Control_L", "Alt_L", "F7"], 3)
def send_cad(src, vnc):
print "Send Ctrl+Alt+Del"
- vnc.send_keys(["Control_L", "Alt_L", "Del"])
+ vnc.send_keys(["Control_L", "Alt_L", "Del"], 3)
def send_cab(src, vnc):
print "Send Ctrl+Alt+BackSpace"
diff -r 4a821c404746 src/libgtk-vnc_sym.version
--- a/src/libgtk-vnc_sym.version Fri Oct 26 09:59:54 2007 -0400
+++ b/src/libgtk-vnc_sym.version Sun Nov 04 20:26:51 2007 -0500
@@ -10,6 +10,7 @@
vnc_display_close;
vnc_display_send_keys;
+ vnc_display_send_pointer;
vnc_display_set_credential;
diff -r 4a821c404746 src/vnc.override
--- a/src/vnc.override Fri Oct 26 09:59:54 2007 -0400
+++ b/src/vnc.override Sun Nov 04 20:26:51 2007 -0500
@@ -16,18 +16,23 @@ _wrap_vnc_display_send_keys(PyGObject *s
_wrap_vnc_display_send_keys(PyGObject *self,
PyObject *args, PyObject *kwargs)
{
- static char *kwlist[] = {"keys", NULL};
+ static char *kwlist[] = {"keys", "flags", NULL};
PyObject *keyList;
int ret, i, len;
+ int flags;
guint *keys;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "O:VncDisplay.send_keys", kwlist,
- &keyList))
- return;
+ "Oi:VncDisplay.send_keys", kwlist,
+ &keyList, &flags)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
- if (!PyList_Check(keyList))
- return;
+ if (!PyList_Check(keyList)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
len = PyList_Size(keyList);
keys = malloc(sizeof(guint)*len);
@@ -38,11 +43,14 @@ _wrap_vnc_display_send_keys(PyGObject *s
sym = PyString_AsString(val);
if (!sym) {
free(keys);
- return;
+ Py_INCREF(Py_None);
+ return Py_None;
}
keys[i] = gdk_keyval_from_name(sym);
}
- vnc_display_send_keys(VNC_DISPLAY(self->obj), keys, len);
+ vnc_display_send_keys(VNC_DISPLAY(self->obj), keys, len, flags);
free(keys);
+ Py_INCREF(Py_None);
+ return Py_None;
}
diff -r 4a821c404746 src/vncdisplay.c
--- a/src/vncdisplay.c Fri Oct 26 09:59:54 2007 -0400
+++ b/src/vncdisplay.c Sun Nov 04 20:26:51 2007 -0500
@@ -74,6 +74,7 @@ typedef enum
VNC_AUTH_CREDENTIAL,
VNC_DESKTOP_RESIZE,
+ VNC_DESKTOP_UPDATE,
VNC_AUTH_FAILURE,
VNC_AUTH_UNSUPPORTED,
@@ -121,7 +122,7 @@ static gboolean expose_event(GtkWidget *
GdkRegion *clear, *copy;
if (priv->shm_image == NULL)
- return TRUE;
+ return FALSE;
x = MIN(expose->area.x, priv->fb.width);
y = MIN(expose->area.y, priv->fb.height);
@@ -151,7 +152,7 @@ static gboolean expose_event(GtkWidget *
gdk_region_destroy(clear);
gdk_region_destroy(copy);
- return TRUE;
+ return FALSE;
}
static void do_keyboard_grab(VncDisplay *obj, gboolean quiet)
@@ -355,7 +356,7 @@ static gboolean key_event(GtkWidget *wid
GdkModifierType consumed;
if (priv->gvnc == NULL || !gvnc_is_initialized(priv->gvnc))
- return TRUE;
+ return FALSE;
/*
* Key handling in VNC is screwy. The event.keyval from GTK is
@@ -393,7 +394,7 @@ static gboolean key_event(GtkWidget *wid
do_pointer_grab(VNC_DISPLAY(widget), FALSE);
}
- return TRUE;
+ return FALSE;
}
static gboolean enter_event(GtkWidget *widget, GdkEventCrossing *crossing,
@@ -437,6 +438,10 @@ static gboolean on_update(void *opaque,
gtk_widget_queue_draw_area(obj, x, y, w, h);
+ g_signal_emit (G_OBJECT (obj),
+ signals[VNC_DESKTOP_UPDATE],
+ 0,
+ x, y, w, h);
return TRUE;
}
@@ -832,17 +837,28 @@ void vnc_display_close(VncDisplay *obj)
}
-void vnc_display_send_keys(VncDisplay *obj, const guint *keyvals, int nkeyvals)
+void vnc_display_send_keys(VncDisplay *obj, const guint *keyvals, int nkeyvals, int flags)
{
int i;
if (obj->priv->gvnc == NULL || !gvnc_is_open(obj->priv->gvnc))
return;
- for (i = 0 ; i < nkeyvals ; i++)
- gvnc_key_event(obj->priv->gvnc, 1, keyvals[i]);
-
- for (i = (nkeyvals-1) ; i >= 0 ; i--)
- gvnc_key_event(obj->priv->gvnc, 0, keyvals[i]);
+ if (flags & 1)
+ for (i = 0 ; i < nkeyvals ; i++)
+ gvnc_key_event(obj->priv->gvnc, 1, keyvals[i]);
+
+ if (flags & 2)
+ for (i = (nkeyvals-1) ; i >= 0 ; i--)
+ gvnc_key_event(obj->priv->gvnc, 0, keyvals[i]);
+}
+
+
+void vnc_display_send_pointer(VncDisplay *obj, int buttons, int x, int y)
+{
+ if (obj->priv->gvnc == NULL || !gvnc_is_open(obj->priv->gvnc))
+ return;
+
+ gvnc_pointer_event(obj->priv->gvnc, buttons, x, y);
}
@@ -980,6 +996,18 @@ static void vnc_display_class_init(VncDi
G_TYPE_NONE,
2,
G_TYPE_INT, G_TYPE_INT);
+
+ signals[VNC_DESKTOP_UPDATE] =
+ g_signal_new("vnc-desktop-update",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_user_marshal_VOID__INT_INT_INT_INT,
+ G_TYPE_NONE,
+ 4,
+ G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
signals[VNC_AUTH_FAILURE] =
g_signal_new("vnc-auth-failure",
diff -r 4a821c404746 src/vncdisplay.h
--- a/src/vncdisplay.h Fri Oct 26 09:59:54 2007 -0400
+++ b/src/vncdisplay.h Sun Nov 04 20:26:51 2007 -0500
@@ -72,7 +72,8 @@ gboolean vnc_display_is_open(VncDisplay
gboolean vnc_display_is_open(VncDisplay *obj);
void vnc_display_close(VncDisplay *obj);
-void vnc_display_send_keys(VncDisplay *obj, const guint *keyvals, int nkeyvals);
+void vnc_display_send_keys(VncDisplay *obj, const guint *keyvals, int nkeyvals, int down);
+void vnc_display_send_pointer(VncDisplay *obj, int buttons, int x, int y);
gboolean vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data);
diff -r 4a821c404746 src/vncmarshal.txt
--- a/src/vncmarshal.txt Fri Oct 26 09:59:54 2007 -0400
+++ b/src/vncmarshal.txt Sun Nov 04 20:26:51 2007 -0500
@@ -1,1 +1,2 @@ VOID:INT,INT
VOID:INT,INT
+VOID:INT,INT,INT,INT
#!/usr/bin/python
#
# Copyright (C) 2007 Daniel P. Berrange <dan berrange com>
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#
#
# A VNC viewer program displaying multiple VNC sessions
# on a 3-d spinning cube....
#
import sys
import gobject
import gtk
import gtkvnc
import math
import clutter
import clutter.keysyms
import clutter.cluttergtk
if len(sys.argv) < 2:
print "syntax: gvncclutter.py DISPLAY-1 [DISPLAY-2....]"
sys.exit(1)
class ClutterVNC:
def __init__(self, layout, group, host, port, password):
self.vnc = gtkvnc.Display()
self.tex = None
self.group = group
layout.add(self.vnc)
self.vnc.realize()
self.vnc.set_credential(gtkvnc.CREDENTIAL_PASSWORD, password)
self.vnc.open_host(host, port)
self.vnc.connect("vnc-desktop-resize", self.reinit_texture)
self.vnc.connect("vnc-desktop-update", self.refresh_texture)
def size(self):
return (self.vnc.get_width(), self.vnc.get_height())
def show(self):
self.tex.show()
def reinit_texture(self, vnc, w, h):
new = 0
if self.tex is None:
self.tex = clutter.Texture()
new = 1
self.tex.set_pixbuf(self.vnc.get_pixbuf())
self.tex.set_size(w, h)
if new:
self.group.add(self.tex)
def refresh_texture(self, vnc, x,y,w,h):
if self.tex is not None:
self.tex.set_pixbuf(self.vnc.get_pixbuf())
class ClutterVNCSet:
def __init__(self, layout):
self.layout = layout
self.embed = clutter.cluttergtk.Embed()
self.embed.set_flags(gtk.CAN_FOCUS)
self.embed.grab_focus()
self.stage = self.embed.get_stage()
self.stage.set_color(clutter.Color(0, 0, 0, 255))
self.stage.set_size(800,800)
self.group = clutter.Group()
self.group.set_position(0,0)
self.group.set_size(800,800)
self.stage.add(self.group)
self.group.show()
self.vncs = []
self.current = 0
self.offset = 0
self.animate = 0
self.timeline = clutter.Timeline(30, 30)
self.timeline.connect("new-frame", self.do_frame)
self.layout.add(self.embed)
self.embed.show_all()
self.group.connect("add", self.child_added)
self.stage.connect("button-press-event", self.button_event)
self.stage.connect("button-release-event", self.button_event)
self.stage.connect("motion-event", self.button_event)
self.stage.connect("key-press-event", self.key_event)
self.stage.connect("key-release-event", self.key_event)
def do_frame(self, timeline, frame):
if self.animate == 1:
self.offset = 1-(frame/30.0)
else:
self.offset = (frame/30.0)-1
self.reposition_all()
def child_added(self, src, child):
self.reposition_all()
def reposition_one(self, tex, pos):
(w,h) = self.stage.get_size()
(cw,ch) = tex.get_size()
nsides = len(self.vncs)
rot = 360/nsides * (pos-self.current+self.offset)
if nsides > 2:
depth = (cw/2) / math.tan(math.radians((360/nsides)/2))
else:
depth = 0
# XXX kill when depth sorting is done
tex.set_opacity(127)
tex.set_position((w-cw)/2, (h-cw)/2)
tex.rotate_y(int(rot), (cw/2), int(-depth))
tex.show()
#print "Rotate %d %f at %f depth %f" % (self.current, self.offset, rot, depth)
def reposition_all(self):
for i in range(len(self.vncs)):
if self.vncs[i].tex is not None:
self.reposition_one(self.vncs[i].tex, i)
# XXX depth sort
def button_state(self, ev):
state = 0
if ev.get_state() & clutter.BUTTON1_MASK:
state = state | (1 << 0)
elif ev.get_state() & clutter.BUTTON2_MASK:
state = state | (1 << 1)
elif ev.get_state() & clutter.BUTTON3_MASK:
state = state | (1 << 2)
elif ev.get_state() & clutter.BUTTON4_MASK:
state = state | (1 << 3)
elif ev.get_state() & clutter.BUTTON5_MASK:
state = state | (1 << 4)
if ev.type == clutter.BUTTON_PRESS:
state = state | (1 << (ev.button-1))
elif ev.type == clutter.BUTTON_RELEASE:
state = state & ~(1 << (ev.button-1))
return state
def button_event(self, src, ev):
vnc = self.vncs[self.current]
(w,h) = self.stage.get_size()
(cw,ch) = vnc.tex.get_size()
x = ev.x - ((w-cw)/2)
y = ev.y - ((h-ch)/2)
state = self.button_state(ev)
#print "Button " + str(state) + " " + str(x) + " " + str(y)
vnc.vnc.send_pointer(state, x, y)
def key_event(self, src, ev):
if ev.type == clutter.KEY_PRESS and \
(ev.keyval == clutter.keysyms.Page_Up or
ev.keyval == clutter.keysyms.Page_Down) and \
(ev.get_state() & clutter.CONTROL_MASK) and \
(ev.get_state() & clutter.MOD1_MASK):
if ev.keyval == clutter.keysyms.Page_Up:
self.animate = -1
if self.current == 0:
self.current = len(self.vncs)-1
else:
self.current = self.current - 1
else:
self.animate = 1
if self.current == (len(self.vncs)-1):
self.current = 0
else:
self.current = self.current + 1
self.timeline.start()
return
vnc = self.vncs[self.current]
kv = gtk.gdk.keyval_name(ev.keyval)
if ev.type == clutter.KEY_PRESS:
vnc.vnc.send_keys([kv], 1)
else:
vnc.vnc.send_keys([kv], 2)
def add_vnc(self, host, port, passwd):
vnc = ClutterVNC(self.layout, self.group, host, port, passwd)
self.vncs.append(vnc)
def split_host_port(disp):
offset = disp.find(":")
if offset != -1:
return (disp[:offset], str(5900 + int(disp[offset+1:])))
else:
return (disp, "5900")
window = gtk.Window()
layout = gtk.VBox()
window.add(layout)
window.show_all()
vncset = ClutterVNCSet(layout)
for i in range(len(sys.argv)-1):
(host,port) = split_host_port(sys.argv[i+1])
vncset.add_vnc(host, port, "123456")
window.set_focus(vncset.embed)
gtk.main()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]