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 | |
| 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')
27 files changed, 1861 insertions, 614 deletions
| diff --git a/app/wlib/gtklib/CMakeLists.txt b/app/wlib/gtklib/CMakeLists.txt index bf20e91..97ab56f 100644 --- a/app/wlib/gtklib/CMakeLists.txt +++ b/app/wlib/gtklib/CMakeLists.txt @@ -18,6 +18,7 @@ set(sources  	menu.c	  	message.c  	notice.c +	opendocument.c  	pixbuf.c  	png.c  	print.c @@ -35,29 +36,43 @@ set(sources  	gtkdraw-cairo.c  	) -  # help system is OS and build specific, add appropriate source files  if(APPLE) -    set(sources  -        ${sources} -	osxhelp.c)	 -else() +   if (XTRKCAD_USE_APPLEHELP)  +   		set(sources  +      	  ${sources} +			osxhelp.c)	 +	else(XTRKCAD_USE_APPLEHELP) +		if(XTRKCAD_USE_BROWSER)  +        	set(sources  +          	  ${sources} +          	  browserhelp.c) +    	else(XTRKCAD_USE_BROWSER) +    	 PKG_CHECK_MODULES(GTK_WEBKIT "webkit-1.0" REQUIRED) +       	 set(sources  +       	     ${sources} +       	     ixhelp.c) +       	endif(XTRKCAD_USE_BROWSER) +    endif(XTRKCAD_USE_APPLEHELP)     +else(APPLE)      if(XTRKCAD_USE_BROWSER)           set(sources               ${sources}              browserhelp.c) -    else() +    else(XTRKCAD_USE_BROWSER) +    	PKG_CHECK_MODULES(GTK_WEBKIT "webkit-1.0" REQUIRED)          set(sources               ${sources}              ixhelp.c) -    endif()     -endif() +    endif(XTRKCAD_USE_BROWSER)     +endif(APPLE)  include_directories(${XTrkCAD_BINARY_DIR})  add_library(xtrkcad-wlib ${headers} ${sources})  # GTK  +find_package (GTK2)  include_directories(${GTK_INCLUDE_DIRS})  target_link_libraries(xtrkcad-wlib ${GTK_LIBRARIES}) @@ -67,7 +82,16 @@ include_directories(${GTK_UNIX_PRINT_INCLUDE_DIRS})  target_link_libraries(xtrkcad-wlib ${GTK_UNIX_PRINT_LIBRARIES})  # add dependency to webkit if configured -if(NOT XTRKCAD_USE_BROWSER) -    include_directories(${GTK_WEBKIT_INCLUDE_DIRS}) -    target_link_libraries(xtrkcad-wlib ${GTK_WEBKIT_LIBRARIES}) -endif() +if (APPLE) +	if(NOT XTRKCAD_USE_APPLEHELP)  +		if(NOT XTRKCAD_USE_BROWSER) +		   include_directories(${GTK_WEBKIT_INCLUDE_DIRS}) +	 	   target_link_libraries(xtrkcad-wlib ${GTK_WEBKIT_LIBRARIES}) +		endif() +	endif()  +else (APPLE) +	if(NOT XTRKCAD_USE_BROWSER) + 	   include_directories(${GTK_WEBKIT_INCLUDE_DIRS}) + 	   target_link_libraries(xtrkcad-wlib ${GTK_WEBKIT_LIBRARIES}) +	endif() +endif(APPLE) diff --git a/app/wlib/gtklib/browserhelp.c b/app/wlib/gtklib/browserhelp.c index 9351e86..aa8f5c7 100644 --- a/app/wlib/gtklib/browserhelp.c +++ b/app/wlib/gtklib/browserhelp.c @@ -22,12 +22,17 @@  #include <stdlib.h>  #include <assert.h> +#include <string.h> + +#include "misc.h"  #include "gtkint.h"  #include "i18n.h"  #include "dynstring.h" +#define debug 0 +  #define DEFAULTBROWSERCOMMAND "xdg-open"  #define  HELPERRORTEXT 			"Help Error - help information can not be found.\n" \ @@ -38,7 +43,7 @@  								"variable.\n Also make sure that the user has sufficient access rights to read these" \   								"files."  /** - * Create a fully qualified url froma topic + * Create a fully qualified url from a topic   *   * \param helpUrl OUT pointer to url, free by caller   * \param topic IN the help topic @@ -63,36 +68,6 @@ TopicToUrl(char **helpUrl, const char *topic)      DynStringFree(&url);  }  /** - * Extend the PATH variable inthe environment to include XTrackCAD's - * script directory. - * - * \return pointer to old path - */ - -static char * -ExtendPath(void) -{ -    char *path = getenv("PATH"); -    DynString newPath; -    DynStringMalloc(&newPath, 16); - -    // append XTrackCAD's directory to the path as a fallback -    DynStringCatCStrs(&newPath, -                      path, -                      ":", -                      wGetAppLibDir(), -                      NULL); - -    setenv("PATH", -           DynStringToCStr(&newPath), -           TRUE); - -    DynStringFree(&newPath); - -    return (path); -} - -/**   * Invoke the system's default browser to display help for <topic>. First the   * system's standard xdg-open command is attempted. If that is not available, the   * version included with the XTrackCAD installation is executed. @@ -104,34 +79,20 @@ void wHelp(const char * topic)  {      int rc;      char *url; -    DynString commandLine;      char *currentPath;      assert(topic != NULL);      assert(strlen(topic)); -    currentPath = ExtendPath(); -    TopicToUrl(&url, topic); +    if (!CheckHelpTopicExists(topic)) return; -    DynStringMalloc(&commandLine, 16); -    DynStringCatCStrs(&commandLine, -                      DEFAULTBROWSERCOMMAND, -                      " ", -                      url, -                      NULL); +    TopicToUrl(&url, topic); -    // the command should be found via the PATH -    rc = system(DynStringToCStr(&commandLine)); +	rc = wOpenFileExternal(url); -    if (rc) { +	if (!rc) {          wNotice(HELPERRORTEXT, _("Cancel"), NULL);      } -    // restore the PATH -    setenv("PATH", -           currentPath, -           TRUE); -      free(url); -    DynStringFree(&commandLine);  } diff --git a/app/wlib/gtklib/button.c b/app/wlib/gtklib/button.c index b5fabe8..51106c8 100644 --- a/app/wlib/gtklib/button.c +++ b/app/wlib/gtklib/button.c @@ -94,15 +94,23 @@ void wlibSetLabel(              } else {                  pixbuf = wlibPixbufFromXBM( bm );              } +            double scaleicon; +            wPrefGetFloat(PREFSECTION, LARGEICON, &scaleicon, 1.0); +            if (scaleicon<1.0) scaleicon=1.0; +            if (scaleicon>2.0) scaleicon=2.0; +            GdkPixbuf *pixbuf2 = +            		gdk_pixbuf_scale_simple(pixbuf, gdk_pixbuf_get_width(pixbuf)*scaleicon, gdk_pixbuf_get_height(pixbuf)*scaleicon, GDK_INTERP_BILINEAR); +            g_object_ref_sink(pixbuf); +            g_object_unref((gpointer)pixbuf);              if (*imageG==NULL) { -                *imageG = gtk_image_new_from_pixbuf(pixbuf); +                *imageG = gtk_image_new_from_pixbuf(pixbuf2);                  gtk_container_add(GTK_CONTAINER(widget), *imageG);                  gtk_widget_show(*imageG);              } else { -                gtk_image_set_from_pixbuf(GTK_IMAGE(*imageG), pixbuf); +                gtk_image_set_from_pixbuf(GTK_IMAGE(*imageG), pixbuf2);              } -            g_object_ref_sink(pixbuf); -            g_object_unref((gpointer)pixbuf); +            g_object_ref_sink(pixbuf2); +            g_object_unref((gpointer)pixbuf2);          } else {              if (*labelG==NULL) {                  *labelG = (GtkLabel*)gtk_label_new(wlibConvertInput(labelStr)); @@ -172,6 +180,18 @@ static void pushButt(  }  /** + * Called after expose event default hander - allows the button to be outlined + */ +static wBool_t exposeButt( +		GtkWidget *widget, +		GdkEventExpose *event, +		gpointer g) +{ +	wControl_p b = (wControl_p)g; +	return wControlExpose(widget,event,b); +} + +/**   * Create a button   *   * \param parent IN parent window @@ -198,7 +218,10 @@ wButton_p wButtonCreate(      void 	* data)  {      wButton_p b; -    b = wlibAlloc(parent, B_BUTTON, x, y, labelStr, sizeof *b, data); +    if (option&BO_ICON)  //The labelStr here is a wIcon_p +    	b = wlibAlloc(parent, B_BUTTON, x, y, " ", sizeof *b, data); +    else +    	b = wlibAlloc(parent, B_BUTTON, x, y, labelStr, sizeof *b, data);      b->option = option;      b->action = action;      wlibComputePos((wControl_p)b); @@ -206,9 +229,12 @@ wButton_p wButtonCreate(      b->widget = gtk_toggle_button_new();      g_signal_connect(GTK_OBJECT(b->widget), "clicked",                           G_CALLBACK(pushButt), b); +    g_signal_connect_after(GTK_OBJECT(b->widget), "expose-event", +    					G_CALLBACK(exposeButt), b);      if (width > 0) {          gtk_widget_set_size_request(b->widget, width, -1);      } +      if( labelStr ){          wButtonSetLabel(b, labelStr);      } @@ -484,6 +510,8 @@ wChoice_p wRadioCreate(      b->valueP = valueP;      wlibComputePos((wControl_p)b); +    ((wControl_p)b)->outline = FALSE; +      if (option&BC_HORZ) {          b->widget = gtk_hbox_new(FALSE, 0);      } else { @@ -506,6 +534,8 @@ wChoice_p wRadioCreate(          gtk_widget_show(butt);          g_signal_connect(GTK_OBJECT(butt), "toggled",                           G_CALLBACK(pushChoice), b); +        g_signal_connect_after(GTK_OBJECT(b->widget), "expose-event", +            					G_CALLBACK(exposeButt), b);          wlibAddHelpString(butt, helpStr);      } @@ -586,6 +616,8 @@ wChoice_p wToggleCreate(      b->action = action;      wlibComputePos((wControl_p)b); +    ((wControl_p)b)->outline = FALSE; +      if (option&BC_HORZ) {          b->widget = gtk_hbox_new(FALSE, 0);      } else { @@ -604,6 +636,8 @@ wChoice_p wToggleCreate(          gtk_widget_show(butt);          g_signal_connect(GTK_OBJECT(butt), "toggled",                           G_CALLBACK(pushChoice), b); +        g_signal_connect_after(GTK_OBJECT(b->widget), "expose-event", +            					G_CALLBACK(exposeButt), b);          wlibAddHelpString(butt, helpStr);      } diff --git a/app/wlib/gtklib/color.c b/app/wlib/gtklib/color.c index 64b96ef..e1689d2 100644 --- a/app/wlib/gtklib/color.c +++ b/app/wlib/gtklib/color.c @@ -100,7 +100,7 @@ static colorMap_t colorMap[] = {      { 208, 208, 208 },	/* Gray */      { 224, 224, 224 },	/* Gray */      { 240, 240, 240 },	/* Gray */ -    {   0,   0,   0 }	/* BlackPixel */ +    { 255, 255, 255 }	/* WhitePixel */  };  #define NUM_GRAYS (16) @@ -125,7 +125,7 @@ wDrawColor wDrawColorGray(      if (n <= 0) {          return wDrawColorBlack; -    } else if (n > NUM_GRAYS) { +    } else if (n >= NUM_GRAYS) {          return wDrawColorWhite;      } else {          n = (n*256)/NUM_GRAYS; @@ -209,7 +209,7 @@ wDrawColor wDrawFindColor(      long rgb0)  {      wDrawColor cc; -    int r0, g0, b0; +    int r0, g0, b0, r1, g1, b1;      int d0;      int i;      colorMap_t tempMapValue; @@ -231,7 +231,10 @@ wDrawColor wDrawFindColor(          colorMap_t * cm_p;          cm_p = &g_array_index(colorMap_garray, colorMap_t, i); -        d1 = abs(r0-cm_p->red) + abs(g0-cm_p->green) + abs(b0-cm_p->blue); +        r1 = (int)cm_p->red; +        g1 = (int)cm_p->green; +        b1 = (int)cm_p->blue; +        d1 = abs(r0-r1) + abs(g0-g1) + abs(b0-b1);          if (d1 == 0) {              return i; diff --git a/app/wlib/gtklib/control.c b/app/wlib/gtklib/control.c index c891924..07d9210 100644 --- a/app/wlib/gtklib/control.c +++ b/app/wlib/gtklib/control.c @@ -35,7 +35,7 @@  #include "gtkint.h" -#define  GTKCONTROLHILITEWIDTH (3) +#define  GTKCONTROLHILITEWIDTH (4)  /**   * Cause the control <b> to be displayed or hidden. @@ -252,6 +252,46 @@ void wControlSetFocus(  {  } +wBool_t wControlExpose ( +		 GtkWidget * widget, +		 GdkEventExpose * event, +		 wControl_p b +		) +{ +	GdkWindow * win = gtk_widget_get_window(b->widget); +	cairo_t * cr = NULL; +	if (win) { +		cr = gdk_cairo_create(win); +	} else return TRUE; + +#ifdef CURSOR_SURFACE +	if (b && b->cursor_surface.surface && b->cursor_surface.show) { +		cairo_set_source_surface(cr,b->cursor_surface.surface,event->area.x, event->area.y); +		cairo_set_operator(cr,CAIRO_OPERATOR_OVER); +		cairo_rectangle(cr,event->area.x, event->area.y, +				event->area.width, event->area.height); +		cairo_fill(cr); +	} +#endif + +	if (b->outline) { +		cairo_set_source_rgb(cr, 0.23, 0.37, 0.80); +		cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); +		cairo_set_line_width(cr, GTKCONTROLHILITEWIDTH); +		cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); +		cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); +		cairo_rectangle(cr,event->area.x+2, event->area.y+2, +						event->area.width-4, event->area.height-4); +		cairo_stroke(cr); +	} + + +	cairo_destroy(cr); + + +    return FALSE; +} +  /**   * Draw a rectangle around a control   * \param b IN the control @@ -279,17 +319,8 @@ void wControlHilite(          return;      } -    cr = gdk_cairo_create(gtk_widget_get_window(b->parent->gtkwin)); -    cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); -    cairo_set_operator(cr, CAIRO_OPERATOR_XOR); -    cairo_set_line_width(cr, GTKCONTROLHILITEWIDTH); -    cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); -    cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); -    cairo_rectangle(cr, -                    b->realX - GTKCONTROLHILITEWIDTH, -                    b->realY - off, -                    b->w + GTKCONTROLHILITEWIDTH, -                    b->h + off + 1); -    cairo_stroke(cr); -    cairo_destroy(cr); +    b->outline = hilite; + +    if (b->widget) +    	gtk_widget_queue_draw(b->widget);  } diff --git a/app/wlib/gtklib/droplist.c b/app/wlib/gtklib/droplist.c index 5fbdd17..69a2efd 100644 --- a/app/wlib/gtklib/droplist.c +++ b/app/wlib/gtklib/droplist.c @@ -235,43 +235,16 @@ wBool_t wDropListSetValues(  }  /** - * Signal handler for the "changed"-signal in drop list's entry field. - * Get the entered text and calls the 'action' for handling of entered - * value. - * * - * \param entry IN entry field of the droplist - * \param data IN the drop list handle - * \return - */ - -static void DropListEntryEntered( -    GtkEntry * entry, -    gpointer userData) -{ -    const gchar * text; - -    text = gtk_entry_get_text(entry); - -    if (text && *text != '\0') { -        gchar *copyOfText = g_strdup(text); -        ((wList_p)userData)->editted = TRUE; -        ((wList_p)userData)->action(-1, copyOfText, 1, ((wList_p)userData)->data, NULL); -        g_free((gpointer)copyOfText); -    } else { -        wBeep(); -    } -} - -/** - * Signal handler for the "changed"-signal in drop list. Gets the selected - * text and determines the selected row in the tree model. + * Signal handler for the "changed"-signal in drop list. + * Gets the selected text and determines the selected row in the tree model. + * Or handles user entered text.   *   * \param comboBox IN the combo_box   * \param data IN the drop list handle   * \return   */ -static int DropListSelectChild( +static int DropListChanged(      GtkComboBox * comboBox,      gpointer data)  { @@ -279,17 +252,14 @@ static int DropListSelectChild(      GtkTreeIter iter;      wIndex_t inx = 0; -    gchar *string; -    wListItem_p addData; +    gchar *string = NULL; +    wListItem_p listItemP = NULL;      if (bl->recursion) {          return 0;      } -    bl->editted = FALSE; - -    /* Obtain currently selected item from combo box. -     * If nothing is selected, do nothing. */ +    /* Obtain currently selected item from combo box. */      if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(comboBox), &iter)) {          GtkTreeModel *model; @@ -301,19 +271,30 @@ static int DropListSelectChild(                   &iter);          inx = atoi(string);          g_free(string); +        string = NULL;          /* Obtain string from model. */          gtk_tree_model_get(model, &iter,                             LISTCOL_TEXT, &string, -                           LISTCOL_DATA, (void *)&addData, +                           LISTCOL_DATA, (void *)&listItemP,                             -1); +        bl->editted = FALSE;      } else { -        return 0; +	/* Nothing selected, user is entering text directly */ +        inx = -1; +        GtkEntry * entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(bl->widget))); +	if ( entry == NULL ) +            return 0; +        const char * string1 = gtk_entry_get_text(entry); +	if ( string1 == NULL ) +            return 0; +        string = g_strdup(string1); +        bl->editted = TRUE;      }      /* selection changed, store new selections and call back */ -    if (bl->last != inx) { +    if (bl->last != inx || bl->editted == TRUE) {          bl->last = inx; @@ -323,11 +304,12 @@ static int DropListSelectChild(          /* selection changed -> callback */          if (string && bl->action) { -            bl->action(inx, string, 1, bl->data, addData->itemData); +            bl->action(inx, string, 1, bl->data, listItemP?listItemP->itemData:NULL);          }      } -    g_free(string); +    if ( string ) +        g_free(string);      return 1;  } @@ -429,14 +411,7 @@ wList_p wDropListCreate(      gtk_widget_set_name(b->widget,"mycombo");      g_signal_connect(GTK_OBJECT(b->widget), "changed", -                     G_CALLBACK(DropListSelectChild), b); - -    if (option & BL_EDITABLE) { -        g_signal_connect(gtk_bin_get_child(GTK_BIN(b->widget)), -                         "changed", -                         G_CALLBACK(DropListEntryEntered), -                         b); -    } +                     G_CALLBACK(DropListChanged), b);      gtk_widget_set_size_request(b->widget, width, -1); diff --git a/app/wlib/gtklib/filesel.c b/app/wlib/gtklib/filesel.c index ca30c7f..a1fb7cc 100644 --- a/app/wlib/gtklib/filesel.c +++ b/app/wlib/gtklib/filesel.c @@ -34,24 +34,92 @@  #define GSEAL_ENABLE  #include <gtk/gtk.h> +#include <glib-object.h>  #include "gtkint.h"  #include "i18n.h"  #define MAX_ALLOWEDFILTERS 10  struct wFilSel_t { -		GtkWidget * window; -		wFilSelCallBack_p action; -		void * data; -		int pattCount; -		GtkFileFilter *filter[ MAX_ALLOWEDFILTERS ]; -		wFilSelMode_e mode; -		int opt; -		const char * title; -		wWin_p parent; -		char *defaultExtension; +		GtkWidget * window; 							/**<  file selector handle*/ +		wFilSelCallBack_p action; 						/**<  */ +		void * data; 									/**<  */ +		int pattCount; 									/**<  number of file patterns*/ +		wBool_t loadPatternsAdded;						/** Already loaded        	*/ +		GtkFileFilter *filter[ MAX_ALLOWEDFILTERS ]; 	/**< array of file patterns */ +		wFilSelMode_e mode; 							/**< used for load or save */ +		int opt; 										/**< see FS_ options */ +		const char * title; 							/**< dialog box title */ +		wWin_p parent; 									/**< parent window */ +		char *defaultExtension; 						/**< to use if no extension specified */  		}; +/** + * Signal handler for 'changed' signal of custom combo box. The filter + * is set accordinng to the file format active in the combo box + *  + * \param comboBox the combo box  + * \param fileSelector data of the file selector + *  + */ + +static void FileFormatChanged( GtkWidget *comboBox,  +						  struct wFilSel_t *fileSelector ) +{ +	// get active entry +	int entry = (int)gtk_combo_box_get_active (GTK_COMBO_BOX(comboBox)); +	 +	if( entry>=0 ) { +		g_object_ref(G_OBJECT( (fileSelector->filter)[ entry ]));  +		gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fileSelector->window ),						 +									(fileSelector->filter)[ entry ]); +	} +} + +/** + * Create a widget containing a combo box for selecting a file format.  + * From an array of filters, the names are retrieved and used to populate + * the combo box.  + * \param IN dialogBox + * \param patterns IN number of entries for combo + * \param filters IN + * \returns the newly created widget + */ +  +static GtkWidget *CreateFileformatSelector(struct wFilSel_t *dialogBox,  +			int patterns,  +			GtkFileFilter **filters) +{ +	GtkWidget *hbox = gtk_hbox_new(FALSE, 12); +	GtkWidget *text = gtk_label_new(_("Save format:")); +	GtkWidget *combo = gtk_combo_box_text_new (); + +	g_signal_connect(G_OBJECT(combo),  +				 "changed", +				 (GCallback)FileFormatChanged, +				 dialogBox ); + + +	gtk_box_pack_start (GTK_BOX(hbox), +				text, +				FALSE, +				FALSE, +				0); +	gtk_box_pack_end (GTK_BOX(hbox), +				combo, +				TRUE, +				TRUE, +				0); +	for(int i=0; i < patterns; i++ ) { +		const char *nameOfFilter = gtk_file_filter_get_name( filters[ i ] ); +		gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(combo), nameOfFilter ); +	} +	gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0); +	 +	gtk_widget_show_all(hbox); +	 +	return(hbox);             +}  /**   * Create a new file selector. Only the internal data structures are @@ -89,31 +157,75 @@ struct wFilSel_t * wFilSelCreate(  	fs->title = strdup( title );  	fs->action = action;  	fs->data = data; +	fs->pattCount = 0; +	fs->loadPatternsAdded = FALSE;  	if (pattList) { -		char * cp = strdup(pattList); +		char * cps = strdup(pattList); +		char *cp, *cp2;  		int count = 0; +		char *patternState, *patternState2;  		//create filters for the passed filter list  		// names and patterns are separated by | -		cp = strtok( cp, "|" );		 -		while ( cp  && count < (MAX_ALLOWEDFILTERS - 1)) { +		// filter elements are also separated by | +		cp = cps; +		while (cp && cp[0]) { +			if (cp[0] == '|') { +				count++; +				if (count && count%2==0) { +					cp[0] = ':';             //Replace every second "|" with ":" +				} +			} +			cp++; +		} +		count = 0; +		cp = cps;							//Restart +		if (opt&FS_PICTURES) {				//Put first  			fs->filter[ count ] = gtk_file_filter_new (); -			gtk_file_filter_set_name ( fs->filter[ count ], cp ); -			cp = strtok( NULL, "|" ); -			gtk_file_filter_add_pattern (fs->filter[ count ], cp ); -			// the first pattern is considered to match the default extension -			if( count == 0 ) { -				fs->defaultExtension = strdup( cp ); -			}	 -			cp = strtok( NULL, "|" ); -			count++; +			g_object_ref_sink( G_OBJECT(fs->filter[ count ] )); +			gtk_file_filter_set_name( fs->filter[ count ], _("Image files") ); +			gtk_file_filter_add_pixbuf_formats( fs->filter[ count ]); +			fs->pattCount = ++count; +		} +		cp = strtok_r( cp, ":", &patternState );          // Break up by colons +		while ( cp  && count < (MAX_ALLOWEDFILTERS - 1)) { +			cp2 = strtok_r( cp, "|", &patternState2 ); +			if (cp2) { +				fs->filter[ count ] = gtk_file_filter_new (); +				gtk_file_filter_set_name ( fs->filter[ count ], cp2 ); + +				cp2 = strtok_r( NULL, "|", &patternState2 ); +				// find multiple patterns separated by ";" +				if (cp2) { +					char * cp1s = strdup(cp2); +					char *cp1; +					char *filterState; + +					cp1 = cp1s; +					cp1 = strtok_r(cp1, ";", &filterState ); +					while (cp1) { +						gtk_file_filter_add_pattern (fs->filter[ count ], cp1 ); +						cp1 = strtok_r(NULL, ";", &filterState ); +					} +					if (cp1s) +						free(cp1s); +				} +				// the first pattern is considered to match the default extension +				if( count == 0 && !(opt&FS_PICTURES)) { +					fs->defaultExtension = strdup( cp2 ); +					int i = 0; +					for (i=0; i<strlen(cp2) && cp2[i] != ' ' && cp2[i] != ';';i++) ; +					if (i<strlen(cp2)) fs->defaultExtension[i] = '\0'; +				} +				fs->pattCount = ++count; +			} +			cp = strtok_r( NULL, ":", &patternState );  		} -		// finally add the all files pattern -		fs->filter[ count ] = gtk_file_filter_new (); -		gtk_file_filter_set_name( fs->filter[ count ], _("All files") ); -		gtk_file_filter_add_pattern( fs->filter[ count ], "*" ); -		fs->pattCount = count++; +		if (cps)  +			free(cps); + +  	} else {  		fs->filter[ 0 ] = NULL;  		fs->pattCount = 0; @@ -145,33 +257,41 @@ int wFilSelect( struct wFilSel_t * fs, const char * dirName )  										   (fs->mode == FS_LOAD ? GTK_STOCK_OPEN : GTK_STOCK_SAVE ), GTK_RESPONSE_ACCEPT,  										   NULL );  		if (fs->window==0) abort(); -		// get confirmation before overwritting an existing file									 -		gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(fs->window), TRUE ); +		if ( fs->mode == FS_SAVE ) { +			// get confirmation before overwritting an existing file									 +			gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(fs->window), TRUE ); +		} -		// allow selecting multiple files -		if( fs->opt & FS_MULTIPLEFILES ) { -			gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(fs->window), TRUE); -		}	 -		// add the file filters to the dialog box -		if( fs->pattCount ) { -			for( i = 0; i <= fs->pattCount; i++ ) { -				gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( fs->window ), fs->filter[ i ] );  -			} -		}												  		/** \todo for loading a shortcut folder could be added linking to the example directory */  	}  	strcpy( name, dirName ); -	if( fs->mode == FS_SAVE ) -		gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(fs->window), name );  +	gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(fs->window), name );  +	if( fs->mode == FS_SAVE || fs->mode == FS_UPDATE ) { +		gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER(fs->window),  +				CreateFileformatSelector(fs, fs->pattCount, fs->filter )); +	}	      // Add a current folder and a shortcut to it for Load/import dialogs      if( fs->mode == FS_LOAD ) { -        gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(fs->window), name );          gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER(fs->window), name, NULL ); +		// allow selecting multiple files +		if( fs->opt & FS_MULTIPLEFILES ) { +			gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(fs->window), TRUE); +		}	 +		// add the file filters to the dialog box +		if( fs->pattCount && !fs->loadPatternsAdded) { + +			for( i = 0; i < fs->pattCount; i++ ) { +				gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( fs->window ), fs->filter[ i ] );  +			} +			fs->loadPatternsAdded = TRUE; +		}												      } -	if( gtk_dialog_run( GTK_DIALOG( fs->window )) == GTK_RESPONSE_ACCEPT ) { +    int resp = gtk_dialog_run( GTK_DIALOG( fs->window )); + +	if( resp == GTK_RESPONSE_ACCEPT || resp == GTK_RESPONSE_APPLY) {  		char **fileNames;	  		GSList *fileNameList; @@ -184,21 +304,36 @@ int wFilSelect( struct wFilSel_t * fs, const char * dirName )  			file = g_filename_from_uri( g_slist_nth_data( fileNameList, i ), &host, &err );  			// check for presence of file extension -			// jump behind tha last directory delimiter +			// jump behind the last directory delimiter  			namePart = strrchr( file, '/' ) + 1;  			// is there a dot in the last part, yes->extension present  			if( !strchr( namePart, '.' ) ){ -				// make room for the extension -				file = g_realloc( file, strlen(file)+strlen(fs->defaultExtension)); -				strcat( file, fs->defaultExtension + 1 ); +				 +				// else try to find the current filter and parse its name +				GtkFileFilter *currentFilter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER(fs->window) ); +				if (currentFilter) { +					const char *nameOfFilter = gtk_file_filter_get_name( currentFilter ); +					char *pattern = strdup( nameOfFilter ); +					char *extension = fs->defaultExtension; +					char *startDelimiter = strstr( pattern, "(*." ); + +					if(startDelimiter) { +						char *endDelimiter = strpbrk(startDelimiter + 3, ",;) "); +						if( endDelimiter ) { +							*endDelimiter = '\0'; +							extension = startDelimiter + 2; +						} +					} +					file = g_realloc( file, strlen(file)+strlen(extension)); +					strcat( file, extension ); +					free( pattern ); +				}  			}	  			fileNames[ i ] = file;  			g_free( g_slist_nth_data ( fileNameList, i));  		} -		if (fs->data) -			strcpy( fs->data, fileNames[ 0 ] ); -		 +		gtk_widget_hide( GTK_WIDGET( fs->window ));  		if (fs->action) {  			fs->action( g_slist_length(fileNameList), fileNames, fs->data );  		} @@ -208,8 +343,9 @@ int wFilSelect( struct wFilSel_t * fs, const char * dirName )  		}  		free( fileNames );  		g_slist_free (fileNameList);	 +	} else { +		gtk_widget_hide( GTK_WIDGET( fs->window ));  	} -	gtk_widget_hide( GTK_WIDGET( fs->window ));  	return 1;  } diff --git a/app/wlib/gtklib/font.c b/app/wlib/gtklib/font.c index 68ba87b..e2f741b 100644 --- a/app/wlib/gtklib/font.c +++ b/app/wlib/gtklib/font.c @@ -185,7 +185,8 @@ PangoLayout *wlibFontCreatePangoLayout(GtkWidget *widget,                                         int *width_p,                                         int *height_p,                                         int *ascent_p, -                                       int *descent_p) +                                       int *descent_p, +									   int *baseline_p)  {      if (!fontInitted) {          fontInit(); @@ -214,14 +215,16 @@ PangoLayout *wlibFontCreatePangoLayout(GtkWidget *widget,                                      FONTSIZE_TO_PANGOSIZE(fs) * PANGO_SCALE);      pango_layout_set_font_description(layout, fontDescription);      /* get layout measures */ -    pango_layout_get_pixel_size(layout, width_p, height_p); +    pango_layout_get_size(layout, width_p, height_p); +    *width_p = *width_p / PANGO_SCALE; +    *height_p = *height_p / PANGO_SCALE;      context = gtk_widget_create_pango_context(widget);      metrics = pango_context_get_metrics(context, fontDescription,                                          pango_context_get_language(context)); -    *ascent_p  = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics)); -    *descent_p = PANGO_PIXELS(pango_font_metrics_get_descent(metrics)); +    *baseline_p = pango_layout_get_baseline(layout) / PANGO_SCALE; +    *ascent_p  = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; +    *descent_p = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;      pango_font_metrics_unref(metrics); -    g_object_ref_sink(context);      g_object_unref(context);  #if WLIB_FONT_DEBUG >= 3      fprintf(stderr, "font layout created:\n"); @@ -347,9 +350,9 @@ wFontSize_t wSelectedFontSize(void)   * \return    describe the return value   */ -void wSetSelectedFontSize(int size) +void wSetSelectedFontSize(wFontSize_t size)  { -    absoluteFontSize = (wFontSize_t)size; +    absoluteFontSize = size;  }  /** 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); +	} + +} + + + + diff --git a/app/wlib/gtklib/gtkint.h b/app/wlib/gtklib/gtkint.h index 2e0511a..410fd7f 100644 --- a/app/wlib/gtklib/gtkint.h +++ b/app/wlib/gtklib/gtkint.h @@ -32,7 +32,9 @@  #define strcasecmp _stricmp  #endif +#ifndef MISC_H  #include "dynarr.h" +#endif  #define BORDERSIZE	(4)  #define LABEL_OFFSET	(3) @@ -40,6 +42,16 @@  extern wWin_p gtkMainW; +#ifdef CURSOR_SURFACE +typedef struct { +		cairo_surface_t* surface; +		wPos_t width; +		wPos_t height; +		wBool_t show; +} wCursorSurface_t, * wSurface_p; +#endif + +  typedef enum {  		W_MAIN, W_POPUP,  		B_BUTTON, B_CANCEL, B_POPUP, B_TEXT, B_INTEGER, B_FLOAT, @@ -59,6 +71,7 @@ typedef void (*setTriggerCallback_p)( wControl_p b );  		wWin_p parent; \  		wPos_t origX, origY; \  		wPos_t realX, realY; \ +		wPos_t default_size_x, default_size_y; \  		wPos_t labelW; \  		wPos_t w, h; \  		int maximize_initially; \ @@ -68,6 +81,8 @@ typedef void (*setTriggerCallback_p)( wControl_p b );  		GtkWidget * widget; \  		GtkWidget * label; \  		doneProcCallback_p doneProc; \ +		/* CURSOR_SURFACE wCursorSurface_t cursor_surface;*/ \ +		wBool_t outline; \  		void * data;  struct wWin_t { @@ -171,6 +186,7 @@ typedef struct {  GdkColor *wlibGetColor(wDrawColor color, wBool_t normal);  /* control.c */ +wBool_t wControlExpose (GtkWidget * widget, GdkEventExpose * event, wControl_p b);  /* droplist.c */  enum columns { @@ -191,7 +207,7 @@ wList_p wDropListCreate(wWin_p parent, wPos_t x, wPos_t y, const char *helpStr,  /* filesel.c */  /* font.c */ -PangoLayout *wlibFontCreatePangoLayout(GtkWidget *widget, void *cairo, wFont_p fp, wFontSize_t fs, const char *s, int *width_p, int *height_p, int *ascent_p, int *descent_p); +PangoLayout *wlibFontCreatePangoLayout(GtkWidget *widget, void *cairo, wFont_p fp, wFontSize_t fs, const char *s, int *width_p, int *height_p, int *ascent_p, int *descent_p, int *baseline_p);  void wlibFontDestroyPangoLayout(PangoLayout *layout);  const char *wlibFontTranslate(wFont_p fp); @@ -255,6 +271,7 @@ struct wDraw_t {  		GdkPixmap * pixmap;  		GdkPixmap * pixmapBackup; +		cairo_surface_t * temp_surface;  		double dpi; @@ -273,6 +290,9 @@ struct wDraw_t {  		wBool_t delayUpdate;  		cairo_t *printContext;  		cairo_surface_t *curPrintSurface; +		GdkPixbuf * background; + +		wBool_t bTempMode;  		};  void WlibApplySettings(GtkPrintOperation *op); @@ -280,7 +300,7 @@ void WlibSaveSettings(GtkPrintOperation *op);  void psPrintLine(wPos_t x0, wPos_t y0, wPos_t x1, wPos_t y1, wDrawWidth width, wDrawLineType_e lineType, wDrawColor color, wDrawOpts opts);  void psPrintArc(wPos_t x0, wPos_t y0, wPos_t r, double angle0, double angle1, wBool_t drawCenter, wDrawWidth width, wDrawLineType_e lineType, wDrawColor color, wDrawOpts opts);  void psPrintFillRectangle(wPos_t x0, wPos_t y0, wPos_t x1, wPos_t y1, wDrawColor color, wDrawOpts opts); -void psPrintFillPolygon(wPos_t p[][2], int cnt, wDrawColor color, wDrawOpts opts); +void psPrintFillPolygon(wPos_t p[][2], wPolyLine_e type[], int cnt, wDrawColor color, wDrawOpts opts, int fill, int open);  void psPrintFillCircle(wPos_t x0, wPos_t y0, wPos_t r, wDrawColor color, wDrawOpts opts);  void psPrintString(wPos_t x, wPos_t y, double a, char *s, wFont_p fp, double fs, wDrawColor color, wDrawOpts opts);  static void WlibGetPaperSize(void); diff --git a/app/wlib/gtklib/help.c b/app/wlib/gtklib/help.c index dbb69f6..8f2766d 100644 --- a/app/wlib/gtklib/help.c +++ b/app/wlib/gtklib/help.c @@ -28,9 +28,12 @@  #include <gtk/gtk.h>  #include <gdk/gdk.h> +#include "misc.h" +  #include "gtkint.h"  #include "i18n.h" +  /**   * Handle the commands issued from the Help drop-down. Currently, we only have a table   * of contents, but search etc. might be added in the future. @@ -44,11 +47,19 @@ DoHelpMenu(void *data)  {      int func = (intptr_t)data; +    const char * topic; +      switch (func) {      case 1:          wHelp("index");          break; +    case 3: +    	topic = GetCurCommandName(); +    	if (topic && topic[0]) +    		wHelp(topic); +    	break; +      default:          break;      } @@ -56,6 +67,10 @@ DoHelpMenu(void *data)      return;  } +void wDoAccelHelp(wAccelKey_e key, void * context) { +	DoHelpMenu(context); +} +  /**   * Add the entries for Help to the drop-down.   * @@ -66,4 +81,5 @@ DoHelpMenu(void *data)  void wMenuAddHelp(wMenu_p m)  {      wMenuPushCreate(m, NULL, _("&Contents"), 0, DoHelpMenu, (void*)1); +    wMenuPushCreate(m, NULL, _("Co&mmand Context help"), 0, DoHelpMenu, (void*)3);  } diff --git a/app/wlib/gtklib/ixhelp.c b/app/wlib/gtklib/ixhelp.c index f1e3983..5079f61 100644 --- a/app/wlib/gtklib/ixhelp.c +++ b/app/wlib/gtklib/ixhelp.c @@ -404,6 +404,13 @@ void wHelp(const char * topic)  {      char *htmlFile; +    //Take off any topic characters after a '-' + +    if (!topic || !topic[0]) return; + + +    if (!CheckHelpTopicExists(topic)) return; +      if (!wHelpWindow) {          directory = malloc(BUFSIZ);          assert(directory != NULL); @@ -417,6 +424,7 @@ void wHelp(const char * topic)      /* need space for the 'html' extension plus dot plus \0 */      htmlFile = malloc(strlen(topic) + 6); +      assert(htmlFile != NULL);      sprintf(htmlFile, "%s.html", topic); @@ -424,4 +432,6 @@ void wHelp(const char * topic)      load_into_view(htmlFile, MAIN_VIEW);      gtk_widget_show_all(wHelpWindow);      gtk_window_present(GTK_WINDOW(wHelpWindow)); + +    free(htmlFile);  } diff --git a/app/wlib/gtklib/list.c b/app/wlib/gtklib/list.c index 8e99efe..ac66aba 100644 --- a/app/wlib/gtklib/list.c +++ b/app/wlib/gtklib/list.c @@ -238,6 +238,7 @@ wIndex_t wListGetValues(      if (bl->type == B_DROPLIST && bl->editted) {          entry_value = gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(                                               bl->widget)))); +	item_data = NULL;          inx = bl->last = -1;      } else {          inx = bl->last; @@ -404,6 +405,8 @@ void wListDelete(                                        NULL,                                        inx);          gtk_list_store_remove(b->listStore, &iter); + +          b->count--;      } @@ -486,7 +489,7 @@ wIndex_t wListAddValue(          wlibTreeViewAddRow(b, (char *)labelStr, bm, id_p);      } -    free(id_p->label); +    //free(id_p->label);      b->count++;      b->recursion--; diff --git a/app/wlib/gtklib/liststore.c b/app/wlib/gtklib/liststore.c index 820366a..088bf33 100644 --- a/app/wlib/gtklib/liststore.c +++ b/app/wlib/gtklib/liststore.c @@ -127,6 +127,8 @@ wlibListStoreClear(GtkListStore *listStore)      id_p = wlibListStoreGetContext(listStore, i++);      while (id_p) { +        if (id_p->label) +            g_free(id_p->label);          g_free(id_p);          id_p = wlibListStoreGetContext(listStore, i++);      } diff --git a/app/wlib/gtklib/menu.c b/app/wlib/gtklib/menu.c index d19805a..79695d4 100644 --- a/app/wlib/gtklib/menu.c +++ b/app/wlib/gtklib/menu.c @@ -555,7 +555,7 @@ wMenuList_p wMenuListCreate(   * behind it. In case the maximum number of items is reached the last item is removed.   *   * \param ml 		IN handle for the menu list - the placeholder item - * \param index 	IN currently ignored + * \param index 	IN position of new menu item   * \param labelStr 	IN the menu label for the new item    * \param data 		IN application data for the new item   * \return     @@ -611,7 +611,11 @@ void wMenuListAdd(  		g_object_set_data( G_OBJECT(MMENUITEM( mi )), WLISTITEM,  mi );  		// add the item to the menu -		gtk_menu_shell_insert((GtkMenuShell *)(MPARENT( ml )->menu), MMENUITEM( mi ), i + 1 ); +		if ( index < 0 ) +			index = 0; +		if ( index >= ml->count ) +			index = ml->count - 1; +		gtk_menu_shell_insert((GtkMenuShell *)(MPARENT( ml )->menu), MMENUITEM( mi ), i + index + 1 );  		g_signal_connect( GTK_OBJECT(MMENUITEM( mi )), "activate", G_CALLBACK(pushMenuList), mi );  		gtk_widget_show(MMENUITEM( mi )); diff --git a/app/wlib/gtklib/notice.c b/app/wlib/gtklib/notice.c index b72afd6..0134b4f 100644 --- a/app/wlib/gtklib/notice.c +++ b/app/wlib/gtklib/notice.c @@ -58,8 +58,13 @@ static void doNotice(      GtkWidget * widget,      long value)  { -    noticeValue = value; -    gtk_widget_destroy(noticeW.win); +    if (value != 2) { +	// event not from from closing the window but from a button press +	// Close the Notice dialog +    	gtk_widget_destroy(noticeW.win); +	// Remember the button +        noticeValue = value; +    }      wlibDoModal(NULL, FALSE);  } @@ -106,6 +111,8 @@ int wNoticeEx(int type,          parent = GTK_WINDOW(gtkMainW->gtkwin);      } +    wDestroySplash(); +      dialog = gtk_message_dialog_new(parent,                                      GTK_DIALOG_DESTROY_WITH_PARENT,                                      flag, @@ -113,6 +120,8 @@ int wNoticeEx(int type,                                      "%s", msg);      gtk_window_set_title(GTK_WINDOW(dialog), headline); +    gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); +      res = gtk_dialog_run(GTK_DIALOG(dialog));      gtk_widget_destroy(dialog); @@ -174,6 +183,7 @@ int wNotice3(      char *can = NULL;      char *alt = NULL; +    wDestroySplash();      nw->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); @@ -243,6 +253,9 @@ int wNotice3(          }      } +    g_signal_connect(GTK_WINDOW(nw->win), +            "destroy", G_CALLBACK(doNotice), (void*)2); +      gtk_widget_grab_default(nw->butt[ 0 ]);      gtk_widget_grab_focus(nw->butt[ 0 ]); @@ -253,6 +266,7 @@ int wNotice3(          /*		gdk_window_set_group( nw->win->window, gtkMainW->gtkwin->window ); */      } +    noticeValue = 0; // Default: Cancel      wlibDoModal(NULL, TRUE);      if (aff) { diff --git a/app/wlib/gtklib/opendocument.c b/app/wlib/gtklib/opendocument.c new file mode 100644 index 0000000..c03f9cb --- /dev/null +++ b/app/wlib/gtklib/opendocument.c @@ -0,0 +1,117 @@ +/** \file opendocument.c + * open a document using the systems default application for that doc + */ + +/*  XTrkCad - Model Railroad CAD + *  Copyright (C) 2018 Martin Fischer + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#include "gtkint.h" +#include "i18n.h" + +#include "dynstring.h" + +#if defined (_WIN32) + +#define DEFAULTOPENCOMMAND "start" + +#endif + +#if defined(__APPLE__) && defined(__MACH__) + +#define DEFAULTOPENCOMMAND "open" + +#else + +#define DEFAULTOPENCOMMAND "xdg-open" + +#endif + +/** + * Extend the PATH variable in the environment to include XTrackCAD's + * script directory. + * + * \return pointer to old path + */ + +static char * +ExtendPath(void) +{ +    char *path = strdup(getenv("PATH")); +    DynString newPath; +    DynStringMalloc(&newPath, 16); + +    // append XTrackCAD's directory to the path as a fallback +    DynStringCatCStrs(&newPath, +                      path, +                      ":", +                      wGetAppLibDir(), +                      NULL); + +    setenv("PATH", +           DynStringToCStr(&newPath), +           TRUE); + +    DynStringFree(&newPath); + +    return (path); +} + +/** + * Invoke the system's default application to open a file. First the + * system's standard xdg-open command is attempted. If that is not available, the + * version included with the XTrackCAD installation is executed. + * + * \param topic IN URI of document + */ + +unsigned wOpenFileExternal(char * filename) +{ +    int rc; +    DynString commandLine; +    char *currentPath; + +    assert(filename != NULL); +    assert(strlen(filename)); + +    currentPath = ExtendPath(); +     +    DynStringMalloc(&commandLine, 16); +    DynStringCatCStrs(&commandLine, +                      DEFAULTOPENCOMMAND, +                      " \"", +                      filename, +					  "\"", +                      NULL); + +    // the command should be found via the PATH +    rc = system(DynStringToCStr(&commandLine)); + +    // restore the PATH +    setenv("PATH", +           currentPath, +           TRUE); + +    free(currentPath); +    DynStringFree(&commandLine); +     +    return(rc==0); +} diff --git a/app/wlib/gtklib/osxhelp.c b/app/wlib/gtklib/osxhelp.c index 829ec94..4ec1f5e 100644 --- a/app/wlib/gtklib/osxhelp.c +++ b/app/wlib/gtklib/osxhelp.c @@ -28,6 +28,7 @@  #include <errno.h>  #include <fcntl.h> +#include "misc.h"  #include "gtkint.h"  #include "i18n.h" @@ -39,6 +40,7 @@ static pid_t pidOfChild;  static int handleOfPipe;  extern char *wExecutableName; +  /**   * Create the fully qualified filename for the help helper   * @@ -70,14 +72,21 @@ char *ChildProgramFile(char *parentProgram)  void wHelp(const char * topic)  {      pid_t newPid; -    int len;      int status;      const char html[] = ".html"; +    static char *directory;				/**< base directory for HTML files */ +    char * htmlFile; + + struct { +    int length;      char *page; -     + } buffer; + + 	if (!CheckHelpTopicExists(topic)) return; +      // check whether child already exists      if (pidOfChild != 0) { -        if (waitpid(pidOfChild, &status, WNOHANG) > 0) { +        if (waitpid(pidOfChild, &status, WNOHANG) < 0) {              // child exited -> clean up              close(handleOfPipe);              unlink(HELPCOMMANDPIPE); @@ -88,7 +97,8 @@ void wHelp(const char * topic)      // (re)start child      if (pidOfChild == 0) { -        mkfifo(HELPCOMMANDPIPE, 0666); +    	unlink(HELPCOMMANDPIPE); +        int rc = mkfifo(HELPCOMMANDPIPE, 0666);          newPid = fork();  /* New process starts here */          if (newPid > 0) { @@ -107,27 +117,46 @@ void wHelp(const char * topic)          }      } -    if (!handleOfPipe) { -        handleOfPipe = open(HELPCOMMANDPIPE, O_WRONLY); - -        if (handleOfPipe < 0) { -            kill(pidOfChild, SIGKILL);  /* tidy up on next call */ -        } +    buffer.page = malloc(sizeof(int)+strlen(topic) + strlen(html) + 1); +    if (!buffer.page) { +        return;      } -    page = malloc(strlen(topic) + strlen(html) + 1); +    strcpy(buffer.page, topic); +    strcat(buffer.page, html); +    buffer.length = strlen(buffer.page); -    if (!page) { -        return; +    if (buffer.length>255) { +    	printf("Help Topic too long %s", buffer.page); +    	return;      } -    strcpy(page, topic); -    strcat(page, html); -    len = strlen(page); +    if (!handleOfPipe) { +		handleOfPipe = open(HELPCOMMANDPIPE, O_WRONLY); + +		if (handleOfPipe < 0) { +			if (pidOfChild) +				kill(pidOfChild, SIGKILL);  /* tidy up on next call */ +			handleOfPipe = 0; +			return; +		} + +	} + +    int written = 0; +    int towrite = sizeof(int); + +    while (written < towrite){ +    	written += write(handleOfPipe, &buffer.length, sizeof(int)); +    } +    written =0; +    towrite = strlen(buffer.page); +    while (written < towrite){ +        written += write(handleOfPipe, buffer.page+written, towrite-written); +    } -    write(handleOfPipe, &len, sizeof(int)); -    write(handleOfPipe, page, strlen(page)+1); +    fsync(handleOfPipe); -    free(page); +    free(buffer.page);  } diff --git a/app/wlib/gtklib/print.c b/app/wlib/gtklib/print.c index 8e96e3b..860a7c7 100644 --- a/app/wlib/gtklib/print.c +++ b/app/wlib/gtklib/print.c @@ -70,9 +70,9 @@ extern wDrawColor wDrawColorBlack;   *   */ -static GtkPrintSettings *settings;			/**< current printer settings */ +static GtkPrintSettings *settings = NULL;			/**< current printer settings */  static GtkPageSetup *page_setup;			/**< current paper settings */ -static GtkPrinter *selPrinter;				/**< printer selected by user */ +static GtkPrinter *selPrinter = NULL;				/**< printer selected by user */  static GtkPrintJob *curPrintJob;			/**< currently active print job */  extern struct wDraw_t psPrint_d; @@ -131,7 +131,6 @@ WlibApplySettings(GtkPrintOperation *op)              // create  default print settings              settings = gtk_print_settings_new();          } -          g_error_free(err);      } @@ -247,12 +246,13 @@ void wPrintSetup(wPrintSetupCallBack_p callback)      GError *err;      GtkWidget *dialog; -    WlibApplySettings(NULL); +    if ( !settings ) +        WlibApplySettings(NULL);      new_page_setup = gtk_print_run_page_setup_dialog(GTK_WINDOW(gtkMainW->gtkwin),                       page_setup, settings); -    if (page_setup) { +    if (page_setup && (page_setup != new_page_setup)) {      //Can be the same if no mods...          g_object_unref(page_setup);      } @@ -264,6 +264,51 @@ void wPrintSetup(wPrintSetupCallBack_p callback)  /*****************************************************************************   * + *  + * + */ + + +static GtkPrinter * pDefaultPrinter = NULL; +gboolean isDefaultPrinter( GtkPrinter * printer, gpointer data ) +{ +const char * pPrinterName = gtk_printer_get_name( printer ); +	if ( gtk_printer_is_default( printer ) ) { +		pDefaultPrinter = printer; +		return TRUE; +	} +	return FALSE; +} + +static void getDefaultPrinter() +{ +	pDefaultPrinter = NULL; +	gtk_enumerate_printers( isDefaultPrinter, NULL, NULL, TRUE ); +}  + +const char * wPrintGetName() +{ +	static char sPrinterName[100]; +	WlibApplySettings( NULL ); +	const char * pPrinterName =  +		gtk_print_settings_get( settings, "format-for-printer" ); +	if ( pPrinterName == NULL ) { +		getDefaultPrinter(); +		if ( pDefaultPrinter ) +			pPrinterName = gtk_printer_get_name( pDefaultPrinter ); +	} +	if ( pPrinterName == NULL ) { +		pPrinterName = ""; +	} +	strncpy (sPrinterName, pPrinterName, sizeof sPrinterName - 1 ); +	sPrinterName[ sizeof sPrinterName - 1 ] = '\0'; +	for ( char * cp = sPrinterName; *cp; cp++ ) +		if ( *cp == ':' ) +			*cp = '-'; +	return sPrinterName; +} +/***************************************************************************** + *   * BASIC PRINTING   *   */ @@ -299,12 +344,53 @@ static void setLineType(      }      cairo_set_line_width(cr, lineWidth); - -    if (lineType == wDrawLineDash) { -        cairo_set_dash(cr, dashes, len_dashes, 0.0); -    } else { -        cairo_set_dash(cr, NULL, 0, 0.0); +    switch(lineType) { +    	case wDrawLineDot: +    	{ +    		double dashes[] = { 1,  2 , 1,  2}; +    	    static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +    	    cairo_set_dash(cr, dashes, len_dashes, 0.0); +    	    break; +    	} +    	case wDrawLineDash: +    	{ +    		double dashes[] = { DASH_LENGTH, 3 };							//Reduce gap in between dashes +    		static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +    		cairo_set_dash(cr, dashes, len_dashes, 0.0); +			break; +    	} +    	case wDrawLineDashDot: +    	{ +    		double dashes[] = { 3, 2, 1, 2}; +    		static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +    		cairo_set_dash(cr, dashes, len_dashes, 0.0); +    		break; +    	} +    	case wDrawLineDashDotDot: +    	{ +    		double dashes[] = { 3, 2, 1, 2, 1, 2}; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cr, dashes, len_dashes, 0.0); +			break; +    	} +    	case wDrawLineCenter: +		{ +			double dashes[] = { 1.5*DASH_LENGTH, 3, DASH_LENGTH, 3}; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cr, dashes, len_dashes, 0.0); +			break; +		} +    	case wDrawLinePhantom: +		{ +			double dashes[] = { 1.5*DASH_LENGTH, 3, DASH_LENGTH, 3, DASH_LENGTH, 3}; +			static int len_dashes  = sizeof(dashes) / sizeof(dashes[0]); +			cairo_set_dash(cr, dashes, len_dashes, 0.0); +			break; +		} +    	default: +    		cairo_set_dash(cr, NULL, 0, 0.0);      } +  }  /** @@ -479,14 +565,18 @@ void psPrintFillRectangle(   * \param cnt IN the number of points   * \param color IN fill color   * \param opts IN options + * \paran fill IN Fill or not   * \return   */  void psPrintFillPolygon(      wPos_t p[][2], +	wPolyLine_e type[],      int cnt,      wDrawColor color, -    wDrawOpts opts) +    wDrawOpts opts, +	int fill, +	int open )  {      int inx;      cairo_t *cr = psPrint_d.printContext; @@ -501,13 +591,67 @@ void psPrintFillPolygon(      psSetColor(color); -    cairo_move_to(cr, p[ 0 ][ 0 ], p[ 0 ][ 1 ]); +    wPos_t mid0[2], mid1[2], mid2[2], mid3[2], mid4[2];      for (inx=0; inx<cnt; inx++) { -        cairo_line_to(cr, p[ inx ][ 0 ], p[ inx ][ 1 ]); +    	int j = inx-1; +    	int k = inx+1; +    	if (j < 0) j = cnt-1; +    	if (k > cnt-1) k = 0; +		double len0, len1; +		double d0x = (p[inx][0]-p[j][0]); +		double d0y = (p[inx][1]-p[j][1]); +		double d1x = (p[k][0]-p[inx][0]); +		double d1y = (p[k][1]-p[inx][1]); +		len0 = (d0x*d0x+d0y*d0y); +		len1 = (d1x*d1x+d1y*d1y); +		mid0[0] = (d0x/2)+p[j][0]; +		mid0[1] = (d0y/2)+p[j][1]; +		mid1[0] = (d1x/2)+p[inx][0]; +		mid1[1] = (d1y/2)+p[inx][1]; +		if (type && (type[inx] == wPolyLineRound) && (len1>0) && (len0>0)) { +			double ratio = sqrt(len0/len1); +			if (len0 < len1) { +				mid1[0] = ((d1x*ratio)/2)+p[inx][0]; +				mid1[1] = ((d1y*ratio)/2)+p[inx][1]; +			} else { +				mid0[0] = p[inx][0]-(d0x/(2*ratio)); +				mid0[1] = p[inx][1]-(d0y/(2*ratio)); +			} +		} +		mid3[0] = (p[inx][0]-mid0[0])/2+mid0[0]; +		mid3[1] = (p[inx][1]-mid0[1])/2+mid0[1]; +		mid4[0] = (mid1[0]-p[inx][0])/2+p[inx][0]; +		mid4[1] = (mid1[1]-p[inx][1])/2+p[inx][1]; +		wPos_t save[2]; +		if (inx==0) { +			 if (!type || (type && type[0] == wPolyLineStraight) || open) { +				 cairo_move_to(cr, p[ 0 ][ 0 ], p[ 0 ][ 1 ]); +				 save[0] = p[0][0]; save[1] = p[0][1]; +			 } else { +				 cairo_move_to(cr, mid0[0], mid0[1]); +				 if (type[inx] == wPolyLineSmooth) +				 	cairo_curve_to(cr, p[inx][0], p[inx][1], p[inx][0], p[inx][1], mid1[0], mid1[1]); +				 else +				 	cairo_curve_to(cr, mid3[0], mid3[1], mid4[0], mid4[1], mid1[0], mid1[1]); +				 save[0] = mid0[0]; save[1] = mid0[1]; +			 } +		} else if (!type || (type && type[inx] == wPolyLineStraight) || (open && (inx==cnt-1)) ) { +			cairo_line_to(cr, p[ inx ][ 0 ], p[ inx ][ 1 ]); +		} else { +			cairo_line_to(cr, mid0[ 0 ], mid0[ 1 ]); +			if (type && type[inx] == wPolyLineSmooth) +				cairo_curve_to(cr, p[inx][0],p[inx][1],p[inx][0],p[inx][1],mid1[0],mid1[1]); +			else +				cairo_curve_to(cr, mid3[0],mid3[1],mid4[0],mid4[1],mid1[0],mid1[1]); +		} +		if ((inx==cnt-1) && !open) { +			cairo_line_to(cr, save[0], save[1]); +		}      } -    cairo_fill(cr); +    if (fill && !open) cairo_fill(cr); +    else cairo_stroke(cr);  }  /** @@ -602,6 +746,7 @@ void psPrintString(      cairo_matrix_transform_point(&matrix, &x0, &y0); +    cairo_identity_matrix(cr);      layout = pango_cairo_create_layout(cr); @@ -609,7 +754,6 @@ void psPrintString(      /** \todo use a getter function instead of double conversion */      desc = pango_font_description_from_string(wlibFontTranslate(fp)); -      pango_font_description_set_size(desc, fs * PANGO_SCALE * scale_text);      // render the string to a Pango layout @@ -617,28 +761,41 @@ void psPrintString(      pango_layout_set_text(layout, s, -1);      pango_layout_set_width(layout, -1);      pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); -    pango_layout_get_pixel_size(layout, &text_width, &text_height); +    pango_layout_get_size(layout, &text_width, &text_height); + +    text_width = text_width / PANGO_SCALE; +    text_height = text_height / PANGO_SCALE;      // get the height of the string      pcontext = pango_cairo_create_context(cr);      metrics = pango_context_get_metrics(pcontext, desc,                                          pango_context_get_language(pcontext)); -    ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE *scale_adjust; - -    cairo_identity_matrix(cr); +    ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; -    cairo_translate(cr, x0 + ((ascent + (bBorder*scale_adjust)) * sin(-a * M_PI / 180.0))+((lBorder*scale_adjust)* cos(a * M_PI / 180.0)), -    					y0 - ((ascent + (bBorder*scale_adjust)) * cos( a * M_PI / 180.0))+((lBorder*scale_adjust)* sin(a * M_PI / 180.0))); +    int baseline = pango_layout_get_baseline(layout) / PANGO_SCALE; +    cairo_translate(cr, x0,	y0 );      cairo_rotate(cr, -a * M_PI / 180.0); +    cairo_translate( cr, 0, -baseline ); + +    cairo_move_to(cr,0,0); + +    pango_cairo_update_layout(cr, layout); +      // set the color      psSetColor(color);      // and show the string -    pango_cairo_show_layout(cr, layout); - +    if(!(opts & wDrawOutlineFont)) { +		pango_cairo_show_layout(cr, layout); +	} else { +		PangoLayoutLine *line; +		line = pango_layout_get_line_readonly (layout, 0); +		pango_cairo_layout_line_path (cr, line); +		cairo_stroke( cr );	 +	}      // free unused objects      g_object_unref(layout);      g_object_unref(pcontext); @@ -704,21 +861,20 @@ WlibGetPaperSize(void)   * \return   */ -void wPrintGetPageSize( -    double * w, -    double * h) -{ -    // if necessary load the settings -    if (!settings) { -        WlibApplySettings(NULL); -    } - -    WlibGetPaperSize(); -    *w = paperWidth -lBorder - rBorder; -    *h = paperHeight - tBorder - bBorder; +void wPrintGetMargins( +	double * tMargin, +	double * rMargin, +	double * bMargin, +	double * lMargin ) +{ +	if ( tMargin ) *tMargin = tBorder; +	if ( rMargin ) *rMargin = rBorder; +	if ( bMargin ) *bMargin = bBorder; +	if ( lMargin ) *lMargin = lBorder;  } +  /**   * Get the paper size. The size returned is the physical size of the   * currently selected paper. @@ -727,7 +883,7 @@ void wPrintGetPageSize(   * \return   */ -void wPrintGetPhysSize( +void wPrintGetPageSize(      double * w,      double * h)  { @@ -854,13 +1010,13 @@ wBool_t wPrintDocStart(const char * title, int fTotalPageCount, int * copiesP)                                      NULL);          psPrint_d.printContext = cairo_create(psPrint_d.curPrintSurface); +        WlibApplySettings( NULL );          //update the paper dimensions          WlibGetPaperSize();          /* for all surfaces including files the resolution is always 72 ppi (as all GTK uses PDF) */          surface_type = cairo_surface_get_type(psPrint_d.curPrintSurface); -        const char * printer_name = gtk_print_settings_get_printer(settings);          /*           * Override up-scaling for some printer drivers/Linux systems that don't support the latest CUPS           * - the user sets the environment variable XTRKCADPRINTSCALE to a value @@ -871,7 +1027,8 @@ wBool_t wPrintDocStart(const char * title, int fTotalPageCount, int * copiesP)           */          char * sEnvScale = PRODUCT "PRINTSCALE"; -        if ((strcmp(printer_name,"Print to File") == 0) || getenv(sEnvScale) == NULL) { +	const char * sPrinterName = gtk_printer_get_name( selPrinter ); +        if ((strcmp(sPrinterName,"Print to File") == 0) || getenv(sEnvScale) == NULL) {  			double p_def = 600;  			cairo_surface_set_fallback_resolution(psPrint_d.curPrintSurface, p_def, p_def);  			psPrint_d.dpi = p_def; diff --git a/app/wlib/gtklib/single.c b/app/wlib/gtklib/single.c index 45ed6e4..600f1dd 100644 --- a/app/wlib/gtklib/single.c +++ b/app/wlib/gtklib/single.c @@ -50,8 +50,10 @@ struct wString_t {  	char *valueP;			/**< pointer to result buffer */  	wIndex_t valueL;	 	/**< maximum length */  	wStringCallBack_p action;  	/**< callback for changes */ -	wBool_t busy;		 	/**< busy flag to prevent re-entry problems? */	 +	wBool_t notice_activate; /** if flag set to observe enter key **/ +	wBool_t enter_pressed;	/**< flag if enter was pressed */  	wBool_t hasSignal;		/** needs signal to be suppressed */ +	int count;				/** number of 100ms since last entry **/  	guint	timer;			/**< timer source for inactivity timer */  }; @@ -142,33 +144,43 @@ static gboolean killTimer(  }	  /** - *	Timer handler for string activity. This timer expires if the user - * 	doesn't change an entry value within the preset time.  + *	Timer handler for string activity. This timer checks the input if the user + * 	doesn't change an entry value for the preset time (0.5s).   */  static gboolean  timeoutString( wString_p bs )   { - +	const char *new_value;  	if ( !bs )  		return( FALSE );  	if (bs->widget == 0)   		abort(); -	if (bs->action) { -		const char *s; -		 -		s = gtk_entry_get_text(GTK_ENTRY(bs->widget)); -		if ( s ) -			bs->action(s, bs->data); +	bs->count--; + +	if (bs->count==0) { +		// get the currently entered value +	    new_value = wStringGetValue(bs); +		if (bs->valueP != NULL) +			strcpy(bs->valueP, new_value); + +		if (bs->action) { +			bs->enter_pressed = FALSE;     //Normal input +			if ( new_value ) +				bs->action(new_value,bs->data); +		} +	} +	if (bs->count<=0) { +		bs->timer = 0; +		return( FALSE );   //Stop timer +	} else { +		return TRUE;       //Wait 100ms  	} - -	bs->timer = 0; -	return( FALSE );  }  /** - * Signal handler for 'activate' signal: callback with the current value and then  + * Signal handler for 'activate' signal: enter pressed - callback with the current value and then   * select the whole default value   *   * \param widget 	IN the edit field @@ -181,6 +193,7 @@ static gboolean stringActivated(      wString_p b)   {  	const char *s; +	const char * output = "\n";  	if ( !b )  		return( FALSE ); @@ -191,14 +204,22 @@ static gboolean stringActivated(  		strcpy(b->valueP, s);  	if (b->action) { -		b->action(s, b->data); +		b->enter_pressed = TRUE; +		b->action( output, b->data);  	}  	// select the complete default value to make editing it easier  	gtk_editable_select_region( GTK_EDITABLE( widget ), 0, -1 ); -	return( FALSE ); +	return( TRUE ); +} + +static gboolean stringExposed(GtkWidget* widget, GdkEventExpose * event, gpointer g ) +{ +	wControl_p b = (wControl_p)g; +	return wControlExpose(widget,event,b);  } +  /**   * Signal handler for changes in an entry field   * @@ -213,25 +234,27 @@ static void stringChanged(  {  	const char *new_value; -	if ( !b || b->busy ) +	if ( !b  )  		return; +	b->count = 5;              /* set ~500 ms from now */ +  	// get the entered value -	new_value = wStringGetValue(b); -	if (b->valueP != NULL) -		strcpy(b->valueP, new_value); -	 +	//new_value = wStringGetValue(b); +	//if (b->valueP != NULL) +	//	strcpy(b->valueP, new_value); +	//  	//   	if (b->action){  		// if one exists, remove the inactivity timer -		if( b->timer ) -			g_source_remove( b->timer ); +		if( !b->timer ) { +			//g_source_remove( b->timer );  		// create a new timer -		b->timer = g_timeout_add( TIMEOUT_INACTIVITY, +			b->timer = g_timeout_add( TIMEOUT_INACTIVITY/5,  								  (GSourceFunc)timeoutString,  -								  b ); -		 +								  	  b ); +		}  	}	  	return;  } @@ -318,9 +341,12 @@ wString_p wStringCreate(  	// link into help   	wlibAddHelpString(b->widget, helpStr); -	g_signal_connect(GTK_OBJECT(b->widget), "changed", G_CALLBACK(stringChanged), b); -	//g_signal_connect(GTK_OBJECT(b->widget), "activate", G_CALLBACK(stringActivated), b); +	//g_signal_connect(GTK_OBJECT(b->widget), "changed", G_CALLBACK(stringChanged), b); +	//if (option&BO_ENTER) +		g_signal_connect(GTK_OBJECT(b->widget), "activate", G_CALLBACK(stringActivated), b);  	b->hasSignal = 1; +		g_signal_connect_after(GTK_OBJECT(b->widget), "expose-event", +	    							G_CALLBACK(stringExposed), b);  	// set the default text	and select it to make replacing it easier  	if (b->valueP) { diff --git a/app/wlib/gtklib/splash.c b/app/wlib/gtklib/splash.c index 0d5be50..5d56e9f 100644 --- a/app/wlib/gtklib/splash.c +++ b/app/wlib/gtklib/splash.c @@ -63,7 +63,7 @@ wCreateSplash(char *appName, char *appVer)      gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);      gtk_window_set_resizable(GTK_WINDOW(window), FALSE);      gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_SPLASHSCREEN); -#if GTK_MINOR_VERSION > 5 +#if GTK_MAJOR_VERSION > 1 || GTK_MINOR_VERSION > 5      gtk_window_set_focus_on_map(GTK_WINDOW(window), FALSE);  #endif @@ -108,7 +108,6 @@ wCreateSplash(char *appName, char *appVer)      message = label;      gtk_widget_show(window); -      return (TRUE);  } @@ -121,8 +120,9 @@ wCreateSplash(char *appName, char *appVer)  int  wSetSplashInfo(char *msg)  { -    if (msg) { -        gtk_label_set_text((GtkLabel *)message, msg); +	if (!window) return FALSE; +    if (msg && message) { +        gtk_label_set_text(GTK_LABEL(message), msg);          wFlush();          return TRUE;      } @@ -139,6 +139,8 @@ void  wDestroySplash(void)  {      /* kill window */ -    gtk_widget_destroy(window); +    if (window) gtk_widget_destroy(window); +    window = NULL; +      return;  } diff --git a/app/wlib/gtklib/statusbar.c b/app/wlib/gtklib/statusbar.c index 3730eab..3a2fd0d 100644 --- a/app/wlib/gtklib/statusbar.c +++ b/app/wlib/gtklib/statusbar.c @@ -67,6 +67,7 @@ void wStatusSetValue(      }      gtk_entry_set_text(GTK_ENTRY(b->labelWidget), wlibConvertInput(arg)); +    gtk_widget_queue_draw (GTK_WIDGET(b->labelWidget));  }  /**   * Create a window for a simple text. @@ -99,6 +100,9 @@ wStatus_p wStatusCreate(      gtk_editable_set_editable(GTK_EDITABLE(b->labelWidget), FALSE);      gtk_entry_set_has_frame(GTK_ENTRY(b->labelWidget), FALSE);      gtk_widget_set_can_focus(b->labelWidget, FALSE); +    gtk_widget_set_sensitive(b->labelWidget, FALSE); +    GdkColor black = {0, 0x0000, 0x0000, 0x0000}; +    gtk_widget_modify_text(b->labelWidget,GTK_STATE_INSENSITIVE,&black);      gtk_entry_set_text(GTK_ENTRY(b->labelWidget),                         message?wlibConvertInput(message):""); @@ -138,7 +142,7 @@ wStatusGetWidth(const char *testString)      gtk_widget_destroy(entry);      g_object_unref(entry); -    return (requisition.width+8); +    return (requisition.width);  }  /** diff --git a/app/wlib/gtklib/text.c b/app/wlib/gtklib/text.c index f7ba288..0812ace 100644 --- a/app/wlib/gtklib/text.c +++ b/app/wlib/gtklib/text.c @@ -98,6 +98,8 @@ void wTextAppend(wText_p bt,  {      GtkTextBuffer *tb;      GtkTextIter ti1; +    GtkTextMark *tm; +          if (bt->text == 0) {          abort(); @@ -109,6 +111,18 @@ void wTextAppend(wText_p bt,      // append to end of buffer      gtk_text_buffer_get_end_iter(tb, &ti1);      gtk_text_buffer_insert(tb, &ti1, text, -1); +     +    if ( bt->option & BT_TOP ) { +        // and scroll to start of text +        gtk_text_buffer_get_start_iter(tb, &ti1); +    } else { +        // and scroll to end of text +        gtk_text_buffer_get_end_iter(tb, &ti1); +    } +    tm = gtk_text_buffer_create_mark(tb, NULL, &ti1, TRUE ); +    gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW(bt->text), tm ); +    gtk_text_buffer_delete_mark( tb, tm ); +       bt->changed = FALSE;  } @@ -116,7 +130,7 @@ void wTextAppend(wText_p bt,   * Get the text from a text buffer in system codepage   * The caller is responsible for free'ing the allocated storage.   * - * \todo handling of return from gtkConvertOutput can be improved + * Dont convert from UTF8   *   * \param bt IN the text widget   * \return    pointer to the converted text @@ -135,8 +149,8 @@ static char *wlibGetText(wText_p bt)      tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(bt->text));      gtk_text_buffer_get_bounds(tb, &ti1, &ti2);      cp = gtk_text_buffer_get_text(tb, &ti1, &ti2, FALSE); -    cp1 = wlibConvertOutput(cp); -    res = strdup(cp1); +    //cp1 = wlibConvertOutput(cp); +    res = strdup(cp);      g_free(cp);      return res;  } @@ -375,7 +389,7 @@ wBool_t wTextPrint(   * Get the length of text   *   * \param bt IN the text widget - * \return    length of string + * \return    length of string including terminating \0   */  int wTextGetSize(wText_p bt) @@ -383,7 +397,7 @@ int wTextGetSize(wText_p bt)      char *cp = wlibGetText(bt);      int len = strlen(cp);      free(cp); -    return len; +    return len + 1;  }  /** diff --git a/app/wlib/gtklib/timer.c b/app/wlib/gtklib/timer.c index 812908f..80c71fb 100644 --- a/app/wlib/gtklib/timer.c +++ b/app/wlib/gtklib/timer.c @@ -109,6 +109,9 @@ void wlibSetTrigger(  void wPause(      long count)		/* milliseconds */  { +	while (gtk_events_pending()) +	    gtk_main_iteration();			//Allow GTK to finish before pausing +      struct timeval timeout;      sigset_t signal_mask;      sigset_t oldsignal_mask; diff --git a/app/wlib/gtklib/util.c b/app/wlib/gtklib/util.c index e6587a0..a265938 100644 --- a/app/wlib/gtklib/util.c +++ b/app/wlib/gtklib/util.c @@ -197,6 +197,8 @@ void * wlibAlloc(          abort();      } +    w->outline = FALSE; +      w->type = type;      w->parent = parent;      w->origX = origX; @@ -369,7 +371,7 @@ void wFlush(              void)  {      while (gtk_events_pending()) { -        gtk_main_iteration(); +        gtk_main_iteration_do(FALSE);      }      gdk_display_sync(gdk_display_get_default()); @@ -385,13 +387,81 @@ void wWinTop(wWin_p win)  }  /** - * Not implemented + * Set the cursor in GTK   *   * \param cursor IN   */ -void wSetCursor(wCursor_t cursor) +void wSetCursor(wDraw_p bd, wCursor_t cursor)  { +	static GdkCursor * gdkcursors[wCursorQuestion+1]; +	GdkCursor * gdkcursor; +	//GdkWindow * gdkwindow = gtk_widget_get_window(GTK_WIDGET(win->gtkwin));; +	GdkWindow * gdkwindow = gdk_get_default_root_window(); +	GdkDisplay * display = gdk_window_get_display(gdkwindow); +	if (!gdkcursors[cursor]) { +		switch(cursor) { +			case wCursorAppStart: +				//gdkcursor = gdk_cursor_new_from_name (display,"progress"); +				gdkcursor = gdk_cursor_new(GDK_WATCH); +				break; +			case wCursorHand: +				//gdkcursor = gdk_cursor_new_from_name (display,"pointer"); +				gdkcursor = gdk_cursor_new(GDK_HAND2); +							break; +			case wCursorNo: +				//gdkcursor = gdk_cursor_new_from_name (display,"not-allowed"); +				gdkcursor = gdk_cursor_new(GDK_X_CURSOR); +							break; +			case wCursorSizeAll: +				//gdkcursor = gdk_cursor_new_from_name (display,"move"); +				gdkcursor = gdk_cursor_new(GDK_FLEUR); +							break; +			case wCursorSizeNESW: +				//gdkcursor = gdk_cursor_new_from_name (display,"nesw-resize"); +				gdkcursor = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER); +							break; +			case wCursorSizeNS: +				//gdkcursor = gdk_cursor_new_from_name (display,"ns-resize"); +				gdkcursor = gdk_cursor_new(GDK_DOUBLE_ARROW); +							break; +			case wCursorSizeNWSE: +				//gdkcursor = gdk_cursor_new_from_name (display,"nwse-resize"); +				gdkcursor = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER); +							break; +			case wCursorSizeWE: +				//gdkcursor = gdk_cursor_new_from_name (display,"ew-resize"); +				gdkcursor = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW); +							break; +			case wCursorWait: +				//gdkcursor = gdk_cursor_new_from_name (display,"wait"); +				gdkcursor = gdk_cursor_new(GDK_WATCH); +							break; +			case wCursorIBeam: +				//gdkcursor = gdk_cursor_new_from_name (display,"text"); +				gdkcursor = gdk_cursor_new(GDK_XTERM); +							break; +			case wCursorCross: +				//gdkcursor = gdk_cursor_new_from_name (display,"crosshair"); +				gdkcursor = gdk_cursor_new(GDK_TCROSS); +							break; +			case wCursorQuestion: +				//gdkcursor = gdk_cursor_new_from_name (display,"help"); +				gdkcursor = gdk_cursor_new(GDK_QUESTION_ARROW); +							break; +			case wCursorNone: +				gdkcursor = gdk_cursor_new(GDK_BLANK_CURSOR); +			case wCursorNormal: +			default: +				//gdkcursor = gdk_cursor_new_from_name (display,"default"); +				gdkcursor = gdk_cursor_new(GDK_LEFT_PTR); +							break; + +		} +		gdkcursors[cursor] = gdkcursor; +	} else gdkcursor = gdkcursors[cursor]; + +	gdk_window_set_cursor ( gtk_widget_get_window(bd->widget), gdkcursor);  }  /** @@ -413,11 +483,17 @@ const char * wMemStats(void)  void wGetDisplaySize(wPos_t * w, wPos_t * h)  { - -    *w = gdk_screen_width(); -    *h = gdk_screen_height(); +	GdkScreen *screen = gdk_screen_get_default(); +	guint monitor = gdk_screen_get_primary_monitor(screen); +	GdkRectangle screen_geometry = { 0, 0, 0, 0 }; +	 +	gdk_screen_get_monitor_geometry( screen, monitor, &screen_geometry ); +	 +	*w = screen_geometry.width; +	*h = screen_geometry.height;  } +  static dynArr_t conversionBuffer_da;  /** diff --git a/app/wlib/gtklib/window.c b/app/wlib/gtklib/window.c index 49770c5..1468c89 100644 --- a/app/wlib/gtklib/window.c +++ b/app/wlib/gtklib/window.c @@ -29,6 +29,9 @@  #define GTK_DISABLE_DEPRECATED  #define GSEAL_ENABLE +#define MIN_WIDTH 100 +#define MIN_HEIGHT 100 +  #include <gtk/gtk.h>  #include <gdk/gdk.h>  #include <gdk/gdkkeysyms.h> @@ -37,8 +40,11 @@  wWin_p gtkMainW; -#define MIN_WIN_WIDTH (50) -#define MIN_WIN_HEIGHT (50) +#define MIN_WIN_WIDTH 150 +#define MIN_WIN_HEIGHT 150 + +#define MIN_WIN_WIDTH_MAIN 400 +#define MIN_WIN_HEIGHT_MAIN 400  #define SECTIONWINDOWSIZE  "gtklib window size"  #define SECTIONWINDOWPOS   "gtklib window pos" @@ -93,6 +99,7 @@ static GdkRectangle getMonitorDimensions(GtkWidget * widget) {  	gdk_screen_get_monitor_geometry(screen,monitor,&monitor_dimensions); +  	return monitor_dimensions;  } @@ -106,40 +113,47 @@ static GdkRectangle getMonitorDimensions(GtkWidget * widget) {  static void getWinSize(wWin_p win, const char * nameStr)  { -    int w, h; +    int w=50, h=50;      const char *cp;      char *cp1, *cp2; +      /*       * Clamp window to be no bigger than one monitor size (to start - the user can always maximize)       */      GdkRectangle monitor_dimensions = getMonitorDimensions(GTK_WIDGET(win->gtkwin)); -    wPos_t maxDisplayWidth = monitor_dimensions.width-5; -    wPos_t maxDisplayHeight = monitor_dimensions.height-25; +    wPos_t maxDisplayWidth = monitor_dimensions.width-10; +    wPos_t maxDisplayHeight = monitor_dimensions.height-50; -    if ((win->option&F_RESIZE) && + +    if ((win->option&F_RECALLSIZE) &&              (win->option&F_RECALLPOS) &&              (cp = wPrefGetString(SECTIONWINDOWSIZE, nameStr)) &&              (w = strtod(cp, &cp1), cp != cp1) &&              (h = strtod(cp1, &cp2), cp1 != cp2)) { -        if (w < 10) { -            w = 10; -        } - -        if (h < 10) { -            h = 10; -        } +    	win->option &= ~F_AUTOSIZE; -        if (w > maxDisplayWidth) w = maxDisplayWidth; -        if (h > maxDisplayHeight) h = maxDisplayHeight; +		if (w < 50) { +			w = 50; +		} -        win->w = win->origX = w; -        win->h = win->origY = h; -        win->option &= ~F_AUTOSIZE; +		if (h < 50) { +			h = 50; +		}      } + +	if (w > maxDisplayWidth) w = maxDisplayWidth; +	if (h > maxDisplayHeight) h = maxDisplayHeight; + +	if (w<MIN_WIDTH) w = MIN_WIDTH; +	if (h<MIN_HEIGHT) h = MIN_HEIGHT; + +	win->w = win->origX = w; +	win->h = win->origY = h; +  }  /** @@ -152,8 +166,7 @@ static void getWinSize(wWin_p win, const char * nameStr)  static void saveSize(wWin_p win)  { -    if ((win->option&F_RESIZE) && -            (win->option&F_RECALLPOS) && +    if ((win->option&F_RECALLSIZE) &&              gtk_widget_get_visible(GTK_WIDGET(win->gtkwin))) {          char pos_s[20]; @@ -210,7 +223,7 @@ static void getPos(wWin_p win)              }              gtk_window_move(GTK_WINDOW(win->gtkwin), x, y); -            gtk_window_resize(GTK_WINDOW(win->gtkwin), win->w, win->h); +            //gtk_window_resize(GTK_WINDOW(win->gtkwin), win->w, win->h);          }      }  } @@ -285,9 +298,17 @@ void wWinSetSize(  {      win->busy = TRUE;      win->w = width; -    win->h = height + BORDERSIZE + ((win->option&F_MENUBAR)?win->menu_height:0); -    gtk_widget_set_size_request(win->gtkwin, win->w, win->h); -    gtk_widget_set_size_request(win->widget, win->w, win->h); +   win->h = height + BORDERSIZE + ((win->option&F_MENUBAR)?MENUH:0); +    if (win->option&F_RESIZE) { +       	gtk_window_resize(GTK_WINDOW(win->gtkwin), win->w, win->h); +    	gtk_widget_set_size_request(win->widget, win->w-10, win->h-10); +    } +    else { +    	gtk_widget_set_size_request(win->gtkwin, win->w, win->h); +    	gtk_widget_set_size_request(win->widget, win->w, win->h); +    } + +      win->busy = FALSE;  } @@ -304,7 +325,7 @@ void wWinShow(      wWin_p win,		/* Window */      wBool_t show)		/* Command */  { -    GtkRequisition requisition; +    //GtkRequisition min_req, pref_req;      if (debugWindow >= 2) {          printf("Set Show %s\n", win->labelStr?win->labelStr:"No label"); @@ -314,31 +335,48 @@ void wWinShow(          abort();      } +    int width, height; +      if (show) {          keyState = 0;          getPos(win); +        if (!win->shown) { +			gtk_widget_show(win->gtkwin); +			gtk_widget_show(win->widget); +		} +          if (win->option & F_AUTOSIZE) { -            gtk_widget_size_request(win->gtkwin, &requisition); +        	GtkAllocation allocation; +        	GtkRequisition requistion; +        	gtk_widget_size_request(win->widget,&requistion); + +        	width = win->w; +        	height = win->h; + +            if (requistion.width != width || requistion.height != height ) { -            if (requisition.width != win->w || requisition.height != win->h) { -                //gtk_window_resize(GTK_WINDOW(win->gtkwin), win->w, win->h); -            	gtk_widget_set_size_request(win->gtkwin, win->w, win->h); -                gtk_widget_set_size_request(win->widget, win->w-20, win->h); +				width = requistion.width; +				height = requistion.height; + +            	win->w = width; +            	win->h = height; + + +            	gtk_window_set_resizable(GTK_WINDOW(win->gtkwin),TRUE);                  if (win->option&F_MENUBAR) {                      gtk_widget_set_size_request(win->menubar, win->w-20, MENUH); -                    GtkAllocation allocation; +                      gtk_widget_get_allocation(win->menubar, &allocation);                      win->menu_height = allocation.height;                  }              } +            gtk_window_resize(GTK_WINDOW(win->gtkwin), width+10, height+10);          } -        if (!win->shown) { -            gtk_widget_show(win->gtkwin); -            gtk_widget_show(win->widget); -        } +        gtk_window_present(GTK_WINDOW(win->gtkwin)); +          gdk_window_raise(gtk_widget_get_window(win->gtkwin)); @@ -606,11 +644,24 @@ static int fixed_expose_event(      GdkEventExpose * event,      wWin_p win)  { +	int rc; +      if (event->count==0) { -        return window_redraw(win, TRUE); +        rc = window_redraw(win, TRUE);      } else { -        return FALSE; +        rc = FALSE;      } +    cairo_t* cr = gdk_cairo_create (gtk_widget_get_window(widget)); +#ifdef CURSOR_SURFACE +    if (win && win->cursor_surface.surface && win->cursor_surface.show) { +		cairo_set_source_surface(cr,win->cursor_surface.surface,event->area.x, event->area.y); +		cairo_set_operator(cr,CAIRO_OPERATOR_OVER); +		cairo_rectangle(cr,event->area.x, event->area.y, +				event->area.width, event->area.height); +		cairo_fill(cr); +	} +#endif +    return rc;  }  static int resizeTime(wWin_p win) { @@ -738,10 +789,8 @@ wBool_t catch_shift_ctrl_alt_keys(      GdkEventKey *event,      void * data)  { -    int state; -    state = 0; - -    switch (event->keyval) { +    int state = 0; +    switch (event->keyval ) {      case GDK_KEY_Shift_L:      case GDK_KEY_Shift_R:          state |= WKEY_SHIFT; @@ -756,6 +805,13 @@ wBool_t catch_shift_ctrl_alt_keys(      case GDK_KEY_Alt_R:          state |= WKEY_ALT;          break; + +    case GDK_KEY_Meta_L: +    case GDK_KEY_Meta_R: +	// Pressing SHIFT and then ALT generates a Meta key +	//printf( "Meta\n" ); +        state |= WKEY_ALT; +        break;      }      if (state != 0) { @@ -764,10 +820,8 @@ wBool_t catch_shift_ctrl_alt_keys(          } else {              keyState &= ~state;          } -          return TRUE;      } -      return FALSE;  } @@ -786,7 +840,7 @@ static gint window_char_event(          return FALSE;      } -    if (event->state == 0) { +    if ( ( event->state & GDK_MODIFIER_MASK ) == 0 ) {          if (event->keyval == GDK_KEY_Escape) {              for (bb=win->first; bb; bb=bb->next) {                  if (bb->type == B_BUTTON && (bb->option&BB_CANCEL)) { @@ -804,6 +858,31 @@ static gint window_char_event(      }  } +void wSetGeometry(wWin_p win, int min_width, int max_width, int min_height, int max_height, int base_width, int base_height, double aspect_ratio ) { +	GdkGeometry hints; +	GdkWindowHints hintMask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE; +    hints.min_width = min_width; +	hints.max_width = max_width; +	hints.min_height = min_height; +	hints.max_height = max_height; +	hints.min_aspect = hints.max_aspect = aspect_ratio; +	hints.base_width = base_width; +	hints.base_height = base_height; +	if( base_width != -1 && base_height != -1 ) { +		hintMask |= GDK_HINT_BASE_SIZE; +	} +	 +	if(aspect_ratio > -1.0 ) { +		hintMask |= GDK_HINT_ASPECT; +	}	 + +	gtk_window_set_geometry_hints( +			GTK_WINDOW(win->gtkwin), +			win->gtkwin, +			&hints, +			hintMask); +} +  /*   ******************************************************************************* @@ -862,12 +941,14 @@ static wWin_p wWinCommonCreate(          w->gtkwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);          if (gtkMainW) { -            gtk_window_set_transient_for(GTK_WINDOW(w->gtkwin), -                                         GTK_WINDOW(gtkMainW->gtkwin)); +        	if (!(w->option&F_NOTTRANSIENT)) +        		gtk_window_set_transient_for(GTK_WINDOW(w->gtkwin), +        									GTK_WINDOW(gtkMainW->gtkwin));          }      } +    getWinSize(w, nameStr);      if (winType != W_MAIN) { -            getWinSize(w, nameStr); +            gtk_widget_set_app_paintable (w->gtkwin,TRUE);      }      if (option & F_HIDE) { @@ -898,21 +979,39 @@ static wWin_p wWinCommonCreate(      gtk_container_add(GTK_CONTAINER(w->gtkwin), w->widget); + + +      if (w->option&F_AUTOSIZE) {          w->realX = 0; -        w->w = 0; +        w->w = MIN_WIN_WIDTH+20;          w->realY = h; -        w->h = 0; +        w->h = MIN_WIN_HEIGHT;      } else if (w->origX != 0){ -        w->w = w->realX = w->origX; -        w->h = w->realY = w->origY+h; -        gtk_window_set_default_size(GTK_WINDOW(w->gtkwin), w->w, w->h); +        w->realX = w->origX; +        w->realY = w->origY+h; + +        w->default_size_x = w->w; +        w->default_size_y = w->h;          //gtk_widget_set_size_request(w->widget, w->w-20, w->h);          if (w->option&F_MENUBAR) {              gtk_widget_set_size_request(w->menubar, w->w-20, MENUH);          }      } +    int scr_w, scr_h; +	wGetDisplaySize(&scr_w, &scr_h); +	if (scr_w < MIN_WIN_WIDTH) scr_w = MIN_WIN_WIDTH+10; +	if (scr_h < MIN_WIN_HEIGHT) scr_h = MIN_WIN_HEIGHT; +	if (winType != W_MAIN) { +		wSetGeometry(w, MIN_WIN_WIDTH, scr_w-10, MIN_WIN_HEIGHT, scr_h, -1, -1, -1); +	} else { +		if (scr_w < MIN_WIN_WIDTH_MAIN+10) scr_w = MIN_WIN_WIDTH_MAIN+200; +		if (scr_h < MIN_WIN_HEIGHT_MAIN+10) scr_h = MIN_WIN_HEIGHT_MAIN+200; +		wSetGeometry(w, MIN_WIN_WIDTH_MAIN, scr_w-10, MIN_WIN_HEIGHT_MAIN, scr_h-10, -1, -1, -1); +     } + +      w->first = w->last = NULL;      w->winProc = winProc; @@ -934,6 +1033,7 @@ static wWin_p wWinCommonCreate(      if (w->option & F_RESIZE) {          gtk_window_set_resizable(GTK_WINDOW(w->gtkwin), TRUE); +        gtk_window_resize(GTK_WINDOW(w->gtkwin), w->w, w->h);      } else {          gtk_window_set_resizable(GTK_WINDOW(w->gtkwin), FALSE);      } diff --git a/app/wlib/gtklib/wpref.c b/app/wlib/gtklib/wpref.c index c2541f9..124305a 100644 --- a/app/wlib/gtklib/wpref.c +++ b/app/wlib/gtklib/wpref.c @@ -168,7 +168,7 @@ const char * wGetAppWorkDir(  			if ( stat( appEtcConfig, &stFileInfo ) == 0 ) {  				char copyConfigCmd[(BUFSIZ * 2) + 3];  				sprintf( copyConfigCmd, "cp %s %s", appEtcConfig, appWorkDir ); -				system( copyConfigCmd ); +				int rc = system( copyConfigCmd );  			}  		}  	} @@ -293,7 +293,7 @@ void wPrefSetString(  			if (p->val)  				free(p->val);  			p->dirty = TRUE; -			p->val = strdup( sval ); +			p->val = (sval?strdup( sval ):NULL);  			return;  		}  	} @@ -302,7 +302,7 @@ void wPrefSetString(  	p->name = strdup(name);  	p->section = strdup(section);  	p->dirty = TRUE; -	p->val = strdup(sval); +	p->val = (sval?strdup(sval):NULL);  }  /** @@ -456,7 +456,9 @@ void wPrefFlush(  		return;  	for (p=&prefs(0); p<&prefs(prefs_da.cnt); p++) { -		fprintf( prefFile,  "%s.%s: %s\n", p->section, p->name, p->val ); +		if(p->val) { +			fprintf( prefFile,  "%s.%s: %s\n", p->section, p->name, p->val ); +		}	  	}  	fclose( prefFile );  } | 
