--- Begin Message ---
- To: John-Paul Gignac <jjgignac@ncln.ca>
- Cc: submit@bugs.debian.org
- Subject: Re: Screen Magnifier for svncviewer
- From: Ola Lundqvist <opal@debian.org>
- Date: Mon, 28 Jul 2003 23:09:34 +0200
- Message-id: <20030728210934.GB5915@chrystal.opal.dhs.org>
- Reply-to: opal@debian.org
- In-reply-to: <20030728210542.GA13356@ncln.ca>
- References: <20030728210542.GA13356@ncln.ca>
Package: svncviewer
Severity: wishlist
Tags: patch
Hello
On Mon, Jul 28, 2003 at 05:05:42PM -0400, John-Paul Gignac wrote:
> Ola,
>
> I've attached a patch for a screen magnifier for svncviewer. I'm
> submitting the patch to you since I can't find any indication that the
> original authors are still supporting svncviewer.
>
> This simple utility is an attempt to address the need for an
> unobtrusive open source screen magnifier for the visually impaired.
> This is just a first version but it has the complete basic level
> of functionality.
Really nice. I'll see if I can find it useful and stable enough to
include it in the svncviewer for Debian.
> The magnifier operates as a wrapper around the three vgagl functions
> gl_putbox, gl_fillbox and gl_copybox. I've ensured that the patch can
> be completely disabled by commenting out a single line. (vncviewer.h:132)
>
> To use it, recompile and execute the patched version of svgalib, and
> press the Print Screen key to enable the magnifier. The magnifier
> occupies the bottom 25% of the display. The desktop scrolls up and
> down in response to mouse movements within the top 75% of the display.
> The magnified region follows the mouse pointer in real time. As you can
> imagine, it's fairly heavy on CPU usage, but for those with poor vision,
> it's a very acceptable compromise.
>
> I'd like to request that you either incorporate the patch into the Debian
> release of svncviewer, or create a separate package (Eg, svncviewer-mag)
> with the incorporated change.
I'll think about it. It was a loong time since I got svga working
so it might take some time to verify it. :)
Regards,
// Ola
> Thank you for your time!
>
> John-Paul Gignac
> diff -uN svncviewer-0.1.1/Imakefile svncviewer-mag-0.1.1/Imakefile
> --- svncviewer-0.1.1/Imakefile Sat Jul 26 18:38:07 2003
> +++ svncviewer-mag-0.1.1/Imakefile Sun Jul 27 21:04:20 2003
> @@ -7,8 +7,8 @@
>
> CCOPTIONS = -Wall
>
> -SRCS = args.c rfbproto.c sockets.c svncviewer.c svga.c kbd.c
> -OBJS = args.o rfbproto.o sockets.o svncviewer.o svga.o kbd.o
> +SRCS = args.c rfbproto.c sockets.c svncviewer.c svga.c kbd.c magnifier.c
> +OBJS = args.o rfbproto.o sockets.o svncviewer.o svga.o kbd.o magnifier.o
> INCLUDES = -I../include -I.
> #VNCAUTH_LIB = /usr/lib/libvncauth.a
> SVGALIB = -lvgagl -lvga
> Common subdirectories: svncviewer-0.1.1/debian and svncviewer-mag-0.1.1/debian
> diff -uN svncviewer-0.1.1/kbd.c svncviewer-mag-0.1.1/kbd.c
> --- svncviewer-0.1.1/kbd.c Tue Jul 27 15:56:49 1999
> +++ svncviewer-mag-0.1.1/kbd.c Mon Jul 28 14:41:16 2003
> @@ -107,6 +107,13 @@
> exit (0);
> }
>
> +#ifdef MAGNIFIER
> + if (ks == XK_Print && KeyState[key] == KEY_EVENTPRESS) {
> + mag_toggle();
> + continue;
> + }
> +#endif
> +
> /*
> * This is important:
> * We do not send `NoSymbol's to the server. It can deal with
> diff -uN svncviewer-0.1.1/magnifier.c svncviewer-mag-0.1.1/magnifier.c
> --- svncviewer-0.1.1/magnifier.c Wed Dec 31 19:00:00 1969
> +++ svncviewer-mag-0.1.1/magnifier.c Mon Jul 28 14:43:33 2003
> @@ -0,0 +1,304 @@
> +/*
> + * magnifier.c - a screen magnifier for svncviewer
> + */
> +
> +#include <vncviewer.h>
> +
> +#ifdef MAGNIFIER
> +
> +#undef gl_copybox
> +#undef gl_fillbox
> +#undef gl_putbox
> +
> +#include <vga.h>
> +#include <vgagl.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +CARD8 *mag_buffer = NULL;
> +CARD8 *mag_magnifier = NULL;
> +int mag_width = 0;
> +int mag_pixel = 0;
> +
> +static int y_offset = 0;
> +static int new_y_offset = 0;
> +static int cur_mouse_x = 0, cur_mouse_y = 0;
> +static int magnifier_height = 150;
> +static int magnifier_margin = 4;
> +static int scroll_margin = 40;
> +static int magnification_level = 5;
> +static int zoom_x = 0, zoom_y = 0;
> +static int zoom_w, zoom_h;
> +static int new_zoom_x = 0, new_zoom_y = 0;
> +static int magnifier_on = 0;
> +
> +static void mag_refresh(int x, int y,int width,int height);
> +
> +#define max(a,b) ((a)>(b)?(a):(b))
> +#define min(a,b) ((a)<(b)?(a):(b))
> +
> +void
> +mag_init(void)
> +{
> + if( mag_magnifier) free( mag_magnifier);
> + if( mag_buffer) free( mag_buffer);
> +
> + magnifier_height = si.framebufferHeight / 4;
> + scroll_margin = magnifier_height * 3 / 4;
> +
> + mag_pixel = myFormat.bitsPerPixel / 8;
> + mag_width = mag_pixel * si.framebufferWidth;
> + mag_buffer = (CARD8 *)malloc( mag_width * si.framebufferHeight);
> + mag_magnifier = (CARD8 *)malloc( mag_width * magnifier_height);
> +
> + zoom_w = (si.framebufferWidth - magnifier_margin * 2) / magnification_level;
> + zoom_h = (magnifier_height - magnifier_margin * 2) / magnification_level;
> +}
> +
> +void
> +mag_putbox(int x, int y, int width, int height, void *buf)
> +{
> + int bytesPerLine = mag_pixel * width;
> + CARD8 *line = mag_buffer + mag_width * y + x * mag_pixel;
> + CARD8 *src = buf;
> + int q;
> +
> + // First, copy the data into the memory buffer
> + for (q = 0; q < height; q++) {
> + memcpy( line, src, bytesPerLine);
> + src += bytesPerLine;
> + line += mag_width;
> + }
> +
> + mag_refresh(x, y, width, height);
> +}
> +
> +void
> +mag_copybox(int x1, int y1, int w, int h, int x2, int y2)
> +{
> + CARD8 *srcline, *destline;
> + int q, width = mag_pixel * w, increment;
> +
> + if( y1 >= y2) {
> + // Copy forwards
> + srcline = mag_buffer + mag_width * y1 + x1 * mag_pixel;
> + destline = mag_buffer + mag_width * y2 + x2 * mag_pixel;
> + increment = mag_width;
> + } else {
> + // Copy backwards
> + srcline = mag_buffer + mag_width * (y1 + h - 1) + x1 * mag_pixel;
> + destline = mag_buffer + mag_width * (y2 + h - 1) + x2 * mag_pixel;
> + increment = -mag_width;
> + }
> +
> + // First, copy the data within the memory buffer
> + for (q = 0; q < h; q++) {
> + memmove( destline, srcline, width);
> + srcline += increment;
> + destline += increment;
> + }
> +
> + // Now copy the results to the display
> + mag_refresh(x2, y2, w, h);
> +}
> +
> +void
> +mag_fillbox( int x, int y, int w, int h, int c)
> +{
> + CARD8 *line = mag_buffer + mag_width * y + mag_pixel * x, *pixel;
> + int q, p;
> +
> + switch( myFormat.bitsPerPixel) {
> + case 8:
> + for (q = 0; q < h; q++) {
> + pixel = line;
> + for (p = 0; p < w; p++) {
> + *(pixel++) = (CARD8)c;
> + }
> + line += mag_width;
> + }
> + break;
> + case 16:
> + for (q = 0; q < h; q++) {
> + pixel = line;
> + for (p = 0; p < w; p++) {
> + *(CARD16*)pixel = (CARD16)c;
> + pixel += 2;
> + }
> + line += mag_width;
> + }
> + break;
> + case 32:
> + for (q = 0; q < h; q++) {
> + pixel = line;
> + for (p = 0; p < w; p++) {
> + *(CARD32*)pixel = (CARD32)c;
> + pixel += 4;
> + }
> + line += mag_width;
> + }
> + break;
> + }
> +
> + // Now copy the results to the display
> + mag_refresh(x, y, w, h);
> +}
> +
> +void
> +mag_mousepos( int x, int y)
> +{
> + cur_mouse_x = x;
> + cur_mouse_y = y;
> +
> + // Compute the vertical scroll offset
> + if( y > si.framebufferHeight - magnifier_height - scroll_margin) {
> + new_y_offset = max( new_y_offset, y - si.framebufferHeight +
> + magnifier_height + scroll_margin);
> + new_y_offset = min( new_y_offset, magnifier_height);
> + }
> + else if( y < magnifier_height + scroll_margin) {
> + new_y_offset = min( new_y_offset, y - scroll_margin);
> + new_y_offset = max( new_y_offset, 0);
> + }
> +
> + // Compute the zoom area coordinates
> + new_zoom_x = x - (si.framebufferWidth - magnifier_margin * 2) /
> + magnification_level / 2;
> + new_zoom_x = max(min(new_zoom_x, si.framebufferWidth - zoom_w), 0);
> + new_zoom_y = y - (magnifier_height - magnifier_margin * 2) /
> + magnification_level / 2;
> + new_zoom_y = max(min(new_zoom_y, si.framebufferHeight - zoom_h), 0);
> +}
> +
> +static void
> +magnify_area(int x,int y,int w,int h)
> +{
> + int x2,y2,q,p,i,j,c;
> + CARD8 *src, *dest, *from, *to;
> +
> + if( !magnifier_on) return;
> +
> + if( zoom_x != new_zoom_x || zoom_y != new_zoom_y) {
> + // The magnifier is due to scroll - If the rectangle contains
> + // the mouse pointer then scroll now.
> + if( cur_mouse_x >= x && cur_mouse_x < x + w &&
> + cur_mouse_y >= y && cur_mouse_y < y + h) {
> +
> + zoom_x = new_zoom_x;
> + zoom_y = new_zoom_y;
> +
> + // redraw the whole thing
> + x = 0;
> + y = 0;
> + w = si.framebufferWidth;
> + h = si.framebufferHeight;
> + }
> + }
> +
> + // Clip the source area to the magnification area
> + if( x < zoom_x) {
> + w -= zoom_x - x;
> + x = zoom_x;
> + }
> + if( x + w > zoom_x + zoom_w) {
> + w = zoom_x + zoom_w - x;
> + }
> + if( y < zoom_y) {
> + h -= zoom_y - y;
> + y = zoom_y;
> + }
> + if( y + h > zoom_y + zoom_h) {
> + h = zoom_y + zoom_h - y;
> + }
> + if( w <= 0 || h <= 0) return;
> +
> + // Figure out the target coordinate
> + x2 = magnifier_margin + (x - zoom_x) * magnification_level;
> + y2 = magnifier_margin + (y - zoom_y) * magnification_level;
> +
> + src = mag_buffer + y * mag_width + x * mag_pixel;
> + dest = mag_magnifier + y2 * mag_width + x2 * mag_pixel;
> +
> + for( q = 0; q < h; q++) {
> + from = src;
> + to = dest;
> + for( p = 0; p < w; p++) {
> + for( i=0; i < magnification_level; i++) {
> + for( c=0; c < mag_pixel; c++) {
> + *(to++) = from[c];
> + }
> + }
> + from += mag_pixel;
> + }
> + to = dest + mag_width;
> + for( j=1; j < magnification_level; j++) {
> + memcpy( to, dest, w * mag_pixel * magnification_level);
> + to += mag_width;
> + }
> + dest = to;
> + src += mag_width;
> + }
> +
> + // Now copy the magnifier to the display
> + gl_putboxpart( x2, y2 + si.framebufferHeight - magnifier_height,
> + w * magnification_level, h * magnification_level,
> + si.framebufferWidth, magnifier_height,
> + mag_magnifier, x2, y2);
> +}
> +
> +static void
> +mag_refresh(int x, int y,int width,int height)
> +{
> + int y_vis, h_vis;
> +
> + if( magnifier_on && new_y_offset != y_offset) {
> + // The screen is due to scroll - If the rectangle contains the mouse
> + // pointer then scroll now.
> + if( cur_mouse_x >= x && cur_mouse_x < x + width &&
> + cur_mouse_y >= y && cur_mouse_y < y + height) {
> +
> + y_offset = new_y_offset;
> +
> + // redraw the whole thing
> + x = 0;
> + y = 0;
> + width = si.framebufferWidth;
> + height = si.framebufferHeight;
> + }
> + }
> +
> + magnify_area( x, y, width, height);
> +
> + y_vis = y;
> + h_vis = height;
> +
> + if( magnifier_on) {
> + // Clip to the visible part of the display
> + if (y_vis < y_offset) {
> + h_vis -= (y_offset - y_vis);
> + y_vis = y_offset;
> + }
> + if (y_vis + h_vis > si.framebufferHeight-magnifier_height+y_offset) {
> + h_vis = si.framebufferHeight-magnifier_height+y_offset - y_vis;
> + }
> + if (h_vis <= 0) return;
> + }
> +
> + // Perform the copy
> + gl_putboxpart(x, y_vis - (magnifier_on ? y_offset : 0), width, h_vis,
> + si.framebufferWidth, si.framebufferHeight,
> + mag_buffer, x, y_vis);
> +}
> +
> +void
> +mag_toggle(void)
> +{
> + magnifier_on ^= 1;
> + mag_refresh(0,0,si.framebufferWidth,si.framebufferHeight);
> + if( magnifier_on) {
> + gl_fillbox( 0, si.framebufferHeight - magnifier_height,
> + si.framebufferWidth, magnifier_height, 0);
> + magnify_area(0,0,si.framebufferWidth,si.framebufferHeight);
> + }
> +}
> +#endif
> diff -uN svncviewer-0.1.1/makefile svncviewer-mag-0.1.1/makefile
> --- svncviewer-0.1.1/makefile Sun Nov 14 09:26:19 1999
> +++ svncviewer-mag-0.1.1/makefile Sun Jul 27 21:04:24 2003
> @@ -1,7 +1,7 @@
>
>
> -SRCS = args.c rfbproto.c sockets.c svncviewer.c svga.c kbd.c
> -OBJS = args.o rfbproto.o sockets.o svncviewer.o svga.o kbd.o
> +SRCS = args.c rfbproto.c sockets.c svncviewer.c svga.c kbd.c magnifier.c
> +OBJS = args.o rfbproto.o sockets.o svncviewer.o svga.o kbd.o magnifier.o
> INCLUDES = -I../include -I. -I../vnc/include
> VNCAUTH_LIB = ../libvncauth/libvncauth.a
> SVGALIB = -lvgagl -lvga
> diff -uN svncviewer-0.1.1/svga.c svncviewer-mag-0.1.1/svga.c
> --- svncviewer-0.1.1/svga.c Sun Mar 15 13:38:03 1998
> +++ svncviewer-mag-0.1.1/svga.c Mon Jul 28 14:41:16 2003
> @@ -100,6 +100,12 @@
>
> x = mouse_getx ();
> y = mouse_gety ();
> +
> +#ifdef MAGNIFIER
> + // Inform the magnifier of the mouse position
> + mag_mousepos(x, y);
> +#endif
> +
> button = mouse_getbutton ();
> button = ((button & 1) << 2) | ((button >> 2) & 1) | (button & 0xfa);
> SendPointerEvent (x, y, button);
> @@ -168,6 +174,12 @@
> myFormat.blueShift = 0;
> }
> }
> +
> +#ifdef MAGNIFIER
> + // Initialize the magnifier
> + mag_init();
> +#endif
> +
> return;
>
> nomode:
> Binary files svncviewer-0.1.1/svncviewer and svncviewer-mag-0.1.1/svncviewer differ
> diff -uN svncviewer-0.1.1/vncviewer.h svncviewer-mag-0.1.1/vncviewer.h
> --- svncviewer-0.1.1/vncviewer.h Sun Mar 15 13:26:02 1998
> +++ svncviewer-mag-0.1.1/vncviewer.h Mon Jul 28 14:45:12 2003
> @@ -129,6 +129,22 @@
> extern void CopyDataToScreen(CARD8 *buf, int x, int y, int width, int height);
> extern Bool svncKeyboardInit(void);
>
> +#define MAGNIFIER
> +#ifdef MAGNIFIER
> +/* magnifier.c */
> +
> +extern void mag_init(void);
> +extern void mag_putbox(int x, int y, int width, int height, void *buf);
> +extern void mag_copybox(int x1, int y1, int w, int h, int x2, int y2);
> +extern void mag_fillbox( int x, int y, int w, int h, int c);
> +extern void mag_mousepos( int x, int y);
> +extern void mag_toggle(void);
> +
> +#define gl_copybox mag_copybox
> +#define gl_fillbox mag_fillbox
> +#define gl_putbox mag_putbox
> +#endif
> +
> #define STORE_COLOUR(xc) gl_setpalettecolor ((xc).pixel, (xc).red >> 10, \
> (xc).green >> 10, (xc).blue >> 10)
> #define COPY_AREA(x1 ,y1, w, h, x2, y2) gl_copybox (x1, y1, w, h, x2, y2)
--
--------------------- Ola Lundqvist ---------------------------
/ opal@debian.org Annebergsslingan 37 \
| opal@lysator.liu.se 654 65 KARLSTAD |
| +46 (0)54-10 14 30 +46 (0)70-332 1551 |
| http://www.opal.dhs.org UIN/icq: 4912500 |
\ gpg/f.p.: 7090 A92B 18FE 7994 0C36 4FE4 18A1 B1CF 0FE5 3DD9 /
---------------------------------------------------------------
--- End Message ---