1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is the X11 print system utilities library.
15
* The Initial Developer of the Original Code is Roland Mainz
16
* <roland.mainz@informatik.med.uni-giessen.de>.
17
* All Rights Reserved.
21
* Alternatively, the contents of this file may be used under the
22
* terms of the GNU General Public License Version 2 or later (the
23
* "GPL"), in which case the provisions of the GPL are applicable
24
* instead of those above. If you wish to allow use of your
25
* version of this file only under the terms of the GPL and not to
26
* allow others to use your version of this file under the MPL,
27
* indicate your decision by deleting the provisions above and
28
* replace them with the notice and other provisions required by
29
* the GPL. If you do not delete the provisions above, a recipient
30
* may use your version of this file under either the MPL or the
34
#include "xprintutil.h"
47
#define strtok_r(s1, s2, x) PL_strtok_r((s1), (s2), (x))
48
#endif /* USE_MOZILLA_TYPES */
50
/* List of tokens which can be used to separate entries in the
51
* $XPSERVERLIST env var */
52
static const char XPServerListSeparators[] = " \t\v\n\r\f";
54
/* conformace only; X11 API does (currrently) not make use of |const|.
55
* If Xlib API gets fixed these macros can be turned into empty
56
* placeholders... (|#define MAKE_STRING_WRITABLE(x)|) :-)
58
#define MAKE_STRING_WRITABLE(str) (((str)?((str) = strdup(str)):0))
59
#define FREE_WRITABLE_STRING(str) free((void *)(str))
60
#define STRING_AS_WRITABLE(str) ((char *)(str))
62
/* Local prototypes */
63
static const char *XpuGetDefaultXpPrintername(void);
64
static const char *XpuGetXpServerList( void );
65
static const char *XpuEnumerateXpAttributeValue( const char *value, void **vcptr );
66
static const char *XpuGetCurrentAttributeGroup( void **vcptr );
67
static void XpuDisposeEnumerateXpAttributeValue( void **vc );
68
static Bool XpuEnumerateMediumSourceSizes( Display *pdpy, XPContext pcontext,
69
const char **tray_name,
70
const char **medium_name, int *mbool,
71
float *ma1, float *ma2, float *ma3, float *ma4,
73
static void XpuDisposeEnumerateMediumSourceSizes( void **vc );
76
** XprintUtil functions start with Xpu
80
int XpuCheckExtension( Display *pdpy )
82
char *display = XDisplayString(pdpy);
86
if( XpQueryVersion(pdpy, &major, &minor) != 0 )
88
XPU_DEBUG_ONLY(printf("XpuCheckExtension: XpQueryVersion '%s' %d %d\n", XPU_NULLXSTR(display), (int)major, (int)minor));
93
XPU_DEBUG_ONLY(printf("XpuCheckExtension: XpQueryVersion '%s' returned 0(=Xprint not supported)\n", XPU_NULLXSTR(display)));
99
/* Get the default printer name from the XPRINTER env var.
100
* If XPRINTER env var is not present looks for PDPRINTER, LPDEST, and
101
* PRINTER (in that order)
102
* See CDE's DtPrintSetupBox(3) manual page, too...
105
const char *XpuGetDefaultXpPrintername(void)
108
/* BUG/TODO: XpPrinter resource needs to be sourced, too... */
109
s = getenv("XPRINTER");
112
s = getenv("PDPRINTER");
115
s = getenv("LPDEST");
118
s = getenv("PRINTER");
126
const char *XpuGetXpServerList( void )
129
/* BUG/TODO: XpServerList resource needs to be sourced first, then append
130
* contents of XPSERVERLIST, then remove duplicates...
132
s = getenv("XPSERVERLIST");
140
Bool XpuXprintServersAvailable( void )
145
* - XpServerList resource needs to be sourced, too...
146
* (see comment for |XpuGetXpServerList|, too)
147
* - There should be some validation whether the server entries
151
* b) available (hard to implement when XOpenDisplay() should be avoided)
153
s = getenv("XPSERVERLIST");
154
/* Check if serverlist is non-empty */
163
/* a valid server name must at least contain the ':'-seperator
164
* and a number (e.g. ":1") */
170
int XpuGetPrinter2( char *printer, char *display, Display **pdpyptr, XPContext *pcontextptr )
175
XPU_DEBUG_ONLY(printf("XpuGetPrinter2: probing display '%s' for '%s'\n", XPU_NULLXSTR(display), XPU_NULLXSTR(printer)));
177
if( (pdpy = XOpenDisplay(display)) != NULL )
179
if( XpuCheckExtension(pdpy) )
184
/* get list of available printers... */
185
list = XpGetPrinterList(pdpy, printer, &list_count);
186
if( list != NULL ) XpFreePrinterList(list);
188
/* ...and check if printer exists... */
189
if( (list != NULL) && (list_count > 0) )
191
if( (pcontext = XpCreateContext(pdpy, printer)) != None )
194
*pcontextptr = pcontext;
198
XPU_DEBUG_ONLY(printf("XpuGetPrinter2: could not create print context for '%s'\n", XPU_NULLXSTR(printer)));
203
XPU_DEBUG_ONLY(printf("display '%s' does not support the Xprint extension\n", XPU_NULLXSTR(display)));
211
XPU_DEBUG_ONLY(printf("could not open display '%s'\n", XPU_NULLXSTR(display)));
217
/* acceps "printer" or "printer@display" */
218
int XpuGetPrinter( const char *arg_printername, Display **pdpyptr, XPContext *pcontextptr )
229
XPU_DEBUG_ONLY(printf("XpuGetPrinter: looking for '%s'\n", XPU_NULLXSTR(arg_printername)));
231
/* strtok_r will modify string - duplicate it first... */
232
printername = strdup(arg_printername);
233
if( printername == NULL )
236
if( (s = strtok_r(printername, "@", &tok_lasts)) != NULL )
239
char *display = strtok_r(NULL, "@", &tok_lasts);
241
/* if we have a display - open it and grab printer */
242
if( display != NULL )
244
if( XpuGetPrinter2(name, display, pdpyptr, pcontextptr) )
250
/* if we did not get a display, travel througth all displays */
253
char *sl = strdup(XpuGetXpServerList());
257
for( display = strtok_r(sl, XPServerListSeparators, &tok_lasts) ;
259
display = strtok_r(NULL, XPServerListSeparators, &tok_lasts) )
261
if( XpuGetPrinter2(name, display, pdpyptr, pcontextptr) )
275
XPU_DEBUG_ONLY(printf("XpuGetPrinter: failure\n"));
281
void XpuClosePrinterDisplay(Display *pdpy, XPContext pcontext)
285
if( pcontext != None )
286
XpDestroyContext(pdpy, pcontext);
292
void XpuSetOneAttribute( Display *pdpy, XPContext pcontext,
293
XPAttributes type, const char *attribute_name, const char *value, XPAttrReplacement replacement_rule )
295
/* Alloc buffer for sprintf() stuff below */
296
char *buffer = (char *)malloc(strlen(attribute_name)+strlen(value)+4);
300
sprintf(buffer, "%s: %s", attribute_name, value);
301
XpSetAttributes(pdpy, pcontext, type, buffer, replacement_rule);
306
void XpuSetOneLongAttribute( Display *pdpy, XPContext pcontext,
307
XPAttributes type, const char *attribute_name, long value, XPAttrReplacement replacement_rule )
309
/* Alloc buffer for sprintf() stuff below */
310
char *buffer = (char *)malloc(strlen(attribute_name)+32+4);
314
sprintf(buffer, "%s: %ld", attribute_name, value);
315
XpSetAttributes(pdpy, pcontext, type, buffer, replacement_rule);
320
/* Check if attribute value is supported or not
321
* Use this function _only_ if XpuGetSupported{Job,Doc,Page}Attributes()
322
* does not help you...
324
int XpuCheckSupported( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name, const char *query )
329
MAKE_STRING_WRITABLE(attribute_name);
330
if( attribute_name == NULL )
333
value = XpGetOneAttribute(pdpy, pcontext, type, STRING_AS_WRITABLE(attribute_name));
335
XPU_DEBUG_ONLY(printf("XpuCheckSupported: XpGetOneAttribute(%s) returned '%s'\n", XPU_NULLXSTR(attribute_name), XPU_NULLXSTR(value)));
337
FREE_WRITABLE_STRING(attribute_name);
343
for( s = XpuEnumerateXpAttributeValue(value, &tok_lasts) ; s != NULL ; s = XpuEnumerateXpAttributeValue(NULL, &tok_lasts) )
345
XPU_DEBUG_ONLY(printf("XpuCheckSupported: probing '%s'=='%s'\n", XPU_NULLXSTR(s), XPU_NULLXSTR(query)));
346
if( !strcmp(s, query) )
349
XpuDisposeEnumerateXpAttributeValue(&tok_lasts);
354
XpuDisposeEnumerateXpAttributeValue(&tok_lasts);
362
int XpuSetJobTitle( Display *pdpy, XPContext pcontext, const char *title )
364
if( XpuGetSupportedJobAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_JOB_NAME )
366
XpuSetOneAttribute(pdpy, pcontext, XPJobAttr, "*job-name", title, XPAttrMerge);
371
XPU_DEBUG_ONLY(printf("XpuSetJobTitle: XPUATTRIBUTESUPPORTED_JOB_NAME not supported ('%s')\n", XPU_NULLXSTR(title)));
376
int XpuGetOneLongAttribute( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name, long *result )
380
MAKE_STRING_WRITABLE(attribute_name);
381
if( attribute_name == NULL )
383
s = XpGetOneAttribute(pdpy, pcontext, type, STRING_AS_WRITABLE(attribute_name));
389
XPU_DEBUG_ONLY(printf("XpuGetOneLongAttribute: '%s' got '%s'\n", XPU_NULLXSTR(attribute_name), XPU_NULLXSTR(s)));
391
tmp = strtol(s, (char **)NULL, 10);
393
if( !(((tmp == 0L) || (tmp == LONG_MIN) || (tmp == LONG_MAX)) &&
394
((errno == ERANGE) || (errno == EINVAL))) )
398
XPU_DEBUG_ONLY(printf("XpuGetOneLongAttribute: result %ld\n", *result));
399
FREE_WRITABLE_STRING(attribute_name);
407
FREE_WRITABLE_STRING(attribute_name);
415
void dumpXpAttributes( Display *pdpy, XPContext pcontext )
418
printf("------------------------------------------------\n");
419
printf("--> Job\n%s\n", s=XpuGetJobAttributes(pdpy, pcontext)); XFree(s);
420
printf("--> Doc\n%s\n", s=XpuGetDocAttributes(pdpy, pcontext)); XFree(s);
421
printf("--> Page\n%s\n", s=XpuGetPageAttributes(pdpy, pcontext)); XFree(s);
422
printf("--> Printer\n%s\n", s=XpuGetPrinterAttributes(pdpy, pcontext)); XFree(s);
423
printf("--> Server\n%s\n", s=XpuGetServerAttributes(pdpy, pcontext)); XFree(s);
424
printf("image resolution %d\n", (int)XpGetImageResolution(pdpy, pcontext));
425
printf("------------------------------------------------\n");
430
typedef struct XpuIsNotifyEventContext_
434
} XpuIsNotifyEventContext;
437
Bool IsXpNotifyEvent( Display *pdpy, XEvent *ev, XPointer arg )
440
XpuIsNotifyEventContext *context = (XpuIsNotifyEventContext *)arg;
441
XPPrintEvent *pev = (XPPrintEvent *)ev;
443
match = pev->type == (context->event_base+XPPrintNotify) &&
444
pev->detail == context->detail;
446
XPU_DEBUG_ONLY(printf("XpuWaitForPrintNotify: %d=IsXpNotifyEvent(%d,%d)\n",
453
void XpuWaitForPrintNotify( Display *pdpy, int xp_event_base, int detail )
456
XpuIsNotifyEventContext matchcontext;
458
matchcontext.event_base = xp_event_base;
459
matchcontext.detail = detail;
460
XIfEvent(pdpy, &dummy, IsXpNotifyEvent, (XPointer)&matchcontext);
464
const char *skip_matching_brackets(const char *start)
466
const char *s = start;
476
case '\0': return(NULL);
477
case '{': level++; break;
478
case '}': level--; break;
487
const char *search_next_space(const char *start)
489
const char *s = start;
507
/* PRIVATE context data for XpuEnumerateXpAttributeValue() */
508
typedef struct _XpuAttributeValueEnumeration
511
size_t original_value_len; /* original length of value */
515
} XpuAttributeValueEnumeration;
518
/* Hacked parser for Xp values and enumerations */
520
const char *XpuEnumerateXpAttributeValue( const char *value, void **vcptr )
522
XpuAttributeValueEnumeration **cptr = (XpuAttributeValueEnumeration **)vcptr;
523
XpuAttributeValueEnumeration *context;
531
XpuAttributeValueEnumeration *e;
532
const char *s = value;
533
Bool isGroup = FALSE;
535
e = (XpuAttributeValueEnumeration *)malloc(sizeof(XpuAttributeValueEnumeration));
539
/* Skip leading '{'. */
540
while(*s=='{' && isGroup==FALSE)
545
/* Skip leading blanks. */
551
/* Read group name. */
557
if(strncmp(tmp, "''", s-tmp) != 0)
559
e->group = strdup(tmp);
560
e->group[s-tmp] = '\0';
564
e->original_value_len = strlen(s);
565
e->value = (char *)malloc(e->original_value_len+4); /* We may look up to three bytes beyond the string */
567
memset(e->value+e->original_value_len+1, 0, 3); /* quad termination */
568
e->start = e->s = e->value;
575
if( !context || !context->s )
578
/* Skip leading blanks, '\'' or '}' */
579
while(isspace(*(context->s)) || *(context->s)=='\'' /*|| *(context->s)=='}'*/ )
582
if( *(context->s) == '\0' )
585
context->start = context->s;
586
if( *(context->start) == '{' )
587
context->s = (char *)skip_matching_brackets(context->start);
589
context->s = (char *)search_next_space(context->start);
591
/* end of string reached ? */
594
*(context->s) = '\0';
598
/* Check if we reached a new attribute group */
599
tmp = context->start;
604
void *prev_cptr = *vcptr;
606
tmp+=2; /* We have 3*'\0' at the end of the string - this is legal! */
611
/* Start the parser again */
613
ret = XpuEnumerateXpAttributeValue(tmp, vcptr);
615
/* Free old context */
616
XpuDisposeEnumerateXpAttributeValue(&prev_cptr);
626
return(context->start);
629
/* Get enumeration group for last string returned by |XpuEnumerateXpAttributeValue|... */
631
const char *XpuGetCurrentAttributeGroup( void **vcptr )
633
XpuAttributeValueEnumeration **cptr = (XpuAttributeValueEnumeration **)vcptr;
639
return((*cptr)->group);
644
void XpuDisposeEnumerateXpAttributeValue( void **vc )
648
XpuAttributeValueEnumeration *context = *((XpuAttributeValueEnumeration **)vc);
649
free(context->value);
651
free(context->group);
656
/* parse a paper size string
657
* (example: '{na-letter False {6.3500 209.5500 6.3500 273.0500}}') */
659
Bool XpuParseMediumSourceSize( const char *value,
660
const char **medium_name, int *mbool,
661
float *ma1, float *ma2, float *ma3, float *ma4 )
669
const char *cur_locale;
671
if( value && value[0]!='{' && value[0]!='\0' )
674
value_len = strlen(value);
676
/* alloc buffer for |medium_name| and |boolbuf| in one step
677
* (both must be large enougth to hold at least |strlen(value)+1| bytes) */
678
name = (char *)malloc(value_len*2 + 4);
679
boolbuf = name + value_len+2; /* |boolbuf| starts directly after |name| */
681
/* remove '{' && '}' */
688
if( *s!='{' && *s!='}' )
696
/* separate medium name from string */
697
d = (char *)search_next_space(name);
706
/* ... continue to parse the remaining string... */
710
/* Force C/POSIX radix for scanf()-parsing (see bug 131831 ("Printing
711
* does not work in de_AT@euro locale")), do the parsing and restore
712
* the original locale.
713
* XXX: This may affect all threads and not only the calling one...
716
#define CUR_LOCALE_SIZE 256
717
char cur_locale[CUR_LOCALE_SIZE+1];
718
strncpy(cur_locale, setlocale(LC_NUMERIC, NULL), CUR_LOCALE_SIZE);
719
cur_locale[CUR_LOCALE_SIZE]='\0';
720
setlocale(LC_NUMERIC, "C");
721
num_input_items = sscanf(d, "%s %f %f %f %f", boolbuf, ma1, ma2, ma3, ma4);
722
setlocale(LC_NUMERIC, cur_locale);
723
#undef CUR_LOCALE_SIZE
726
if( num_input_items != 5 )
732
if( !strcmp(boolbuf, "true") )
734
else if( !strcmp(boolbuf, "false") )
745
/* parse a paper size string
746
* (example: '{na-letter False {6.3500 209.5500 6.3500 273.0500}}') */
748
Bool XpuEnumerateMediumSourceSizes( Display *pdpy, XPContext pcontext,
749
const char **tray_name,
750
const char **medium_name, int *mbool,
751
float *ma1, float *ma2, float *ma3, float *ma4,
754
const char *medium_spec;
755
const char *value = NULL;
757
if( pdpy && pcontext )
759
value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "medium-source-sizes-supported");
766
medium_spec = XpuEnumerateXpAttributeValue(value, vcptr);
770
XFree((void *)value);
774
/* enumeration done? */
778
if (XpuParseMediumSourceSize(medium_spec,
782
*tray_name = XpuGetCurrentAttributeGroup(vcptr);
787
/* Should never ever happen! */
788
fprintf(stderr, "XpuEnumerateMediumSourceSize: error parsing '%s'\n", medium_spec);
795
void XpuDisposeEnumerateMediumSourceSizes( void **vc )
797
XpuDisposeEnumerateXpAttributeValue(vc);
801
/* future: Migrate this functionality into |XpGetPrinterList| - just do
802
* not pass a |Display *| to |XpGetPrinterList|
804
XPPrinterList XpuGetPrinterList( const char *printer, int *res_list_count )
806
XPPrinterRec *rec = NULL;
807
int rec_count = 1; /* Allocate one more |XPPrinterRec| structure
810
const char *default_printer_name = XpuGetDefaultXpPrintername();
811
int default_printer_rec_index = -1;
813
if( !res_list_count )
816
sl = strdup(XpuGetXpServerList());
817
MAKE_STRING_WRITABLE(printer);
824
for( display = strtok_r(sl, XPServerListSeparators, &tok_lasts) ;
826
display = strtok_r(NULL, XPServerListSeparators, &tok_lasts) )
830
if( (pdpy = XOpenDisplay(display)) != NULL )
834
size_t display_len = strlen(display);
836
/* get list of available printers... */
837
list = XpGetPrinterList(pdpy, STRING_AS_WRITABLE(printer), &list_count);
839
if( list && list_count )
843
for( i = 0 ; i < list_count ; i++ )
847
/* Workaround for http://bugzilla.mozilla.org/show_bug.cgi?id=193499
848
* ("Xprint print/print preview crashes Mozilla") where the Solaris
849
* Xprt may create invalid entries (e.g. |XpGetPrinterList| will
850
* return |list[i].name==NULL| due to empty lines in the printer list.
856
rec = (XPPrinterRec *)realloc(rec, sizeof(XPPrinterRec)*rec_count);
857
if( !rec ) /* failure */
860
s = (char *)malloc(strlen(list[i].name)+display_len+4);
861
sprintf(s, "%s@%s", list[i].name, display);
862
rec[rec_count-2].name = s;
863
rec[rec_count-2].desc = (list[i].desc)?(strdup(list[i].desc)):(NULL);
865
/* Test for default printer (if the user set one).*/
866
if( default_printer_name )
868
/* Default_printer_name may either contain the FQPN(=full
869
* qualified printer name ("foo@myhost:5") or just the name
871
if( (!strcmp(list[i].name, default_printer_name)) ||
872
(!strcmp(s, default_printer_name)) )
874
/* Remember index of default printer that we can swap it to
875
* the head of the array below... */
876
default_printer_rec_index = rec_count-2;
881
XpFreePrinterList(list);
893
/* users: DO NOT COUNT ON THIS DETAIL
894
* (this is only to make current impl. of XpuFreePrinterList() easier)
895
* I may remove this implementation detail in a later revision of
898
rec[rec_count-1].name = NULL;
899
rec[rec_count-1].desc = NULL;
907
/* The default printer is always the first one in the printer list... */
908
if( (default_printer_rec_index != -1) && rec )
912
rec[0] = rec[default_printer_rec_index];
913
rec[default_printer_rec_index] = tmp;
916
*res_list_count = rec_count;
917
FREE_WRITABLE_STRING(printer);
922
void XpuFreePrinterList( XPPrinterList list )
926
XPPrinterRec *curr = list;
928
/* See the warning abouve about using this implementation detail for
929
* checking for the list's end... */
930
while( curr->name != NULL )
942
/* Set number of copies to print from this document */
943
int XpuSetDocumentCopies( Display *pdpy, XPContext pcontext, long num_copies )
945
if( XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_COPY_COUNT)
947
XpuSetOneLongAttribute(pdpy, pcontext, XPDocAttr, "*copy-count", num_copies, XPAttrMerge);
952
XPU_DEBUG_ONLY(printf("XpuSetContentOrientation: XPUATTRIBUTESUPPORTED_COPY_COUNT not supported\n"));
959
XpuMediumSourceSizeList XpuGetMediumSourceSizeList( Display *pdpy, XPContext pcontext, int *numEntriesPtr )
961
XpuMediumSourceSizeList list = NULL;
962
int rec_count = 1; /* allocate one more |XpuMediumSourceSizeRec| structure
971
const char *tray_name,
974
const char *default_tray,
976
int default_medium_rec_index = -1;
978
default_tray = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "default-input-tray");
981
fprintf(stderr, "XpuGetMediumSourceSizeList: Internal error, no 'default-input-tray' found.\n");
984
default_medium = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "default-medium");
987
fprintf(stderr, "XpuGetMediumSourceSizeList: Internal error, no 'default-medium' found.\n");
988
XFree((void *)default_tray);
992
for( status = XpuEnumerateMediumSourceSizes(pdpy, pcontext, &tray_name, &medium_name, &mbool,
993
&ma1, &ma2, &ma3, &ma4, &tok_lasts) ;
995
status = XpuEnumerateMediumSourceSizes(NULL, None, &tray_name, &medium_name, &mbool,
996
&ma1, &ma2, &ma3, &ma4, &tok_lasts) )
999
list = (XpuMediumSourceSizeRec *)realloc(list, sizeof(XpuMediumSourceSizeRec)*rec_count);
1003
list[rec_count-2].tray_name = (tray_name)?(strdup(tray_name)):(NULL);
1004
list[rec_count-2].medium_name = strdup(medium_name);
1005
list[rec_count-2].mbool = mbool;
1006
list[rec_count-2].ma1 = ma1;
1007
list[rec_count-2].ma2 = ma2;
1008
list[rec_count-2].ma3 = ma3;
1009
list[rec_count-2].ma4 = ma4;
1011
/* Default medium ? */
1012
if( (!strcmp(medium_name, default_medium)) &&
1013
((tray_name && (*default_tray))?(!strcmp(tray_name, default_tray)):(True)) )
1015
default_medium_rec_index = rec_count-2;
1019
XpuDisposeEnumerateMediumSourceSizes(&tok_lasts);
1023
/* users: DO NOT COUNT ON THIS DETAIL
1024
* (this is only to make current impl. of XpuFreeMediumSourceSizeList() easier)
1025
* I may remove this implementation detail in a later revision of
1027
list[rec_count-1].tray_name = NULL;
1028
list[rec_count-1].medium_name = NULL;
1036
/* Make the default medium always the first item in the list... */
1037
if( (default_medium_rec_index != -1) && list )
1039
XpuMediumSourceSizeRec tmp;
1041
list[0] = list[default_medium_rec_index];
1042
list[default_medium_rec_index] = tmp;
1045
*numEntriesPtr = rec_count;
1049
void XpuFreeMediumSourceSizeList( XpuMediumSourceSizeList list )
1053
XpuMediumSourceSizeRec *curr = list;
1055
/* See the warning abouve about using this implementation detail for
1056
* checking for the list's end... */
1057
while( curr->medium_name != NULL )
1059
if( curr->tray_name)
1060
free((void *)curr->tray_name);
1061
free((void *)curr->medium_name);
1070
int XpuSetMediumSourceSize( Display *pdpy, XPContext pcontext, XPAttributes type, XpuMediumSourceSizeRec *medium_spec )
1072
/* Set the "default-medium" and "*default-input-tray"
1073
* (if |XpuEnumerateMediumSourceSizes| returned one) XPDocAttr's
1074
* attribute and return */
1075
if (medium_spec->tray_name)
1077
XpuSetOneAttribute(pdpy, pcontext, type, "*default-input-tray", medium_spec->tray_name, XPAttrMerge);
1079
XpuSetOneAttribute(pdpy, pcontext, type, "*default-medium", medium_spec->medium_name, XPAttrMerge);
1084
/* Set document medium size */
1085
int XpuSetDocMediumSourceSize( Display *pdpy, XPContext pcontext, XpuMediumSourceSizeRec *medium_spec )
1087
XpuSupportedFlags doc_supported_flags;
1089
doc_supported_flags = XpuGetSupportedDocAttributes(pdpy, pcontext);
1091
if( (doc_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_MEDIUM) == 0 )
1094
if (medium_spec->tray_name)
1096
if( (doc_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_INPUT_TRAY) == 0 )
1100
return XpuSetMediumSourceSize(pdpy, pcontext, XPDocAttr, medium_spec);
1103
/* Set page medium size */
1104
int XpuSetPageMediumSourceSize( Display *pdpy, XPContext pcontext, XpuMediumSourceSizeRec *medium_spec )
1106
XpuSupportedFlags page_supported_flags;
1108
page_supported_flags = XpuGetSupportedPageAttributes(pdpy, pcontext);
1110
if( (page_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_MEDIUM) == 0 )
1113
if (medium_spec->tray_name)
1115
if( (page_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_INPUT_TRAY) == 0 )
1119
return XpuSetMediumSourceSize(pdpy, pcontext, XPPageAttr, medium_spec);
1123
#define ABS(x) ((x)<0?-(x):(x))
1125
#define MORE_OR_LESS_EQUAL(a, b, tolerance) (ABS((a) - (b)) <= (tolerance))
1127
XpuMediumSourceSizeRec *
1128
XpuFindMediumSourceSizeBySize( XpuMediumSourceSizeList mlist, int mlist_count,
1129
float page_width_mm, float page_height_mm, float tolerance )
1132
for( i = 0 ; i < mlist_count ; i++ )
1134
XpuMediumSourceSizeRec *curr = &mlist[i];
1135
float total_width = curr->ma1 + curr->ma2,
1136
total_height = curr->ma3 + curr->ma4;
1138
/* Match width/height*/
1139
if( ((page_width_mm !=-1.f)?(MORE_OR_LESS_EQUAL(total_width, page_width_mm, tolerance)):(True)) &&
1140
((page_height_mm!=-1.f)?(MORE_OR_LESS_EQUAL(total_height, page_height_mm, tolerance)):(True)) )
1149
XpuMediumSourceSizeRec *
1150
XpuFindMediumSourceSizeByBounds( XpuMediumSourceSizeList mlist, int mlist_count,
1151
float m1, float m2, float m3, float m4, float tolerance )
1154
for( i = 0 ; i < mlist_count ; i++ )
1156
XpuMediumSourceSizeRec *curr = &mlist[i];
1159
if( ((m1!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma1, m1, tolerance)):(True)) &&
1160
((m2!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma2, m2, tolerance)):(True)) &&
1161
((m3!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma3, m3, tolerance)):(True)) &&
1162
((m4!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma4, m4, tolerance)):(True)) )
1171
XpuMediumSourceSizeRec *
1172
XpuFindMediumSourceSizeByName( XpuMediumSourceSizeList mlist, int mlist_count,
1173
const char *tray_name, const char *medium_name )
1176
for( i = 0 ; i < mlist_count ; i++ )
1178
XpuMediumSourceSizeRec *curr = &mlist[i];
1180
/* Match by tray name and/or medium name */
1181
if( ((tray_name && curr->tray_name)?(!strcasecmp(curr->tray_name, tray_name)):(tray_name==NULL)) &&
1182
((medium_name)?(!strcasecmp(curr->medium_name, medium_name)):(True)) )
1191
XpuResolutionList XpuGetResolutionList( Display *pdpy, XPContext pcontext, int *numEntriesPtr )
1193
XpuResolutionList list = NULL;
1194
int rec_count = 1; /* Allocate one more |XpuResolutionRec| structure
1199
long default_resolution = -1;
1200
int default_resolution_rec_index = -1;
1202
/* Get default document resolution */
1203
if( XpuGetOneLongAttribute(pdpy, pcontext, XPDocAttr, "default-printer-resolution", &default_resolution) != 1 )
1205
default_resolution = -1;
1208
value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "printer-resolutions-supported");
1211
fprintf(stderr, "XpuGetResolutionList: Internal error, no 'printer-resolutions-supported' XPPrinterAttr found.\n");
1215
for( s = strtok_r(value, " ", &tok_lasts) ;
1217
s = strtok_r(NULL, " ", &tok_lasts) )
1221
tmp = strtol(s, (char **)NULL, 10);
1223
if( ((tmp == 0L) || (tmp == LONG_MIN) || (tmp == LONG_MAX)) &&
1224
((errno == ERANGE) || (errno == EINVAL)) )
1226
fprintf(stderr, "XpuGetResolutionList: Internal parser errror for '%s'.\n", s);
1231
list = (XpuResolutionRec *)realloc(list, sizeof(XpuResolutionRec)*rec_count);
1235
list[rec_count-2].dpi = tmp;
1237
if( default_resolution != -1 )
1239
/* Is this the default resolution ? */
1240
if( list[rec_count-2].dpi == default_resolution )
1242
default_resolution_rec_index = rec_count-2;
1251
/* users: DO NOT COUNT ON THIS DETAIL
1252
* (this is only to make current impl. of XpuFreeMediumSourceSizeList() easier)
1253
* I may remove this implementation detail in a later revision of
1255
list[rec_count-1].dpi = -1;
1263
/* Make the default resolution always the first item in the list... */
1264
if( (default_resolution_rec_index != -1) && list )
1266
XpuResolutionRec tmp;
1268
list[0] = list[default_resolution_rec_index];
1269
list[default_resolution_rec_index] = tmp;
1272
*numEntriesPtr = rec_count;
1276
void XpuFreeResolutionList( XpuResolutionList list )
1284
/* Find resolution in resolution list.
1285
* Lower resolutions are preferred over larger resolution if |dpi_a| <= |dpi_b|,
1286
* otherwise larger resolutions are preferred over small resolutions
1288
XpuResolutionRec *XpuFindResolution( XpuResolutionList list, int list_count, long dpi_a, long dpi_b )
1290
XpuResolutionRec *match = NULL;
1293
if( dpi_a <= dpi_b )
1295
/* Search list, lower resolutions are better... */
1296
for( i = 0 ; i < list_count ; i++ )
1298
XpuResolutionRec *curr = &list[i];
1300
if( curr->dpi >= dpi_a && curr->dpi <= dpi_b )
1302
if( !match || (curr->dpi < match->dpi) )
1311
/* Search list, higher resolutions are better... */
1312
for( i = 0 ; i < list_count ; i++ )
1314
XpuResolutionRec *curr = &list[i];
1316
if( curr->dpi >= dpi_b && curr->dpi <= dpi_a )
1318
if( !match || (curr->dpi > match->dpi) )
1329
/* Get default page (if defined) or document resolution
1330
* this function may fail in the following conditions:
1331
* - No default resolution set yet
1332
* - X DPI != Y DPI (not yet implemented in Xprt)
1334
Bool XpuGetResolution( Display *pdpy, XPContext pcontext, long *dpi_ptr )
1336
/* Try to get the current page's resolution (pages may differ in resolution if the DDX supports this) */
1337
if( XpuGetOneLongAttribute(pdpy, pcontext, XPPageAttr, "default-printer-resolution", dpi_ptr) == 1 )
1342
/* Get document resolution */
1343
if( XpuGetOneLongAttribute(pdpy, pcontext, XPDocAttr, "default-printer-resolution", dpi_ptr) == 1 )
1352
int XpuSetResolution( Display *pdpy, XPContext pcontext, XPAttributes type, XpuResolutionRec *rec )
1354
XpuSetOneLongAttribute(pdpy, pcontext, type, "*default-printer-resolution", rec->dpi, XPAttrMerge);
1358
/* Set document resolution
1359
* Retun error if printer does not support setting a resolution
1361
int XpuSetDocResolution( Display *pdpy, XPContext pcontext, XpuResolutionRec *rec )
1363
if( (XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_DEFAULT_PRINTER_RESOLUTION) == 0 )
1366
return XpuSetResolution(pdpy, pcontext, XPDocAttr, rec);
1369
/* Set page medium size
1370
* Retun error if printer does not support setting a resolution or if per-page
1371
* resolution changes are not allowed.
1373
int XpuSetPageResolution( Display *pdpy, XPContext pcontext, XpuResolutionRec *rec )
1375
if( (XpuGetSupportedPageAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_DEFAULT_PRINTER_RESOLUTION) == 0 )
1378
return XpuSetResolution(pdpy, pcontext, XPPageAttr, rec);
1381
XpuOrientationList XpuGetOrientationList( Display *pdpy, XPContext pcontext, int *numEntriesPtr )
1383
XpuOrientationList list = NULL;
1384
int rec_count = 1; /* Allocate one more |XpuOrientationRec|
1385
* structure as terminator */
1389
const char *default_orientation = NULL;
1390
int default_orientation_rec_index = -1;
1392
/* Get default document orientation */
1393
default_orientation = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "content-orientation");
1394
if( !default_orientation )
1396
fprintf(stderr, "XpuGetOrientationList: Internal error, no 'content-orientation' XPDocAttr found.\n");
1400
value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "content-orientations-supported");
1403
fprintf(stderr, "XpuGetOrientationList: Internal error, no 'content-orientations-supported' XPPrinterAttr found.\n");
1407
for( s = strtok_r(value, " ", &tok_lasts) ;
1409
s = strtok_r(NULL, " ", &tok_lasts) )
1412
list = (XpuOrientationRec *)realloc(list, sizeof(XpuOrientationRec)*rec_count);
1416
list[rec_count-2].orientation = strdup(s);
1418
/* Default resolution ? */
1419
if( !strcmp(list[rec_count-2].orientation, default_orientation) )
1421
default_orientation_rec_index = rec_count-2;
1426
XFree((void *)default_orientation);
1430
/* users: DO NOT COUNT ON THIS DETAIL
1431
* (this is only to make current impl. of XpuFreeOrientationList() easier)
1432
* I may remove this implementation detail in a later revision of
1434
list[rec_count-1].orientation = NULL;
1442
/* Make the default orientation always the first item in the list... */
1443
if( (default_orientation_rec_index != -1) && list )
1445
XpuOrientationRec tmp;
1447
list[0] = list[default_orientation_rec_index];
1448
list[default_orientation_rec_index] = tmp;
1451
*numEntriesPtr = rec_count;
1455
void XpuFreeOrientationList( XpuOrientationList list )
1459
XpuOrientationRec *curr = list;
1461
/* See the warning abouve about using this implementation detail for
1462
* checking for the list's end... */
1463
while( curr->orientation != NULL )
1465
free((void *)curr->orientation);
1473
XpuFindOrientationByName( XpuOrientationList list, int list_count, const char *orientation )
1477
for( i = 0 ; i < list_count ; i++ )
1479
XpuOrientationRec *curr = &list[i];
1480
if (!strcasecmp(curr->orientation, orientation))
1488
int XpuSetOrientation( Display *pdpy, XPContext pcontext, XPAttributes type, XpuOrientationRec *rec )
1490
XpuSetOneAttribute(pdpy, pcontext, type, "*content-orientation", rec->orientation, XPAttrMerge);
1494
/* Set document orientation
1495
* Retun error if printer does not support setting an orientation
1497
int XpuSetDocOrientation( Display *pdpy, XPContext pcontext, XpuOrientationRec *rec )
1499
if( (XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_CONTENT_ORIENTATION) == 0 )
1502
return XpuSetOrientation(pdpy, pcontext, XPDocAttr, rec);
1505
/* Set page orientation
1506
* Retun error if printer does not support setting an orientation or if
1507
* per-page orientations changes are not allowed
1509
int XpuSetPageOrientation( Display *pdpy, XPContext pcontext, XpuOrientationRec *rec )
1511
if( (XpuGetSupportedPageAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_CONTENT_ORIENTATION) == 0 )
1514
return XpuSetOrientation(pdpy, pcontext, XPPageAttr, rec);
1517
XpuPlexList XpuGetPlexList( Display *pdpy, XPContext pcontext, int *numEntriesPtr )
1519
XpuPlexList list = NULL;
1520
int rec_count = 1; /* Allocate one more |XpuPlexList| structure
1525
const char *default_plex = NULL;
1526
int default_plex_rec_index = -1;
1528
/* Get default document plex */
1529
default_plex = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "plex");
1532
fprintf(stderr, "XpuGetPlexList: Internal error, no 'plex' XPDocAttr found.\n");
1536
value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "plexes-supported");
1539
fprintf(stderr, "XpuGetPlexList: Internal error, no 'plexes-supported' XPPrinterAttr found.\n");
1543
for( s = strtok_r(value, " ", &tok_lasts) ;
1545
s = strtok_r(NULL, " ", &tok_lasts) )
1548
list = (XpuPlexRec *)realloc(list, sizeof(XpuPlexRec)*rec_count);
1552
list[rec_count-2].plex = strdup(s);
1554
/* Default plex ? */
1555
if( !strcmp(list[rec_count-2].plex, default_plex) )
1557
default_plex_rec_index = rec_count-2;
1562
XFree((void *)default_plex);
1566
/* users: DO NOT COUNT ON THIS DETAIL
1567
* (this is only to make current impl. of XpuFreePlexList() easier)
1568
* I may remove this implementation detail in a later revision of
1570
list[rec_count-1].plex = NULL;
1578
/* Make the default plex always the first item in the list... */
1579
if( (default_plex_rec_index != -1) && list )
1583
list[0] = list[default_plex_rec_index];
1584
list[default_plex_rec_index] = tmp;
1587
*numEntriesPtr = rec_count;
1591
void XpuFreePlexList( XpuPlexList list )
1595
XpuPlexRec *curr = list;
1597
/* See the warning abouve about using this implementation detail for
1598
* checking for the list's end... */
1599
while( curr->plex != NULL )
1601
free((void *)curr->plex);
1609
XpuFindPlexByName( XpuPlexList list, int list_count, const char *plex )
1613
for( i = 0 ; i < list_count ; i++ )
1615
XpuPlexRec *curr = &list[i];
1616
if (!strcasecmp(curr->plex, plex))
1624
int XpuSetContentPlex( Display *pdpy, XPContext pcontext, XPAttributes type, XpuPlexRec *rec )
1626
XpuSetOneAttribute(pdpy, pcontext, type, "*plex", rec->plex, XPAttrMerge);
1630
/* Set document plex
1631
* Retun error if printer does not support setting an plex
1633
int XpuSetDocPlex( Display *pdpy, XPContext pcontext, XpuPlexRec *rec )
1635
if( (XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_PLEX) == 0 )
1638
return XpuSetContentPlex(pdpy, pcontext, XPDocAttr, rec);
1642
* Retun error if printer does not support setting an plex or if
1643
* per-page plex changes are not allowed
1645
int XpuSetPagePlex( Display *pdpy, XPContext pcontext, XpuPlexRec *rec )
1647
if( (XpuGetSupportedPageAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_PLEX) == 0 )
1650
return XpuSetContentPlex(pdpy, pcontext, XPPageAttr, rec);
1654
/* Return flags to indicate which attributes are supported and which not... */
1656
XpuSupportedFlags XpuGetSupportedAttributes( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name )
1660
XpuSupportedFlags flags = 0;
1662
MAKE_STRING_WRITABLE(attribute_name);
1663
if( attribute_name == NULL )
1666
value = XpGetOneAttribute(pdpy, pcontext, type, STRING_AS_WRITABLE(attribute_name));
1668
FREE_WRITABLE_STRING(attribute_name);
1674
for( s = XpuEnumerateXpAttributeValue(value, &tok_lasts) ; s != NULL ; s = XpuEnumerateXpAttributeValue(NULL, &tok_lasts) )
1676
if( !strcmp(s, "job-name") ) flags |= XPUATTRIBUTESUPPORTED_JOB_NAME;
1677
else if( !strcmp(s, "job-owner") ) flags |= XPUATTRIBUTESUPPORTED_JOB_OWNER;
1678
else if( !strcmp(s, "notification-profile") ) flags |= XPUATTRIBUTESUPPORTED_NOTIFICATION_PROFILE;
1679
else if( !strcmp(s, "copy-count") ) flags |= XPUATTRIBUTESUPPORTED_COPY_COUNT;
1680
else if( !strcmp(s, "document-format") ) flags |= XPUATTRIBUTESUPPORTED_DOCUMENT_FORMAT;
1681
else if( !strcmp(s, "content-orientation") ) flags |= XPUATTRIBUTESUPPORTED_CONTENT_ORIENTATION;
1682
else if( !strcmp(s, "default-printer-resolution") ) flags |= XPUATTRIBUTESUPPORTED_DEFAULT_PRINTER_RESOLUTION;
1683
else if( !strcmp(s, "default-input-tray") ) flags |= XPUATTRIBUTESUPPORTED_DEFAULT_INPUT_TRAY;
1684
else if( !strcmp(s, "default-medium") ) flags |= XPUATTRIBUTESUPPORTED_DEFAULT_MEDIUM;
1685
else if( !strcmp(s, "plex") ) flags |= XPUATTRIBUTESUPPORTED_PLEX;
1688
XpuDisposeEnumerateXpAttributeValue(&tok_lasts);
1695
XpuSupportedFlags XpuGetSupportedJobAttributes(Display *pdpy, XPContext pcontext)
1697
return XpuGetSupportedAttributes(pdpy, pcontext, XPPrinterAttr, "job-attributes-supported");
1700
XpuSupportedFlags XpuGetSupportedDocAttributes(Display *pdpy, XPContext pcontext)
1702
return XpuGetSupportedAttributes(pdpy, pcontext, XPPrinterAttr, "document-attributes-supported");
1705
XpuSupportedFlags XpuGetSupportedPageAttributes(Display *pdpy, XPContext pcontext)
1707
return XpuGetSupportedAttributes(pdpy, pcontext, XPPrinterAttr, "xp-page-attributes-supported");