Package:  xrdp
Version:  0.5.0-2
Severity: important
Tags:     patch
User:     debian-...@lists.debian.org
Usertags: debian-edu

The attached patch fixes two things.  First, it implement support for
server desktop resize in xrdp, allowing the server to tell the client to
resize the desktop.  Next, it implement a workaround for a bug in
rdesktop (<URL: http://bugs.debian.org/709529 >), making sure rdesktop
handle desktop resizes properly.  The patch is written by my college
Dag-Erling Smørgrav, which is too busy to push the patches upstream
himself.

Please include the patch in a future version of xrdp.

-- 
Happy hacking
Petter Reinholdtsen
--- xrdp-HEAD-a9cfc23.orig/vnc/vnc.h	2012-10-06 22:58:55.585928184 +0200
+++ xrdp-HEAD-a9cfc23/vnc/vnc.h	2012-10-07 19:24:30.877751563 +0200
@@ -102,6 +102,7 @@
   int mod_width;
   int mod_height;
   int mod_bpp;
+  int next_update_incremental;
   char mod_name[256];
   int mod_mouse_state;
   int palette[256];
--- xrdp-HEAD-a9cfc23.orig/vnc/vnc.c	2012-10-06 22:58:55.585928184 +0200
+++ xrdp-HEAD-a9cfc23/vnc/vnc.c	2012-10-07 19:24:30.877751563 +0200
@@ -22,6 +22,62 @@
 
 #include "vnc.h"
 
+/******************************************************************************
+ * Send a framebuffer update request.
+ *
+ * Requests either a full or incremental update based on the value of the
+ * next_update_incremental flag, and resets the flag to 1 so the next
+ * update will be incremental unless something (like a framebuffer resize
+ * event) causes the flag to be cleared again.
+ */
+static int DEFAULT_CC
+request_framebuffer_update(struct vnc* v, int x, int y, int w, int h)
+{
+  struct stream* s;
+  int error;
+
+  make_stream(s);
+  init_stream(s, 16);
+  out_uint8(s, 3);
+  out_uint8(s, v->next_update_incremental);
+  v->next_update_incremental = 1;
+  out_uint16_be(s, x);
+  out_uint16_be(s, y);
+  out_uint16_be(s, w ? w : v->mod_width);
+  out_uint16_be(s, h ? h : v->mod_height);
+  error = lib_send(v, s->data, 10);
+  free_stream(s);
+  return error;
+}
+
+/******************************************************************************
+ * Process a framebuffer resize event.
+ *
+ * If the server size differs from the client size, perform a server reset
+ * and ask that the next framebuffer update request be a full update
+ * rather than an incremental update.
+ *
+ * It is very important to *only* request a full update if the size
+ * actually changed, since servers that support the ExtendedDesktopSize
+ * encoding will send one after every framebuffer update.
+ */
+static int DEFAULT_CC
+resize_framebuffer(struct vnc* v)
+{
+  char text[256];
+
+  if (v->mod_width != v->server_width || v->mod_height != v->server_height)
+  {
+    v->mod_width = v->server_width;
+    v->mod_height = v->server_height;
+    v->server_reset(v, v->mod_width, v->mod_height, v->mod_bpp);
+    v->next_update_incremental = 0;
+    g_sprintf(text, "desktop resized to %dx%d", v->mod_width, v->mod_height);
+    v->server_msg(v, text, 1);
+  }
+  return 0;
+}
+
 /******************************************************************************/
 /* taken from vncauth.c */
 void DEFAULT_CC
@@ -306,18 +362,11 @@
   else if (msg == 200) /* invalidate */
   {
     /* FrambufferUpdateRequest */
-    init_stream(s, 8192);
-    out_uint8(s, 3);
-    out_uint8(s, 0);
     x = (param1 >> 16) & 0xffff;
-    out_uint16_be(s, x);
     y = param1 & 0xffff;
-    out_uint16_be(s, y);
     cx = (param2 >> 16) & 0xffff;
-    out_uint16_be(s, cx);
     cy = param2 & 0xffff;
-    out_uint16_be(s, cy);
-    error = lib_send(v, s->data, 10);
+    error = request_framebuffer_update(v, x, y, cx, cy);
   }
   free_stream(s);
   return error;
@@ -621,6 +670,30 @@
           error = v->server_set_cursor(v, x, y, cursor_data, cursor_mask);
         }
       }
