--- 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 ---