[Message Prev][Message Next][Thread Prev][Thread Next][Message Index][Thread Index]

Cursor support patch for rdesktop




Hi,

Here's another patch for rdesktop: this one adds proper cursor support,
i.e. you get all the standard windows pointers from the NT server, and the
cursor changes shape as you move it over different bits of the screen,
etc. 

Unfortunately this has the side effect that you can now get the annoying
egg timers where you previously would not have done.  ;-) 

This patch has currently only been tested on a intel linux box, and as it
does some rather dodgy endian conversions and image flipping operations I
strongly suspect in its present state it will have problems on various
other platforms.  Also, this is my first attempt at Xlib programming so I
expect i've also got some stupid bugs in the code. 

However, it works great for me. :-)

Finally it's worth noting that unlike windows, X windows pointers
apparently have to be monochrome, so my code does a very simple
conversion to black and white. If you've selected some bizarre coloured
pointer scheme in NT you might not get quite what you were expecting. 


Ben.

/   Ben McKeegan, I.T. Manager          http://ziggy.fitz.cam.ac.uk/   \
\   Fitzwilliam College, University of Cambridge, UK.                  /

diff -u rdesktop-1.0.0.orig/cache.c rdesktop-1.0.0/cache.c
--- rdesktop-1.0.0.orig/cache.c	Mon Oct 16 08:37:51 2000
+++ rdesktop-1.0.0/cache.c	Mon Nov  6 00:11:38 2000
@@ -188,3 +188,41 @@
 	}
 }
 
+/* CURSOR CACHE */
+static HCURSOR cursorcache[0x20];
+
+/* Retrieve cursor from cache */
+HCURSOR cache_get_cursor(uint16 cache_idx)
+{
+        HCURSOR cursor;
+
+        if (cache_idx < NUM_ELEMENTS(cursorcache))
+        {
+                cursor = cursorcache[cache_idx];
+                if (cursor != NULL)
+                        return cursor;
+        }
+
+        ERROR("get cursor %d\n", cache_idx);
+        return NULL;
+}
+
+/* Store cursor in cache */
+void cache_put_cursor(uint16 cache_idx, HCURSOR cursor)
+{
+	HCURSOR old;
+
+        if (cache_idx < NUM_ELEMENTS(cursorcache))
+        {
+                old = cursorcache[cache_idx];
+                if (old != NULL)
+                        ui_destroy_cursor(old);
+
+                cursorcache[cache_idx] = cursor;
+        }
+        else
+        {
+                ERROR("put cursor %d\n", cache_idx);
+        }
+}
+
diff -u rdesktop-1.0.0.orig/constants.h rdesktop-1.0.0/constants.h
--- rdesktop-1.0.0.orig/constants.h	Mon Oct 16 09:44:47 2000
+++ rdesktop-1.0.0/constants.h	Mon Nov  6 00:11:38 2000
@@ -132,7 +132,9 @@
 
 enum RDP_POINTER_PDU_TYPE
 {
-	RDP_POINTER_MOVE = 3
+	RDP_POINTER_MOVE = 3,
+	RDP_POINTER_COLOR =6,
+        RDP_POINTER_CACHED =7
 };
 
 enum RDP_INPUT_DEVICE
Common subdirectories: rdesktop-1.0.0.orig/crypto and rdesktop-1.0.0/crypto
diff -u rdesktop-1.0.0.orig/proto.h rdesktop-1.0.0/proto.h
--- rdesktop-1.0.0.orig/proto.h	Mon Oct 16 09:44:47 2000
+++ rdesktop-1.0.0/proto.h	Mon Nov  6 00:11:38 2000
@@ -65,6 +65,8 @@
 void cache_put_text(uint8 cache_id, void *data, int length);
 uint8 *cache_get_desktop(uint32 offset, int cx, int cy);
 void cache_put_desktop(uint32 offset, int cx, int cy, int scanline, uint8 *data);
+HCURSOR cache_get_cursor(uint16 cache_idx);
+void cache_put_cursor(uint16 cache_idx, HCURSOR cursor);
 
 /* xwin.c */
 BOOL ui_create_window(char *title);
@@ -74,6 +76,9 @@
 HBITMAP ui_create_bitmap(int width, int height, uint8 *data);
 void ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 *data);
 void ui_destroy_bitmap(HBITMAP bmp);
+HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 *mask, uint8 *data);
+void ui_set_cursor(HCURSOR cursor);
+void ui_destroy_cursor(HCURSOR cursor);
 HGLYPH ui_create_glyph(int width, int height, uint8 *data);
 void ui_destroy_glyph(HGLYPH glyph);
 HCOLOURMAP ui_create_colourmap(COLOURMAP *colours);
diff -u rdesktop-1.0.0.orig/rdp.c rdesktop-1.0.0/rdp.c
--- rdesktop-1.0.0.orig/rdp.c	Mon Oct 16 09:44:48 2000
+++ rdesktop-1.0.0/rdp.c	Mon Nov  6 00:11:38 2000
@@ -451,7 +451,9 @@
 static void process_pointer_pdu(STREAM s)
 {
 	uint16 message_type;
-	uint16 x, y;
+	uint16 x, y, width, height, cache_idx, masklen, datalen;
+	uint8 *mask,*data;
+	HCURSOR cursor;
 
 	in_uint16_le(s, message_type);
 	in_uint8s(s, 2); /* pad */
@@ -465,6 +467,25 @@
 				ui_move_pointer(x, y);
 			break;
 
+		case RDP_POINTER_COLOR:
+                        in_uint16_le(s, cache_idx);
+			in_uint16_le(s, x);
+                        in_uint16_le(s, y);
+			in_uint16_le(s, width);
+			in_uint16_le(s, height);
+			in_uint16_le(s, masklen);
+			in_uint16_le(s, datalen);
+			in_uint8p(s, data, datalen);
+                        in_uint8p(s, mask, masklen);
+
+			cursor = ui_create_cursor(x,y,width,height,mask,data);
+			ui_set_cursor(cursor);
+			cache_put_cursor(cache_idx, cursor);
+			break;
+		case RDP_POINTER_CACHED:
+			in_uint16_le(s, cache_idx);
+			ui_set_cursor(cache_get_cursor(cache_idx));
+			break;
 		default:
 			DEBUG("Pointer message 0x%x\n", message_type);
 	}
