Jacek Caban : server: Introduce IOCTL_CONDRV_SCROLL ioctl.

Alexandre Julliard julliard at winehq.org
Wed Jul 29 15:47:00 CDT 2020


Module: wine
Branch: master
Commit: 7ae370a5491b58eeec03961b09dcf5ae5e53e411
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=7ae370a5491b58eeec03961b09dcf5ae5e53e411

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Wed Jul 29 12:36:05 2020 +0200

server: Introduce IOCTL_CONDRV_SCROLL ioctl.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 include/wine/condrv.h |  29 +++++++++----
 server/console.c      | 118 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 135 insertions(+), 12 deletions(-)

diff --git a/include/wine/condrv.h b/include/wine/condrv.h
index 839db84ea5..a6df63155c 100644
--- a/include/wine/condrv.h
+++ b/include/wine/condrv.h
@@ -22,6 +22,7 @@
 #define _INC_CONDRV
 
 #include "winioctl.h"
+#include "wincon.h"
 
 /* common console input and output ioctls */
 #define IOCTL_CONDRV_GET_MODE              CTL_CODE(FILE_DEVICE_CONSOLE,  0, METHOD_BUFFERED, FILE_READ_PROPERTIES)
@@ -43,6 +44,7 @@
 #define IOCTL_CONDRV_SET_OUTPUT_INFO       CTL_CODE(FILE_DEVICE_CONSOLE, 33, METHOD_BUFFERED, FILE_WRITE_PROPERTIES)
 #define IOCTL_CONDRV_ACTIVATE              CTL_CODE(FILE_DEVICE_CONSOLE, 34, METHOD_BUFFERED, FILE_WRITE_DATA)
 #define IOCTL_CONDRV_FILL_OUTPUT           CTL_CODE(FILE_DEVICE_CONSOLE, 35, METHOD_BUFFERED, FILE_WRITE_DATA)
+#define IOCTL_CONDRV_SCROLL                CTL_CODE(FILE_DEVICE_CONSOLE, 36, METHOD_BUFFERED, FILE_WRITE_DATA)
 
 /* console renderer ioctls */
 #define IOCTL_CONDRV_GET_RENDERER_EVENTS   CTL_CODE(FILE_DEVICE_CONSOLE, 70, METHOD_BUFFERED, FILE_READ_PROPERTIES)
@@ -133,6 +135,16 @@ struct condrv_output_info_params
     struct condrv_output_info info;   /* output info */
 };
 
+#define SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM     0x0001
+#define SET_CONSOLE_OUTPUT_INFO_CURSOR_POS      0x0002
+#define SET_CONSOLE_OUTPUT_INFO_SIZE            0x0004
+#define SET_CONSOLE_OUTPUT_INFO_ATTR            0x0008
+#define SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW  0x0010
+#define SET_CONSOLE_OUTPUT_INFO_MAX_SIZE        0x0020
+#define SET_CONSOLE_OUTPUT_INFO_FONT            0x0040
+#define SET_CONSOLE_OUTPUT_INFO_COLORTABLE      0x0080
+#define SET_CONSOLE_OUTPUT_INFO_POPUP_ATTR      0x0100
+
 /* IOCTL_CONDRV_FILL_OUTPUT params */
 struct condrv_fill_output_params
 {
@@ -145,15 +157,14 @@ struct condrv_fill_output_params
     unsigned short attr;              /* attribute to write */
 };
 
-#define SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM     0x0001
-#define SET_CONSOLE_OUTPUT_INFO_CURSOR_POS      0x0002
-#define SET_CONSOLE_OUTPUT_INFO_SIZE            0x0004
-#define SET_CONSOLE_OUTPUT_INFO_ATTR            0x0008
-#define SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW  0x0010
-#define SET_CONSOLE_OUTPUT_INFO_MAX_SIZE        0x0020
-#define SET_CONSOLE_OUTPUT_INFO_FONT            0x0040
-#define SET_CONSOLE_OUTPUT_INFO_COLORTABLE      0x0080
-#define SET_CONSOLE_OUTPUT_INFO_POPUP_ATTR      0x0100
+/* IOCTL_CONDRV_SCROLL params */
+struct condrv_scroll_params
+{
+    SMALL_RECT   scroll;              /* source rectangle */
+    COORD        origin;              /* destination coordinates */
+    SMALL_RECT   clip;                /* clipping rectangle */
+    char_info_t  fill;                /* empty character info */
+};
 
 /* IOCTL_CONDRV_GET_RENDERER_EVENTS result */
 struct condrv_renderer_event
