Merge remote-tracking branch 'origin/master' into for-steve
[sxemacs] / src / ui / X11 / xmu.c
1 /* This file contains compatibility routines for systems without Xmu.
2  * You would be better served by installing Xmu on your machine or
3  * yelling at your vendor to ship it.
4  */
5
6 /* XEmacs changes: rindex -> strrchr */
7
8 /* Synched up with: Not in FSF. */
9
10 #include <config.h>
11
12 #ifndef HAVE_XMU
13 /*
14  * Copyright 1989 Massachusetts Institute of Technology
15  *
16  * Permission to use, copy, modify, and distribute this software and its
17  * documentation for any purpose and without fee is hereby granted, provided
18  * that the above copyright notice appear in all copies and that both that
19  * copyright notice and this permission notice appear in supporting
20  * documentation, and that the name of M.I.T. not be used in advertising
21  * or publicity pertaining to distribution of the software without specific,
22  * written prior permission.  M.I.T. makes no representations about the
23  * suitability of this software for any purpose.  It is provided "as is"
24  * without express or implied warranty.
25  *
26  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
28  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
30  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
31  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32  */
33 #include <X11/cursorfont.h>
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36 #include <X11/Intrinsic.h>
37
38 /* for XmuCopyISOLatin1Lowered */
39 #define XK_LATIN1
40 #include <X11/keysymdef.h>
41 #undef XK_LATIN1
42
43 #if (XtSpecificationRelease >= 5)
44 /*
45  * Don't know why, but this works with X11R5, not X11R4.
46  * Anyway, _XExtension is defined in Xlib.h in X11R4, so we do not need
47  * Xlibint in that case...
48  */
49 #include <X11/Xlibint.h>
50 #endif
51 #include <X11/Xproto.h>
52 #include <stdio.h>
53 #include <ctype.h>
54
55 int XmuCursorNameToIndex(const char *name)
56 {
57         static const struct _CursorName {
58                 const char *name;
59                 unsigned int shape;
60         } cursor_names[] = {
61                 {
62                 "x_cursor", XC_X_cursor}, {
63                 "arrow", XC_arrow}, {
64                 "based_arrow_down", XC_based_arrow_down}, {
65                 "based_arrow_up", XC_based_arrow_up}, {
66                 "boat", XC_boat}, {
67                 "bogosity", XC_bogosity}, {
68                 "bottom_left_corner", XC_bottom_left_corner}, {
69                 "bottom_right_corner", XC_bottom_right_corner}, {
70                 "bottom_side", XC_bottom_side}, {
71                 "bottom_tee", XC_bottom_tee}, {
72                 "box_spiral", XC_box_spiral}, {
73                 "center_ptr", XC_center_ptr}, {
74                 "circle", XC_circle}, {
75                 "clock", XC_clock}, {
76                 "coffee_mug", XC_coffee_mug}, {
77                 "cross", XC_cross}, {
78                 "cross_reverse", XC_cross_reverse}, {
79                 "crosshair", XC_crosshair}, {
80                 "diamond_cross", XC_diamond_cross}, {
81                 "dot", XC_dot}, {
82                 "dotbox", XC_dotbox}, {
83                 "double_arrow", XC_double_arrow}, {
84                 "draft_large", XC_draft_large}, {
85                 "draft_small", XC_draft_small}, {
86                 "draped_box", XC_draped_box}, {
87                 "exchange", XC_exchange}, {
88                 "fleur", XC_fleur}, {
89                 "gobbler", XC_gobbler}, {
90                 "gumby", XC_gumby}, {
91                 "hand1", XC_hand1}, {
92                 "hand2", XC_hand2}, {
93                 "heart", XC_heart}, {
94                 "icon", XC_icon}, {
95                 "iron_cross", XC_iron_cross}, {
96                 "left_ptr", XC_left_ptr}, {
97                 "left_side", XC_left_side}, {
98                 "left_tee", XC_left_tee}, {
99                 "leftbutton", XC_leftbutton}, {
100                 "ll_angle", XC_ll_angle}, {
101                 "lr_angle", XC_lr_angle}, {
102                 "man", XC_man}, {
103                 "middlebutton", XC_middlebutton}, {
104                 "mouse", XC_mouse}, {
105                 "pencil", XC_pencil}, {
106                 "pirate", XC_pirate}, {
107                 "plus", XC_plus}, {
108                 "question_arrow", XC_question_arrow}, {
109                 "right_ptr", XC_right_ptr}, {
110                 "right_side", XC_right_side}, {
111                 "right_tee", XC_right_tee}, {
112                 "rightbutton", XC_rightbutton}, {
113                 "rtl_logo", XC_rtl_logo}, {
114                 "sailboat", XC_sailboat}, {
115                 "sb_down_arrow", XC_sb_down_arrow}, {
116                 "sb_h_double_arrow", XC_sb_h_double_arrow}, {
117                 "sb_left_arrow", XC_sb_left_arrow}, {
118                 "sb_right_arrow", XC_sb_right_arrow}, {
119                 "sb_up_arrow", XC_sb_up_arrow}, {
120                 "sb_v_double_arrow", XC_sb_v_double_arrow}, {
121                 "shuttle", XC_shuttle}, {
122                 "sizing", XC_sizing}, {
123                 "spider", XC_spider}, {
124                 "spraycan", XC_spraycan}, {
125                 "star", XC_star}, {
126                 "target", XC_target}, {
127                 "tcross", XC_tcross}, {
128                 "top_left_arrow", XC_top_left_arrow}, {
129                 "top_left_corner", XC_top_left_corner}, {
130                 "top_right_corner", XC_top_right_corner}, {
131                 "top_side", XC_top_side}, {
132                 "top_tee", XC_top_tee}, {
133                 "trek", XC_trek}, {
134                 "ul_angle", XC_ul_angle}, {
135                 "umbrella", XC_umbrella}, {
136                 "ur_angle", XC_ur_angle}, {
137                 "watch", XC_watch}, {
138         "xterm", XC_xterm},};
139         const struct _CursorName *table;
140         int i;
141         char tmp[40];
142
143         if (strlen(name) >= sizeof tmp)
144                 return -1;
145         for (i = 0; i < strlen(name); i++)
146                 if (isupper((unsigned char)name[i]))
147                         tmp[i] = tolower((unsigned char)name[i]);
148                 else
149                         tmp[i] = name[i];
150         tmp[i] = 0;
151
152         for (i = 0, table = cursor_names; i < XtNumber(cursor_names);
153              i++, table++) {
154                 if (strcmp(tmp, table->name) == 0)
155                         return table->shape;
156         }
157
158         return -1;
159 }
160
161 /*
162  * Based on an optimized version provided by Jim Becker, August 5, 1988.
163  */
164
165 #define MAX_SIZE 255
166
167 /* shared data for the image read/parse logic */
168 static short hexTable[256];     /* conversion value */
169 static int hex_initialized;     /* easier to fill in at run time */
170
171 /*
172  *      Table index for the hex values. Initialized once, first time.
173  *      Used for translation value or delimiter significance lookup.
174  */
175 static void initHexTable(void)
176 {
177         /*
178          * We build the table at run time for several reasons:
179          *
180          *     1.  portable to non-ASCII machines.
181          *     2.  still reentrant since we set the init flag after setting table.
182          *     3.  easier to extend.
183          *     4.  less prone to bugs.
184          */
185         hexTable['0'] = 0;
186         hexTable['1'] = 1;
187         hexTable['2'] = 2;
188         hexTable['3'] = 3;
189         hexTable['4'] = 4;
190         hexTable['5'] = 5;
191         hexTable['6'] = 6;
192         hexTable['7'] = 7;
193         hexTable['8'] = 8;
194         hexTable['9'] = 9;
195         hexTable['A'] = 10;
196         hexTable['B'] = 11;
197         hexTable['C'] = 12;
198         hexTable['D'] = 13;
199         hexTable['E'] = 14;
200         hexTable['F'] = 15;
201         hexTable['a'] = 10;
202         hexTable['b'] = 11;
203         hexTable['c'] = 12;
204         hexTable['d'] = 13;
205         hexTable['e'] = 14;
206         hexTable['f'] = 15;
207
208         /* delimiters of significance are flagged w/ negative value */
209         hexTable[' '] = -1;
210         hexTable[','] = -1;
211         hexTable['}'] = -1;
212         hexTable['\n'] = -1;
213         hexTable['\t'] = -1;
214
215         hex_initialized = 1;
216 }
217
218 /*
219  *      read next hex value in the input stream, return -1 if EOF
220  */
221 static int NextInt(FILE * fstream)
222 {
223         int ch;
224         int value = 0;
225         int gotone = 0;
226         int done = 0;
227
228         /* loop, accumulate hex value until find delimiter  */
229         /* skip any initial delimiters found in read stream */
230
231         while (!done) {
232                 ch = getc(fstream);
233                 if (ch == EOF) {
234                         value = -1;
235                         done++;
236                 } else {
237                         /* trim high bits, check type and accumulate */
238                         ch &= 0xff;
239                         if (isascii(ch) && isxdigit(ch)) {
240                                 value = (value << 4) + hexTable[ch];
241                                 gotone++;
242                         } else if ((hexTable[ch]) < 0 && gotone)
243                                 done++;
244                 }
245         }
246         return value;
247 }
248
249 /*
250  * The data returned by the following routine is always in left-most byte
251  * first and left-most bit first.  If it doesn't return BitmapSuccess then
252  * its arguments won't have been touched.  This routine should look as much
253  * like the Xlib routine XReadBitmapfile as possible.
254  */
255 int XmuReadBitmapData(FILE * fstream,   /* handle on file  */
256                       unsigned int *width,      /* RETURNED */
257                       unsigned int *height,     /* RETURNED */
258                       unsigned char **datap,    /* RETURNED */
259                       int *x_hot, int *y_hot)
260 {                               /* RETURNED */
261         unsigned char *data = NULL;     /* working variable */
262         char line[MAX_SIZE];    /* input line from file */
263         int size;               /* number of bytes of data */
264         char name_and_type[MAX_SIZE];   /* an input line */
265         char *type;             /* for parsing */
266         int value;              /* from an input line */
267         int version10p;         /* boolean, old format */
268         int padding;            /* to handle alignment */
269         int bytes_per_line;     /* per scanline of data */
270         unsigned int ww = 0;    /* width */
271         unsigned int hh = 0;    /* height */
272         int hx = -1;            /* x hotspot */
273         int hy = -1;            /* y hotspot */
274
275 #ifndef Xmalloc
276 #define Xmalloc(size) malloc(size)
277 #endif
278
279         /* first time initialization */
280         if (!hex_initialized)
281                 initHexTable();
282
283         /* error cleanup and return macro   */
284 #define RETURN(code) { if (data) free (data); return code; }
285
286         while (fgets(line, MAX_SIZE, fstream)) {
287                 if (strlen(line) == MAX_SIZE - 1) {
288                         RETURN(BitmapFileInvalid);
289                 }
290                 if (sscanf(line, "#define %s %d", name_and_type, &value) == 2) {
291                         if (!(type = strrchr(name_and_type, '_')))
292                                 type = name_and_type;
293                         else
294                                 type++;
295
296                         if (!strcmp("width", type))
297                                 ww = (unsigned int)value;
298                         if (!strcmp("height", type))
299                                 hh = (unsigned int)value;
300                         if (!strcmp("hot", type)) {
301                                 if (type-- == name_and_type
302                                     || type-- == name_and_type)
303                                         continue;
304                                 if (!strcmp("x_hot", type))
305                                         hx = value;
306                                 if (!strcmp("y_hot", type))
307                                         hy = value;
308                         }
309                         continue;
310                 }
311
312                 if (sscanf(line, "static short %s = {", name_and_type) == 1)
313                         version10p = 1;
314                 else if (sscanf
315                          (line, "static unsigned char %s = {",
316                           name_and_type) == 1)
317                         version10p = 0;
318                 else if (sscanf(line, "static char %s = {", name_and_type) == 1)
319                         version10p = 0;
320                 else
321                         continue;
322
323                 if (!(type = strrchr(name_and_type, '_')))
324                         type = name_and_type;
325                 else
326                         type++;
327
328                 if (strcmp("bits[]", type))
329                         continue;
330
331                 if (!ww || !hh)
332                         RETURN(BitmapFileInvalid);
333
334                 if ((ww % 16) && ((ww % 16) < 9) && version10p)
335                         padding = 1;
336                 else
337                         padding = 0;
338
339                 bytes_per_line = (ww + 7) / 8 + padding;
340
341                 size = bytes_per_line * hh;
342                 data = (unsigned char *)Xmalloc((unsigned int)size);
343                 if (!data)
344                         RETURN(BitmapNoMemory);
345
346                 if (version10p) {
347                         unsigned char *ptr;
348                         int bytes;
349
350                         for (bytes = 0, ptr = data; bytes < size; (bytes += 2)) {
351                                 if ((value = NextInt(fstream)) < 0)
352                                         RETURN(BitmapFileInvalid);
353                                 *(ptr++) = value;
354                                 if (!padding || ((bytes + 2) % bytes_per_line))
355                                         *(ptr++) = value >> 8;
356                         }
357                 } else {
358                         unsigned char *ptr;
359                         int bytes;
360
361                         for (bytes = 0, ptr = data; bytes < size;
362                              bytes++, ptr++) {
363                                 if ((value = NextInt(fstream)) < 0)
364                                         RETURN(BitmapFileInvalid);
365                                 *ptr = value;
366                         }
367                 }
368                 break;
369         }                       /* end while */
370
371         if (data == NULL) {
372                 RETURN(BitmapFileInvalid);
373         }
374
375         *datap = data;
376         data = NULL;
377         *width = ww;
378         *height = hh;
379         if (x_hot)
380                 *x_hot = hx;
381         if (y_hot)
382                 *y_hot = hy;
383
384         RETURN(BitmapSuccess);
385 }
386
387 int XmuReadBitmapDataFromFile(const char *filename,
388                               /* Remaining args are RETURNED */
389                               unsigned int *width,
390                               unsigned int *height,
391                               unsigned char **datap, int *x_hot, int *y_hot)
392 {
393         FILE *fstream;
394         int status;
395
396         if ((fstream = fopen(filename, "r")) == NULL) {
397                 return BitmapOpenFailed;
398         }
399         status = XmuReadBitmapData(fstream, width, height, datap, x_hot, y_hot);
400         fclose(fstream);
401         return status;
402 }
403
404 /*
405  * XmuPrintDefaultErrorMessage - print a nice error that looks like the usual
406  * message.  Return 1 if the caller should consider exiting, else 0.
407  */
408 int XmuPrintDefaultErrorMessage(Display * dpy, XErrorEvent * event, FILE * fp)
409 {
410         char buffer[BUFSIZ];
411         char mesg[BUFSIZ];
412         char number[32];
413         char *mtype = "XlibMessage";
414         _XExtension *ext = (_XExtension *) NULL;
415         XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
416         XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
417         fprintf(fp, "%s:  %s\n  ", mesg, buffer);
418         XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d",
419                               mesg, BUFSIZ);
420         fprintf(fp, mesg, event->request_code);
421         if (event->request_code < 128) {
422                 int sz = snprintf(number, sizeof(number), "%d", event->request_code);
423                 assert(sz >= 0 && sz < sizeof(number));
424                 XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer,
425                                       BUFSIZ);
426         } else {
427                 /* XXX this is non-portable */
428                 for (ext = dpy->ext_procs;
429                      ext && (ext->codes.major_opcode != event->request_code);
430                      ext = ext->next) ;
431                 if (ext) {
432                         strncpy(buffer, ext->name, sizeof(buffer));
433                         buffer[sizeof(buffer)-1] = '\0';
434                 } else
435                         buffer[0] = '\0';
436         }
437         fprintf(fp, " (%s)", buffer);
438         fputs("\n  ", fp);
439 #if (XtSpecificationRelease >= 5)
440         if (event->request_code >= 128) {
441                 XGetErrorDatabaseText(dpy, mtype, "MinorCode",
442                                       "Request Minor code %d", mesg, BUFSIZ);
443                 fprintf(fp, mesg, event->minor_code);
444                 if (ext) {
445                         in sz = snprintf(mesg, sizeof(mesg), "%s.%d", ext->name,
446                                          event->minor_code);
447                         assert(sz >= 0 && sz < sizeof(mesg));
448                         XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer,
449                                               BUFSIZ);
450                         fprintf(fp, " (%s)", buffer);
451                 }
452                 fputs("\n  ", fp);
453         }
454         if (event->error_code >= 128) {
455                 /* let extensions try to print the values */
456                 /* XXX this is non-portable code */
457                 for (ext = dpy->ext_procs; ext; ext = ext->next) {
458                         if (ext->error_values)
459                                 (*ext->error_values) (dpy, event, fp);
460                 }
461                 /* the rest is a fallback, providing a simple default */
462                 /* kludge, try to find the extension that caused it */
463                 buffer[0] = '\0';
464                 for (ext = dpy->ext_procs; ext; ext = ext->next) {
465                         if (ext->error_string)
466                                 (*ext->error_string) (dpy, event->error_code,
467                                                       &ext->codes, buffer,
468                                                       BUFSIZ);
469                         if (buffer[0])
470                                 break;
471                 }
472                 if (buffer[0]) {
473                         int sz = snprintf(buffer, sizeof(buffer), "%s.%d",
474                                           ext->name,
475                                           event->error_code - ext->codes.first_error);
476                         assert(sz >= 0 && sz < sizeof(buffer));
477                 } else
478                         strncpy(buffer, "Value", sizeof(buffer));
479                 XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ);
480                 if (*mesg) {
481                         fprintf(fp, mesg, event->resourceid);
482                         fputs("\n  ", fp);
483                 }
484         } else if ((event->error_code == BadWindow) ||
485                    (event->error_code == BadPixmap) ||
486                    (event->error_code == BadCursor) ||
487                    (event->error_code == BadFont) ||
488                    (event->error_code == BadDrawable) ||
489                    (event->error_code == BadColor) ||
490                    (event->error_code == BadGC) ||
491                    (event->error_code == BadIDChoice) ||
492                    (event->error_code == BadValue) ||
493                    (event->error_code == BadAtom)) {
494                 if (event->error_code == BadValue)
495                         XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
496                                               mesg, BUFSIZ);
497                 else if (event->error_code == BadAtom)
498                         XGetErrorDatabaseText(dpy, mtype, "AtomID",
499                                               "AtomID 0x%x", mesg, BUFSIZ);
500                 else
501                         XGetErrorDatabaseText(dpy, mtype, "ResourceID",
502                                               "ResourceID 0x%x", mesg, BUFSIZ);
503                 fprintf(fp, mesg, event->resourceid);
504                 fputs("\n  ", fp);
505         }
506 #elif (XtSpecificationRelease == 4)
507         XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
508                               mesg, BUFSIZ);
509         fprintf(fp, mesg, event->minor_code);
510         fputs("\n  ", fp);
511         if (ext) {
512                 int sz = snprintf(mesg, sizeof(mesg), "%s.%d", ext->name, event->minor_code);
513                 assert(sz >= 0 && sz < sizeof(mesg));
514                 XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer,
515                                       BUFSIZ);
516                 fprintf(fp, " (%s)", buffer);
517         }
518         XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
519                               mesg, BUFSIZ);
520         fprintf(fp, mesg, event->resourceid);
521         fputs("\n  ", fp);
522 #else
523         ERROR ! Unsupported release of X11
524 #endif
525             XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
526                                   mesg, BUFSIZ);
527         fprintf(fp, mesg, event->serial);
528         fputs("\n  ", fp);
529         XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
530                               mesg, BUFSIZ);
531         fprintf(fp, mesg, NextRequest(dpy) - 1);
532         fputs("\n", fp);
533         if (event->error_code == BadImplementation)
534                 return 0;
535         return 1;
536 }
537
538 /*
539  * XmuSimpleErrorHandler - ignore errors for XQueryTree, XGetWindowAttributes,
540  * and XGetGeometry; print a message for everything else.  In all case, do
541  * not exit.
542  */
543 int XmuSimpleErrorHandler(Display * dpy, XErrorEvent * errorp)
544 {
545         switch (errorp->request_code) {
546         case X_QueryTree:
547         case X_GetWindowAttributes:
548                 if (errorp->error_code == BadWindow)
549                         return 0;
550                 break;
551         case X_GetGeometry:
552                 if (errorp->error_code == BadDrawable)
553                         return 0;
554                 break;
555         }
556         /* got a "real" X error */
557         return XmuPrintDefaultErrorMessage(dpy, errorp, stderr);
558 }
559
560 void XmuCopyISOLatin1Lowered(char *dst, const char *src)
561 {
562         unsigned char *dest = (unsigned char *)dst;
563         unsigned char *source = (unsigned char *)src;
564
565         for (; *source; source++, dest++) {
566                 if ((*source >= XK_A) && (*source <= XK_Z))
567                         *dest = *source + (XK_a - XK_A);
568                 else if ((*source >= XK_Agrave) && (*source <= XK_Odiaeresis))
569                         *dest = *source + (XK_agrave - XK_Agrave);
570                 else if ((*source >= XK_Ooblique) && (*source <= XK_Thorn))
571                         *dest = *source + (XK_oslash - XK_Ooblique);
572                 else
573                         *dest = *source;
574         }
575         *dest = '\0';
576 }
577 #endif                          /* !HAVE_XMU */