diff -u rdesktop-1.0.0.orig/types.h rdesktop-1.0.0/types.h
--- rdesktop-1.0.0.orig/types.h	Mon Oct 16 08:37:52 2000
+++ rdesktop-1.0.0/types.h	Mon Nov  6 00:11:38 2000
@@ -32,6 +32,7 @@
 typedef void *HBITMAP;
 typedef void *HGLYPH;
 typedef void *HCOLOURMAP;
+typedef void *HCURSOR;
 
 typedef struct _COLOURENTRY
 {
diff -u rdesktop-1.0.0.orig/xwin.c rdesktop-1.0.0/xwin.c
--- rdesktop-1.0.0.orig/xwin.c	Mon Oct 16 09:44:48 2000
+++ rdesktop-1.0.0/xwin.c	Mon Nov  6 00:11:38 2000
@@ -19,8 +19,10 @@
 */
 
 #include <X11/Xlib.h>
+#include <X11/Xutil.h>
 #include <time.h>
 #include "rdesktop.h"
+#include <stdlib.h>
 
 extern int width;
 extern int height;
@@ -232,6 +234,103 @@
 void ui_destroy_bitmap(HBITMAP bmp)
 {
 	XFreePixmap(display, (Pixmap)bmp);
+}
+
+HCURSOR ui_create_cursor(unsigned int x, unsigned int y, int width, int height, uint8 *mask, uint8 *data)
+{
+  
+  XImage *imagecursor;
+  XImage *imagemask;
+  Pixmap maskbitmap, cursorbitmap;
+  Cursor cursor;
+  XColor bg,fg;
+  GC gc;
+  int i,x1,y1,scanlinelen;
+  uint8 *cdata,*cmask;
+  uint8 c;
+  
+  cdata=(uint8 *)malloc(sizeof(uint8)*width*height);
+  if (!cdata) 
+    return NULL;
+  
+  scanlinelen=(width+7)>>3;
+  cmask=(uint8 *)malloc(sizeof(uint8)*scanlinelen*height);
+  if (!cmask)
+    {
+      free(cdata);
+      return NULL;
+    }
+  
+  i=(height-1)*scanlinelen;
+  while (i >=0)
+    {
+      for(x1=0; x1<scanlinelen; x1++)
+	{
+	  c= *(mask++);
+	  cmask[i+x1] = ((c&0x1)<<7)|((c&0x2)<<5)|((c&0x4)<<3)|((c&0x8)<<1)|((c&0x10)>>1)|((c&0x20)>>3)|((c&0x40)>>5)|((c&0x80)>>7);
+	}
+      i -= scanlinelen;
+    }
+  
+  fg.red = 0;
+  fg.blue = 0;
+  fg.green = 0;
+  fg.flags = DoRed | DoBlue | DoGreen;
+  bg.red = 65535;
+  bg.blue = 65535;
+  bg.green = 65535;
+  bg.flags = DoRed | DoBlue | DoGreen;
+  
+  maskbitmap = XCreatePixmap(display, wnd, width, height, 1);
+  cursorbitmap = XCreatePixmap(display, wnd, width, height, 1);
+  gc= XCreateGC(display, maskbitmap, 0, NULL);
+  XSetFunction(display, gc, GXcopy);  
+
+  imagemask = XCreateImage(display, visual, 1, XYBitmap, 0,
+		       cmask, width, height, 8, 0);
+
+  imagecursor = XCreateImage(display, visual, 1, XYBitmap, 0,
+		       cdata, width, height, 8, 0);
+
+  for (y1=height-1; y1>=0; y1--) 
+    for (x1=0; x1<width; x1++) {
+      if (data[0] >= 0x80 || data[1] >= 0x80 || data[2] >= 0x80)
+	if (XGetPixel(imagemask,x1,y1))
+	  {
+	    XPutPixel(imagecursor,x1,y1,0);
+	    XPutPixel(imagemask,x1,y1,0); /* mask is blank for text cursor! */
+	  }
+	else
+	  XPutPixel(imagecursor,x1,y1,1);
+      else
+	XPutPixel(imagecursor,x1,y1,0);
+      data+=3;
+    }
+  
+  XPutImage(display, maskbitmap, gc, imagemask, 0, 0, 0, 0, width, height);
+  XPutImage(display, cursorbitmap, gc, imagecursor, 0, 0, 0, 0, width, height);
+  XFree(imagemask);
+  XFree(imagecursor);
+  free(cmask); 
+  free(cdata);
+  XFreeGC(display,gc);
+  
+  cursor = XCreatePixmapCursor(display, cursorbitmap, maskbitmap, &fg, &bg, x, y);
+
+ XFreePixmap(display,maskbitmap); 
+ XFreePixmap(display,cursorbitmap);
+
+ return (HCURSOR)cursor;
+}
+
+void ui_set_cursor(HCURSOR cursor)
+{
+	XDefineCursor(display, wnd, (Cursor)cursor);
+}
+
+void ui_destroy_cursor(HCURSOR cursor)
+{
+        XFreeCursor(display, (Cursor)cursor);
 }
 
 HGLYPH ui_create_glyph(int width, int height, uint8 *data)