+      else if (encoding == 0xffffff21) /* desktop resize */
+      {
+        /* note new dimensions for later */
+        v->server_width = cx;
+        v->server_height = cy;
+      }
+      else if (encoding == 0xfffffecc) /* extended desktop resize */
+      {
+        init_stream(s, 8192);
+        error = lib_recv(v, s->data, 4);
+        if (error == 0)
+        {
+          in_uint8(s, k); /* number of screens */
+          in_uint8s(s, 3);
+          error = lib_recv(v, s->data, k * 16);
+          if (error == 0)
+          {
+            in_uint8s(s, k * 16); /* skip screen list */
+            /* note new dimensions for later */
+            v->server_width = cx;
+            v->server_height = cy;
+          }
+        }
+      }
       else
       {
         g_sprintf(text, "error in lib_framebuffer_update encoding = %8.8x",
@@ -634,19 +707,16 @@
     error = v->server_end_update(v);
   }
   g_free(data);
+  free_stream(s);
+  if (v->mod_width != v->server_width || v->mod_height != v->server_height)
+  {
+    /* perform actual resize outside the update */
+    resize_framebuffer(v);
+  }
   if (error == 0)
   {
-    /* FrambufferUpdateRequest */
-    init_stream(s, 8192);
-    out_uint8(s, 3);
-    out_uint8(s, 1);
-    out_uint16_be(s, 0);
-    out_uint16_be(s, 0);
-    out_uint16_be(s, v->mod_width);
-    out_uint16_be(s, v->mod_height);
-    error = lib_send(v, s->data, 10);
+    error = request_framebuffer_update(v, 0, 0, 0, 0);
   }
-  free_stream(s);
   return error;
 }
 
@@ -1077,12 +1147,14 @@
     init_stream(s, 8192);
     out_uint8(s, 2);
     out_uint8(s, 0);
-    out_uint16_be(s, 3);
+    out_uint16_be(s, 5);
     out_uint32_be(s, 0); /* raw */
     out_uint32_be(s, 1); /* copy rect */
     out_uint32_be(s, 0xffffff11); /* cursor */
+    out_uint32_be(s, 0xffffff21); /* desktop resize */
+    out_uint32_be(s, 0xfffffecc); /* extended desktop resize */
     v->server_msg(v, "sending encodings", 0);
-    error = lib_send(v, s->data, 4 + 3 * 4);
+    error = lib_send(v, s->data, 4 + 5 * 4);
   }
   if (error == 0)
   {
@@ -1090,16 +1162,8 @@
   }
   if (error == 0)
   {
-    /* FrambufferUpdateRequest */
-    init_stream(s, 8192);
-    out_uint8(s, 3);
-    out_uint8(s, 0);
-    out_uint16_be(s, 0);
-    out_uint16_be(s, 0);
-    out_uint16_be(s, v->mod_width);
-    out_uint16_be(s, v->mod_height);
-    v->server_msg(v, "sending framebuffer update request", 0);
-    error = lib_send(v, s->data, 10);
+    v->next_update_incremental = 0;
+    error = request_framebuffer_update(v, 0, 0, 0, 0);
   }
   if (error == 0)
   {
--- xrdp-HEAD-a9cfc23.orig/xrdp/xrdp_mm.c	2012-10-06 22:58:55.587928185 +0200
+++ xrdp-HEAD-a9cfc23/xrdp/xrdp_mm.c	2012-10-07 19:24:30.878751564 +0200
@@ -1361,6 +1361,7 @@
 server_reset(struct xrdp_mod* mod, int width, int height, int bpp)
 {
   struct xrdp_wm* wm = (struct xrdp_wm *)NULL;
+  int oldwidth, oldheight;
 
   wm = (struct xrdp_wm*)(mod->wm);
   if (wm->client_info == 0)
@@ -1379,6 +1380,9 @@
   {
     return 0;
   }
+  /* store the old dimensions for the rdesktop hack below */
+  oldwidth = wm->client_info->width;
+  oldheight = wm->client_info->height;
   /* reset lib, client_info gets updated in libxrdp_reset */
   if (libxrdp_reset(wm->session, width, height, bpp) != 0)
   {
@@ -1392,6 +1396,21 @@
   /* load some stuff */
   xrdp_wm_load_static_colors(wm);
   xrdp_wm_load_static_pointers(wm);
+  /*
+   * This is a workaround for a bug in rdesktop.  When the screen size
+   * changes, rdesktop resizes its window (unless running in full-screen
+   * mode) but does not reset the clipping rectangle, causing the portion
+   * of the screen outside the old boundaries to remain blank.  By drawing
+   * a line that lies partly outside the screen, we trick rdesktop into
+   * resetting the clipping rectangle.  Note that the line must lie partly
+   * within the screen boundaries, or it will simply be ignored.
+   */
+  if (oldwidth < width || oldheight < height)
+  {
+    server_begin_update(mod);
+    server_draw_line(mod, width - 2, height - 2, width, height);
+    server_end_update(mod);
+  }
   return 0;
 }
 

Reply via email to