diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 21:26:53 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 21:26:53 +0200 | 
| commit | df247efec654e512242e4f4f1b0212034f9e01fe (patch) | |
| tree | 25c02e16957f3aa613af30c140fd8e8a3d52fda6 /app/wlib/gtklib/gtkdraw-cairo.c | |
| parent | d0b6a8a4ec298024f14f704f9e40a6f9d324ccf3 (diff) | |
| parent | a5ade52caa489cf0a713e0f02b764000d203140e (diff) | |
Merge branch 'release/debian/1%5.2.0Beta2.1-1' into masterdebian/1%5.2.0Beta2.1-1
Diffstat (limited to 'app/wlib/gtklib/gtkdraw-cairo.c')
| -rw-r--r-- | app/wlib/gtklib/gtkdraw-cairo.c | 995 | 
1 files changed, 738 insertions, 257 deletions
| diff --git a/app/wlib/gtklib/gtkdraw-cairo.c b/app/wlib/gtklib/gtkdraw-cairo.c index 5042667..4498a2c 100644 --- a/app/wlib/gtklib/gtkdraw-cairo.c +++ b/app/wlib/gtklib/gtkdraw-cairo.c @@ -32,6 +32,9 @@  #include <gtk/gtk.h>  #include <gdk/gdk.h> +// Trace low level drawing actions +int iDrawLog = 0; +  #include "gtkint.h"  #include "gdk/gdkkeysyms.h" @@ -41,12 +44,16 @@  static long drawVerbose = 0; +// Hack to do TempRedraw or MainRedraw +// For Windows only +wBool_t wDrawDoTempDraw = TRUE; +  struct wDrawBitMap_t {  		int w;  		int h;  		int x;  		int y; -		const char * bits; +		const unsigned char * bits;  		GdkPixmap * pixmap;  		GdkBitmap * mask;  		}; @@ -102,64 +109,148 @@ struct wDraw_t psPrint_d;   *  *******************************************************************************/ - - -static GdkGC * selectGC( -		wDraw_p bd, +static cairo_t* gtkDrawCreateCairoCursorContext( +		wControl_p ct, +		cairo_surface_t * surf,  		wDrawWidth width,  		wDrawLineType_e lineType,  		wDrawColor color,  		wDrawOpts opts )  { -	if(width < 0.0) -	{ -		width = - width; -	} +	cairo_t* cairo; + +	cairo = cairo_create(surf); + +	width = width ? abs(width) : 1; +	cairo_set_line_width(cairo, width); + +	cairo_set_line_cap(cairo, CAIRO_LINE_CAP_BUTT); +	cairo_set_line_join(cairo, CAIRO_LINE_JOIN_MITER); -	if(opts & wDrawOptTemp) +	switch(lineType)  	{ -		if(bd->lastColor != color || !bd->lastColorInverted) +		case wDrawLineSolid:  		{ -			gdk_gc_set_foreground( bd->gc, wlibGetColor(color,FALSE) ); -			bd->lastColor = color; -			bd->lastColorInverted = TRUE; +			cairo_set_dash(cairo, 0, 0, 0); +			break;  		} -		gdk_gc_set_function( bd->gc, GDK_XOR ); -		gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER ); -	} -	else -	{ -		if(bd->lastColor != color || bd->lastColorInverted) +		case wDrawLineDash:  		{ -			gdk_gc_set_foreground( bd->gc, wlibGetColor(color,TRUE) ); -			bd->lastColor = color; -			bd->lastColorInverted = FALSE; +			double dashes[] = { 5, 3 }; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0); +			break;  		} -		gdk_gc_set_function( bd->gc, GDK_COPY ); -		if (lineType==wDrawLineDash) +		case wDrawLineDot:  		{ -			gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER ); +			double dashes[] = { 1, 2 }; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0); +			break;  		} -		else +		case wDrawLineDashDot: +		{ +			double dashes[] = { 5, 2, 1, 2 }; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0); +			break; +		} +		case wDrawLineDashDotDot:  		{ -			gdk_gc_set_line_attributes( bd->gc, width, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER ); +			double dashes[] = { 5, 2, 1, 2, 1, 2 }; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0); +			break; +		} +		case wDrawLineCenter: +		{ +			double dashes[] = { 8, 3, 5, 3}; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0.0); +			break; +		} +		case wDrawLinePhantom: +		{ +			double dashes[] = { 8, 3, 5, 3, 5, 3}; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0.0); +			break;  		} -		gdk_gc_set_function(bd->gc, GDK_NOOP);  	} -	return bd->gc; +	GdkColor * gcolor; + + +	cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); +	gcolor = wlibGetColor(color, TRUE); + +	if (ct->type == B_DRAW)  { +		wDraw_p bd = (wDraw_p)ct; +		bd->lastColor = color; +	} + +	cairo_set_source_rgba(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0, 1.0); + +	return cairo; +} + + +wBool_t wDrawSetTempMode( +	wDraw_p bd, +	wBool_t bTemp ) +{ +	wBool_t ret = bd->bTempMode; +	bd->bTempMode = bTemp; +	if ( ret == FALSE && bTemp == TRUE ) { +		// Main to Temp drawing +		wDrawClearTemp( bd ); +	} +	return ret;  }  static cairo_t* gtkDrawCreateCairoContext(  		wDraw_p bd, +		GdkDrawable * win,  		wDrawWidth width,  		wDrawLineType_e lineType,  		wDrawColor color,  		wDrawOpts opts )  { -	cairo_t* cairo = gdk_cairo_create(bd->pixmap); +	cairo_t* cairo; + +	if (win) +		cairo = gdk_cairo_create(win); +	else { +		if (opts & wDrawOptTemp) { +			if ( ! bd->bTempMode ) +				printf( "Temp draw in Main Mode. Contact Developers. See %s:%d\n", "gtkdraw-cario.c", __LINE__+1 ); +/* Temp Draw In Main Mode: +	You are seeing this message because there is a wDraw*() call on tempD but you are not in the context of TempRedraw() +	Typically this happens when Cmd<Object>() is processing a C_DOWN or C_MOVE action and it writes directly to tempD +	Instead it sould set some state which allows c_redraw to do the actual drawing +	If you set a break point on the printf you'll see the offending wDraw*() call in the traceback +	It should be sufficient to remove that draw code or move it to C_REDRAW +	This is not fatal but the draw will be ineffective because the next TempRedraw() will erase the temp surface +	before the expose event can copy (or bitblt) it +*/ +			cairo = cairo_create(bd->temp_surface); +		} else { +			if ( bd->bTempMode ) +				printf( "Main draw in Temp Mode. Contact Developers. See %s:%d\n", "gtkdraw-cario.c", __LINE__+1 ); +/* Main Draw In Temp Mode: +	You are seeing this message because there is a wDraw*() call on mainD but you are in the context of TempRedraw() +	Typically this happens when C_REDRAW action calls wDraw*() on mainD, in which case it should be writing to tempD. +	Or the wDraw*() call should be removed if it is redundant. +	If you set a break point on the printf you'll see the offending wDraw*() call in the traceback +	This is not fatal but could result in garbage being left on the screen if the command is cancelled. +*/ +			cairo = gdk_cairo_create(bd->pixmap); +		} +	}  	width = width ? abs(width) : 1; +	if ( color == wDrawColorWhite ) +		width += 1;  // Remove ghosts  	cairo_set_line_width(cairo, width);  	cairo_set_line_cap(cairo, CAIRO_LINE_CAP_BUTT); @@ -179,24 +270,52 @@ static cairo_t* gtkDrawCreateCairoContext(  			cairo_set_dash(cairo, dashes, len_dashes, 0);  			break;  		} -	} +		case wDrawLineDot: +		{ +			double dashes[] = { 1, 2 }; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0); +			break; +		} +		case wDrawLineDashDot: +		{ +			double dashes[] = { 5, 2, 1, 2 }; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0); +			break; +		} +		case wDrawLineDashDotDot: +		{ +			double dashes[] = { 5, 2, 1, 2, 1, 2 }; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0); +			break; +		} +		case wDrawLineCenter: +		{ +			double dashes[] = { 8, 3, 5, 3}; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0.0); +			break; +		} +		case wDrawLinePhantom: +		{ +			double dashes[] = { 8, 3, 5, 3, 5, 3}; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cairo, dashes, len_dashes, 0.0); +			break; +		} -	if(opts & wDrawOptTemp) -	{ -		cairo_set_source_rgba(cairo, 0, 0, 0, 0); -		cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); -	} -	else -	{ -		long rgbcolor = wDrawGetRGB(color); -		int r0, g0, b0; -		r0 = (int)(rgbcolor>>16)&0xFF; -		g0 = (int)(rgbcolor>>8)&0xFF; -		b0 = (int)(rgbcolor)&0xFF; -		cairo_set_source_rgb(cairo, r0/255.0, g0/255.0, b0/255.0); - -		cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);  	} +	GdkColor * gcolor; + + +	cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); +	gcolor = wlibGetColor(color, TRUE); + +	bd->lastColor = color; + +	cairo_set_source_rgb(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0);  	return cairo;  } @@ -206,6 +325,36 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  	return NULL;  } +#ifdef CURSOR_SURFACE +cairo_t* CreateCursorSurface(wControl_p ct, wSurface_p surface, wPos_t width, wPos_t height, wDrawColor color, wDrawOpts opts) { + +		cairo_t * cairo = NULL; + +		if ((opts&wDrawOptCursor) || (opts&wDrawOptCursorRmv)) { + +			if (surface!=NULL || surface->width != width || surface->height != height) { +				if (surface->surface) cairo_surface_destroy(surface->surface); +				surface->surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width,height ); +				surface->width = width; +				surface->height = height; + +			} + +			cairo = gtkDrawCreateCairoCursorContext(ct,surface->surface,0,wDrawLineSolid, color, opts); +			cairo_save(cairo); +			cairo_set_source_rgba(cairo, 0.0, 0.0, 0.0, 0.0); +			cairo_paint(cairo); +			cairo_restore(cairo); +			surface->show = TRUE; +			cairo_set_operator(cairo,CAIRO_OPERATOR_SOURCE); + +		} + +		return cairo; + +} +#endif +    void wDrawDelayUpdate(  		wDraw_p bd,  		wBool_t delay ) @@ -239,36 +388,19 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		psPrintLine( x0, y0, x1, y1, width, lineType, color, opts );  		return;  	} -	gc = selectGC( bd, width, lineType, color, opts );  	x0 = INMAPX(bd,x0);  	y0 = INMAPY(bd,y0);  	x1 = INMAPX(bd,x1);  	y1 = INMAPY(bd,y1); -	gdk_draw_line( bd->pixmap, gc, x0, y0, x1, y1 ); -	cairo_t* cairo = gtkDrawCreateCairoContext(bd, width, lineType, color, opts); +	cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, width, lineType, color, opts);  	cairo_move_to(cairo, x0 + 0.5, y0 + 0.5);  	cairo_line_to(cairo, x1 + 0.5, y1 + 0.5);  	cairo_stroke(cairo);  	gtkDrawDestroyCairoContext(cairo); +	if (bd->widget) +		gtk_widget_queue_draw(GTK_WIDGET(bd->widget)); //,x0,y0+1,x1,y1+1); -	if ( bd->delayUpdate || bd->widget == NULL ) return; -	width /= 2; -	if (x0 < x1) { -		update_rect.x = x0-1-width; -		update_rect.width = x1-x0+2+width+width; -	} else { -		update_rect.x = x1-1-width; -		update_rect.width = x0-x1+2+width+width; -	} -	if (y0 < y1) { -		update_rect.y = y0-1-width; -		update_rect.height = y1-y0+2+width+width; -	} else { -		update_rect.y = y1-1-width; -		update_rect.height = y0-y1+2+width+width; -	} -	gtk_widget_draw( bd->widget, &update_rect );  }  /** @@ -299,33 +431,20 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		wDrawOpts opts )  {  	int x, y, w, h; -	GdkGC * gc; -	GdkRectangle update_rect;  	if ( bd == &psPrint_d ) {  		psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts );  		return;  	} -	gc = selectGC( bd, width, lineType, color, opts ); +  	if (r < 6.0/75.0) return;  	x = INMAPX(bd,x0-r);  	y = INMAPY(bd,y0+r);  	w = 2*r;  	h = 2*r; -	// remove the old arc -	gdk_draw_arc( bd->pixmap, gc, FALSE, x, y, w, h, (int)((-angle0 + 90)*64.0), (int)(-angle1*64.0) ); - -	// and its center point -	if (drawCenter) { -		x = INMAPX(bd,x0); -		y = INMAPY(bd,y0); -		gdk_draw_line( bd->pixmap, gc, x - ( CENTERMARK_LENGTH/2), y, x + ( CENTERMARK_LENGTH/2), y ); -		gdk_draw_line( bd->pixmap, gc, x, y - ( CENTERMARK_LENGTH/2), x, y + ( CENTERMARK_LENGTH/2)); -	} -  	// now create the new arc -	cairo_t* cairo = gtkDrawCreateCairoContext(bd, width, lineType, color, opts); +	cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, width, lineType, color, opts);  	cairo_new_path(cairo);  	// its center point marker @@ -337,6 +456,7 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		cairo_move_to(cairo, INMAPX(bd, x0), INMAPY(bd, y0 - (CENTERMARK_LENGTH / 2 )));  		cairo_line_to(cairo, INMAPX(bd, x0) , INMAPY(bd, y0  + (CENTERMARK_LENGTH / 2)));  		cairo_new_sub_path( cairo ); +  	}  	// draw the curve itself @@ -344,14 +464,10 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  	cairo_stroke(cairo);  	gtkDrawDestroyCairoContext(cairo); +	if (bd->widget && !bd->delayUpdate) +			gtk_widget_queue_draw_area(bd->widget,x,y,w,h); + -	if ( bd->delayUpdate || bd->widget == NULL) return; -	width /= 2; -	update_rect.x = x-1-width; -	update_rect.y = y-1-width; -	update_rect.width = w+2+width+width; -	update_rect.height = h+2+width+width; -	gtk_widget_draw( bd->widget, &update_rect );  } @@ -361,28 +477,21 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		wDrawColor color,  		wDrawOpts opts )  { -	GdkGC * gc;  	GdkRectangle update_rect;  	if ( bd == &psPrint_d ) {  		/*psPrintArc( x0, y0, r, angle0, angle1, drawCenter, width, lineType, color, opts );*/  		return;  	} -	gc = selectGC( bd, 0, wDrawLineSolid, color, opts ); -	gdk_draw_point( bd->pixmap, gc, INMAPX(bd, x0 ), INMAPY(bd, y0 ) ); -	cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts); +	cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts);  	cairo_new_path(cairo);  	cairo_arc(cairo, INMAPX(bd, x0), INMAPY(bd, y0), 0.75, 0, 2 * M_PI);  	cairo_stroke(cairo);  	gtkDrawDestroyCairoContext(cairo); +	if (bd->widget && !bd->delayUpdate) +		gtk_widget_queue_draw_area(bd->widget,INMAPX(bd,x0-0.75),INMAPY(bd,y0+0.75),2,2); -	if ( bd->delayUpdate || bd->widget == NULL) return; -	update_rect.x = INMAPX(bd, x0 )-1; -	update_rect.y = INMAPY(bd, y0 )-1; -	update_rect.width = 2; -	update_rect.height = 2; -	gtk_widget_draw( bd->widget, &update_rect );  }  /******************************************************************************* @@ -407,6 +516,7 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  	int h;  	gint ascent;  	gint descent; +	gint baseline;  	double angle = -M_PI * a / 180.0;  	if ( bd == &psPrint_d ) { @@ -418,23 +528,27 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  	y = INMAPY(bd,y);  	/* draw text */ -	cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts); +	cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts);  	cairo_save( cairo ); -	cairo_translate( cairo, x, y ); -	cairo_rotate( cairo, angle ); +	cairo_identity_matrix(cairo);  	layout = wlibFontCreatePangoLayout(bd->widget, cairo, fp, fs, s,  									  (int *) &w, (int *) &h, -									  (int *) &ascent, (int *) &descent); +									  (int *) &ascent, (int *) &descent, (int *) &baseline); -	/* cairo does not support the old method of text removal by overwrite; force always write here and -           refresh on cancel event */ +	/* cairo does not support the old method of text removal by overwrite; +	 * if color is White, then overwrite old text with a White rectangle */  	GdkColor* const gcolor = wlibGetColor(color, TRUE);  	cairo_set_source_rgb(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0); -	cairo_move_to( cairo, 0, -ascent ); +	cairo_translate( cairo, x, y ); +	cairo_rotate( cairo, angle ); +	cairo_translate( cairo, 0, -baseline); + +	cairo_move_to(cairo, 0, 0); +	pango_cairo_update_layout(cairo, layout);  	pango_cairo_show_layout(cairo, layout);  	wlibFontDestroyPangoLayout(layout);  	cairo_restore( cairo ); @@ -446,17 +560,21 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  	 * for simplicity sake I added plain text height ascent and descent,  	 * mathematically correct would be to use the trigonometrical functions as well  	 */ -	update_rect.x      = (gint) x - ascent - descent - 1; -	update_rect.y      = (gint) y - (gint) ascent - 1; -	update_rect.width  = (gint) (w * cos( angle ) + 2 + ascent + descent); -	update_rect.height = (gint) (h * sin( angle ) + ascent + descent + 2 ); +	update_rect.x      = (gint) x - 2; +	update_rect.y      = (gint) y - (gint) (baseline + descent) - 2; +	update_rect.width  = (gint) (w * cos( angle ) + h * sin(angle))+2; +	update_rect.height = (gint) (h * sin( angle ) + w * cos(angle))+2;  	gtk_widget_draw(bd->widget, &update_rect); +	if (bd->widget && !bd->delayUpdate) +		gtk_widget_queue_draw_area(bd->widget, update_rect.x, update_rect.y, update_rect.width, update_rect.height); +      }   void wDrawGetTextSize(  		wPos_t *w,  		wPos_t *h,  		wPos_t *d, +		wPos_t *a,  		wDraw_p bd,  		const char * s,  		wFont_p fp, @@ -466,21 +584,31 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  	int textHeight;  	int ascent;  	int descent; +	int baseline;  	*w = 0;  	*h = 0; +	/* draw text */ +	cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, wDrawColorBlack, bd->bTempMode?wDrawOptTemp:0 ); + +	cairo_identity_matrix(cairo); +  	wlibFontDestroyPangoLayout( -		wlibFontCreatePangoLayout(bd->widget, NULL, fp, fs, s, +		wlibFontCreatePangoLayout(bd->widget, cairo, fp, fs, s,  								 &textWidth, (int *) &textHeight, -								 (int *) &ascent, (int *) &descent)); +								 (int *) &ascent, (int *) &descent, (int *) &baseline) );  	*w = (wPos_t) textWidth;  	*h = (wPos_t) textHeight; -	*d = (wPos_t) textHeight-ascent; +	*a = (wPos_t) ascent; +	//*d = (wPos_t) textHeight-ascent; +	*d = (wPos_t) descent;  	if (debugWindow >= 3)  		fprintf(stderr, "text metrics: w=%d, h=%d, d=%d\n", *w, *h, *d); + +	gtkDrawDestroyCairoContext(cairo);  } @@ -490,6 +618,28 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {   *  *******************************************************************************/ +static void wlibDrawFilled( +	cairo_t * cairo, +	wDrawColor color, +	wDrawOpts opt ) +{ +	if ( (opt & wDrawOptTransparent) != 0 ) { +		if ( (opt & wDrawOptTemp) == 0 ) { +			cairo_set_source_rgb(cairo, 0,0,0); +			cairo_set_operator(cairo, CAIRO_OPERATOR_DIFFERENCE); +			cairo_fill_preserve(cairo); +		} +		GdkColor * gcolor = wlibGetColor(color, TRUE); +		cairo_set_source_rgba(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0, 1.0); +		cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); +		cairo_stroke_preserve(cairo); +		cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); +		cairo_set_source_rgba(cairo, gcolor->red / 65535.0, gcolor->green / 65535.0, gcolor->blue / 65535.0, 0.3); +	} +	cairo_fill(cairo); +} + +   void wDrawFilledRectangle(  		wDraw_p bd,  		wPos_t x, @@ -499,7 +649,6 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		wDrawColor color,  		wDrawOpts opt )  { -	GdkGC * gc;  	GdkRectangle update_rect;  	if ( bd == &psPrint_d ) { @@ -507,47 +656,46 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		return;  	} -	gc = selectGC( bd, 0, wDrawLineSolid, color, opt );  	x = INMAPX(bd,x);  	y = INMAPY(bd,y)-h; -	gdk_draw_rectangle( bd->pixmap, gc, TRUE, x, y, w, h ); -	cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt); +	cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opt);  	cairo_move_to(cairo, x, y);  	cairo_rel_line_to(cairo, w, 0);  	cairo_rel_line_to(cairo, 0, h);  	cairo_rel_line_to(cairo, -w, 0); -	cairo_fill(cairo); +	cairo_rel_line_to(cairo, 0, -h); +	wlibDrawFilled( cairo, color, opt ); +  	gtkDrawDestroyCairoContext(cairo); +	if (bd->widget && !bd->delayUpdate) +		gtk_widget_queue_draw_area(GTK_WIDGET(bd->widget),x,y,w,h); -	if ( bd->delayUpdate || bd->widget == NULL) return; -	update_rect.x = x-1; -	update_rect.y = y-1; -	update_rect.width = w+2; -	update_rect.height = h+2; -	gtk_widget_draw( bd->widget, &update_rect );  } - void wDrawFilledPolygon( + void wDrawPolygon(  		wDraw_p bd,  		wPos_t p[][2], +		wPolyLine_e type[],  		int cnt,  		wDrawColor color, -		wDrawOpts opt ) +		wDrawWidth dw, +		wDrawLineType_e lt, +		wDrawOpts opt, +		int fill, +		int open )  { -	GdkGC * gc;  	static int maxCnt = 0;  	static GdkPoint *points;  	int i; -	GdkRectangle update_rect;  	if ( bd == &psPrint_d ) { -		psPrintFillPolygon( p, cnt, color, opt ); +		psPrintFillPolygon( p, type, cnt, color, opt, fill, open );  		return;  	} -	if (cnt > maxCnt) { +		if (cnt > maxCnt) {  		if (points == NULL)  			points = (GdkPoint*)malloc( cnt*sizeof *points );  		else @@ -556,43 +704,100 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  			abort();  		maxCnt = cnt;  	} - -	update_rect.x = bd->w; -	update_rect.y = bd->h; -	update_rect.width = 0; -	update_rect.height = 0; -	for (i=0; i<cnt; i++) { -		points[i].x = INMAPX(bd,p[i][0]); -		points[i].y = INMAPY(bd,p[i][1]); -		if (update_rect.x > points[i].x) -			update_rect.x = points[i].x; -		if (update_rect.width < points[i].x) -			update_rect.width = points[i].x; -		if (update_rect.y > points[i].y) -			update_rect.y = points[i].y; -		if (update_rect.height < points[i].y) -			update_rect.height = points[i].y; +	wPos_t min_x,max_x,min_y,max_y; +	min_x = max_x = INMAPX(bd,p[0][0]); +	min_y = max_y = INMAPY(bd,p[0][1]); +    for (i=0; i<cnt; i++) { +    	points[i].x = INMAPX(bd,p[i][0]); +    	if (points[i].x < min_x) min_x = points[i].x; +    	if (points[i].x > max_x) max_x = points[i].x; +    	if (points[i].y > max_y) max_y = points[i].y; +    	points[i].y = INMAPY(bd,p[i][1]);  	} -	update_rect.x -= 1; -	update_rect.y -= 1; -	update_rect.width -= update_rect.x-2; -	update_rect.height -= update_rect.y-2; -	gc = selectGC( bd, 0, wDrawLineSolid, color, opt ); -	gdk_draw_polygon( bd->pixmap, gc, TRUE,	points, cnt ); - -	cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt); + +	cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, fill?0:dw, fill?wDrawLineSolid:lt, color, opt); +  	for(i = 0; i < cnt; ++i)  	{ -		if(i) +		int j = i-1; +		int k = i+1; +		if (j < 0) j = cnt-1; +		if (k > cnt-1) k = 0; +		GdkPoint mid0, mid1, mid3, mid4; +		// save is static because of an apparent compiler bug on Linux +		// This happens with RelWithDebInfo target +		// If the first segment is a line then save should = points[0] +		// However it becomes mid0 instead which causes the last corner to be misplaced. +		static GdkPoint save; +		double len0, len1; +		double d0x = (points[i].x-points[j].x); +		double d0y = (points[i].y-points[j].y); +		double d1x = (points[k].x-points[i].x); +		double d1y = (points[k].y-points[i].y); +		len0 = (d0x*d0x+d0y*d0y); +		len1 = (d1x*d1x+d1y*d1y); +		mid0.x = (d0x/2)+points[j].x; +		mid0.y = (d0y/2)+points[j].y; +		mid1.x = (d1x/2)+points[i].x; +		mid1.y = (d1y/2)+points[i].y; +		if (type && (type[i] == wPolyLineRound) && (len1>0) && (len0>0)) { +			double ratio = sqrt(len0/len1); +			if (len0 < len1) { +				mid1.x = ((d1x*ratio)/2)+points[i].x; +				mid1.y = ((d1y*ratio)/2)+points[i].y; +			} else { +				mid0.x = points[i].x-(d0x/(2*ratio)); +				mid0.y = points[i].y-(d0y/(2*ratio)); +			} +		} +		mid3.x = (points[i].x-mid0.x)/2+mid0.x; +		mid3.y = (points[i].y-mid0.y)/2+mid0.y; +		mid4.x = (mid1.x-points[i].x)/2+points[i].x; +		mid4.y = (mid1.y-points[i].y)/2+points[i].y; +		points[i].x = round(points[i].x)+0.5; +		points[i].y = round(points[i].y)+0.5; +		mid0.x = round(mid0.x)+0.5; +		mid0.y = round(mid0.y)+0.5; +		mid1.x = round(mid1.x)+0.5; +		mid1.y = round(mid1.y)+0.5; +		mid3.x = round(mid3.x)+0.5; +		mid3.y = round(mid3.y)+0.5; +		mid4.x = round(mid4.x)+0.5; +		mid4.y = round(mid4.y)+0.5; +		if(i==0) { +			if (!type || type[i] == wPolyLineStraight || open) { +				cairo_move_to(cairo, points[i].x, points[i].y); +				save = points[0]; +			} else { +				cairo_move_to(cairo, mid0.x, mid0.y); +				if (type[i] == 1) +					cairo_curve_to(cairo, points[i].x, points[i].y, points[i].x, points[i].y, mid1.x, mid1.y); +				else +					cairo_curve_to(cairo, mid3.x, mid3.y, mid4.x, mid4.y, mid1.x, mid1.y); +				save = mid0; +			} +		} else if (!type || type[i] == wPolyLineStraight || (open && (i==cnt-1))) {  			cairo_line_to(cairo, points[i].x, points[i].y); -		else -			cairo_move_to(cairo, points[i].x, points[i].y); +		} else { +			cairo_line_to(cairo, mid0.x, mid0.y); +			if (type[i] == wPolyLineSmooth) +				cairo_curve_to(cairo, points[i].x, points[i].y, points[i].x, points[i].y, mid1.x, mid1.y); +			else +				cairo_curve_to(cairo, mid3.x, mid3.y, mid4.x, mid4.y, mid1.x, mid1.y); +		} +		if ((i==cnt-1) && !open) { +			cairo_line_to(cairo, save.x, save.y); +		} +	} +	if (fill && !open) { +		wlibDrawFilled( cairo, color, opt ); +	} else { +		cairo_stroke(cairo);  	} -	cairo_fill(cairo);  	gtkDrawDestroyCairoContext(cairo); +	if (bd->widget && !bd->delayUpdate) +			gtk_widget_queue_draw_area(GTK_WIDGET(bd->widget),min_x,min_y,max_x-min_y,max_y-min_y); -	if ( bd->delayUpdate || bd->widget == NULL) return; -	gtk_widget_draw( bd->widget, &update_rect );  }   void wDrawFilledCircle( @@ -603,60 +808,64 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		wDrawColor color,  		wDrawOpts opt )  { -	GdkGC * gc;  	int x, y, w, h; -	GdkRectangle update_rect;  	if ( bd == &psPrint_d ) {  		psPrintFillCircle( x0, y0, r, color, opt );  		return;  	} -	gc = selectGC( bd, 0, wDrawLineSolid, color, opt );  	x = INMAPX(bd,x0-r);  	y = INMAPY(bd,y0+r);  	w = 2*r;  	h = 2*r; -	gdk_draw_arc( bd->pixmap, gc, TRUE, x, y, w, h, 0, 360*64 ); -	cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opt); +	cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opt);  	cairo_arc(cairo, INMAPX(bd, x0), INMAPY(bd, y0), r, 0, 2 * M_PI); -	cairo_fill(cairo); +	wlibDrawFilled( cairo, color, opt );  	gtkDrawDestroyCairoContext(cairo); -	if ( bd->delayUpdate || bd->widget == NULL) return; -	update_rect.x = x-1; -	update_rect.y = y-1; -	update_rect.width = w+2; -	update_rect.height = h+2; -	gtk_widget_draw( bd->widget, &update_rect ); +	if (bd->widget) +			gtk_widget_queue_draw_area(GTK_WIDGET(bd->widget),x,y,w,h);  } + void wDrawClearTemp(wDraw_p bd) { +	//Wipe out temp space with 0 alpha (transparent) + +	static long cDCT = 0; +	if ( iDrawLog ) +		printf( "wDrawClearTemp %ld\n", cDCT++ ); +	cairo_t* cairo = cairo_create(bd->temp_surface); + +	cairo_set_source_rgba(cairo, 0.0, 0.0, 0.0, 0.0); +	cairo_set_operator (cairo, CAIRO_OPERATOR_SOURCE); +	cairo_move_to(cairo, 0, 0); +	cairo_rel_line_to(cairo, bd->w, 0); +	cairo_rel_line_to(cairo, 0, bd->h); +	cairo_rel_line_to(cairo, -bd->w, 0); +	cairo_fill(cairo); +	cairo_destroy(cairo); + +	if (bd->widget && !bd->delayUpdate) +		gtk_widget_queue_draw(bd->widget); + }   void wDrawClear(  		wDraw_p bd )  { -	GdkGC * gc; -	GdkRectangle update_rect; -	gc = selectGC( bd, 0, wDrawLineSolid, wDrawColorWhite, 0 ); -	gdk_draw_rectangle(bd->pixmap, gc, TRUE, 0, 0, bd->w, bd->h); - -	cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, wDrawColorWhite, 0); +	cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, wDrawColorWhite, 0);  	cairo_move_to(cairo, 0, 0);  	cairo_rel_line_to(cairo, bd->w, 0);  	cairo_rel_line_to(cairo, 0, bd->h);  	cairo_rel_line_to(cairo, -bd->w, 0);  	cairo_fill(cairo); +	if (bd->widget) +		gtk_widget_queue_draw(bd->widget);  	gtkDrawDestroyCairoContext(cairo); -	if ( bd->delayUpdate || bd->widget == NULL) return; -	update_rect.x = 0; -	update_rect.y = 0; -	update_rect.width = bd->w; -	update_rect.height = bd->h; -	gtk_widget_draw( bd->widget, &update_rect ); +	wDrawClearTemp(bd);  }   void * wDrawGetContext( @@ -678,7 +887,7 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		int h,  		int x,  		int y, -		const char * fbits ) +		const unsigned char * fbits )  {  	wDrawBitMap_p bm; @@ -700,72 +909,107 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		wDrawColor color,  		wDrawOpts opts )  { -	//GdkGC * gc; -	GdkRectangle update_rect;  	int i, j, wb;  	wPos_t xx, yy;  	wControl_p b; -	GdkDrawable * gdk_window; +	wWin_p win; +	GdkDrawable * gdk_drawable, * cairo_surface; +	GtkWidget * widget = bd->widget; +	 +	static long cDBM = 0; +	if ( iDrawLog ) +		printf( "wDrawBitMap %ld\n", cDBM++ );  	x = INMAPX( bd, x-bm->x );  	y = INMAPY( bd, y-bm->y )-bm->h;  	wb = (bm->w+7)/8; -	//gc = selectGC( bd, 0, wDrawLineSolid, color, opts ); -	cairo_t* cairo = gtkDrawCreateCairoContext(bd, 0, wDrawLineSolid, color, opts); + +	cairo_t* cairo; + +#ifdef CURSOR_SURFACE +	if (opts&wDrawOptCursorRmv) color = wDrawColorWhite;   //Wipeout existing cursor draw (simplistic first) + + +	if ((opts&wDrawOptCursor) || (opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) { + +		cairo = CreateCursorSurface((wControl_p)bd,&bd->cursor_surface, bd->w, bd->h, color, opts); + +		if ((opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) { +			bd->cursor_surface.show = FALSE; +		} else bd->cursor_surface.show = TRUE; + +		widget = bd->widget; + + +	} else { +		cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts); +		widget = bd->widget; +	} + +	GtkWidget * new_widget = widget; +	GdkGC * gc = NULL; +	GdkWindow * gdk_window = NULL; + +	win = bd->parent; +#endif +	cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, color, opts); +  	for ( i=0; i<bm->w; i++ )  		for ( j=0; j<bm->h; j++ )  			if ( bm->bits[ j*wb+(i>>3) ] & (1<<(i&07)) ) {  				xx = x+i;  				yy = y+j; +#ifdef CURSOR_SURFACE  				if ( 0 <= xx && xx < bd->w &&  					 0 <= yy && yy < bd->h ) { -					gdk_window = bd->pixmap;  					b = (wControl_p)bd;  				} else if ( (opts&wDrawOptNoClip) != 0 ) {  					xx += bd->realX;  					yy += bd->realY;  					b = wlibGetControlFromPos( bd->parent, xx, yy ); -					if ( b ) { -						if ( b->type == B_DRAW ) -							gdk_window = ((wDraw_p)b)->pixmap; -						else -							gdk_window = b->widget->window; +					if ( b) {  						xx -= b->realX;  						yy -= b->realY; +						new_widget = b->widget;  					} else { -						gdk_window = bd->parent->widget->window; +						new_widget = bd->parent->widget;  					}  				} else {  					continue;  				} -/*printf( "gdk_draw_point( %ld, gc, %d, %d )\n", (long)gdk_window, xx, yy );*/ -				//gdk_draw_point( gdk_window, gc, xx, yy ); -				cairo_rectangle(cairo, xx-0.5, yy-0.5, 1, 1); -				cairo_fill(cairo); -				if ( b && b->type == B_DRAW ) { -					update_rect.x = xx-1; -					update_rect.y = yy-1; -					update_rect.width = 3; -					update_rect.height = 3; -					gtk_widget_draw( b->widget, &update_rect ); + +				if (new_widget != widget) { +					if (cairo) +						cairo_destroy(cairo); +					cairo = NULL; +					if (widget && (widget != bd->parent->widget)) +						gtk_widget_queue_draw(GTK_WIDGET(widget)); +					if ( (opts&wDrawOptCursor) || (opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) { +						if (!b) b = (wControl_p)(bd->parent->widget); +						cairo = CreateCursorSurface(b,&b->cursor_surface, b->w, b->h, color, opts); +						widget = b->widget; +						gc = NULL; +						if ((opts&wDrawOptCursorRmv) || (opts&wDrawOptCursorQuit)) +							b->cursor_surface.show = FALSE; +						else +							b->cursor_surface.show = TRUE; +					} else { +						continue; +					} +					widget = new_widget;  				} -			} -	gtkDrawDestroyCairoContext(cairo); -#ifdef LATER -	gdk_draw_pixmap(bd->pixmap, gc, -		bm->pixmap, -		0, 0, -		x, y, -		bm->w, bm->h ); +				if ((opts&wDrawOptCursorQuit) || (opts&wDrawOptCursorQuit) ) continue;  #endif -	if ( bd->delayUpdate || bd->widget == NULL) return; +				cairo_rectangle(cairo, xx, yy, 1, 1); +				cairo_fill(cairo); +			} + +	cairo_destroy(cairo); + +	if (widget && !bd->delayUpdate) +		gtk_widget_queue_draw_area(GTK_WIDGET(widget), x, y, bm->w, bm->h); -	update_rect.x = x; -	update_rect.y = y; -	update_rect.width = bm->w; -	update_rect.height = bm->h; -	gtk_widget_draw( bd->widget, &update_rect );  } @@ -780,19 +1024,19 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {   void wDrawSaveImage(  		wDraw_p bd )  { +	cairo_t * cr;  	if ( bd->pixmapBackup ) {  		gdk_pixmap_unref( bd->pixmapBackup );  	}  	bd->pixmapBackup = gdk_pixmap_new( bd->widget->window, bd->w, bd->h, -1 ); -	selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 ); -	gdk_gc_set_function(bd->gc, GDK_COPY); +	cr = gdk_cairo_create(bd->pixmapBackup); +	gdk_cairo_set_source_pixmap(cr, bd->pixmap, 0, 0); +    cairo_paint(cr); +	cairo_destroy(cr); + +	cr = NULL; -	gdk_draw_pixmap( bd->pixmapBackup, bd->gc, -				bd->pixmap, -				0, 0, -				0, 0, -				bd->w, bd->h );  } @@ -802,14 +1046,13 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  	GdkRectangle update_rect;  	if ( bd->pixmapBackup ) { -		selectGC( bd, 0, wDrawLineSolid, bd->lastColor, 0 ); -		gdk_gc_set_function(bd->gc, GDK_COPY); +		cairo_t * cr; +		cr = gdk_cairo_create(bd->pixmap); +		gdk_cairo_set_source_pixmap(cr, bd->pixmapBackup, 0, 0); +		cairo_paint(cr); +		cairo_destroy(cr); -		gdk_draw_pixmap( bd->pixmap, bd->gc, -				bd->pixmapBackup, -				0, 0, -				0, 0, -				bd->w, bd->h ); +		cr = NULL;  		if ( bd->delayUpdate || bd->widget == NULL ) return;  		update_rect.x = 0; @@ -845,6 +1088,9 @@ static cairo_t* gtkDrawDestroyCairoContext(cairo_t *cairo) {  		if (bd->pixmap)  			gdk_pixmap_unref( bd->pixmap );  		bd->pixmap = gdk_pixmap_new( bd->widget->window, w, h, -1 ); +		if (bd->temp_surface) +			cairo_surface_destroy( bd->temp_surface); +		bd->temp_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, w,h );  		wDrawClear( bd );  		if (!redraw) @@ -914,13 +1160,37 @@ static gint draw_expose_event(  		GdkEventExpose *event,  		wDraw_p bd)  { -	gdk_draw_pixmap(widget->window, -		widget->style->fg_gc[GTK_WIDGET_STATE (widget)], -		bd->pixmap, -		event->area.x, event->area.y, -		event->area.x, event->area.y, -		event->area.width, event->area.height); -	return FALSE; +	static long cDEE = 0; +	if ( iDrawLog ) +		printf( "draw_expose_event %ld %dx%d+%dx%d %dx%d+%dx%d\n", cDEE++, +			event->area.x, event->area.y, event->area.width, event->area.height, +			0, bd->w, 0, bd->h ); + +	cairo_t* cairo = gdk_cairo_create (widget->window); +	gdk_cairo_set_source_pixmap(cairo,bd->pixmap,0,0); +	cairo_rectangle(cairo,event->area.x, event->area.y, +					event->area.width, event->area.height); +	cairo_set_operator(cairo,CAIRO_OPERATOR_SOURCE); +	cairo_fill(cairo); + +	cairo_set_source_surface(cairo,bd->temp_surface,0,0); +	cairo_rectangle(cairo,event->area.x, event->area.y, +				event->area.width, event->area.height); +	cairo_set_operator(cairo,CAIRO_OPERATOR_OVER); +	cairo_fill(cairo); + +#ifdef CURSOR_SURFACE +	if (bd->cursor_surface.surface && bd->cursor_surface.show) { +		cairo_set_source_surface(cairo,bd->cursor_surface.surface,0,0); +		cairo_set_operator(cairo,CAIRO_OPERATOR_OVER); +		cairo_rectangle(cairo,event->area.x, event->area.y, +				       event->area.width, event->area.height); +		cairo_fill(cairo); +	} +#endif +	cairo_destroy(cairo); + +	return TRUE;  } @@ -929,32 +1199,113 @@ static gint draw_configure_event(  		GdkEventConfigure *event,  		wDraw_p bd)  { -	return FALSE; +	return TRUE;  } -static const char * actionNames[] = { "None", "Move", "LDown", "LDrag", "LUp", "RDown", "RDrag", "RUp", "Text", "ExtKey", "WUp", "WDown" }; +static const char * actionNames[] = { "None", "Move", "LDown", "LDrag", "LUp", "RDown", "RDrag", "RUp", "Text", "ExtKey", "WUp", "WDown", "DblL", "ModK", "ScrU", "ScrD", "ScrL", "ScrR" };  /**   * Handler for scroll events, ie mouse wheel activity   */ +static int scrollTimer; +static int timer_busy_count; +static wAction_t lastAction; + +static int ScrollTimerPop(wDraw_p bd) { + +		if (timer_busy_count>1) { +			 timer_busy_count = 0; +			 scrollTimer = 0; +		} else { +			timer_busy_count++; +			return TRUE; +		} +		if (drawVerbose >= 2) +			printf( "%s-Pop\n", actionNames[lastAction] ); +		bd->action( bd, bd->context, lastAction, 0, 0 ); + +		return FALSE; +} + +  static gint draw_scroll_event(  		GtkWidget *widget,  		GdkEventScroll *event,  		wDraw_p bd)  {  	wAction_t action; +	static int oldEventX = 0; +	static int oldEventY = 0; +	static int newEventX = 0; +	static int newEventY = 0; + +	if (event->state & (GDK_SHIFT_MASK|GDK_BUTTON2_MASK|GDK_MOD1_MASK)) { + +		newEventX = OUTMAPX(bd, event->x); +		newEventY = OUTMAPY(bd, event->y); +		oldEventX = OUTMAPX(bd, event->x_root); +		oldEventY = OUTMAPX(bd, event->y_root); + +		switch( event->direction ) { +			case GDK_SCROLL_UP: +				if (event->state & GDK_CONTROL_MASK) +					action = wActionScrollRight; +				else +					action = wActionScrollUp; +				break; +			case GDK_SCROLL_DOWN: +				if (event->state & GDK_CONTROL_MASK) +					action = wActionScrollLeft; +				else +					action = wActionScrollDown; +				break; +			case GDK_SCROLL_LEFT: +				action = wActionScrollLeft; +				break; +			case GDK_SCROLL_RIGHT: +				action = wActionScrollRight; +				break; +			default: +				return TRUE; +				break; +		} -	switch( event->direction ) { -	case GDK_SCROLL_UP: -		action = wActionWheelUp; -		break; -	case GDK_SCROLL_DOWN: -		action = wActionWheelDown; -		break; -	default: -		action = 0; -		break; +		if (drawVerbose >= 2) +			printf( "%sNew[%dx%d]Delta[%dx%d]\n", actionNames[action], +				newEventX, newEventY, oldEventX, oldEventY ); + + + +			if (scrollTimer) {					// Already have a timer +				lastAction = action; +                return TRUE; +            } else { +            	 lastAction = action; +            	 timer_busy_count = 0; +                 scrollTimer = g_timeout_add(25,(GSourceFunc)ScrollTimerPop,bd);   // 25ms delay +                 return TRUE; +            } + + +	} else { + +		switch( event->direction ) { +		case GDK_SCROLL_UP: +			action = wActionWheelUp; +			break; +		case GDK_SCROLL_DOWN: +			action = wActionWheelDown; +			break; +		case GDK_SCROLL_LEFT: +			return TRUE; +			break; +		case GDK_SCROLL_RIGHT: +			return TRUE; +			break; +		default: +			break; +		}  	}  	if (action != 0) { @@ -973,7 +1324,7 @@ static gint draw_leave_event(  		GdkEvent * event )  {  	wlibHelpHideBalloon(); -	return FALSE; +	return TRUE;  } @@ -996,6 +1347,7 @@ static gint draw_button_event(  	switch ( event->button ) {  	case 1: /* left mouse button */  		action = event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp; +		if (event->type==GDK_2BUTTON_PRESS) action = wActionLDownDouble;  		/*bd->action( bd, bd->context, event->type==GDK_BUTTON_PRESS?wActionLDown:wActionLUp, bd->lastX, bd->lastY );*/  		break;  	case 3: /* right mouse button */ @@ -1050,6 +1402,35 @@ static gint draw_motion_event(  	return TRUE;  } +static gint draw_char_release_event( +		GtkWidget * widget, +		GdkEventKey *event, +		wDraw_p bd ) +{ +		GdkModifierType modifiers; +		guint key = event->keyval; +		wModKey_e modKey = wModKey_None; +		switch (key) { +			case GDK_KEY_Alt_L:     modKey = wModKey_Alt; break; +			case GDK_KEY_Alt_R:     modKey = wModKey_Alt; break; +			case GDK_KEY_Shift_L:	modKey = wModKey_Shift; break; +			case GDK_KEY_Shift_R:	modKey = wModKey_Shift; break; +			case GDK_KEY_Control_L:	modKey = wModKey_Ctrl; break; +			case GDK_KEY_Control_R:	modKey = wModKey_Ctrl; break; +				default: ; +		} + +		if (modKey!= wModKey_None && (bd->option & BD_MODKEYS)) { +			 bd->action(bd, bd->context, wActionModKey+((int)modKey<<8), bd->lastX, bd->lastY ); +			 	 if (!(bd->option & BD_NOFOCUS)) +			 		 gtk_widget_grab_focus( bd->widget ); +			 	 return TRUE; +		} else { +			return FALSE; +		} +		return FALSE; +} +  static gint draw_char_event(  		GtkWidget * widget, @@ -1059,6 +1440,7 @@ static gint draw_char_event(  	GdkModifierType modifiers;  	guint key = event->keyval;  	wAccelKey_e extKey = wAccelKey_None; +	wModKey_e modKey = wModKey_None;  	switch (key) {  	case GDK_KEY_Escape:	key = 0x1B; break;  	case GDK_KEY_Return: @@ -1092,17 +1474,37 @@ static gint draw_char_event(  	case GDK_KEY_F10:       extKey = wAccelKey_F10; break;  	case GDK_KEY_F11:       extKey = wAccelKey_F11; break;  	case GDK_KEY_F12:       extKey = wAccelKey_F12; break; -	default: ; +	case GDK_KEY_Alt_L:     modKey = wModKey_Alt; break; +	case GDK_KEY_Alt_R:     modKey = wModKey_Alt; break; +	case GDK_KEY_Shift_L:	modKey = wModKey_Shift; break; +	case GDK_KEY_Shift_R:	modKey = wModKey_Shift; break; +	case GDK_KEY_Control_L:	modKey = wModKey_Ctrl; break; +	case GDK_KEY_Control_R:	modKey = wModKey_Ctrl; break; +		default: ;  	}  	if (extKey != wAccelKey_None) {  		if ( wlibFindAccelKey( event ) == NULL ) {  			bd->action( bd, bd->context, wActionExtKey + ((int)extKey<<8), bd->lastX, bd->lastY );  		} +		if (!(bd->option & BD_NOFOCUS)) +				gtk_widget_grab_focus( bd->widget ); +		return TRUE; +	} else if ((key >=wAccelKey_Up) && (key<=wAccelKey_Left) && bd->action) { +		bd->action( bd, bd->context, wActionText+(key<<8), bd->lastX, bd->lastY ); +		if (!(bd->option & BD_NOFOCUS)) +			gtk_widget_grab_focus( bd->widget );  		return TRUE;  	} else if (key <= 0xFF && (event->state&(GDK_CONTROL_MASK|GDK_MOD1_MASK)) == 0 && bd->action) {  		bd->action( bd, bd->context, wActionText+(key<<8), bd->lastX, bd->lastY ); +		if (!(bd->option & BD_NOFOCUS)) +				gtk_widget_grab_focus( bd->widget );  		return TRUE; +	} else if (modKey!= wModKey_None && (bd->option & BD_MODKEYS)) { +				bd->action(bd, bd->context, wActionModKey+((int)modKey<<8), bd->lastX, bd->lastY ); +				if (!(bd->option & BD_NOFOCUS)) +								gtk_widget_grab_focus( bd->widget ); +				return TRUE;  	} else {  		return FALSE;  	} @@ -1140,6 +1542,7 @@ int xw, xh, cw, ch;  	bd->context = context;  	bd->redraw = redraw;  	bd->action = action; +	bd->bTempMode = FALSE;  	wlibComputePos( (wControl_p)bd );  	bd->widget = gtk_drawing_area_new(); @@ -1159,6 +1562,8 @@ int xw, xh, cw, ch;  						   (GtkSignalFunc) draw_scroll_event, bd);  	gtk_signal_connect_after (GTK_OBJECT (bd->widget), "key_press_event",  						   (GtkSignalFunc) draw_char_event, bd); +	gtk_signal_connect_after (GTK_OBJECT (bd->widget), "key_release_event", +							   (GtkSignalFunc) draw_char_release_event, bd);  	gtk_signal_connect (GTK_OBJECT (bd->widget), "leave_notify_event",  						   (GtkSignalFunc) draw_leave_event, bd);  	gtk_widget_set_can_focus(bd->widget,!(option & BD_NOFOCUS)); @@ -1168,7 +1573,7 @@ int xw, xh, cw, ch;  							  | GDK_LEAVE_NOTIFY_MASK  							  | GDK_BUTTON_PRESS_MASK  							  | GDK_BUTTON_RELEASE_MASK -/*							  | GDK_SCROLL_MASK */ +							  | GDK_SCROLL_MASK  							  | GDK_POINTER_MOTION_MASK  							  | GDK_POINTER_MOTION_HINT_MASK  							  | GDK_KEY_PRESS_MASK @@ -1182,6 +1587,8 @@ int xw, xh, cw, ch;  	wlibControlGetSize( (wControl_p)bd );  	gtk_widget_realize( bd->widget );  	bd->pixmap = gdk_pixmap_new( bd->widget->window, width, height, -1 ); +	bd->temp_surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width,height ); +	wDrawClear(bd);  	bd->gc = gdk_gc_new( parent->gtkwin->window );  	gdk_gc_copy( bd->gc, parent->gtkwin->style->base_gc[GTK_STATE_NORMAL] );  { @@ -1219,6 +1626,7 @@ wDraw_p wBitMapCreate(          wPos_t w, wPos_t h, int arg )  	bd->maxH = bd->h = h;  	bd->pixmap = gdk_pixmap_new( gtkMainW->widget->window, w, h, -1 ); +	bd->widget = gtk_pixmap_new(bd->pixmap, NULL);  	if ( bd->pixmap == NULL ) {  		wNoticeEx( NT_ERROR, "CreateBitMap: pixmap_new failed", "Ok", NULL );  		return FALSE; @@ -1242,3 +1650,76 @@ wBool_t wBitMapDelete(          wDraw_p d )  	return TRUE;  } +/******************************************************************************* + * + * Background + * + ******************************************************************************/ +int wDrawSetBackground(    wDraw_p bd, char * path, char ** error) { + +	GError *err = NULL; + +	if (bd->background) { +		g_object_unref(bd->background); +	} + +	if (path) { +		bd->background = gdk_pixbuf_new_from_file (path, &err); +		if (!bd->background) { +			*error = err->message; +			return -1; +		} +	} else { +		bd->background = NULL; +		return 1; +	} +	return 0; + +} + +void wDrawShowBackground( wDraw_p bd, wPos_t pos_x, wPos_t pos_y, wPos_t size, wAngle_t angle, int screen) { + +	if (bd->background) { +		cairo_t* cairo = gtkDrawCreateCairoContext(bd, NULL, 0, wDrawLineSolid, wDrawColorWhite, bd->bTempMode?wDrawOptTemp:0 ); +		cairo_save(cairo); +		int pixels_width = gdk_pixbuf_get_width(bd->background); +		int pixels_height = gdk_pixbuf_get_height(bd->background); +		double scale; +		double posx,posy,width,sized; +		posx = (double)pos_x; +		posy = (double)pos_y; +		if (size == 0) { +			scale = 1.0; +		} else { +			sized = (double)size; +			width = (double)pixels_width; +			scale = sized/width; +		} +		cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); +		double rad = M_PI*(angle/180); +		posy = (double)bd->h-((pixels_height*fabs(cos(rad))+pixels_width*fabs(sin(rad)))*scale)-posy; +		//width = (double)(pixels_width*scale); +		//height = (double)(pixels_height*scale); +		cairo_translate(cairo,posx,posy); +		cairo_scale(cairo, scale, scale); +		cairo_translate(cairo, fabs(pixels_width/2.0*cos(rad))+fabs(pixels_height/2.0*sin(rad)), +				fabs(pixels_width/2.0*sin(rad))+fabs(pixels_height/2.0*cos(rad))); +		cairo_rotate(cairo, M_PI*(angle/180.0)); +		// We need to clip around the image, or cairo will paint garbage data +		cairo_rectangle(cairo, -pixels_width/2.0, -pixels_height/2.0, pixels_width, pixels_height); +		cairo_clip(cairo); +		gdk_cairo_set_source_pixbuf(cairo, bd->background, -pixels_width/2.0, -pixels_height/2.0); +		cairo_pattern_t *mask = cairo_pattern_create_rgba (1.0,1.0,1.0,(100.0-screen)/100.0); +		cairo_mask(cairo,mask); +		cairo_pattern_destroy(mask); +		cairo_restore(cairo); +		gtkDrawDestroyCairoContext(cairo); + +		gtk_widget_queue_draw(bd->widget); +	} + +} + + + + | 