diff --git a/server/console.c b/server/console.c
index 8bd3e94e65..f924ddc06b 100644
--- a/server/console.c
+++ b/server/console.c
@@ -1446,7 +1446,85 @@ static int fill_console_output( struct screen_buffer *screen_buffer, char_info_t
 
 /* scroll parts of a screen buffer */
 static void scroll_console_output( struct screen_buffer *screen_buffer, int xsrc, int ysrc, int xdst, int ydst,
-                                   int w, int h )
+                                   int w, int h, const rectangle_t *clip, char_info_t fill )
+{
+    struct condrv_renderer_event evt;
+    rectangle_t src, dst;
+    int x, y;
+
+    src.left   = max( xsrc, clip->left );
+    src.top    = max( ysrc, clip->top );
+    src.right  = min( xsrc + w - 1, clip->right );
+    src.bottom = min( ysrc + h - 1, clip->bottom );
+
+    dst.left   = xdst;
+    dst.top    = ydst;
+    dst.right  = xdst + w - 1;
+    dst.bottom = ydst + h - 1;
+
+    if (dst.left < clip->left)
+    {
+        xsrc += clip->left - dst.left;
+        w -= clip->left - dst.left;
+        dst.left = clip->left;
+    }
+    if (dst.top < clip->top)
+    {
+        ysrc += clip->top - dst.top;
+        h -= clip->top - dst.top;
+        dst.top = clip->top;
+    }
+    if (dst.right  > clip->right)  w -= dst.right  - clip->right;
+    if (dst.bottom > clip->bottom) h -= dst.bottom - clip->bottom;
+
+    if (w > 0 && h > 0)
+    {
+        if (ysrc < ydst)
+        {
+            for (y = h; y > 0; y--)
+            {
+                memcpy( &screen_buffer->data[(dst.top + y - 1) * screen_buffer->width + dst.left],
+                        &screen_buffer->data[(ysrc + y - 1) * screen_buffer->width + xsrc],
+                        w * sizeof(screen_buffer->data[0]) );
+            }
+        }
+        else
+        {
+            for (y = 0; y < h; y++)
+            {
+                /* we use memmove here because when psrc and pdst are the same,
+                 * copies are done on the same row, so the dst and src blocks
+                 * can overlap */
+                memmove( &screen_buffer->data[(dst.top + y) * screen_buffer->width + dst.left],
+                         &screen_buffer->data[(ysrc + y) * screen_buffer->width + xsrc],
+                         w * sizeof(screen_buffer->data[0]) );
+            }
+        }
+    }
+
+    for (y = src.top; y <= src.bottom; y++)
+    {
+        int left  = src.left;
+        int right = src.right;
+        if (dst.top <= y && y <= dst.bottom)
+        {
+            if (dst.left <= src.left) left  = max( left, dst.right + 1 );
+            if (dst.left >= src.left) right = min( right, dst.left - 1 );
+        }
+        for (x = left; x <= right; x++) screen_buffer->data[y * screen_buffer->width + x] = fill;
+    }
+
+    /* FIXME: this could be enhanced, by signalling scroll */
+    evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
+    memset(&evt.u, 0, sizeof(evt.u));
+    evt.u.update.top    = min( src.top, dst.top );
+    evt.u.update.bottom = max( src.bottom, dst.bottom );
+    console_input_events_append( screen_buffer->input, &evt );
+}
+
+/* scroll parts of a screen buffer */
+static void scroll_console_output_req( struct screen_buffer *screen_buffer, int xsrc, int ysrc, int xdst, int ydst,
+                                       int w, int h )
 {
     int				j;
     char_info_t *psrc, *pdst;
@@ -1811,6 +1889,40 @@ static int screen_buffer_ioctl( struct fd *fd, ioctl_code_t code, struct async *
             return !get_error();
         }
 
+    case IOCTL_CONDRV_SCROLL:
+        {
+            const struct condrv_scroll_params *params = get_req_data();
+            rectangle_t clip;
+            if (get_req_data_size() != sizeof(*params))
+            {
+                set_error( STATUS_INVALID_PARAMETER );
+                return 0;
+            }
+            if (console_input_is_bare( screen_buffer->input ) || !screen_buffer->input)
+            {
+                set_error( STATUS_OBJECT_TYPE_MISMATCH );
+                return 0;
+            }
+            clip.left   = max( params->clip.Left, 0 );
+            clip.top    = max( params->clip.Top,  0 );
+            clip.right  = min( params->clip.Right,  screen_buffer->width - 1 );
+            clip.bottom = min( params->clip.Bottom, screen_buffer->height - 1 );
+            if (clip.left > clip.right || clip.top > clip.bottom || params->scroll.Left < 0 || params->scroll.Top < 0 ||
+                params->scroll.Right >= screen_buffer->width || params->scroll.Bottom >= screen_buffer->height ||
+                params->scroll.Right < params->scroll.Left || params->scroll.Top > params->scroll.Bottom ||
+                params->origin.X < 0 || params->origin.X >= screen_buffer->width || params->origin.Y < 0 ||
+                params->origin.Y >= screen_buffer->height)
+            {
+                set_error( STATUS_INVALID_PARAMETER );
+                return 0;
+            }
+
+            scroll_console_output( screen_buffer, params->scroll.Left, params->scroll.Top, params->origin.X, params->origin.Y,
+                                   params->scroll.Right - params->scroll.Left + 1, params->scroll.Bottom - params->scroll.Top + 1,
+                                   &clip, params->fill );
+            return !get_error();
+        }
+
     default:
         set_error( STATUS_INVALID_HANDLE );
         return 0;
@@ -2182,8 +2294,8 @@ DECL_HANDLER(move_console_output)
             release_object( screen_buffer );
             return;
         }
-        scroll_console_output( screen_buffer, req->x_src, req->y_src, req->x_dst, req->y_dst,
-                               req->w, req->h );
+        scroll_console_output_req( screen_buffer, req->x_src, req->y_src, req->x_dst, req->y_dst,
+                                   req->w, req->h );
         release_object( screen_buffer );
     }
 }




More information about the wine-cvs mailing list