summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/gsdevice.c6
-rw-r--r--base/gslibctx.c68
-rw-r--r--base/gslibctx.h16
-rw-r--r--base/gxdevcli.h3
-rw-r--r--base/gxdevsop.h9
-rw-r--r--devices/gdevdsp.c228
-rw-r--r--devices/gdevdsp.h23
-rw-r--r--devices/gdevdsp2.h1
-rw-r--r--doc/API.htm127
-rw-r--r--pcl/pl/plapi.c20
-rw-r--r--pcl/pl/plapi.h33
-rw-r--r--pcl/pl/plmain.c66
-rw-r--r--psi/gsdll2.def2
-rw-r--r--psi/gsdll32.def2
-rw-r--r--psi/gsdll32metro.def3
-rw-r--r--psi/gsdll64.def2
-rw-r--r--psi/gsdll64metro.def2
-rw-r--r--psi/gsdllARM32metro.def2
-rw-r--r--psi/iapi.c62
-rw-r--r--psi/iapi.h33
-rw-r--r--psi/idisp.c70
-rw-r--r--psi/idisp.h5
-rw-r--r--psi/imain.c6
-rw-r--r--psi/int.mak2
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>&quot;display&quot;</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)