diff --git a/devel.but b/devel.but index 29ef78c..3a7c9cd 100644 --- a/devel.but +++ b/devel.but @@ -1975,18 +1975,19 @@ In fact these global functions are not implemented directly by the front end; instead, they are implemented centrally in \c{drawing.c} and form a small piece of middleware. The drawing API as supplied by the front end is a structure containing a set of function pointers, -plus a \cq{void *} handle which is passed to each of those -functions. This enables a single front end to switch between -multiple implementations of the drawing API if necessary. For -example, the Windows API supplies a printing mechanism integrated -into the same GDI which deals with drawing in windows, and therefore -the same API implementation can handle both drawing and printing; -but on Unix, the most common way for applications to print is by -producing PostScript output directly, and although it would be -\e{possible} to write a single (say) \cw{draw_rect()} function which -checked a global flag to decide whether to do GTK drawing operations -or output PostScript to a file, it's much nicer to have two separate -functions and switch between them as appropriate. +plus a \cq{void *} handle which is indirectly passed to each of those +functions as a member of the same drawing object as used by the +backend. This enables a single front end to switch between multiple +implementations of the drawing API if necessary. For example, the +Windows API supplies a printing mechanism integrated into the same GDI +which deals with drawing in windows, and therefore the same API +implementation can handle both drawing and printing; but on Unix, the +most common way for applications to print is by producing PostScript +output directly, and although it would be \e{possible} to write a +single (say) \cw{draw_rect()} function which checked a global flag to +decide whether to do GTK drawing operations or output PostScript to a +file, it's much nicer to have two separate functions and switch +between them as appropriate. When drawing, the puzzle window is indexed by pixel coordinates, with the top left pixel defined as \cw{(0,0)} and the bottom right @@ -2689,17 +2690,38 @@ API; the platform-independent module \c{ps.c} also provides an implementation of it which outputs PostScript. Thus, any platform which wants to do PS printing can do so with minimum fuss.) -The following entries all describe function pointer fields in a -structure called \c{drawing_api}. Each of the functions takes a -\cq{void *} context pointer, which it should internally cast back to -a more useful type. Thus, a drawing \e{object} (\c{drawing *)} -suitable for passing to the back end redraw or printing functions -is constructed by passing a \c{drawing_api} and a \cq{void *} to the -function \cw{drawing_new()} (see \k{drawing-new}). +The following entries (with the exception of the \cw{version} field) +all describe function pointer fields in a structure called +\c{drawing_api}. Each of the functions takes a \cq{drawing *} pointer, +which in turn contains a \cq{void *handle} member that the front end +can access and internally cast back to a more useful type. Since this +is a fairly common thing for front ends to do, the +\cw{GET_HANDLE_AS_TYPE()} macro is provided to do this for you (see +\k{utils-get-handle-as-type}). + +A drawing \e{object} (\c{drawing *)} suitable for passing to the back +end redraw or printing functions is constructed by passing a +\c{drawing_api} and a \cq{void *} to the function \cw{drawing_new()} +(see \k{drawing-new}). + +\S{drawingapi-version} \cw{version} + +\c int version; + +This is an integer giving the version of the drawing API implemented +by the front end. For the version of the API described in this +document, this field should be \cw{1}. + +On occasion, there may be a breaking change to the drawing API, such +as the introduction of a new function or a change to the semantics of +an existing function. The intent of this version field is to signal to +front end authors when such a breaking change occurs. As such changes +can be disruptive to downstream front ends, they should be done +sparingly. \S{drawingapi-draw-text} \cw{draw_text()} -\c void (*draw_text)(void *handle, int x, int y, int fonttype, +\c void (*draw_text)(drawing *dr, int x, int y, int fonttype, \c int fontsize, int align, int colour, \c const char *text); @@ -2708,7 +2730,7 @@ function; see \k{drawing-draw-text}. \S{drawingapi-draw-rect} \cw{draw_rect()} -\c void (*draw_rect)(void *handle, int x, int y, int w, int h, +\c void (*draw_rect)(drawing *dr, int x, int y, int w, int h, \c int colour); This function behaves exactly like the back end \cw{draw_rect()} @@ -2716,7 +2738,7 @@ function; see \k{drawing-draw-rect}. \S{drawingapi-draw-line} \cw{draw_line()} -\c void (*draw_line)(void *handle, int x1, int y1, int x2, int y2, +\c void (*draw_line)(drawing *dr, int x1, int y1, int x2, int y2, \c int colour); This function behaves exactly like the back end \cw{draw_line()} @@ -2724,7 +2746,7 @@ function; see \k{drawing-draw-line}. \S{drawingapi-draw-polygon} \cw{draw_polygon()} -\c void (*draw_polygon)(void *handle, const int *coords, int npoints, +\c void (*draw_polygon)(drawing *dr, const int *coords, int npoints, \c int fillcolour, int outlinecolour); This function behaves exactly like the back end \cw{draw_polygon()} @@ -2732,7 +2754,7 @@ function; see \k{drawing-draw-polygon}. \S{drawingapi-draw-circle} \cw{draw_circle()} -\c void (*draw_circle)(void *handle, int cx, int cy, int radius, +\c void (*draw_circle)(drawing *dr, int cx, int cy, int radius, \c int fillcolour, int outlinecolour); This function behaves exactly like the back end \cw{draw_circle()} @@ -2754,7 +2776,7 @@ and provide a low-quality alternative using \cw{draw_polygon()}. \S{drawingapi-draw-update} \cw{draw_update()} -\c void (*draw_update)(void *handle, int x, int y, int w, int h); +\c void (*draw_update)(drawing *dr, int x, int y, int w, int h); This function behaves exactly like the back end \cw{draw_update()} function; see \k{drawing-draw-update}. @@ -2766,21 +2788,21 @@ than bothering to define an empty function. The middleware in \S{drawingapi-clip} \cw{clip()} -\c void (*clip)(void *handle, int x, int y, int w, int h); +\c void (*clip)(drawing *dr, int x, int y, int w, int h); This function behaves exactly like the back end \cw{clip()} function; see \k{drawing-clip}. \S{drawingapi-unclip} \cw{unclip()} -\c void (*unclip)(void *handle); +\c void (*unclip)(drawing *dr); This function behaves exactly like the back end \cw{unclip()} function; see \k{drawing-unclip}. \S{drawingapi-start-draw} \cw{start_draw()} -\c void (*start_draw)(void *handle); +\c void (*start_draw)(drawing *dr); This function is called at the start of drawing. It allows the front end to initialise any temporary data required to draw with, such as @@ -2792,7 +2814,7 @@ called unless drawing is attempted. \S{drawingapi-end-draw} \cw{end_draw()} -\c void (*end_draw)(void *handle); +\c void (*end_draw)(drawing *dr); This function is called at the end of drawing. It allows the front end to do cleanup tasks such as deallocating device contexts and @@ -2804,7 +2826,7 @@ called unless drawing is attempted. \S{drawingapi-status-bar} \cw{status_bar()} -\c void (*status_bar)(void *handle, const char *text); +\c void (*status_bar)(drawing *dr, const char *text); This function behaves exactly like the back end \cw{status_bar()} function; see \k{drawing-status-bar}. @@ -2819,7 +2841,7 @@ called unless drawing is attempted. \S{drawingapi-blitter-new} \cw{blitter_new()} -\c blitter *(*blitter_new)(void *handle, int w, int h); +\c blitter *(*blitter_new)(drawing *dr, int w, int h); This function behaves exactly like the back end \cw{blitter_new()} function; see \k{drawing-blitter-new}. @@ -2830,7 +2852,7 @@ called unless drawing is attempted. \S{drawingapi-blitter-free} \cw{blitter_free()} -\c void (*blitter_free)(void *handle, blitter *bl); +\c void (*blitter_free)(drawing *dr, blitter *bl); This function behaves exactly like the back end \cw{blitter_free()} function; see \k{drawing-blitter-free}. @@ -2841,7 +2863,7 @@ called unless drawing is attempted. \S{drawingapi-blitter-save} \cw{blitter_save()} -\c void (*blitter_save)(void *handle, blitter *bl, int x, int y); +\c void (*blitter_save)(drawing *dr, blitter *bl, int x, int y); This function behaves exactly like the back end \cw{blitter_save()} function; see \k{drawing-blitter-save}. @@ -2852,7 +2874,7 @@ called unless drawing is attempted. \S{drawingapi-blitter-load} \cw{blitter_load()} -\c void (*blitter_load)(void *handle, blitter *bl, int x, int y); +\c void (*blitter_load)(drawing *dr, blitter *bl, int x, int y); This function behaves exactly like the back end \cw{blitter_load()} function; see \k{drawing-blitter-load}. @@ -2863,7 +2885,7 @@ called unless drawing is attempted. \S{drawingapi-begin-doc} \cw{begin_doc()} -\c void (*begin_doc)(void *handle, int pages); +\c void (*begin_doc)(drawing *dr, int pages); This function is called at the beginning of a printing run. It gives the front end an opportunity to initialise any required printing @@ -2875,7 +2897,7 @@ called unless printing is attempted. \S{drawingapi-begin-page} \cw{begin_page()} -\c void (*begin_page)(void *handle, int number); +\c void (*begin_page)(drawing *dr, int number); This function is called during printing, at the beginning of each page. It gives the page number (numbered from 1 rather than 0, so @@ -2887,7 +2909,7 @@ called unless printing is attempted. \S{drawingapi-begin-puzzle} \cw{begin_puzzle()} -\c void (*begin_puzzle)(void *handle, float xm, float xc, +\c void (*begin_puzzle)(drawing *dr, float xm, float xc, \c float ym, float yc, int pw, int ph, float wmm); This function is called during printing, just before printing a @@ -2930,7 +2952,7 @@ called unless printing is attempted. \S{drawingapi-end-puzzle} \cw{end_puzzle()} -\c void (*end_puzzle)(void *handle); +\c void (*end_puzzle)(drawing *dr); This function is called after the printing of a specific puzzle is complete. @@ -2941,7 +2963,7 @@ called unless printing is attempted. \S{drawingapi-end-page} \cw{end_page()} -\c void (*end_page)(void *handle, int number); +\c void (*end_page)(drawing *dr, int number); This function is called after the printing of a page is finished. @@ -2951,7 +2973,7 @@ called unless printing is attempted. \S{drawingapi-end-doc} \cw{end_doc()} -\c void (*end_doc)(void *handle); +\c void (*end_doc)(drawing *dr); This function is called after the printing of the entire document is finished. This is the moment to close files, send things to the @@ -2963,7 +2985,7 @@ called unless printing is attempted. \S{drawingapi-line-width} \cw{line_width()} -\c void (*line_width)(void *handle, float width); +\c void (*line_width)(drawing *dr, float width); This function is called to set the line thickness, during printing only. Note that the width is a \cw{float} here, where it was an @@ -2979,7 +3001,7 @@ called unless printing is attempted. \S{drawingapi-line-dotted} \cw{line_dotted()} -\c void (*line_dotted)(void *handle, bool dotted); +\c void (*line_dotted)(drawing *dr, bool dotted); This function is called to toggle drawing of dotted lines, during printing only. @@ -2990,7 +3012,7 @@ called unless printing is attempted. \S{drawingapi-text-fallback} \cw{text_fallback()} -\c char *(*text_fallback)(void *handle, const char *const *strings, +\c char *(*text_fallback)(drawing *dr, const char *const *strings, \c int nstrings); This function behaves exactly like the back end \cw{text_fallback()} @@ -3013,9 +3035,10 @@ implement. They are described in this section. \c void *handle); This function creates a drawing object. It is passed a -\c{drawing_api}, which is a structure containing nothing but -function pointers; and also a \cq{void *} handle. The handle is -passed back to each function pointer when it is called. +\c{drawing_api}, which is a structure containing function pointers and +a version field; and also a \cq{void *} handle. The handle is stored +in the drawing object, from where it may be accessed by each function +pointer when it is called. The \c{midend} parameter is used for rewriting the status bar contents: \cw{status_bar()} (see \k{drawing-status-bar}) has to call @@ -3024,6 +3047,10 @@ If the drawing object is to be used only for printing, or if the game is known not to call \cw{status_bar()}, this parameter may be \cw{NULL}. +A fatal error is produced if the \cw{version} field of the +\c{drawing_api} does not match the expected version (see +\k{drawingapi-version} for the expected version number). + \S{drawing-free} \cw{drawing_free()} \c void drawing_free(drawing *dr); @@ -5351,6 +5378,15 @@ argument is respectively less than, equal to, or greater than the second. This function is intended to be passed to \c{qsort()} for sorting ints in ascending order. +\S{utils-get-handle-as-type} \cw{GET_HANDLE_AS_TYPE()} + +\c #define GET_HANDLE_AS_TYPE(dr, type) ((type*)((dr)->handle)) + +This macro, defined in the main Puzzles header file, retrieves the +\c{handle} field from a \c{drawing *} pointer and casts it to \c{type +*}. It is intended for use in implementations of drawing API +functions, where this operation is idiomatic. + \C{writing} How to write a new puzzle This chapter gives a guide to how to actually write a new puzzle: diff --git a/drawing.c b/drawing.c index 2c8816c..a754b06 100644 --- a/drawing.c +++ b/drawing.c @@ -42,9 +42,12 @@ struct print_colour { float grey; }; -struct drawing { - const drawing_api *api; - void *handle; +typedef struct drawing_internal { + /* we implement data hiding by casting `struct drawing*` pointers + * to `struct drawing_internal*` */ + struct drawing pub; + + /* private data */ struct print_colour *colours; int ncolours, coloursize; float scale; @@ -52,53 +55,70 @@ struct drawing { * this may set it to NULL. */ midend *me; char *laststatus; -}; +} drawing_internal; + +#define PRIVATE_CAST(dr) ((drawing_internal*)(dr)) +#define PUBLIC_CAST(dri) ((drawing*)(dri)) + +/* See puzzles.h for a description of the version number. */ +#define DRAWING_API_VERSION 1 drawing *drawing_new(const drawing_api *api, midend *me, void *handle) { - drawing *dr = snew(drawing); - dr->api = api; - dr->handle = handle; - dr->colours = NULL; - dr->ncolours = dr->coloursize = 0; - dr->scale = 1.0F; - dr->me = me; - dr->laststatus = NULL; - return dr; + if(api->version != DRAWING_API_VERSION) { + fatal("Drawing API version mismatch: expected: %d, actual: %d\n", DRAWING_API_VERSION, api->version); + /* shouldn't get here */ + return NULL; + } + + drawing_internal *dri = snew(drawing_internal); + dri->pub.api = api; + dri->pub.handle = handle; + dri->colours = NULL; + dri->ncolours = dri->coloursize = 0; + dri->scale = 1.0F; + dri->me = me; + dri->laststatus = NULL; + return PUBLIC_CAST(dri); } void drawing_free(drawing *dr) { - sfree(dr->laststatus); - sfree(dr->colours); - sfree(dr); + drawing_internal *dri = PRIVATE_CAST(dr); + sfree(dri->laststatus); + sfree(dri->colours); + sfree(dri); } void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, const char *text) { - dr->api->draw_text(dr->handle, x, y, fonttype, fontsize, align, - colour, text); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->draw_text(dr, x, y, fonttype, fontsize, align, + colour, text); } void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) { - dr->api->draw_rect(dr->handle, x, y, w, h, colour); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->draw_rect(dr, x, y, w, h, colour); } void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { - dr->api->draw_line(dr->handle, x1, y1, x2, y2, colour); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->draw_line(dr, x1, y1, x2, y2, colour); } void draw_thick_line(drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour) { + drawing_internal *dri = PRIVATE_CAST(dr); if (thickness < 1.0F) thickness = 1.0F; - if (dr->api->draw_thick_line) { - dr->api->draw_thick_line(dr->handle, thickness, - x1, y1, x2, y2, colour); + if (dri->pub.api->draw_thick_line) { + dri->pub.api->draw_thick_line(dr, thickness, + x1, y1, x2, y2, colour); } else { /* We'll fake it up with a filled polygon. The tweak to the * thickness empirically compensates for rounding errors, because @@ -117,59 +137,67 @@ void draw_thick_line(drawing *dr, float thickness, p[5] = y2 - tvhatx; p[6] = x1 + tvhaty; p[7] = y1 - tvhatx; - dr->api->draw_polygon(dr->handle, p, 4, colour, colour); + dri->pub.api->draw_polygon(dr, p, 4, colour, colour); } } void draw_polygon(drawing *dr, const int *coords, int npoints, int fillcolour, int outlinecolour) { - dr->api->draw_polygon(dr->handle, coords, npoints, fillcolour, - outlinecolour); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->draw_polygon(dr, coords, npoints, fillcolour, + outlinecolour); } void draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour) { - dr->api->draw_circle(dr->handle, cx, cy, radius, fillcolour, - outlinecolour); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->draw_circle(dr, cx, cy, radius, fillcolour, + outlinecolour); } void draw_update(drawing *dr, int x, int y, int w, int h) { - if (dr->api->draw_update) - dr->api->draw_update(dr->handle, x, y, w, h); + drawing_internal *dri = PRIVATE_CAST(dr); + if (dri->pub.api->draw_update) + dri->pub.api->draw_update(dr, x, y, w, h); } void clip(drawing *dr, int x, int y, int w, int h) { - dr->api->clip(dr->handle, x, y, w, h); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->clip(dr, x, y, w, h); } void unclip(drawing *dr) { - dr->api->unclip(dr->handle); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->unclip(dr); } void start_draw(drawing *dr) { - dr->api->start_draw(dr->handle); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->start_draw(dr); } void end_draw(drawing *dr) { - dr->api->end_draw(dr->handle); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->end_draw(dr); } char *text_fallback(drawing *dr, const char *const *strings, int nstrings) { + drawing_internal *dri = PRIVATE_CAST(dr); int i; /* * If the drawing implementation provides one of these, use it. */ - if (dr && dr->api->text_fallback) - return dr->api->text_fallback(dr->handle, strings, nstrings); + if (dr && dri->pub.api->text_fallback) + return dri->pub.api->text_fallback(dr, strings, nstrings); /* * Otherwise, do the simple thing and just pick the first string @@ -196,18 +224,19 @@ char *text_fallback(drawing *dr, const char *const *strings, int nstrings) void status_bar(drawing *dr, const char *text) { + drawing_internal *dri = PRIVATE_CAST(dr); char *rewritten; - if (!dr->api->status_bar) + if (!dri->pub.api->status_bar) return; - assert(dr->me); + assert(dri->me); - rewritten = midend_rewrite_statusbar(dr->me, text); - if (!dr->laststatus || strcmp(rewritten, dr->laststatus)) { - dr->api->status_bar(dr->handle, rewritten); - sfree(dr->laststatus); - dr->laststatus = rewritten; + rewritten = midend_rewrite_statusbar(dri->me, text); + if (!dri->laststatus || strcmp(rewritten, dri->laststatus)) { + dri->pub.api->status_bar(dr, rewritten); + sfree(dri->laststatus); + dri->laststatus = rewritten; } else { sfree(rewritten); } @@ -215,74 +244,85 @@ void status_bar(drawing *dr, const char *text) blitter *blitter_new(drawing *dr, int w, int h) { - return dr->api->blitter_new(dr->handle, w, h); + drawing_internal *dri = PRIVATE_CAST(dr); + return dri->pub.api->blitter_new(dr, w, h); } void blitter_free(drawing *dr, blitter *bl) { - dr->api->blitter_free(dr->handle, bl); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->blitter_free(dr, bl); } void blitter_save(drawing *dr, blitter *bl, int x, int y) { - dr->api->blitter_save(dr->handle, bl, x, y); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->blitter_save(dr, bl, x, y); } void blitter_load(drawing *dr, blitter *bl, int x, int y) { - dr->api->blitter_load(dr->handle, bl, x, y); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->blitter_load(dr, bl, x, y); } void print_begin_doc(drawing *dr, int pages) { - dr->api->begin_doc(dr->handle, pages); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->begin_doc(dr, pages); } void print_begin_page(drawing *dr, int number) { - dr->api->begin_page(dr->handle, number); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->begin_page(dr, number); } void print_begin_puzzle(drawing *dr, float xm, float xc, float ym, float yc, int pw, int ph, float wmm, float scale) { - dr->scale = scale; - dr->ncolours = 0; - dr->api->begin_puzzle(dr->handle, xm, xc, ym, yc, pw, ph, wmm); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->scale = scale; + dri->ncolours = 0; + dri->pub.api->begin_puzzle(dr, xm, xc, ym, yc, pw, ph, wmm); } void print_end_puzzle(drawing *dr) { - dr->api->end_puzzle(dr->handle); - dr->scale = 1.0F; + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->end_puzzle(dr); + dri->scale = 1.0F; } void print_end_page(drawing *dr, int number) { - dr->api->end_page(dr->handle, number); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->end_page(dr, number); } void print_end_doc(drawing *dr) { - dr->api->end_doc(dr->handle); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->end_doc(dr); } void print_get_colour(drawing *dr, int colour, bool printing_in_colour, int *hatch, float *r, float *g, float *b) { - assert(colour >= 0 && colour < dr->ncolours); - if (dr->colours[colour].hatch_when == 2 || - (dr->colours[colour].hatch_when == 1 && !printing_in_colour)) { - *hatch = dr->colours[colour].hatch; + drawing_internal *dri = PRIVATE_CAST(dr); + assert(colour >= 0 && colour < dri->ncolours); + if (dri->colours[colour].hatch_when == 2 || + (dri->colours[colour].hatch_when == 1 && !printing_in_colour)) { + *hatch = dri->colours[colour].hatch; } else { *hatch = -1; if (printing_in_colour) { - *r = dr->colours[colour].r; - *g = dr->colours[colour].g; - *b = dr->colours[colour].b; + *r = dri->colours[colour].r; + *g = dri->colours[colour].g; + *b = dri->colours[colour].b; } else { - *r = *g = *b = dr->colours[colour].grey; + *r = *g = *b = dri->colours[colour].grey; } } } @@ -290,18 +330,19 @@ void print_get_colour(drawing *dr, int colour, bool printing_in_colour, static int print_generic_colour(drawing *dr, float r, float g, float b, float grey, int hatch, int hatch_when) { - if (dr->ncolours >= dr->coloursize) { - dr->coloursize = dr->ncolours + 16; - dr->colours = sresize(dr->colours, dr->coloursize, + drawing_internal *dri = PRIVATE_CAST(dr); + if (dri->ncolours >= dri->coloursize) { + dri->coloursize = dri->ncolours + 16; + dri->colours = sresize(dri->colours, dri->coloursize, struct print_colour); } - dr->colours[dr->ncolours].hatch = hatch; - dr->colours[dr->ncolours].hatch_when = hatch_when; - dr->colours[dr->ncolours].r = r; - dr->colours[dr->ncolours].g = g; - dr->colours[dr->ncolours].b = b; - dr->colours[dr->ncolours].grey = grey; - return dr->ncolours++; + dri->colours[dri->ncolours].hatch = hatch; + dri->colours[dri->ncolours].hatch_when = hatch_when; + dri->colours[dri->ncolours].r = r; + dri->colours[dri->ncolours].g = g; + dri->colours[dri->ncolours].b = b; + dri->colours[dri->ncolours].grey = grey; + return dri->ncolours++; } int print_mono_colour(drawing *dr, int grey) @@ -336,6 +377,8 @@ int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch) void print_line_width(drawing *dr, int width) { + drawing_internal *dri = PRIVATE_CAST(dr); + /* * I don't think it's entirely sensible to have line widths be * entirely relative to the puzzle size; there is a point @@ -348,10 +391,11 @@ void print_line_width(drawing *dr, int width) * _square root_ of the main puzzle scale. Double the puzzle * size, and the line width multiplies by 1.4. */ - dr->api->line_width(dr->handle, (float)sqrt(dr->scale) * width); + dri->pub.api->line_width(dr, (float)sqrt(dri->scale) * width); } void print_line_dotted(drawing *dr, bool dotted) { - dr->api->line_dotted(dr->handle, dotted); + drawing_internal *dri = PRIVATE_CAST(dr); + dri->pub.api->line_dotted(dr, dotted); } diff --git a/emcc.c b/emcc.c index 6aa9c6b..b7aeec9 100644 --- a/emcc.c +++ b/emcc.c @@ -456,22 +456,22 @@ static void ids_changed(void *ignored) * drawing functions. (Well, half of it; the other half is on the JS * side.) */ -static void js_start_draw(void *handle) +static void js_start_draw(drawing *dr) { js_canvas_start_draw(); } -static void js_clip(void *handle, int x, int y, int w, int h) +static void js_clip(drawing *dr, int x, int y, int w, int h) { js_canvas_clip_rect(x, y, w, h); } -static void js_unclip(void *handle) +static void js_unclip(drawing *dr) { js_canvas_unclip(); } -static void js_draw_text(void *handle, int x, int y, int fonttype, +static void js_draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, const char *text) { @@ -491,31 +491,31 @@ static void js_draw_text(void *handle, int x, int y, int fonttype, fontsize, fonttype == FONT_FIXED, text); } -static void js_draw_rect(void *handle, int x, int y, int w, int h, int colour) +static void js_draw_rect(drawing *dr, int x, int y, int w, int h, int colour) { js_canvas_draw_rect(x, y, w, h, colour); } -static void js_draw_line(void *handle, int x1, int y1, int x2, int y2, +static void js_draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { js_canvas_draw_line(x1, y1, x2, y2, 1, colour); } -static void js_draw_thick_line(void *handle, float thickness, +static void js_draw_thick_line(drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour) { js_canvas_draw_line(x1, y1, x2, y2, thickness, colour); } -static void js_draw_poly(void *handle, const int *coords, int npoints, +static void js_draw_poly(drawing *dr, const int *coords, int npoints, int fillcolour, int outlinecolour) { js_canvas_draw_poly(coords, npoints, fillcolour, outlinecolour); } -static void js_draw_circle(void *handle, int cx, int cy, int radius, +static void js_draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour) { js_canvas_draw_circle(cx, cy, radius, fillcolour, outlinecolour); @@ -526,7 +526,7 @@ struct blitter { int w, h; /* easier to retain here */ }; -static blitter *js_blitter_new(void *handle, int w, int h) +static blitter *js_blitter_new(drawing *dr, int w, int h) { blitter *bl = snew(blitter); bl->w = w; @@ -535,7 +535,7 @@ static blitter *js_blitter_new(void *handle, int w, int h) return bl; } -static void js_blitter_free(void *handle, blitter *bl) +static void js_blitter_free(drawing *dr, blitter *bl) { js_canvas_free_blitter(bl->id); sfree(bl); @@ -569,7 +569,7 @@ static void trim_rect(int *x, int *y, int *w, int *h) *h = y1 - y0; } -static void js_blitter_save(void *handle, blitter *bl, int x, int y) +static void js_blitter_save(drawing *dr, blitter *bl, int x, int y) { int w = bl->w, h = bl->h; trim_rect(&x, &y, &w, &h); @@ -577,7 +577,7 @@ static void js_blitter_save(void *handle, blitter *bl, int x, int y) js_canvas_copy_to_blitter(bl->id, x, y, w, h); } -static void js_blitter_load(void *handle, blitter *bl, int x, int y) +static void js_blitter_load(drawing *dr, blitter *bl, int x, int y) { int w = bl->w, h = bl->h; trim_rect(&x, &y, &w, &h); @@ -585,30 +585,31 @@ static void js_blitter_load(void *handle, blitter *bl, int x, int y) js_canvas_copy_from_blitter(bl->id, x, y, w, h); } -static void js_draw_update(void *handle, int x, int y, int w, int h) +static void js_draw_update(drawing *dr, int x, int y, int w, int h) { trim_rect(&x, &y, &w, &h); if (w > 0 && h > 0) js_canvas_draw_update(x, y, w, h); } -static void js_end_draw(void *handle) +static void js_end_draw(drawing *dr) { js_canvas_end_draw(); } -static void js_status_bar(void *handle, const char *text) +static void js_status_bar(drawing *dr, const char *text) { js_canvas_set_statusbar(text); } -static char *js_text_fallback(void *handle, const char *const *strings, +static char *js_text_fallback(drawing *dr, const char *const *strings, int nstrings) { return dupstr(strings[0]); /* Emscripten has no trouble with UTF-8 */ } static const struct drawing_api js_drawing = { + 1, js_draw_text, js_draw_rect, js_draw_line, diff --git a/fuzzpuzz.c b/fuzzpuzz.c index 3fb632e..9a563ff 100644 --- a/fuzzpuzz.c +++ b/fuzzpuzz.c @@ -65,7 +65,7 @@ static const char *fuzz_one(bool (*readfn)(void *, void *, int), void *rctx, char *gamename; int i, w, h; const game *ourgame = NULL; - static const drawing_api drapi = { NULL }; + static const drawing_api drapi = { 1, NULL }; midend *me; err = identify_game(&gamename, readfn, rctx); diff --git a/gtk.c b/gtk.c index a40a701..dbaa980 100644 --- a/gtk.c +++ b/gtk.c @@ -329,9 +329,9 @@ void frontend_default_colour(frontend *fe, float *output) output[0] = output[1] = output[2] = 0.9F; } -static void gtk_status_bar(void *handle, const char *text) +static void gtk_status_bar(drawing *dr, const char *text) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); if (fe->headless) return; @@ -1164,9 +1164,9 @@ static void align_and_draw_text(int index, int align, int x, int y, * The exported drawing functions. */ -static void gtk_start_draw(void *handle) +static void gtk_start_draw(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); fe->bbox_l = fe->w; fe->bbox_r = 0; fe->bbox_u = fe->h; @@ -1174,23 +1174,23 @@ static void gtk_start_draw(void *handle) setup_drawing(fe); } -static void gtk_clip(void *handle, int x, int y, int w, int h) +static void gtk_clip(drawing *dr, int x, int y, int w, int h) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); do_clip(fe, x, y, w, h); } -static void gtk_unclip(void *handle) +static void gtk_unclip(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); do_unclip(fe); } -static void gtk_draw_text(void *handle, int x, int y, int fonttype, +static void gtk_draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, const char *text) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); int i; /* @@ -1220,45 +1220,45 @@ static void gtk_draw_text(void *handle, int x, int y, int fonttype, align_and_draw_text(fe, i, align, x, y, text); } -static void gtk_draw_rect(void *handle, int x, int y, int w, int h, int colour) +static void gtk_draw_rect(drawing *dr, int x, int y, int w, int h, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); fe->dr_api->set_colour(fe, colour); do_draw_rect(fe, x, y, w, h); } -static void gtk_draw_line(void *handle, int x1, int y1, int x2, int y2, +static void gtk_draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); fe->dr_api->set_colour(fe, colour); do_draw_line(fe, x1, y1, x2, y2); } -static void gtk_draw_thick_line(void *handle, float thickness, +static void gtk_draw_thick_line(drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); fe->dr_api->set_colour(fe, colour); do_draw_thick_line(fe, thickness, x1, y1, x2, y2); } -static void gtk_draw_poly(void *handle, const int *coords, int npoints, +static void gtk_draw_poly(drawing *dr, const int *coords, int npoints, int fillcolour, int outlinecolour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); do_draw_poly(fe, coords, npoints, fillcolour, outlinecolour); } -static void gtk_draw_circle(void *handle, int cx, int cy, int radius, +static void gtk_draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); do_draw_circle(fe, cx, cy, radius, fillcolour, outlinecolour); } -static blitter *gtk_blitter_new(void *handle, int w, int h) +static blitter *gtk_blitter_new(drawing *dr, int w, int h) { blitter *bl = snew(blitter); setup_blitter(bl, w, h); @@ -1267,23 +1267,23 @@ static blitter *gtk_blitter_new(void *handle, int w, int h) return bl; } -static void gtk_blitter_free(void *handle, blitter *bl) +static void gtk_blitter_free(drawing *dr, blitter *bl) { teardown_blitter(bl); sfree(bl); } -static void gtk_blitter_save(void *handle, blitter *bl, int x, int y) +static void gtk_blitter_save(drawing *dr, blitter *bl, int x, int y) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); do_blitter_save(fe, bl, x, y); bl->x = x; bl->y = y; } -static void gtk_blitter_load(void *handle, blitter *bl, int x, int y) +static void gtk_blitter_load(drawing *dr, blitter *bl, int x, int y) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) { x = bl->x; y = bl->y; @@ -1291,18 +1291,18 @@ static void gtk_blitter_load(void *handle, blitter *bl, int x, int y) do_blitter_load(fe, bl, x, y); } -static void gtk_draw_update(void *handle, int x, int y, int w, int h) +static void gtk_draw_update(drawing *dr, int x, int y, int w, int h) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); if (fe->bbox_l > x ) fe->bbox_l = x ; if (fe->bbox_r < x+w) fe->bbox_r = x+w; if (fe->bbox_u > y ) fe->bbox_u = y ; if (fe->bbox_d < y+h) fe->bbox_d = y+h; } -static void gtk_end_draw(void *handle) +static void gtk_end_draw(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); teardown_drawing(fe); @@ -1324,7 +1324,7 @@ static void gtk_end_draw(void *handle) } #ifdef USE_PANGO -static char *gtk_text_fallback(void *handle, const char *const *strings, +static char *gtk_text_fallback(drawing *dr, const char *const *strings, int nstrings) { /* @@ -1336,20 +1336,20 @@ static char *gtk_text_fallback(void *handle, const char *const *strings, #endif #ifdef USE_PRINTING -static void gtk_begin_doc(void *handle, int pages) +static void gtk_begin_doc(drawing *dr, int pages) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); gtk_print_operation_set_n_pages(fe->printop, pages); } -static void gtk_begin_page(void *handle, int number) +static void gtk_begin_page(drawing *dr, int number) { } -static void gtk_begin_puzzle(void *handle, float xm, float xc, +static void gtk_begin_puzzle(drawing *dr, float xm, float xc, float ym, float yc, int pw, int ph, float wmm) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); double ppw, pph, pox, poy, dpmmx, dpmmy; double scale; @@ -1385,29 +1385,29 @@ static void gtk_begin_puzzle(void *handle, float xm, float xc, fe->hatchspace = 1.0 * pw / wmm; } -static void gtk_end_puzzle(void *handle) +static void gtk_end_puzzle(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); cairo_restore(fe->cr); } -static void gtk_end_page(void *handle, int number) +static void gtk_end_page(drawing *dr, int number) { } -static void gtk_end_doc(void *handle) +static void gtk_end_doc(drawing *dr) { } -static void gtk_line_width(void *handle, float width) +static void gtk_line_width(drawing *dr, float width) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); cairo_set_line_width(fe->cr, width); } -static void gtk_line_dotted(void *handle, bool dotted) +static void gtk_line_dotted(drawing *dr, bool dotted) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); if (dotted) { const double dash = 35.0; @@ -1435,6 +1435,7 @@ static const struct internal_drawing_api internal_printing = { #endif static const struct drawing_api gtk_drawing = { + 1, gtk_draw_text, gtk_draw_rect, gtk_draw_line, diff --git a/nestedvm.c b/nestedvm.c index 0a9fdbc..c13a0b8 100644 --- a/nestedvm.c +++ b/nestedvm.c @@ -54,59 +54,59 @@ void frontend_default_colour(frontend *fe, float *output) output[0] = output[1]= output[2] = 0.8f; } -void nestedvm_status_bar(void *handle, const char *text) +void nestedvm_status_bar(drawing *dr, const char *text) { _call_java(4,0,(int)text,0); } -void nestedvm_start_draw(void *handle) +void nestedvm_start_draw(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); _call_java(5, 0, fe->w, fe->h); _call_java(4, 1, fe->ox, fe->oy); } -void nestedvm_clip(void *handle, int x, int y, int w, int h) +void nestedvm_clip(drawing *dr, int x, int y, int w, int h) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); _call_java(5, w, h, 0); _call_java(4, 3, x + fe->ox, y + fe->oy); } -void nestedvm_unclip(void *handle) +void nestedvm_unclip(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); _call_java(4, 4, fe->ox, fe->oy); } -void nestedvm_draw_text(void *handle, int x, int y, int fonttype, int fontsize, +void nestedvm_draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, const char *text) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); _call_java(5, x + fe->ox, y + fe->oy, (fonttype == FONT_FIXED ? 0x10 : 0x0) | align); _call_java(7, fontsize, colour, (int)text); } -void nestedvm_draw_rect(void *handle, int x, int y, int w, int h, int colour) +void nestedvm_draw_rect(drawing *dr, int x, int y, int w, int h, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); _call_java(5, w, h, colour); _call_java(4, 5, x + fe->ox, y + fe->oy); } -void nestedvm_draw_line(void *handle, int x1, int y1, int x2, int y2, +void nestedvm_draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); _call_java(5, x2 + fe->ox, y2 + fe->oy, colour); _call_java(4, 6, x1 + fe->ox, y1 + fe->oy); } -void nestedvm_draw_poly(void *handle, int *coords, int npoints, +void nestedvm_draw_poly(drawing *dr, int *coords, int npoints, int fillcolour, int outlinecolour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); int i; _call_java(4, 7, npoints, 0); for (i = 0; i < npoints; i++) { @@ -115,10 +115,10 @@ void nestedvm_draw_poly(void *handle, int *coords, int npoints, _call_java(4, 8, outlinecolour, fillcolour); } -void nestedvm_draw_circle(void *handle, int cx, int cy, int radius, +void nestedvm_draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); _call_java(5, cx+fe->ox, cy+fe->oy, radius); _call_java(4, 9, outlinecolour, fillcolour); } @@ -127,7 +127,7 @@ struct blitter { int handle, w, h, x, y; }; -blitter *nestedvm_blitter_new(void *handle, int w, int h) +blitter *nestedvm_blitter_new(drawing *dr, int w, int h) { blitter *bl = snew(blitter); bl->handle = -1; @@ -136,16 +136,16 @@ blitter *nestedvm_blitter_new(void *handle, int w, int h) return bl; } -void nestedvm_blitter_free(void *handle, blitter *bl) +void nestedvm_blitter_free(drawing *dr, blitter *bl) { if (bl->handle != -1) _call_java(4, 11, bl->handle, 0); sfree(bl); } -void nestedvm_blitter_save(void *handle, blitter *bl, int x, int y) +void nestedvm_blitter_save(drawing *dr, blitter *bl, int x, int y) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); if (bl->handle == -1) bl->handle = _call_java(4,10,bl->w, bl->h); bl->x = x; @@ -153,9 +153,9 @@ void nestedvm_blitter_save(void *handle, blitter *bl, int x, int y) _call_java(8, bl->handle, x + fe->ox, y + fe->oy); } -void nestedvm_blitter_load(void *handle, blitter *bl, int x, int y) +void nestedvm_blitter_load(drawing *dr, blitter *bl, int x, int y) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); assert(bl->handle != -1); if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) { x = bl->x; @@ -164,12 +164,12 @@ void nestedvm_blitter_load(void *handle, blitter *bl, int x, int y) _call_java(9, bl->handle, x + fe->ox, y + fe->oy); } -void nestedvm_end_draw(void *handle) +void nestedvm_end_draw(drawing *dr) { _call_java(4,2,0,0); } -char *nestedvm_text_fallback(void *handle, const char *const *strings, +char *nestedvm_text_fallback(drawing *dr, const char *const *strings, int nstrings) { /* @@ -180,6 +180,7 @@ char *nestedvm_text_fallback(void *handle, const char *const *strings, } const struct drawing_api nestedvm_drawing = { + 1, nestedvm_draw_text, nestedvm_draw_rect, nestedvm_draw_line, diff --git a/nullfe.c b/nullfe.c index 9a57832..b6022d4 100644 --- a/nullfe.c +++ b/nullfe.c @@ -13,7 +13,6 @@ void get_random_seed(void **randseed, int *randseedsize) { char *c = snewn(1, char); *c = 0; *randseed = c; *randseedsize = 1; } void deactivate_timer(frontend *fe) {} void activate_timer(frontend *fe) {} -struct drawing { char dummy; }; drawing *drawing_new(const drawing_api *api, midend *me, void *handle) { return snew(drawing); } void drawing_free(drawing *dr) { sfree(dr); } diff --git a/osx.m b/osx.m index 44bb96f..88a6510 100644 --- a/osx.m +++ b/osx.m @@ -1507,10 +1507,10 @@ struct frontend { /* * Drawing routines called by the midend. */ -static void osx_draw_polygon(void *handle, const int *coords, int npoints, +static void osx_draw_polygon(drawing *dr, const int *coords, int npoints, int fillcolour, int outlinecolour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); NSBezierPath *path = [NSBezierPath bezierPath]; int i; @@ -1536,10 +1536,10 @@ static void osx_draw_polygon(void *handle, const int *coords, int npoints, [fe->colours[outlinecolour] set]; [path stroke]; } -static void osx_draw_circle(void *handle, int cx, int cy, int radius, +static void osx_draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); NSBezierPath *path = [NSBezierPath bezierPath]; [[NSGraphicsContext currentContext] setShouldAntialias:YES]; @@ -1559,9 +1559,9 @@ static void osx_draw_circle(void *handle, int cx, int cy, int radius, [fe->colours[outlinecolour] set]; [path stroke]; } -static void osx_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) +static void osx_draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); NSBezierPath *path = [NSBezierPath bezierPath]; NSPoint p1 = { x1 + 0.5, fe->h - y1 - 0.5 }; NSPoint p2 = { x2 + 0.5, fe->h - y2 - 0.5 }; @@ -1579,12 +1579,12 @@ static void osx_draw_line(void *handle, int x1, int y1, int x2, int y2, int colo } static void osx_draw_thick_line( - void *handle, float thickness, + drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); NSBezierPath *path = [NSBezierPath bezierPath]; assert(colour >= 0 && colour < fe->ncolours); @@ -1597,9 +1597,9 @@ static void osx_draw_thick_line( [path stroke]; } -static void osx_draw_rect(void *handle, int x, int y, int w, int h, int colour) +static void osx_draw_rect(drawing *dr, int x, int y, int w, int h, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); NSRect r = { {x, fe->h - y - h}, {w,h} }; [[NSGraphicsContext currentContext] setShouldAntialias:NO]; @@ -1609,11 +1609,11 @@ static void osx_draw_rect(void *handle, int x, int y, int w, int h, int colour) NSRectFill(r); } -static void osx_draw_text(void *handle, int x, int y, int fonttype, +static void osx_draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, const char *text) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); NSString *string = [NSString stringWithUTF8String:text]; NSDictionary *attr; NSFont *font; @@ -1646,7 +1646,7 @@ static void osx_draw_text(void *handle, int x, int y, int fonttype, [string drawAtPoint:point withAttributes:attr]; } -static char *osx_text_fallback(void *handle, const char *const *strings, +static char *osx_text_fallback(drawing *dr, const char *const *strings, int nstrings) { /* @@ -1660,7 +1660,7 @@ struct blitter { int x, y; NSImage *img; }; -static blitter *osx_blitter_new(void *handle, int w, int h) +static blitter *osx_blitter_new(drawing *dr, int w, int h) { blitter *bl = snew(blitter); bl->x = bl->y = -1; @@ -1669,14 +1669,14 @@ static blitter *osx_blitter_new(void *handle, int w, int h) bl->img = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; return bl; } -static void osx_blitter_free(void *handle, blitter *bl) +static void osx_blitter_free(drawing *dr, blitter *bl) { [bl->img release]; sfree(bl); } -static void osx_blitter_save(void *handle, blitter *bl, int x, int y) +static void osx_blitter_save(drawing *dr, blitter *bl, int x, int y) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); int sx, sy, sX, sY, dx, dy, dX, dY; [fe->image unlockFocus]; [bl->img lockFocus]; @@ -1718,9 +1718,9 @@ static void osx_blitter_save(void *handle, blitter *bl, int x, int y) bl->x = x; bl->y = y; } -static void osx_blitter_load(void *handle, blitter *bl, int x, int y) +static void osx_blitter_load(drawing *dr, blitter *bl, int x, int y) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) { x = bl->x; y = bl->y; @@ -1729,14 +1729,14 @@ static void osx_blitter_load(void *handle, blitter *bl, int x, int y) fromRect:NSMakeRect(0, 0, bl->w, bl->h) operation:NSCompositeCopy fraction:1.0]; } -static void osx_draw_update(void *handle, int x, int y, int w, int h) +static void osx_draw_update(drawing *dr, int x, int y, int w, int h) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); [fe->view setNeedsDisplayInRect:NSMakeRect(x, fe->h - y - h, w, h)]; } -static void osx_clip(void *handle, int x, int y, int w, int h) +static void osx_clip(drawing *dr, int x, int y, int w, int h) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); NSRect r = { {x, fe->h - y - h}, {w, h} }; if (!fe->clipped) @@ -1744,31 +1744,32 @@ static void osx_clip(void *handle, int x, int y, int w, int h) [NSBezierPath clipRect:r]; fe->clipped = true; } -static void osx_unclip(void *handle) +static void osx_unclip(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); if (fe->clipped) [[NSGraphicsContext currentContext] restoreGraphicsState]; fe->clipped = false; } -static void osx_start_draw(void *handle) +static void osx_start_draw(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); [fe->image lockFocus]; fe->clipped = false; } -static void osx_end_draw(void *handle) +static void osx_end_draw(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); [fe->image unlockFocus]; } -static void osx_status_bar(void *handle, const char *text) +static void osx_status_bar(drawing *dr, const char *text) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); [fe->window setStatusLine:text]; } const struct drawing_api osx_drawing = { + 1, osx_draw_text, osx_draw_rect, osx_draw_line, diff --git a/ps.c b/ps.c index d0ea0ff..dd4b346 100644 --- a/ps.c +++ b/ps.c @@ -99,11 +99,11 @@ static void ps_stroke(psdata *ps, int colour) ps_setcolour_internal(ps, colour, " stroke"); } -static void ps_draw_text(void *handle, int x, int y, int fonttype, +static void ps_draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, const char *text) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); y = ps->ytop - y; ps_setcolour(ps, colour); @@ -133,9 +133,9 @@ static void ps_draw_text(void *handle, int x, int y, int fonttype, ps_printf(ps, "show\n"); } -static void ps_draw_rect(void *handle, int x, int y, int w, int h, int colour) +static void ps_draw_rect(drawing *dr, int x, int y, int w, int h, int colour) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); y = ps->ytop - y; /* @@ -146,10 +146,10 @@ static void ps_draw_rect(void *handle, int x, int y, int w, int h, int colour) ps_fill(ps, colour); } -static void ps_draw_line(void *handle, int x1, int y1, int x2, int y2, +static void ps_draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); y1 = ps->ytop - y1; y2 = ps->ytop - y2; @@ -157,10 +157,10 @@ static void ps_draw_line(void *handle, int x1, int y1, int x2, int y2, ps_stroke(ps, colour); } -static void ps_draw_polygon(void *handle, const int *coords, int npoints, +static void ps_draw_polygon(drawing *dr, const int *coords, int npoints, int fillcolour, int outlinecolour) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); int i; @@ -179,10 +179,10 @@ static void ps_draw_polygon(void *handle, const int *coords, int npoints, ps_stroke(ps, outlinecolour); } -static void ps_draw_circle(void *handle, int cx, int cy, int radius, +static void ps_draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); cy = ps->ytop - cy; @@ -196,21 +196,21 @@ static void ps_draw_circle(void *handle, int cx, int cy, int radius, ps_stroke(ps, outlinecolour); } -static void ps_unclip(void *handle) +static void ps_unclip(drawing *dr) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); assert(ps->clipped); ps_printf(ps, "grestore\n"); ps->clipped = false; } -static void ps_clip(void *handle, int x, int y, int w, int h) +static void ps_clip(drawing *dr, int x, int y, int w, int h) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); if (ps->clipped) - ps_unclip(ps); + ps_unclip(dr); y = ps->ytop - y; /* @@ -223,16 +223,16 @@ static void ps_clip(void *handle, int x, int y, int w, int h) ps->clipped = true; } -static void ps_line_width(void *handle, float width) +static void ps_line_width(drawing *dr, float width) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); ps_printf(ps, "%g setlinewidth\n", width); } -static void ps_line_dotted(void *handle, bool dotted) +static void ps_line_dotted(drawing *dr, bool dotted) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); if (dotted) { ps_printf(ps, "[ currentlinewidth 3 mul ] 0 setdash\n"); @@ -241,7 +241,7 @@ static void ps_line_dotted(void *handle, bool dotted) } } -static char *ps_text_fallback(void *handle, const char *const *strings, +static char *ps_text_fallback(drawing *dr, const char *const *strings, int nstrings) { /* @@ -284,9 +284,9 @@ static char *ps_text_fallback(void *handle, const char *const *strings, return NULL; } -static void ps_begin_doc(void *handle, int pages) +static void ps_begin_doc(drawing *dr, int pages) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); fputs("%!PS-Adobe-3.0\n", ps->fp); fputs("%%Creator: Simon Tatham's Portable Puzzle Collection\n", ps->fp); @@ -331,18 +331,18 @@ static void ps_begin_doc(void *handle, int pages) fputs("%%EndProlog\n", ps->fp); } -static void ps_begin_page(void *handle, int number) +static void ps_begin_page(drawing *dr, int number) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); fprintf(ps->fp, "%%%%Page: %d %d\ngsave save\n%g dup scale\n", number, number, 72.0 / 25.4); } -static void ps_begin_puzzle(void *handle, float xm, float xc, +static void ps_begin_puzzle(drawing *dr, float xm, float xc, float ym, float yc, int pw, int ph, float wmm) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); fprintf(ps->fp, "gsave\n" "clippath flattenpath pathbbox pop pop translate\n" @@ -358,28 +358,29 @@ static void ps_begin_puzzle(void *handle, float xm, float xc, ps->hatchspace = 1.0 * pw / wmm; } -static void ps_end_puzzle(void *handle) +static void ps_end_puzzle(drawing *dr) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); fputs("grestore\n", ps->fp); } -static void ps_end_page(void *handle, int number) +static void ps_end_page(drawing *dr, int number) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); fputs("restore grestore showpage\n", ps->fp); } -static void ps_end_doc(void *handle) +static void ps_end_doc(drawing *dr) { - psdata *ps = (psdata *)handle; + psdata *ps = GET_HANDLE_AS_TYPE(dr, psdata); fputs("%%EOF\n", ps->fp); } static const struct drawing_api ps_drawing = { + 1, ps_draw_text, ps_draw_rect, ps_draw_line, diff --git a/puzzles.h b/puzzles.h index f1022ea..bac3ec3 100644 --- a/puzzles.h +++ b/puzzles.h @@ -755,43 +755,75 @@ struct game { int flags; }; +#define GET_HANDLE_AS_TYPE(dr, type) ((type*)((dr)->handle)) + +struct drawing { + const drawing_api *api; + void *handle; +}; + /* * Data structure containing the drawing API implemented by the * front end and also by cross-platform printing modules such as * PostScript. */ struct drawing_api { - void (*draw_text)(void *handle, int x, int y, int fonttype, int fontsize, + /* + * API version. Increment this when there is a breaking change to + * this API which requires front ends to change. + * + * There is expliclty not a public LATEST_API_VERSION define, so + * that front end authors will need to manually intervene when the + * version number changes. Naturally, this should be done + * sparingly. + * + * If a function is ever added to this API, please move this field + * to the _end_ of the structure, so that changes thereafter will + * shift the position of the version and lead to a compilation + * error if old implementations are not updated. Then remove this + * comment. + * + * The latest version number is 1. + * + * Change log: + * + * Version 1 (2024-08-14): Introduction of version number, in + * conjunction with changing every API function to take `drawing *` + * instead of `void *`. + */ + int version; + + void (*draw_text)(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, const char *text); - void (*draw_rect)(void *handle, int x, int y, int w, int h, int colour); - void (*draw_line)(void *handle, int x1, int y1, int x2, int y2, + void (*draw_rect)(drawing *dr, int x, int y, int w, int h, int colour); + void (*draw_line)(drawing *dr, int x1, int y1, int x2, int y2, int colour); - void (*draw_polygon)(void *handle, const int *coords, int npoints, + void (*draw_polygon)(drawing *dr, const int *coords, int npoints, int fillcolour, int outlinecolour); - void (*draw_circle)(void *handle, int cx, int cy, int radius, + void (*draw_circle)(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour); - void (*draw_update)(void *handle, int x, int y, int w, int h); - void (*clip)(void *handle, int x, int y, int w, int h); - void (*unclip)(void *handle); - void (*start_draw)(void *handle); - void (*end_draw)(void *handle); - void (*status_bar)(void *handle, const char *text); - blitter *(*blitter_new)(void *handle, int w, int h); - void (*blitter_free)(void *handle, blitter *bl); - void (*blitter_save)(void *handle, blitter *bl, int x, int y); - void (*blitter_load)(void *handle, blitter *bl, int x, int y); - void (*begin_doc)(void *handle, int pages); - void (*begin_page)(void *handle, int number); - void (*begin_puzzle)(void *handle, float xm, float xc, + void (*draw_update)(drawing *dr, int x, int y, int w, int h); + void (*clip)(drawing *dr, int x, int y, int w, int h); + void (*unclip)(drawing *dr); + void (*start_draw)(drawing *dr); + void (*end_draw)(drawing *dr); + void (*status_bar)(drawing *dr, const char *text); + blitter *(*blitter_new)(drawing *dr, int w, int h); + void (*blitter_free)(drawing *dr, blitter *bl); + void (*blitter_save)(drawing *dr, blitter *bl, int x, int y); + void (*blitter_load)(drawing *dr, blitter *bl, int x, int y); + void (*begin_doc)(drawing *dr, int pages); + void (*begin_page)(drawing *dr, int number); + void (*begin_puzzle)(drawing *dr, float xm, float xc, float ym, float yc, int pw, int ph, float wmm); - void (*end_puzzle)(void *handle); - void (*end_page)(void *handle, int number); - void (*end_doc)(void *handle); - void (*line_width)(void *handle, float width); - void (*line_dotted)(void *handle, bool dotted); - char *(*text_fallback)(void *handle, const char *const *strings, + void (*end_puzzle)(drawing *dr); + void (*end_page)(drawing *dr, int number); + void (*end_doc)(drawing *dr); + void (*line_width)(drawing *dr, float width); + void (*line_dotted)(drawing *dr, bool dotted); + char *(*text_fallback)(drawing *dr, const char *const *strings, int nstrings); - void (*draw_thick_line)(void *handle, float thickness, + void (*draw_thick_line)(drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour); }; diff --git a/windows.c b/windows.c index 5273e17..0a02d8a 100644 --- a/windows.c +++ b/windows.c @@ -253,14 +253,14 @@ void get_random_seed(void **randseed, int *randseedsize) *randseedsize = sizeof(SYSTEMTIME); } -static void win_status_bar(void *handle, const char *text) +static void win_status_bar(drawing *dr, const char *text) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); SetWindowText(fe->statusbar, text); } -static blitter *win_blitter_new(void *handle, int w, int h) +static blitter *win_blitter_new(drawing *dr, int w, int h) { blitter *bl = snew(blitter); @@ -272,7 +272,7 @@ static blitter *win_blitter_new(void *handle, int w, int h) return bl; } -static void win_blitter_free(void *handle, blitter *bl) +static void win_blitter_free(drawing *dr, blitter *bl) { if (bl->bitmap) DeleteObject(bl->bitmap); sfree(bl); @@ -287,9 +287,9 @@ static void blitter_mkbitmap(frontend *fe, blitter *bl) /* BitBlt(dstDC, dstX, dstY, dstW, dstH, srcDC, srcX, srcY, dType) */ -static void win_blitter_save(void *handle, blitter *bl, int x, int y) +static void win_blitter_save(drawing *dr, blitter *bl, int x, int y) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); HDC hdc_win, hdc_blit; HBITMAP prev_blit; @@ -316,9 +316,9 @@ static void win_blitter_save(void *handle, blitter *bl, int x, int y) ReleaseDC(fe->hwnd, hdc_win); } -static void win_blitter_load(void *handle, blitter *bl, int x, int y) +static void win_blitter_load(drawing *dr, blitter *bl, int x, int y) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); HDC hdc_win, hdc_blit; HBITMAP prev_blit; @@ -463,9 +463,9 @@ static void win_reset_pen(frontend *fe) DeleteObject(pen); } -static void win_clip(void *handle, int x, int y, int w, int h) +static void win_clip(drawing *dr, int x, int y, int w, int h) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); POINT p, q; if (fe->drawstatus == NOTHING) @@ -476,9 +476,9 @@ static void win_clip(void *handle, int x, int y, int w, int h) IntersectClipRect(fe->hdc, p.x, p.y, q.x, q.y); } -static void win_unclip(void *handle) +static void win_unclip(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); if (fe->drawstatus == NOTHING) return; @@ -486,11 +486,11 @@ static void win_unclip(void *handle) SelectClipRgn(fe->hdc, NULL); } -static void win_draw_text(void *handle, int x, int y, int fonttype, +static void win_draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, const char *text) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); POINT xy; int i; LOGFONT lf; @@ -566,9 +566,9 @@ static void win_draw_text(void *handle, int x, int y, int fonttype, } } -static void win_draw_rect(void *handle, int x, int y, int w, int h, int colour) +static void win_draw_rect(drawing *dr, int x, int y, int w, int h, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); POINT p, q; if (fe->drawstatus == NOTHING) @@ -593,9 +593,9 @@ static void win_draw_rect(void *handle, int x, int y, int w, int h, int colour) } } -static void win_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) +static void win_draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); POINT pp[2]; if (fe->drawstatus == NOTHING) @@ -610,10 +610,10 @@ static void win_draw_line(void *handle, int x1, int y1, int x2, int y2, int colo win_reset_pen(fe); } -static void win_draw_circle(void *handle, int cx, int cy, int radius, +static void win_draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); POINT p, q; assert(outlinecolour >= 0); @@ -634,10 +634,10 @@ static void win_draw_circle(void *handle, int cx, int cy, int radius, win_reset_pen(fe); } -static void win_draw_polygon(void *handle, const int *coords, int npoints, +static void win_draw_polygon(drawing *dr, const int *coords, int npoints, int fillcolour, int outlinecolour) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); POINT *pts; int i; @@ -668,9 +668,9 @@ static void win_draw_polygon(void *handle, const int *coords, int npoints, sfree(pts); } -static void win_start_draw(void *handle) +static void win_start_draw(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); HDC hdc_win; assert(fe->drawstatus == NOTHING); @@ -684,9 +684,9 @@ static void win_start_draw(void *handle) fe->drawstatus = DRAWING; } -static void win_draw_update(void *handle, int x, int y, int w, int h) +static void win_draw_update(drawing *dr, int x, int y, int w, int h) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); RECT r; if (fe->drawstatus != DRAWING) @@ -701,9 +701,9 @@ static void win_draw_update(void *handle, int x, int y, int w, int h) InvalidateRect(fe->hwnd, &r, false); } -static void win_end_draw(void *handle) +static void win_end_draw(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); assert(fe->drawstatus == DRAWING); SelectObject(fe->hdc, fe->prevbm); DeleteDC(fe->hdc); @@ -714,9 +714,9 @@ static void win_end_draw(void *handle) fe->drawstatus = NOTHING; } -static void win_line_width(void *handle, float width) +static void win_line_width(drawing *dr, float width) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) @@ -725,9 +725,9 @@ static void win_line_width(void *handle, float width) fe->linewidth = (int)(width * fe->printpixelscale); } -static void win_line_dotted(void *handle, bool dotted) +static void win_line_dotted(drawing *dr, bool dotted) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) @@ -736,9 +736,9 @@ static void win_line_dotted(void *handle, bool dotted) fe->linedotted = dotted; } -static void win_begin_doc(void *handle, int pages) +static void win_begin_doc(drawing *dr, int pages) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) @@ -761,9 +761,9 @@ static void win_begin_doc(void *handle, int pages) fe->fontstart = fe->nfonts; } -static void win_begin_page(void *handle, int number) +static void win_begin_page(drawing *dr, int number) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) @@ -778,10 +778,10 @@ static void win_begin_page(void *handle, int number) } } -static void win_begin_puzzle(void *handle, float xm, float xc, +static void win_begin_puzzle(drawing *dr, float xm, float xc, float ym, float yc, int pw, int ph, float wmm) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); int ppw, pph, pox, poy; float mmpw, mmph, mmox, mmoy; float scale; @@ -829,14 +829,14 @@ static void win_begin_puzzle(void *handle, float xm, float xc, fe->linedotted = false; } -static void win_end_puzzle(void *handle) +static void win_end_puzzle(drawing *dr) { /* Nothing needs to be done here. */ } -static void win_end_page(void *handle, int number) +static void win_end_page(drawing *dr, int number) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); assert(fe->drawstatus != DRAWING); @@ -852,9 +852,9 @@ static void win_end_page(void *handle, int number) } } -static void win_end_doc(void *handle) +static void win_end_doc(drawing *dr) { - frontend *fe = (frontend *)handle; + frontend *fe = GET_HANDLE_AS_TYPE(dr, frontend); assert(fe->drawstatus != DRAWING); @@ -885,7 +885,7 @@ static void win_end_doc(void *handle) } } -char *win_text_fallback(void *handle, const char *const *strings, int nstrings) +char *win_text_fallback(drawing *dr, const char *const *strings, int nstrings) { /* * We assume Windows can cope with any UTF-8 likely to be @@ -895,6 +895,7 @@ char *win_text_fallback(void *handle, const char *const *strings, int nstrings) } const struct drawing_api win_drawing = { + 1, win_draw_text, win_draw_rect, win_draw_line,