diff options
-rw-r--r-- | base/gsdevice.c | 6 | ||||
-rw-r--r-- | base/gslibctx.c | 68 | ||||
-rw-r--r-- | base/gslibctx.h | 16 | ||||
-rw-r--r-- | base/gxdevcli.h | 3 | ||||
-rw-r--r-- | base/gxdevsop.h | 9 | ||||
-rw-r--r-- | devices/gdevdsp.c | 228 | ||||
-rw-r--r-- | devices/gdevdsp.h | 23 | ||||
-rw-r--r-- | devices/gdevdsp2.h | 1 | ||||
-rw-r--r-- | doc/API.htm | 127 | ||||
-rw-r--r-- | pcl/pl/plapi.c | 20 | ||||
-rw-r--r-- | pcl/pl/plapi.h | 33 | ||||
-rw-r--r-- | pcl/pl/plmain.c | 66 | ||||
-rw-r--r-- | psi/gsdll2.def | 2 | ||||
-rw-r--r-- | psi/gsdll32.def | 2 | ||||
-rw-r--r-- | psi/gsdll32metro.def | 3 | ||||
-rw-r--r-- | psi/gsdll64.def | 2 | ||||
-rw-r--r-- | psi/gsdll64metro.def | 2 | ||||
-rw-r--r-- | psi/gsdllARM32metro.def | 2 | ||||
-rw-r--r-- | psi/iapi.c | 62 | ||||
-rw-r--r-- | psi/iapi.h | 33 | ||||
-rw-r--r-- | psi/idisp.c | 70 | ||||
-rw-r--r-- | psi/idisp.h | 5 | ||||
-rw-r--r-- | psi/imain.c | 6 | ||||
-rw-r--r-- | psi/int.mak | 2 |
24 files changed, 614 insertions, 177 deletions
diff --git a/base/gsdevice.c b/base/gsdevice.c index cd9460374..ec0f79e58 100644 --- a/base/gsdevice.c +++ b/base/gsdevice.c @@ -1346,3 +1346,9 @@ bool gx_color_info_equal(const gx_device_color_info * p1, const gx_device_color_ return false; return true; } + +int gx_callout(gx_device *dev, int id, int size, void *data) +{ + return gs_lib_ctx_callout(dev->memory, dev->dname, + id, size, data); +} diff --git a/base/gslibctx.c b/base/gslibctx.c index b2e046e06..35490b504 100644 --- a/base/gslibctx.c +++ b/base/gslibctx.c @@ -1179,3 +1179,71 @@ int gs_lib_ctx_get_args(gs_lib_ctx_t *ctx, const char * const **argv) *argv = (const char * const *)core->argv; return core->argc; } + +int gs_lib_ctx_register_callout(gs_memory_t *mem, gs_callout_fn fn, void *arg) +{ + gs_lib_ctx_core_t *core; + gs_callout_list_t *entry; + + if (mem == NULL || mem->gs_lib_ctx == NULL || + mem->gs_lib_ctx->core == NULL || fn == NULL) + return 0; + + core = mem->gs_lib_ctx->core; + entry = (gs_callout_list_t *)gs_alloc_bytes(mem->non_gc_memory, + sizeof(*entry), + "gs_callout_list_t"); + if (entry == NULL) + return_error(gs_error_VMerror); + entry->next = core->callouts; + entry->callout = fn; + entry->handle = arg; + core->callouts = entry; + + return 0; +} + +void gs_lib_ctx_deregister_callout(gs_memory_t *mem, gs_callout_fn fn, void *arg) +{ + gs_lib_ctx_core_t *core; + gs_callout_list_t **entry; + + if (mem == NULL || mem->gs_lib_ctx == NULL || + mem->gs_lib_ctx->core == NULL || fn == NULL) + return; + + core = mem->gs_lib_ctx->core; + entry = &core->callouts; + while (*entry) { + if ((*entry)->callout == fn && (*entry)->handle == arg) { + gs_callout_list_t *next = (*entry)->next; + gs_free_object(mem->non_gc_memory, *entry, "gs_callout_list_t"); + *entry = next; + } else { + entry = &(*entry)->next; + } + } +} + +int gs_lib_ctx_callout(gs_memory_t *mem, const char *dev_name, + int id, int size, void *data) +{ + gs_lib_ctx_core_t *core; + gs_callout_list_t *entry; + + if (mem == NULL || mem->gs_lib_ctx == NULL || mem->gs_lib_ctx->core == NULL) + return -1; + + core = mem->gs_lib_ctx->core; + entry = core->callouts; + while (entry) { + int code = entry->callout(mem->gs_lib_ctx->top_of_system, + entry->handle, dev_name, id, size, data); + if (code >= 0) + return code; + if (code != gs_error_unknownerror) + return code; + entry = entry->next; + } + return -1; +} diff --git a/base/gslibctx.h b/base/gslibctx.h index f6ce40a32..173d2dc2a 100644 --- a/base/gslibctx.h +++ b/base/gslibctx.h @@ -81,6 +81,14 @@ typedef struct gs_fs_list_s { struct gs_fs_list_s *next; } gs_fs_list_t; +typedef int (*gs_callout_fn)(void *, void *, const char *, int, int, void *); + +typedef struct gs_callout_list_s { + struct gs_callout_list_s *next; + gs_callout_fn callout; + void *handle; +} gs_callout_list_t; + typedef struct { void *monitor; int refs; @@ -118,6 +126,8 @@ typedef struct { * all builds. */ void *cal_ctx; + gs_callout_list_t *callouts; + /* Stashed args */ int arg_max; int argc; @@ -194,6 +204,12 @@ void *gs_lib_ctx_get_cms_context( const gs_memory_t *mem ); void gs_lib_ctx_set_cms_context( const gs_memory_t *mem, void *cms_context ); int gs_lib_ctx_get_act_on_uel( const gs_memory_t *mem ); +int gs_lib_ctx_register_callout(gs_memory_t *mem, gs_callout_fn, void *arg); +void gs_lib_ctx_deregister_callout(gs_memory_t *mem, gs_callout_fn, void *arg); +int gs_lib_ctx_callout(gs_memory_t *mem, const char *dev_name, + int id, int size, void *data); + + #ifndef GS_THREADSAFE /* HACK to get at non garbage collection memory pointer * diff --git a/base/gxdevcli.h b/base/gxdevcli.h index e7a054321..e7c3a78a4 100644 --- a/base/gxdevcli.h +++ b/base/gxdevcli.h @@ -1982,4 +1982,7 @@ void gx_device_dump(gx_device *dev, const char *text); /* Compare color information structures */ bool gx_color_info_equal(const gx_device_color_info *p1, const gx_device_color_info *p2); +/* Perform a callout to registered handlers from the device. */ +int gx_callout(gx_device *dev, int id, int size, void *data); + #endif /* gxdevcli_INCLUDED */ diff --git a/base/gxdevsop.h b/base/gxdevsop.h index 3ba09fd2b..4c597de08 100644 --- a/base/gxdevsop.h +++ b/base/gxdevsop.h @@ -379,6 +379,15 @@ enum { * 0 otherwise. */ gxdso_supports_alpha, + /* gxdso_reopen_after_init: + * data = NULL + * size = 0 + * Returns 1 if the device should be closed/reopened after gs + * finishes initialisation (e.g. to give it a chance to fetch + * configuration from registered callout handlers), + * 0 otherwise. + */ + gxdso_reopen_after_init, /* Add new gxdso_ keys above this. */ gxdso_pattern__LAST }; diff --git a/devices/gdevdsp.c b/devices/gdevdsp.c index e42ad3696..2fb542b93 100644 --- a/devices/gdevdsp.c +++ b/devices/gdevdsp.c @@ -210,6 +210,7 @@ const gx_device_display gs_display_device = NULL, /* mdev */ NULL, /* callback */ NULL, /* pHandle */ + 0, /* pHandle_set */ 0, /* nFormat */ NULL, /* pBitmap */ 0, /* ulBitmapSize */ @@ -242,12 +243,34 @@ display_open(gx_device * dev) { gx_device_display *ddev = (gx_device_display *) dev; int ccode; + gs_display_get_callback_t data; /* Erase these, in case we are opening a copied device. */ ddev->mdev = NULL; ddev->pBitmap = NULL; ddev->ulBitmapSize = 0; + /* Fetch our callback procedures. */ + data.callback = NULL; + data.caller_handle = NULL; + ccode = gx_callout(dev, DISPLAY_CALLOUT_GET_CALLBACK, sizeof(data), &data); + if (ccode < 0) { + ccode = gx_callout(dev, DISPLAY_CALLOUT_GET_CALLBACK_LEGACY, sizeof(data), &data); + if (ccode < 0) { + ddev->callback = NULL; + ddev->pHandle = NULL; + if (ccode != gs_error_unknownerror) + return ccode; + } else { + ddev->callback = data.callback; + ddev->pHandle_set = 0; + } + } else { + ddev->callback = data.callback; + ddev->pHandle = data.caller_handle; + ddev->pHandle_set = 1; + } + /* Allow device to be opened "disabled" without a callback. */ /* The callback will be set later and the device re-opened. */ if (ddev->callback == NULL) @@ -805,27 +828,31 @@ display_get_params(gx_device * dev, gs_param_list * plist) size_t dptr; char buf[64]; - idx = ((int)sizeof(size_t)) * 8 - 4; - buf[i++] = '1'; - buf[i++] = '6'; - buf[i++] = '#'; - dptr = (size_t)(ddev->pHandle); - while (idx >= 0) { - val = (int)(dptr >> idx) & 0xf; - if (val <= 9) - buf[i++] = '0' + val; - else - buf[i++] = 'a' - 10 + val; - idx -= 4; - } - buf[i] = '\0'; + code = gx_default_get_params(dev, plist); + if (code < 0) + return code; + + if (!ddev->pHandle_set) { + idx = ((int)sizeof(size_t)) * 8 - 4; + buf[i++] = '1'; + buf[i++] = '6'; + buf[i++] = '#'; + dptr = (size_t)(ddev->pHandle); + while (idx >= 0) { + val = (int)(dptr >> idx) & 0xf; + if (val <= 9) + buf[i++] = '0' + val; + else + buf[i++] = 'a' - 10 + val; + idx -= 4; + } + buf[i] = '\0'; - param_string_from_transient_string(dhandle, buf); + param_string_from_transient_string(dhandle, buf); + code = param_write_string(plist, "DisplayHandle", &dhandle); + } - code = gx_default_get_params(dev, plist); (void)(code < 0 || - (code = param_write_string(plist, - "DisplayHandle", &dhandle)) < 0 || (code = param_write_int(plist, "DisplayFormat", &ddev->nFormat)) < 0 || (code = param_write_float(plist, @@ -890,96 +917,98 @@ display_put_params(gx_device * dev, gs_param_list * plist) break; } - /* 64-bit systems need to use DisplayHandle as a string */ - switch (code = param_read_string(plist, "DisplayHandle", &dh)) { - case 0: - found_string_handle = 1; - break; - default: - if ((code == gs_error_typecheck) && (sizeof(size_t) <= 4)) { - /* 32-bit systems can use the older long type */ - switch (code = param_read_long(plist, "DisplayHandle", - (long *)(&handle))) { - case 0: - if (dev->is_open) { - if (ddev->pHandle != handle) - ecode = gs_error_rangecheck; - else + if (!ddev->pHandle_set) { + /* 64-bit systems need to use DisplayHandle as a string */ + switch (code = param_read_string(plist, "DisplayHandle", &dh)) { + case 0: + found_string_handle = 1; + break; + default: + if ((code == gs_error_typecheck) && (sizeof(size_t) <= 4)) { + /* 32-bit systems can use the older long type */ + switch (code = param_read_long(plist, "DisplayHandle", + (long *)(&handle))) { + case 0: + if (dev->is_open) { + if (ddev->pHandle != handle) + ecode = gs_error_rangecheck; + else + break; + } + else { + ddev->pHandle = handle; break; - } - else { - ddev->pHandle = handle; + } + goto hdle; + default: + ecode = code; + hdle:param_signal_error(plist, "DisplayHandle", ecode); + case 1: break; - } - goto hdle; - default: - ecode = code; - hdle:param_signal_error(plist, "DisplayHandle", ecode); - case 1: - break; + } + break; } + ecode = code; + param_signal_error(plist, "DisplayHandle", ecode); + /* fall through */ + case 1: + dh.data = 0; break; - } - ecode = code; - param_signal_error(plist, "DisplayHandle", ecode); - /* fall through */ - case 1: - dh.data = 0; - break; - } - if (found_string_handle) { - /* - * Convert from a string to a pointer. - * It is assumed that size_t has the same size as a pointer. - * Allow formats (1234), (10#1234) or (16#04d2). - */ - size_t ptr = 0; - int i; - int base = 10; - int val; - code = 0; - for (i=0; i<dh.size; i++) { - val = dh.data[i]; - if ((val >= '0') && (val <= '9')) - val = val - '0'; - else if ((val >= 'A') && (val <= 'F')) - val = val - 'A' + 10; - else if ((val >= 'a') && (val <= 'f')) - val = val - 'a' + 10; - else if (val == '#') { - base = (int)ptr; - ptr = 0; - if ((base != 10) && (base != 16)) { + } + if (found_string_handle) { + /* + * Convert from a string to a pointer. + * It is assumed that size_t has the same size as a pointer. + * Allow formats (1234), (10#1234) or (16#04d2). + */ + size_t ptr = 0; + int i; + int base = 10; + int val; + code = 0; + for (i=0; i<dh.size; i++) { + val = dh.data[i]; + if ((val >= '0') && (val <= '9')) + val = val - '0'; + else if ((val >= 'A') && (val <= 'F')) + val = val - 'A' + 10; + else if ((val >= 'a') && (val <= 'f')) + val = val - 'a' + 10; + else if (val == '#') { + base = (int)ptr; + ptr = 0; + if ((base != 10) && (base != 16)) { + code = gs_error_rangecheck; + break; + } + continue; + } + else { code = gs_error_rangecheck; break; } - continue; - } - else { - code = gs_error_rangecheck; - break; - } - if (base == 10) - ptr = ptr * 10 + val; - else if (base == 16) - ptr = ptr * 16 + val; - else { - code = gs_error_rangecheck; - break; - } - } - if (code == 0) { - if (dev->is_open) { - if (ddev->pHandle != (void *)ptr) + if (base == 10) + ptr = ptr * 10 + val; + else if (base == 16) + ptr = ptr * 16 + val; + else { code = gs_error_rangecheck; + break; + } + } + if (code == 0) { + if (dev->is_open) { + if (ddev->pHandle != (void *)ptr) + code = gs_error_rangecheck; + } + else + ddev->pHandle = (void *)ptr; + } + if (code < 0) { + ecode = code; + param_signal_error(plist, "DisplayHandle", ecode); } - else - ddev->pHandle = (void *)ptr; - } - if (code < 0) { - ecode = code; - param_signal_error(plist, "DisplayHandle", ecode); } } @@ -1249,6 +1278,9 @@ display_spec_op(gx_device *dev, int op, void *data, int datasize) if (op == gxdso_supports_devn) { return (dev_proc(dev, fill_rectangle_hl_color) == display_fill_rectangle_hl_color); } + if (op == gxdso_reopen_after_init) { + return 1; + } return gx_default_dev_spec_op(dev, op, data, datasize); } diff --git a/devices/gdevdsp.h b/devices/gdevdsp.h index b702a8e6b..a96bf023e 100644 --- a/devices/gdevdsp.h +++ b/devices/gdevdsp.h @@ -262,4 +262,27 @@ struct display_callback_v1_s { #define DISPLAY_CALLBACK_V1_SIZEOF sizeof(struct display_callback_v1_s) +#define DISPLAY_CALLOUT_GET_CALLBACK 0 +#define DISPLAY_CALLOUT_GET_CALLBACK_LEGACY 1 + +typedef struct { + display_callback *callback; + void *caller_handle; +} gs_display_get_callback_t; + +/* The display device calls a callout to find the callback structure + * and caller_handle from the environment (the DLL caller/user of the + * API). + * It passes: + * id = DISPLAY_CALLOUT_GET_CALLBACK. + * size = sizeof(gs_display_get_callback_t) (or larger); + * data = pointer to gs_display_get_callback_t instance for callout + * handler to fill in. + * + * In order to support the old gsapi_set_display_callback we have a + * related callout, DISPLAY_CALLOUT_GET_CALLBACK_LEGACY. Do not use + * this! + */ + + #endif /* gdevdsp_INCLUDED */ diff --git a/devices/gdevdsp2.h b/devices/gdevdsp2.h index 021f46e00..6a43c0fe2 100644 --- a/devices/gdevdsp2.h +++ b/devices/gdevdsp2.h @@ -27,6 +27,7 @@ typedef struct gx_device_display_s gx_device_display; gx_device_memory *mdev;\ display_callback *callback;\ void *pHandle;\ + int pHandle_set;\ int nFormat;\ void *pBitmap;\ unsigned long ulBitmapSize;\ diff --git a/doc/API.htm b/doc/API.htm index 92d7e0072..0a4679c4f 100644 --- a/doc/API.htm +++ b/doc/API.htm @@ -68,6 +68,8 @@ <li><a href="#set_poll_with_handle"><code>gsapi_set_poll_with_handle</code></a></li> <li><a href="#set_poll"><code>gsapi_set_poll</code></a></li> <li><a href="#set_display_callback"><code>gsapi_set_display_callback</code></a></li> +<li><a href="#register_callout"><code>gsapi_register_callout</code></a></li> +<li><a href="#deregister_callout"><code>gsapi_deregister_callout</code></a></li> <li><a href="#set_arg_encoding"><code>gsapi_set_arg_encoding</code></a></li> <li><a href="#run"><code>gsapi_run_string_begin</code></a></li> <li><a href="#run"><code>gsapi_run_string_continue</code></a></li> @@ -86,6 +88,8 @@ <li><a href="#add_fs"><code>gsapi_add_fs</code></a></li> <li><a href="#remove_fs"><code>gsapi_remove_fs</code></a></li> <li><a href="#return_codes">Return codes</a></li> +<li><a href="#gsapi_fs_t">gsapi_fs_t</a></li> +<li><a href="#callout">Callouts</a></li> </ul> <li><a href="#Example_usage">Example usage</a></li> <li><a href="#stdio">Standard input and output</a></li> @@ -231,6 +235,18 @@ int <li><code> int +<a href="#register_callout">gsapi_register_callout</a> +(void *instance, gs_callout callout, void *callout_handle); +</code></li> + +<li><code> +void +<a href="#deregister_callout">gsapi_deregister_callout</a> +(void *instance, gs_callout callout, void *callout_handle); +</code></li> + +<li><code> +int <a href="#set_arg_encoding">gsapi_set_arg_encoding</a> (void *instance, int encoding); </code></li> @@ -336,7 +352,7 @@ else { <blockquote> Create a new instance of Ghostscript. This instance is passed to most other gsapi functions. -The caller_handle will be provided to callback functions. +The caller_handle is the default value that will be provided to callback functions. <b>Unless Ghostscript has been compiled with the </code>GS_THREADSAFE</code> define, only one instance at a time is supported.</b> @@ -420,8 +436,14 @@ Otherwise the behaviour of this function matches <h3><a name="set_display_callback"></a><code>gsapi_set_display_callback()</code></h3> <blockquote> +<b>This call is deprecated; please use +<code><a href="#register_callout">gsapi_register_callout</a></code> +to register a <a href="#callout">callout</a> handler for the +<a href="#display">display</a> device in preference.</b> Set the callback structure for the <a href="#display">display</a> -device. If the <a href="#display">display</a> device is used, +device. The handle passed in the callback functions is taken from +the <code>DisplayHandle</code> parameter (or NULL if there is no +such parameter). If the <a href="#display">display</a> device is used, this must be called after <code>gsapi_new_instance()</code> and before <code>gsapi_init_with_args()</code>. @@ -429,6 +451,20 @@ See <code><a href="../base/gdevdsp.h">gdevdsp.h</a></code> for more details. </blockquote> +<h3><a name="register_callout"></a><code>gsapi_register_callout()</code></h3> +<blockquote> +<p>This call registers a <code><a href="#callout">callout</a></code> +handler.</p> +</blockquote> + +<h3><a name="deregister_callout"></a><code>gsapi_deregister_callout()</code></h3> +<blockquote> +<p>This call deregisters a <code><a href="#callout">callout</a></code> handler +previously registered with <code><a href="#register_callout">gsapi_register_callout</a></code>. +All three arguments must match exactly for the callout handler to +be deregistered.</p> +</blockquote> + <h3><a name="set_arg_encoding"></a><code>gsapi_set_arg_encoding()</code></h3> <blockquote> Set the encoding used for the interpretation of all subsequent args @@ -868,6 +904,45 @@ Reopen a stream with a different mode. Behaves like <code>freopen(fname, mode, FILE *)</code>. </dl> +<h3><a name="callout"></a>Callouts</h3> +<blockquote> +<p>Callouts are a mechanism +for the core code (specifically devices) to communicate with the +user of gsapi. This communication can take the form of passing +information out vis-a-vis what devices are doing, or requesting +configuration from the caller to affect exactly how the device +itself works.</p> +<p>This is deliberately an extensible system, so exact details of +callouts should be documented with the device in question. In general +however a callout handler will be of the form:</p> +<pre> +typedef int (*gs_callout)(void *callout_handle, + const char *device_name, + int id, + int size, + void *data); +</pre> +<p>The <code>callout_handle</code> value passed to the callout will +be the value passed in at registration. The <code>device_name</code> +should be a null-terminated string giving the name of the device +(though care should be taken to cope with the case where +<code>device_name</code> is NULL for potential future uses). +The <code>id</code> value will have a (device-specific) meaning; see +the documentation for the device in question for more details. +Finally, <code>size</code> and <code>data</code> have callout +specific meanings, but typically, <code>data</code> will be a pointer +to data block (which may either be uninitialised or wholly/partially +initialised on entry, and may be updated on exit), and <code>size</code> +will be the size (in bytes) of the block pointed to by <code>data</code>. +</p> +<p>A return value of -1 (<code>gs_error_unknownerror</code>) means +the callout was not recognised by the handler, and should be passed +to more handlers. Other negative values are interpreted as standard +Ghostscript error values, and stop the propagation of the callout. +Non-negative return codes mean the callout was handled and should +not be passed to any more registered callout handlers.</p> +</blockquote> + <hr> <h2><a name="Example_usage"></a>Example Usage</h2> <p>To try out the following examples in a development environment like Microsoft's @@ -1097,18 +1172,27 @@ This device provides you with access to the raster output of Ghostscript. It is your responsibility to copy this raster to a display window or printer.</p> <p> -To use this device, you must provide a callback structure -with addresses of a number of callback functions. -The address of the callback structure is provided using -<code>gsapi_set_display_callback()</code>. +In order for this device to operate, it needs access to a structure +containing a set of callback functions, and a callback handle (an +opaque <code>void *</code> that can be used by caller to locate its +own state). There are 2 ways that the device can get this +information, a legacy method, and a modern method. +</p> +<dl> +<dt>Legacy method</dt> +<dd> +<p>The address of the callback structure, is provided +using <code>gsapi_set_display_callback()</code>. This must be called after <code>gsapi_new_instance()</code> and before <code>gsapi_init_with_args()</code>.</p> <p> -The callbacks are for device open, close, resize, sync, page, -memory allocation and updating. -Each callback function contains a handle can be set using</p> +With this call, the callback handle is passed as NULL by default, but can +be overridden by using a parameter. We actively dislike +this way of working, as we consider passing addresses +via the command line distasteful. The handle can be +set using</p> <blockquote> -sDisplayHandle=1234 </blockquote> @@ -1146,6 +1230,31 @@ The previous API, using a number value:</p> is still supported on 32 bit systems, but will cause a "typecheck" error on 64 bit systems, and is considered deprecated. It should not be used in new code.</p> +</dd> +<dt>Modern method +<dd> +<p>The preferred method is to register a callout handler using +<code><a href="#register_callout">gsapi_register_callout</a></code>. +When this handler is called for the <code>"display"</code> +device, with <code>id = 0</code> (= <code>DISPLAY_CALLOUT_GET_CALLBACK</code>), +then <code>data</code> should point to an empty <code>gs_display_get_callback_t</code> +block, with <code>size = sizeof(gs_display_get_callback_t)</code>. +</p> +<pre> +typedef struct { + display_callback *callback; + void *caller_handle; +} gs_display_get_callback_t; +</pre> +<p>The handler should fill in the structure before returning, +with a return code of 0.</p> +</dd> +</dl> +<p> +Note, that the DisplayHandle value is only consulted for +display device callbacks registered using the (legacy, now deprecated) +<code>gsapi_set_display_callback</code> API, not the preferred +<code>gsapi_register_callout</code> based mechanism. <p> The device raster format can be configured using</p> diff --git a/pcl/pl/plapi.c b/pcl/pl/plapi.c index 86588d7ad..ce5559299 100644 --- a/pcl/pl/plapi.c +++ b/pcl/pl/plapi.c @@ -63,6 +63,7 @@ gsapi_new_instance(void **lib, void *caller_handle) } *lib = (void *)(chunk_mem->gs_lib_ctx); + chunk_mem->gs_lib_ctx->core->default_caller_handle = caller_handle; return 0; } @@ -397,3 +398,22 @@ gsapi_remove_fs(void *instance, gsapi_fs_t *fs, void *secret) return; gs_remove_fs(ctx->memory, (gs_fs_t *)fs, secret); } + +GSDLLEXPORT int GSDLLAPI gsapi_register_callout( + void *instance, gs_callout fn, void *handle) +{ + gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance; + if (instance == NULL) + return gs_error_Fatal; + return gs_lib_ctx_register_callout(ctx->memory, fn, handle); +} + +/* Deregister a handler for gs callouts. */ +GSDLLEXPORT void GSDLLAPI gsapi_deregister_callout( + void *instance, gs_callout fn, void *handle) +{ + gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance; + if (instance == NULL) + return; + gs_lib_ctx_deregister_callout(ctx->memory, fn, handle); +} diff --git a/pcl/pl/plapi.h b/pcl/pl/plapi.h index 84118fa26..d59d007ff 100644 --- a/pcl/pl/plapi.h +++ b/pcl/pl/plapi.h @@ -182,10 +182,43 @@ GSDLLEXPORT int GSDLLAPI gsapi_set_poll_with_handle(void *instance, * If the display device is used, this must be called * after gsapi_new_instance() and before gsapi_init_with_args(). * See gdevdisp.h for more details. + * DEPRECATED: Use gsapi_set_display_callback_with_handle instead. */ GSDLLEXPORT int GSDLLAPI gsapi_set_display_callback( void *instance, display_callback *callback); +/* The callout mechanism allows devices to query "callers" (users of the + * DLL) in device specific ways. The callout function pointer type will + * be called with: + * callout_handle = the value given at registration + * device_name = the name of the current device + * id = An integer, guaranteed to be unique within the + * callouts from a given device, identifying the + * purpose of this call. + * size = device/id specific, but typically the size of 'data'. + * data = device/id specific, but typically the pointer to + * an in/out data block. + * Returns an error code (gs_error_unknownerror (-1) if unclaimed, + * non-negative on success, standard gs error numbers recommended). + */ +typedef int (*gs_callout)(void *instance, + void *callout_handle, + const char *device_name, + int id, + int size, + void *data); + +/* Register a handler for gs callouts. + * This must be called after gsapi_new_instance() and (typically) + * before gsapi_init_with_args(). + */ +GSDLLEXPORT int GSDLLAPI gsapi_register_callout( + void *instance, gs_callout callout, void *callout_handle); + +/* Deregister a handler for gs callouts. */ +GSDLLEXPORT void GSDLLAPI gsapi_deregister_callout( + void *instance, gs_callout callout, void *callout_handle); + /* Set the string containing the list of default device names * for example "display x11alpha x11 bbox". Allows the calling * application to influence which device(s) gs will try in order diff --git a/pcl/pl/plmain.c b/pcl/pl/plmain.c index c76d76137..783ac1ed9 100644 --- a/pcl/pl/plmain.c +++ b/pcl/pl/plmain.c @@ -128,7 +128,8 @@ struct pl_main_instance_s pl_interp_implementation_t **implementations; pl_interp_implementation_t *curr_implementation; byte buf[8192]; /* languages read buffer */ - void *disp; /* display device pointer NB wrong - remove */ + void *display; /* display device pointer - to support legacy API. Will + * be removed. */ }; @@ -168,10 +169,50 @@ get_device_index(const gs_memory_t * mem, const char *value) return di; } +static int +legacy_display_callout(void *instance, + void *handle, + const char *dev_name, + int id, + int size, + void *data) +{ + pl_main_instance_t *inst = (pl_main_instance_t *)handle; + + if (dev_name == NULL) + return -1; + if (strcmp(dev_name, "display") != 0) + return -1; + + if (id == DISPLAY_CALLOUT_GET_CALLBACK_LEGACY) { + /* get display callbacks */ + gs_display_get_callback_t *cb = (gs_display_get_callback_t *)data; + cb->callback = inst->display; + return 0; + } + return -1; +} + int pl_main_set_display_callback(pl_main_instance_t *inst, void *callback) { - inst->disp = callback; + int code; + + if (inst->display == NULL && callback != NULL) { + /* First registration. */ + code = gs_lib_ctx_register_callout(inst->memory, + legacy_display_callout, + inst); + if (code < 0) + return code; + } + if (inst->display != NULL && callback == NULL) { + /* Deregistered. */ + gs_lib_ctx_deregister_callout(inst->memory, + legacy_display_callout, + inst); + } + inst->display = callback; return 0; } @@ -816,16 +857,19 @@ pl_top_create_device(pl_main_instance_t * pti, int index) return code; } - /* If the display device is selected (default), set up the callback. NB Move me. */ - if (strcmp(gs_devicename(pti->device), "display") == 0) { - gx_device_display *ddev; - - if (!pti->disp) { - code = -1; - } else { - ddev = (gx_device_display *) pti->device; - ddev->callback = (display_callback *) pti->disp; + if (pti->device->is_open && + dev_proc(pti->device, dev_spec_op)(pti->device, + gxdso_reopen_after_init, + NULL, 0) == 1) { + code = gs_closedevice(pti->device); + if (code < 0) + return code; + code = gs_opendevice(pti->device); + if (code < 0) { + dmprintf(pti->device->memory, + "**** Unable to open the device, quitting.\n"); + return code; } } } diff --git a/psi/gsdll2.def b/psi/gsdll2.def index d69b60c6e..175e22163 100644 --- a/psi/gsdll2.def +++ b/psi/gsdll2.def @@ -18,6 +18,8 @@ EXPORTS gsapi_set_poll gsapi_set_poll_with_handle gsapi_set_display_callback + gsapi_register_callout + gsapi_deregister_callout gsapi_set_arg_encoding gsapi_set_default_device_list gsapi_get_default_device_list diff --git a/psi/gsdll32.def b/psi/gsdll32.def index bef2fe92b..c21b24a8d 100644 --- a/psi/gsdll32.def +++ b/psi/gsdll32.def @@ -30,6 +30,8 @@ EXPORTS gsapi_set_poll gsapi_set_poll_with_handle gsapi_set_display_callback + gsapi_register_callout + gsapi_deregister_callout gsapi_set_arg_encoding gsapi_set_default_device_list gsapi_get_default_device_list diff --git a/psi/gsdll32metro.def b/psi/gsdll32metro.def index 49f38c8b4..4d014e193 100644 --- a/psi/gsdll32metro.def +++ b/psi/gsdll32metro.def @@ -30,6 +30,9 @@ EXPORTS gsapi_set_poll gsapi_set_poll_with_handle gsapi_set_display_callback + gsapi_set_display_callback_with_handle + gsapi_register_callout + gsapi_deregister_callout gsapi_set_arg_encoding gsapi_set_default_device_list gsapi_get_default_device_list diff --git a/psi/gsdll64.def b/psi/gsdll64.def index 44289e923..edc6bb311 100644 --- a/psi/gsdll64.def +++ b/psi/gsdll64.def @@ -30,6 +30,8 @@ EXPORTS gsapi_set_poll gsapi_set_poll_with_handle gsapi_set_display_callback + gsapi_register_callout + gsapi_deregister_callout gsapi_set_arg_encoding gsapi_set_default_device_list gsapi_get_default_device_list diff --git a/psi/gsdll64metro.def b/psi/gsdll64metro.def index cc05cf0bf..9991270fe 100644 --- a/psi/gsdll64metro.def +++ b/psi/gsdll64metro.def @@ -30,6 +30,8 @@ EXPORTS gsapi_set_poll gsapi_set_poll_with_handle gsapi_set_display_callback + gsapi_register_callout + gsapi_deregister_callout gsapi_set_arg_encoding gsapi_set_default_device_list gsapi_get_default_device_list diff --git a/psi/gsdllARM32metro.def b/psi/gsdllARM32metro.def index 0ff322ea0..c54be9a5b 100644 --- a/psi/gsdllARM32metro.def +++ b/psi/gsdllARM32metro.def @@ -30,6 +30,8 @@ EXPORTS gsapi_set_poll gsapi_set_poll_with_handle gsapi_set_display_callback + gsapi_register_callout + gsapi_deregister_callout gsapi_set_arg_encoding gsapi_set_default_device_list gsapi_get_default_device_list diff --git a/psi/iapi.c b/psi/iapi.c index f47fe1531..36d3d0150 100644 --- a/psi/iapi.c +++ b/psi/iapi.c @@ -33,6 +33,7 @@ #include "gslibctx.h" #include "gp.h" #include "gsargs.h" +#include "gdevdsp.h" typedef struct { int a[(int)GS_ARG_ENCODING_LOCAL == (int)PS_ARG_ENCODING_LOCAL ? 1 : -1]; } compile_time_assert_0; typedef struct { int a[(int)GS_ARG_ENCODING_UTF8 == (int)PS_ARG_ENCODING_UTF8 ? 1 : -1]; } compile_time_assert_1; @@ -131,18 +132,77 @@ gsapi_set_poll_with_handle(void *instance, return 0; } +static int +legacy_display_callout(void *instance, + void *handle, + const char *dev_name, + int id, + int size, + void *data) +{ + gs_main_instance *inst = (gs_main_instance *)instance; + + if (dev_name == NULL) + return -1; + if (strcmp(dev_name, "display") != 0) + return -1; + + if (id == DISPLAY_CALLOUT_GET_CALLBACK_LEGACY) { + /* get display callbacks */ + gs_display_get_callback_t *cb = (gs_display_get_callback_t *)data; + cb->callback = inst->display; + return 0; + } + return -1; +} + /* Set the display callback structure */ GSDLLEXPORT int GSDLLAPI gsapi_set_display_callback(void *instance, display_callback *callback) { gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance; + gs_main_instance *minst; + int code; if (instance == NULL) return gs_error_Fatal; - get_minst_from_memory(ctx->memory)->display = callback; + minst = get_minst_from_memory(ctx->memory); + if (minst->display == NULL && callback != NULL) { + /* First registration. */ + code = gs_lib_ctx_register_callout(minst->heap, + legacy_display_callout, + minst); + if (code < 0) + return code; + } + if (minst->display != NULL && callback == NULL) { + /* Deregistered. */ + gs_lib_ctx_deregister_callout(minst->heap, + legacy_display_callout, + minst); + } + minst->display = callback; /* not in a language switched build */ return 0; } +GSDLLEXPORT int GSDLLAPI +gsapi_register_callout(void *instance, gs_callout fn, void *handle) +{ + gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance; + if (instance == NULL) + return gs_error_Fatal; + return gs_lib_ctx_register_callout(ctx->memory, fn, handle); +} + +GSDLLEXPORT void GSDLLAPI +gsapi_deregister_callout(void *instance, gs_callout fn, void *handle) +{ + gs_lib_ctx_t *ctx = (gs_lib_ctx_t *)instance; + if (instance == NULL) + return; + gs_lib_ctx_deregister_callout(ctx->memory, fn, handle); +} + /* Set/Get the default device list string */ GSDLLEXPORT int GSDLLAPI gsapi_set_default_device_list(void *instance, const char *list, int listlen) diff --git a/psi/iapi.h b/psi/iapi.h index 2eb992a4b..605b2f50a 100644 --- a/psi/iapi.h +++ b/psi/iapi.h @@ -226,10 +226,43 @@ GSDLLEXPORT int GSDLLAPI gsapi_set_poll_with_handle(void *instance, * If the display device is used, this must be called * after gsapi_new_instance() and before gsapi_init_with_args(). * See gdevdisp.h for more details. + * DEPRECATED: Use the gsapi_register_callback mechanism instead. */ GSDLLEXPORT int GSDLLAPI gsapi_set_display_callback( void *instance, display_callback *callback); +/* The callout mechanism allows devices to query "callers" (users of the + * DLL) in device specific ways. The callout function pointer type will + * be called with: + * callout_handle = the value given at registration + * device_name = the name of the current device + * id = An integer, guaranteed to be unique within the + * callouts from a given device, identifying the + * purpose of this call. + * size = device/id specific, but typically the size of 'data'. + * data = device/id specific, but typically the pointer to + * an in/out data block. + * Returns an error code (gs_error_unknownerror (-1) if unclaimed, + * non-negative on success, standard gs error numbers recommended). + */ +typedef int (*gs_callout)(void *instance, + void *callout_handle, + const char *device_name, + int id, + int size, + void *data); + +/* Register a handler for gs callouts. + * This must be called after gsapi_new_instance() and (typically) + * before gsapi_init_with_args(). + */ +GSDLLEXPORT int GSDLLAPI gsapi_register_callout( + void *instance, gs_callout callout, void *callout_handle); + +/* Deregister a handler for gs callouts. */ +GSDLLEXPORT void GSDLLAPI gsapi_deregister_callout( + void *instance, gs_callout callout, void *callout_handle); + /* Set the string containing the list of default device names * for example "display x11alpha x11 bbox". Allows the calling * application to influence which device(s) gs will try in order diff --git a/psi/idisp.c b/psi/idisp.c index d1efcbc16..ab8d070cd 100644 --- a/psi/idisp.c +++ b/psi/idisp.c @@ -47,70 +47,36 @@ #include "gsequivc.h" #include "gdevdsp.h" #include "gdevdsp2.h" +#include "gxgstate.h" +#include "gxdevsop.h" int -display_set_callback(gs_main_instance *minst, display_callback *callback) +reopen_device_if_required(gs_main_instance *minst) { i_ctx_t *i_ctx_p; - bool was_open; int code; - int exit_code = 0; - os_ptr op; gx_device *dev; - gx_device_display *ddev; - - /* If display device exists, copy prototype if needed and return - * device true - * If it doesn't exist, return - * false - */ - const char getdisplay[] = - "devicedict /display known dup { /display finddevice exch } if"; - code = gs_main_run_string(minst, getdisplay, 0, &exit_code, - &minst->error_object); - if (code < 0) - return code; i_ctx_p = minst->i_ctx_p; /* run_string may change i_ctx_p if GC */ - op = osp; - check_type(*op, t_boolean); - if (op->value.boolval) { - /* display device was included in Ghostscript so we need - * to set the callback structure pointer within it. - * If the device is already open, close it before - * setting callback, then reopen it. - */ - check_read_type(op[-1], t_device); - if (op[-1].value.pdevice == NULL) - /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ - return_error(gs_error_undefined); - - dev = op[-1].value.pdevice; + dev = gs_currentdevice_inline(i_ctx_p->pgs); + if (dev == NULL) + /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ + return_error(gs_error_undefined); - was_open = dev->is_open; - if (was_open) { - code = gs_closedevice(dev); - if (code < 0) - return code; - } + if (!dev->is_open) + return 0; - ddev = (gx_device_display *) dev; + if (dev_proc(dev, dev_spec_op)(dev, gxdso_reopen_after_init, NULL, 0) != 1) + return 0; - /* Deal with the case where we subclassed the device before we got here */ - while (ddev->child) - ddev = (gx_device_display *)ddev->child; - - ddev->callback = callback; + code = gs_closedevice(dev); + if (code < 0) + return code; - if (was_open) { - code = gs_opendevice(dev); - if (code < 0) { - dmprintf(dev->memory, "**** Unable to open the display device, quitting.\n"); - return code; - } - } - pop(1); /* device */ + code = gs_opendevice(dev); + if (code < 0) { + dmprintf(dev->memory, "**** Unable to reopen the device, quitting.\n"); + return code; } - pop(1); /* boolean */ return 0; } diff --git a/psi/idisp.h b/psi/idisp.h index 4b9eeee94..215d915bd 100644 --- a/psi/idisp.h +++ b/psi/idisp.h @@ -25,7 +25,8 @@ typedef struct display_callback_s display_callback; #endif -/* Called from imain.c to set the display callback in the device instance. */ -int display_set_callback(gs_main_instance *minst, display_callback *callback); +/* Called from imain.c to reopen the device after initialisation if the. + * device requires this. This gives it a chance to refetch any callbacks. */ +int reopen_device_if_required(gs_main_instance *minst); #endif /* idisp_INCLUDED */ diff --git a/psi/imain.c b/psi/imain.c index ed97d06a8..6d012e2a8 100644 --- a/psi/imain.c +++ b/psi/imain.c @@ -306,11 +306,11 @@ int gs_main_init2aux(gs_main_instance * minst) { if (code < 0) return code; minst->init_done = 2; + /* NB this is to be done with device parameters * both minst->display and display_set_callback() are going away */ - if (minst->display) - if ((code = display_set_callback(minst, minst->display)) < 0) + if ((code = reopen_device_if_required(minst)) < 0) return code; if ((code = gs_main_run_string(minst, @@ -344,7 +344,7 @@ gs_main_init2(gs_main_instance * minst) if (code < 0) goto fail; - i_ctx_p = minst->i_ctx_p; /* display_set_callback or run_string may change it */ + i_ctx_p = minst->i_ctx_p; /* reopen_device_if_display or run_string may change it */ /* Now process the initial saved-pages=... argument, if any as well as saved-pages-test */ { diff --git a/psi/int.mak b/psi/int.mak index ec562169d..e6cf79b1e 100644 --- a/psi/int.mak +++ b/psi/int.mak @@ -1897,7 +1897,7 @@ gdevdsp2_h=$(DEVSRCDIR)$(D)gdevdsp2.h $(PSOBJ)idisp.$(OBJ) : $(PSSRC)idisp.c $(OP) $(stdio__h) $(gp_h)\ $(stdpre_h) $(gscdefs_h) $(gsdevice_h) $(gsmemory_h) $(gstypes_h)\ - $(iapi_h) $(iref_h)\ + $(iapi_h) $(iref_h) $(gxgstate_h) $(gxdevsop_h)\ $(imain_h) $(iminst_h) $(idisp_h) $(ostack_h)\ $(gx_h) $(gxdevice_h) $(gxdevmem_h) $(gdevdsp_h) $(gdevdsp2_h)\ $(INT_MAK) $(MAKEDIRS) |