Git init
[framework/uifw/xorg/lib/libxt.git] / src / Initialize.c
1 /***********************************************************
2 Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice (including the next
12 paragraph) shall be included in all copies or substantial portions of the
13 Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 DEALINGS IN THE SOFTWARE.
22
23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                         All Rights Reserved
26
27 Permission to use, copy, modify, and distribute this software and its
28 documentation for any purpose and without fee is hereby granted,
29 provided that the above copyright notice appear in all copies and that
30 both that copyright notice and this permission notice appear in
31 supporting documentation, and that the name of Digital not be
32 used in advertising or publicity pertaining to distribution of the
33 software without specific, written prior permission.
34
35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41 SOFTWARE.
42
43 ******************************************************************/
44
45 /*
46
47 Copyright 1987, 1988, 1994, 1998  The Open Group
48
49 Permission to use, copy, modify, distribute, and sell this software and its
50 documentation for any purpose is hereby granted without fee, provided that
51 the above copyright notice appear in all copies and that both that
52 copyright notice and this permission notice appear in supporting
53 documentation.
54
55 The above copyright notice and this permission notice shall be included in
56 all copies or substantial portions of the Software.
57
58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65 Except as contained in this notice, the name of The Open Group shall not be
66 used in advertising or otherwise to promote the sale, use or other dealings
67 in this Software without prior written authorization from The Open Group.
68
69 */
70
71 /* Make sure all wm properties can make it out of the resource manager */
72
73 #ifdef HAVE_CONFIG_H
74 #include <config.h>
75 #endif
76 #include "IntrinsicI.h"
77 #include "StringDefs.h"
78 #include "CoreP.h"
79 #include "ShellP.h"
80 #include <stdio.h>
81 #include <X11/Xlocale.h>
82 #ifdef XTHREADS
83 #include <X11/Xthreads.h>
84 #endif
85 #ifndef WIN32
86 #define X_INCLUDE_PWD_H
87 #define XOS_USE_XT_LOCKING
88 #include <X11/Xos_r.h>
89 #endif
90
91 #include <stdlib.h>
92
93 #if (defined(SUNSHLIB) || defined(AIXSHLIB)) && defined(SHAREDCODE)
94 /*
95  * If used as a shared library, generate code under a different name so that
96  * the stub routines in sharedlib.c get loaded into the application binary.
97  */
98 #define XtToolkitInitialize _XtToolkitInitialize
99 #define XtOpenApplication _XtOpenApplication
100 #define XtAppInitialize _XtAppInitialize
101 #define XtInitialize _XtInitialize
102 #endif /* (SUNSHLIB || AIXSHLIB) && SHAREDCODE */
103
104 /*
105  * hpux
106  * Hand-patched versions of HP-UX prior to version 7.0 can usefully add
107  * -DUSE_UNAME in the appropriate config file to get long hostnames.
108  */
109
110 #ifdef USG
111 #define USE_UNAME
112 #endif
113
114 #ifdef USE_UNAME
115 #include <sys/utsname.h>
116 #endif
117
118 /* some unspecified magic number of expected search levels for Xrm */
119 #define SEARCH_LIST_SIZE 1000
120
121 /*
122  This is a set of default records describing the command line arguments that
123  Xlib will parse and set into the resource data base.
124
125  This list is applied before the users list to enforce these defaults.  This is
126  policy, which the toolkit avoids but I hate differing programs at this level.
127 */
128
129 static XrmOptionDescRec const opTable[] = {
130 {"+rv",         "*reverseVideo", XrmoptionNoArg,        (XtPointer) "off"},
131 {"+synchronous","*synchronous", XrmoptionNoArg,         (XtPointer) "off"},
132 {"-background", "*background",  XrmoptionSepArg,        (XtPointer) NULL},
133 {"-bd",         "*borderColor", XrmoptionSepArg,        (XtPointer) NULL},
134 {"-bg",         "*background",  XrmoptionSepArg,        (XtPointer) NULL},
135 {"-bordercolor","*borderColor", XrmoptionSepArg,        (XtPointer) NULL},
136 {"-borderwidth",".borderWidth", XrmoptionSepArg,        (XtPointer) NULL},
137 {"-bw",         ".borderWidth", XrmoptionSepArg,        (XtPointer) NULL},
138 {"-display",    ".display",     XrmoptionSepArg,        (XtPointer) NULL},
139 {"-fg",         "*foreground",  XrmoptionSepArg,        (XtPointer) NULL},
140 {"-fn",         "*font",        XrmoptionSepArg,        (XtPointer) NULL},
141 {"-font",       "*font",        XrmoptionSepArg,        (XtPointer) NULL},
142 {"-foreground", "*foreground",  XrmoptionSepArg,        (XtPointer) NULL},
143 {"-geometry",   ".geometry",    XrmoptionSepArg,        (XtPointer) NULL},
144 {"-iconic",     ".iconic",      XrmoptionNoArg,         (XtPointer) "on"},
145 {"-name",       ".name",        XrmoptionSepArg,        (XtPointer) NULL},
146 {"-reverse",    "*reverseVideo", XrmoptionNoArg,        (XtPointer) "on"},
147 {"-rv",         "*reverseVideo", XrmoptionNoArg,        (XtPointer) "on"},
148 {"-selectionTimeout",
149                 ".selectionTimeout", XrmoptionSepArg,   (XtPointer) NULL},
150 {"-synchronous","*synchronous", XrmoptionNoArg,         (XtPointer) "on"},
151 {"-title",      ".title",       XrmoptionSepArg,        (XtPointer) NULL},
152 {"-xnllanguage",".xnlLanguage", XrmoptionSepArg,        (XtPointer) NULL},
153 {"-xrm",        NULL,           XrmoptionResArg,        (XtPointer) NULL},
154 {"-xtsessionID",".sessionID",   XrmoptionSepArg,        (XtPointer) NULL},
155 };
156
157
158 /*
159  * GetHostname - emulates gethostname() on non-bsd systems.
160  */
161
162 static void GetHostname (
163     char *buf,
164     int maxlen)
165 {
166 #ifdef USE_UNAME
167     int len;
168     struct utsname name;
169
170     if (maxlen <= 0 || buf == NULL)
171         return;
172
173     uname (&name);
174     len = strlen (name.nodename);
175     if (len >= maxlen) len = maxlen;
176     (void) strncpy (buf, name.nodename, len-1);
177     buf[len-1] = '\0';
178 #else
179     if (maxlen <= 0 || buf == NULL)
180         return;
181
182     buf[0] = '\0';
183     (void) gethostname (buf, maxlen);
184     buf [maxlen - 1] = '\0';
185 #endif
186 }
187
188
189 #ifdef SUNSHLIB
190 void _XtInherit(void)
191 {
192     extern void __XtInherit();
193     __XtInherit();
194 }
195 #define _XtInherit __XtInherit
196 #endif
197
198
199 #if defined (WIN32) || defined(__CYGWIN__)
200 /*
201  * The Symbol _XtInherit is used in two different manners.
202  * First it could be used as a generic function and second
203  * as an absolute address reference, which will be used to
204  * check the initialisation process of several other libraries.
205  * Because of this the symbol must be accessable by all
206  * client dll's and applications.  In unix environments
207  * this is no problem, because the used shared libraries
208  * format (elf) supports this immediatly.  Under Windows
209  * this isn't true, because a functions address in a dll
210  * is different from the same function in another dll or
211  * applications, because the used Portable Executable
212  * File adds a code stub to each client to provide the
213  * exported symbol name.  This stub uses an indirect
214  * pointer to get the original symbol address, which is
215  * then jumped to, like in this example:
216  *
217  * --- client ---                                     --- dll ----
218  *  ...
219  *  call foo
220  *
221  * foo: jmp (*_imp_foo)               ---->           foo: ....
222  *      nop
223  *      nop
224  *
225  * _imp_foo: .long <index of foo in dll export table, is
226  *                  set to the real address by the runtime linker>
227  *
228  * Now it is clear why the clients symbol foo isn't the same
229  * as in the dll and we can think about how to deal which
230  * this two above mentioned requirements, to export this
231  * symbol to all clients and to allow calling this symbol
232  * as a function.  The solution I've used exports the
233  * symbol _XtInherit as data symbol, because global data
234  * symbols are exported to all clients.  But how to deal
235  * with the second requirement, that this symbol should
236  * be used as function.  The Trick is to build a little
237  * code stub in the data section in the exact manner as
238  * above explained.  This is done with the assembler code
239  * below.
240  *
241  * Ralf Habacker
242  *
243  * References:
244  * msdn          http://msdn.microsoft.com/msdnmag/issues/02/02/PE/PE.asp
245  * cygwin-xfree: http://www.cygwin.com/ml/cygwin-xfree/2003-10/msg00000.html
246  */
247
248 asm (".data\n\
249  .globl __XtInherit        \n\
250  __XtInherit:      jmp *_y \n\
251   _y: .long ___XtInherit   \n\
252     .text                 \n");
253
254 #define _XtInherit __XtInherit
255 #endif
256
257
258 void _XtInherit(void)
259 {
260     XtErrorMsg("invalidProcedure","inheritanceProc",XtCXtToolkitError,
261             "Unresolved inheritance operation",
262               (String *)NULL, (Cardinal *)NULL);
263 }
264
265
266 void XtToolkitInitialize(void)
267 {
268     static Boolean initialized = False;
269
270     LOCK_PROCESS;
271     if (initialized) {
272         UNLOCK_PROCESS;
273         return;
274     }
275     initialized = True;
276     UNLOCK_PROCESS;
277     /* Resource management initialization */
278     XrmInitialize();
279     _XtResourceListInitialize();
280
281     /* Other intrinsic intialization */
282     _XtConvertInitialize();
283     _XtEventInitialize();
284     _XtTranslateInitialize();
285
286     /* Some apps rely on old (broken) XtAppPeekEvent behavior */
287     if(getenv("XTAPPPEEKEVENT_SKIPTIMER"))
288         XtAppPeekEvent_SkipTimer = True;
289     else
290         XtAppPeekEvent_SkipTimer = False;
291 }
292
293
294 String _XtGetUserName(
295     String dest,
296     int len)
297 {
298 #ifdef WIN32
299     String ptr = NULL;
300
301     if ((ptr = getenv("USERNAME"))) {
302         (void) strncpy (dest, ptr, len-1);
303         dest[len-1] = '\0';
304     } else
305         *dest = '\0';
306 #else
307 #ifdef X_NEEDS_PWPARAMS
308     _Xgetpwparams pwparams;
309 #endif
310     struct passwd *pw;
311     char* ptr;
312
313     if ((ptr = getenv("USER"))) {
314         (void) strncpy (dest, ptr, len-1);
315         dest[len-1] = '\0';
316     } else {
317         if ((pw = _XGetpwuid(getuid(),pwparams)) != NULL) {
318             (void) strncpy (dest, pw->pw_name, len-1);
319             dest[len-1] = '\0';
320         } else
321             *dest = '\0';
322     }
323 #endif
324     return dest;
325 }
326
327
328 static String GetRootDirName(
329     String dest,
330     int len)
331 {
332 #ifdef WIN32
333     register char *ptr1;
334     register char *ptr2 = NULL;
335     int len1 = 0, len2 = 0;
336
337     if (ptr1 = getenv("HOME")) {        /* old, deprecated */
338         len1 = strlen (ptr1);
339     } else if ((ptr1 = getenv("HOMEDRIVE")) && (ptr2 = getenv("HOMEDIR"))) {
340         len1 = strlen (ptr1);
341         len2 = strlen (ptr2);
342     } else if (ptr2 = getenv("USERNAME")) {
343         len1 = strlen (ptr1 = "/users/");
344         len2 = strlen (ptr2);
345     }
346     if ((len1 + len2 + 1) < len)
347         sprintf (dest, "%s%s", ptr1, (ptr2) ? ptr2 : "");
348     else
349         *dest = '\0';
350 #else
351 #ifdef X_NEEDS_PWPARAMS
352     _Xgetpwparams pwparams;
353 #endif
354     struct passwd *pw;
355     static char *ptr;
356
357     if (len <= 0 || dest == NULL)
358         return NULL;
359
360     if ((ptr = getenv("HOME"))) {
361         (void) strncpy (dest, ptr, len-1);
362         dest[len-1] = '\0';
363     } else {
364         if ((ptr = getenv("USER")))
365             pw = _XGetpwnam(ptr,pwparams);
366         else
367             pw = _XGetpwuid(getuid(),pwparams);
368         if (pw != NULL) {
369             (void) strncpy (dest, pw->pw_dir, len-1);
370             dest[len-1] = '\0';
371         } else
372             *dest = '\0';
373     }
374 #endif
375     return dest;
376 }
377
378 static void CombineAppUserDefaults(
379     Display *dpy,
380     XrmDatabase *pdb)
381 {
382     char* filename;
383     char* path;
384     Boolean deallocate = False;
385
386     if (!(path = getenv("XUSERFILESEARCHPATH"))) {
387 #if !defined(WIN32) || !defined(__MINGW32__)
388         char *old_path;
389         char homedir[PATH_MAX];
390         GetRootDirName(homedir, PATH_MAX);
391         if (!(old_path = getenv("XAPPLRESDIR"))) {
392             char *path_default = "%s/%%L/%%N%%C:%s/%%l/%%N%%C:%s/%%N%%C:%s/%%L/%%N:%s/%%l/%%N:%s/%%N";
393             if (!(path =
394                   ALLOCATE_LOCAL(6*strlen(homedir) + strlen(path_default))))
395                 _XtAllocError(NULL);
396             sprintf( path, path_default,
397                     homedir, homedir, homedir, homedir, homedir, homedir );
398         } else {
399             char *path_default = "%s/%%L/%%N%%C:%s/%%l/%%N%%C:%s/%%N%%C:%s/%%N%%C:%s/%%L/%%N:%s/%%l/%%N:%s/%%N:%s/%%N";
400             if (!(path =
401                   ALLOCATE_LOCAL( 6*strlen(old_path) + 2*strlen(homedir)
402                                  + strlen(path_default))))
403                 _XtAllocError(NULL);
404             sprintf(path, path_default, old_path, old_path, old_path, homedir,
405                     old_path, old_path, old_path, homedir );
406         }
407         deallocate = True;
408 #endif
409     }
410
411     filename = XtResolvePathname(dpy, NULL, NULL, NULL, path, NULL, 0, NULL);
412     if (filename) {
413         (void)XrmCombineFileDatabase(filename, pdb, False);
414         XtFree(filename);
415     }
416
417     if (deallocate) DEALLOCATE_LOCAL(path);
418 }
419
420 static void CombineUserDefaults(
421     Display *dpy,
422     XrmDatabase *pdb)
423 {
424 #ifdef __MINGW32__
425     char *slashDotXdefaults = "/Xdefaults";
426 #else
427     char *slashDotXdefaults = "/.Xdefaults";
428 #endif
429     char *dpy_defaults = XResourceManagerString(dpy);
430
431     if (dpy_defaults) {
432         XrmCombineDatabase(XrmGetStringDatabase(dpy_defaults), pdb, False);
433     } else {
434         char filename[PATH_MAX];
435         (void) GetRootDirName(filename,
436                         PATH_MAX - strlen (slashDotXdefaults) - 1);
437         (void) strcat(filename, slashDotXdefaults);
438         (void)XrmCombineFileDatabase(filename, pdb, False);
439     }
440 }
441
442 /*ARGSUSED*/
443 static Bool StoreDBEntry(
444     XrmDatabase         *db,
445     XrmBindingList      bindings,
446     XrmQuarkList        quarks,
447     XrmRepresentation   *type,
448     XrmValuePtr         value,
449     XPointer            data)
450 {
451     XrmQPutResource((XrmDatabase *)data, bindings, quarks, *type, value);
452     return False;
453 }
454
455 static XrmDatabase CopyDB(XrmDatabase db)
456 {
457     XrmDatabase copy = NULL;
458     XrmQuark empty = NULLQUARK;
459
460     XrmEnumerateDatabase(db, &empty, &empty, XrmEnumAllLevels,
461                          StoreDBEntry, (XPointer)&copy);
462     return copy;
463 }
464
465 /*ARGSUSED*/
466 static String _XtDefaultLanguageProc(
467     Display   *dpy,     /* unused */
468     String     xnl,
469     XtPointer  closure) /* unused */
470 {
471     if (! setlocale(LC_ALL, xnl))
472         XtWarning("locale not supported by C library, locale unchanged");
473
474     if (! XSupportsLocale()) {
475         XtWarning("locale not supported by Xlib, locale set to C");
476         setlocale(LC_ALL, "C");
477     }
478     if (! XSetLocaleModifiers(""))
479         XtWarning("X locale modifiers not supported, using default");
480
481     return setlocale(LC_ALL, NULL); /* re-query in case overwritten */
482 }
483
484 XtLanguageProc XtSetLanguageProc(
485     XtAppContext      app,
486     XtLanguageProc    proc,
487     XtPointer         closure)
488 {
489     XtLanguageProc    old;
490
491     if (!proc) {
492         proc = _XtDefaultLanguageProc;
493         closure = NULL;
494     }
495
496     if (app) {
497         LOCK_APP(app);
498         LOCK_PROCESS;
499         /* set langProcRec only for this application context */
500         old = app->langProcRec.proc;
501         app->langProcRec.proc = proc;
502         app->langProcRec.closure = closure;
503         UNLOCK_PROCESS;
504         UNLOCK_APP(app);
505     } else {
506         /* set langProcRec for all application contexts */
507         ProcessContext process;
508
509         LOCK_PROCESS;
510         process = _XtGetProcessContext();
511         old = process->globalLangProcRec.proc;
512         process->globalLangProcRec.proc = proc;
513         process->globalLangProcRec.closure = closure;
514         app = process->appContextList;
515         while (app) {
516             app->langProcRec.proc = proc;
517             app->langProcRec.closure = closure;
518             app = app->next;
519         }
520         UNLOCK_PROCESS;
521     }
522     return (old ? old : _XtDefaultLanguageProc);
523 }
524
525 XrmDatabase XtScreenDatabase(
526     Screen *screen)
527 {
528     int scrno;
529     Bool doing_def;
530     XrmDatabase db, olddb;
531     XtPerDisplay pd;
532     Status do_fallback;
533     char *scr_resources;
534     Display *dpy = DisplayOfScreen(screen);
535     DPY_TO_APPCON(dpy);
536
537     LOCK_APP(app);
538     LOCK_PROCESS;
539     if (screen == DefaultScreenOfDisplay(dpy)) {
540         scrno = DefaultScreen(dpy);
541         doing_def = True;
542     } else {
543         scrno = XScreenNumberOfScreen(screen);
544         doing_def = False;
545     }
546     pd = _XtGetPerDisplay(dpy);
547     if ((db = pd->per_screen_db[scrno])) {
548         UNLOCK_PROCESS;
549         UNLOCK_APP(app);
550         return (doing_def ? XrmGetDatabase(dpy) : db);
551     }
552     scr_resources = XScreenResourceString(screen);
553
554     if (ScreenCount(dpy) == 1) {
555         db = pd->cmd_db;
556         pd->cmd_db = NULL;
557     } else {
558         db = CopyDB(pd->cmd_db);
559     }
560     {   /* Environment defaults */
561         char    filenamebuf[PATH_MAX];
562         char    *filename;
563
564         if (!(filename = getenv("XENVIRONMENT"))) {
565             int len;
566 #ifdef __MINGW32__
567             char *slashDotXdefaultsDash = "/Xdefaults-";
568 #else
569             char *slashDotXdefaultsDash = "/.Xdefaults-";
570 #endif
571
572             (void) GetRootDirName(filename = filenamebuf,
573                         PATH_MAX - strlen (slashDotXdefaultsDash) - 1);
574             (void) strcat(filename, slashDotXdefaultsDash);
575             len = strlen(filename);
576             GetHostname (filename+len, PATH_MAX-len);
577         }
578         (void)XrmCombineFileDatabase(filename, &db, False);
579     }
580     if (scr_resources)
581     {   /* Screen defaults */
582         XrmCombineDatabase(XrmGetStringDatabase(scr_resources), &db, False);
583         XFree(scr_resources);
584     }
585     /* Server or host defaults */
586     if (!pd->server_db)
587         CombineUserDefaults(dpy, &db);
588     else {
589         (void) XrmCombineDatabase(pd->server_db, &db, False);
590         pd->server_db = NULL;
591     }
592
593     if (!db)
594         db = XrmGetStringDatabase("");
595     pd->per_screen_db[scrno] = db;
596     olddb = XrmGetDatabase(dpy);
597     /* set database now, for XtResolvePathname to use */
598     XrmSetDatabase(dpy, db);
599     CombineAppUserDefaults(dpy, &db);
600     do_fallback = 1;
601     {   /* System app-defaults */
602         char    *filename;
603
604         if ((filename = XtResolvePathname(dpy, "app-defaults",
605                                          NULL, NULL, NULL, NULL, 0, NULL))) {
606             do_fallback = !XrmCombineFileDatabase(filename, &db, False);
607             XtFree(filename);
608         }
609     }
610     /* now restore old database, if need be */
611     if (!doing_def)
612         XrmSetDatabase(dpy, olddb);
613     if (do_fallback && pd->appContext->fallback_resources)
614     {   /* Fallback defaults */
615         XrmDatabase fdb = NULL;
616         String *res;
617
618         for (res = pd->appContext->fallback_resources; *res; res++)
619             XrmPutLineResource(&fdb, *res);
620         (void)XrmCombineDatabase(fdb, &db, False);
621     }
622     UNLOCK_PROCESS;
623     UNLOCK_APP(app);
624     return db;
625 }
626
627 /*
628  * Merge two option tables, allowing the second to over-ride the first,
629  * so that ambiguous abbreviations can be noticed.  The merge attempts
630  * to make the resulting table lexicographically sorted, but succeeds
631  * only if the first source table is sorted.  Though it _is_ recommended
632  * (for optimizations later in XrmParseCommand), it is not required
633  * that either source table be sorted.
634  *
635  * Caller is responsible for freeing the returned option table.
636  */
637
638 static void _MergeOptionTables(
639     const XrmOptionDescRec *src1,
640     Cardinal num_src1,
641     const XrmOptionDescRec *src2,
642     Cardinal num_src2,
643     XrmOptionDescRec **dst,
644     Cardinal *num_dst)
645 {
646     XrmOptionDescRec *table, *endP;
647     register XrmOptionDescRec *opt1, *whereP, *dstP;
648     register const XrmOptionDescRec *opt2;
649     int i1;
650     Cardinal i2;
651     int dst_len, order;
652     Boolean found;
653     enum {Check, NotSorted, IsSorted} sort_order = Check;
654
655     *dst = table = (XrmOptionDescRec*)
656         __XtMalloc( sizeof(XrmOptionDescRec) * (num_src1 + num_src2) );
657
658     (void) memmove(table, src1, sizeof(XrmOptionDescRec) * num_src1 );
659     if (num_src2 == 0) {
660         *num_dst = num_src1;
661         return;
662     }
663     endP = &table[dst_len = num_src1];
664     for (opt2 = src2, i2= 0; i2 < num_src2; opt2++, i2++) {
665         found = False;
666         whereP = endP-1;        /* assume new option goes at the end */
667         for (opt1 = table, i1 = 0; i1 < dst_len; opt1++, i1++) {
668             /* have to walk the entire new table so new list is ordered
669                (if src1 was ordered) */
670             if (sort_order == Check && i1 > 0
671                 && strcmp(opt1->option, (opt1-1)->option) < 0)
672                 sort_order = NotSorted;
673             if ((order = strcmp(opt1->option, opt2->option)) == 0) {
674                 /* same option names; just overwrite opt1 with opt2 */
675                 *opt1 = *opt2;
676                 found = True;
677                 break;
678                 }
679             /* else */
680             if (sort_order == IsSorted && order > 0) {
681                 /* insert before opt1 to preserve order */
682                 /* shift rest of table forward to make room for new entry */
683                 for (dstP = endP++; dstP > opt1; dstP--)
684                     *dstP = *(dstP-1);
685                 *opt1 = *opt2;
686                 dst_len++;
687                 found = True;
688                 break;
689             }
690             /* else */
691             if (order < 0)
692                 /* opt2 sorts after opt1, so remember this position */
693                 whereP = opt1;
694         }
695         if (sort_order == Check && i1 == dst_len)
696             sort_order = IsSorted;
697         if (!found) {
698            /* when we get here, whereP points to the last entry in the
699               destination that sorts before "opt2".  Shift rest of table
700               forward and insert "opt2" after whereP. */
701             whereP++;
702             for (dstP = endP++; dstP > whereP; dstP--)
703                 *dstP = *(dstP-1);
704             *whereP = *opt2;
705             dst_len++;
706         }
707     }
708     *num_dst = dst_len;
709 }
710
711
712 /* NOTE: name, class, and type must be permanent strings */
713 static Boolean _GetResource(
714     Display *dpy,
715     XrmSearchList list,
716     String name,
717     String class,
718     String type,
719     XrmValue* value)
720 {
721     XrmRepresentation db_type;
722     XrmValue db_value;
723     XrmName Qname = XrmPermStringToQuark(name);
724     XrmClass Qclass = XrmPermStringToQuark(class);
725     XrmRepresentation Qtype = XrmPermStringToQuark(type);
726
727     if (XrmQGetSearchResource(list, Qname, Qclass, &db_type, &db_value)) {
728         if (db_type == Qtype) {
729             if (Qtype == _XtQString)
730                 *(String*)value->addr = db_value.addr;
731             else
732                 (void) memmove(value->addr, db_value.addr, value->size );
733             return True;
734         } else {
735             WidgetRec widget; /* hack, hack */
736             bzero( &widget, sizeof(widget) );
737             widget.core.self = &widget;
738             widget.core.widget_class = coreWidgetClass;
739             widget.core.screen = (Screen*)DefaultScreenOfDisplay(dpy);
740             XtInitializeWidgetClass(coreWidgetClass);
741             if (_XtConvert(&widget,db_type,&db_value,Qtype,value,NULL)) {
742                 return True;
743             }
744         }
745     }
746     return False;
747 }
748
749 XrmDatabase _XtPreparseCommandLine(
750     XrmOptionDescRec *urlist,
751     Cardinal num_urs,
752     int argc,
753     String *argv,
754     /* return */
755     String *applName,
756     String *displayName,
757     String *language)
758 {
759     XrmDatabase db = NULL;
760     XrmOptionDescRec *options;
761     Cardinal num_options;
762     XrmName name_list[3];
763     XrmName class_list[3];
764     XrmRepresentation type;
765     XrmValue val;
766     String *targv;
767     int targc = argc;
768
769     targv = (String *) __XtMalloc(sizeof(char *) * argc);
770     (void) memmove(targv, argv, sizeof(char *) * argc);
771     _MergeOptionTables(opTable, XtNumber(opTable), urlist, num_urs,
772                        &options, &num_options);
773     name_list[0] = class_list[0] = XrmPermStringToQuark(".");
774     name_list[2] = class_list[2] = NULLQUARK;
775     XrmParseCommand(&db, options, num_options, ".", &targc, targv);
776     if (applName) {
777         name_list[1] = XrmPermStringToQuark("name");
778         if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
779             type == _XtQString)
780             *applName = val.addr;
781     }
782     if (displayName) {
783         name_list[1] = XrmPermStringToQuark("display");
784         if (XrmQGetResource(db, name_list, name_list, &type, &val) &&
785             type == _XtQString)
786             *displayName = val.addr;
787     }
788     if (language) {
789         name_list[1] = XrmPermStringToQuark("xnlLanguage");
790         class_list[1] = XrmPermStringToQuark("XnlLanguage");
791         if (XrmQGetResource(db, name_list, class_list, &type, &val) &&
792             type == _XtQString)
793             *language = val.addr;
794     }
795
796     XtFree((char *)targv);
797     XtFree((char *)options);
798     return db;
799 }
800
801
802 static void GetLanguage(
803     Display *dpy,
804     XtPerDisplay pd)
805 {
806     XrmRepresentation type;
807     XrmValue value;
808     XrmName name_list[3];
809     XrmName class_list[3];
810
811     LOCK_PROCESS;
812     if (! pd->language) {
813         name_list[0] = pd->name;
814         name_list[1] = XrmPermStringToQuark("xnlLanguage");
815         class_list[0] = pd->class;
816         class_list[1] = XrmPermStringToQuark("XnlLanguage");
817         name_list[2] = class_list[2] = NULLQUARK;
818         if (!pd->server_db)
819             CombineUserDefaults(dpy, &pd->server_db);
820         if (pd->server_db &&
821             XrmQGetResource(pd->server_db,name_list,class_list, &type, &value)
822             && type == _XtQString)
823             pd->language = (char *) value.addr;
824     }
825
826     if (pd->appContext->langProcRec.proc) {
827         if (! pd->language) pd->language = "";
828         pd->language = (*pd->appContext->langProcRec.proc)
829             (dpy, pd->language, pd->appContext->langProcRec.closure);
830     }
831     else if (! pd->language || pd->language[0] == '\0') /* R4 compatibility */
832         pd->language = getenv("LANG");
833
834     if (pd->language) pd->language = XtNewString(pd->language);
835     UNLOCK_PROCESS;
836 }
837
838 static void ProcessInternalConnection (
839     XtPointer client_data,
840     int* fd,
841     XtInputId* id)
842 {
843     XProcessInternalConnection ((Display *) client_data, *fd);
844 }
845
846 static void ConnectionWatch (
847     Display* dpy,
848     XPointer client_data,
849     int fd,
850     Bool opening,
851     XPointer* watch_data)
852 {
853     XtInputId* iptr;
854     XtAppContext app = XtDisplayToApplicationContext(dpy);
855
856     if (opening) {
857         iptr = (XtInputId *) __XtMalloc(sizeof(XtInputId));
858         *iptr = XtAppAddInput(app, fd, (XtPointer) XtInputReadMask,
859                               ProcessInternalConnection, client_data);
860         *watch_data = (XPointer) iptr;
861     } else {
862         iptr = (XtInputId *) *watch_data;
863         XtRemoveInput(*iptr);
864         (void) XtFree(*watch_data);
865     }
866 }
867
868 void _XtDisplayInitialize(
869         Display *dpy,
870         XtPerDisplay pd,
871         _Xconst char* name,
872         XrmOptionDescRec *urlist,
873         Cardinal num_urs,
874         int *argc,
875         char **argv)
876 {
877         Boolean tmp_bool;
878         XrmValue value;
879         XrmOptionDescRec *options;
880         Cardinal num_options;
881         XrmDatabase db;
882         XrmName name_list[2];
883         XrmClass class_list[2];
884         XrmHashTable* search_list;
885         int search_list_size = SEARCH_LIST_SIZE;
886
887         GetLanguage(dpy, pd);
888
889         /* Parse the command line and remove Xt arguments from argv */
890         _MergeOptionTables( opTable, XtNumber(opTable), urlist, num_urs,
891                             &options, &num_options );
892         XrmParseCommand(&pd->cmd_db, options, num_options, name, argc, argv);
893
894         db = XtScreenDatabase(DefaultScreenOfDisplay(dpy));
895
896         if (!(search_list = (XrmHashTable*)
897                        ALLOCATE_LOCAL( SEARCH_LIST_SIZE*sizeof(XrmHashTable))))
898             _XtAllocError(NULL);
899         name_list[0] = pd->name;
900         class_list[0] = pd->class;
901         name_list[1] = NULLQUARK;
902         class_list[1] = NULLQUARK;
903
904         while (!XrmQGetSearchList(db, name_list, class_list,
905                                   search_list, search_list_size)) {
906             XrmHashTable* old = search_list;
907             Cardinal size = (search_list_size*=2)*sizeof(XrmHashTable);
908             if (!(search_list = (XrmHashTable*)ALLOCATE_LOCAL(size)))
909                 _XtAllocError(NULL);
910             (void) memmove((char*)search_list, (char*)old, (size>>1) );
911             DEALLOCATE_LOCAL(old);
912         }
913
914         value.size = sizeof(tmp_bool);
915         value.addr = (XtPointer)&tmp_bool;
916         if (_GetResource(dpy, search_list, "synchronous", "Synchronous",
917                          XtRBoolean, &value)) {
918             int i;
919             Display **dpyP = pd->appContext->list;
920             pd->appContext->sync = tmp_bool;
921             for (i = pd->appContext->count; i; dpyP++, i--) {
922                 (void) XSynchronize(*dpyP, (Bool)tmp_bool);
923             }
924         } else {
925             (void) XSynchronize(dpy, (Bool)pd->appContext->sync);
926         }
927
928         if (_GetResource(dpy, search_list, "reverseVideo", "ReverseVideo",
929                          XtRBoolean, &value)
930                 && tmp_bool) {
931             pd->rv = True;
932         }
933
934         value.size = sizeof(pd->multi_click_time);
935         value.addr = (XtPointer)&pd->multi_click_time;
936         if (!_GetResource(dpy, search_list,
937                           "multiClickTime", "MultiClickTime",
938                           XtRInt, &value)) {
939             pd->multi_click_time = 200;
940         }
941
942         value.size = sizeof(pd->appContext->selectionTimeout);
943         value.addr = (XtPointer)&pd->appContext->selectionTimeout;
944         (void)_GetResource(dpy, search_list,
945                            "selectionTimeout", "SelectionTimeout",
946                            XtRInt, &value);
947
948 #ifndef NO_IDENTIFY_WINDOWS
949         value.size = sizeof(pd->appContext->identify_windows);
950         value.addr = (XtPointer)&pd->appContext->identify_windows;
951         (void)_GetResource(dpy, search_list,
952                            "xtIdentifyWindows", "XtDebug",
953                            XtRBoolean, &value);
954 #endif
955
956         XAddConnectionWatch(dpy, ConnectionWatch, (XPointer) dpy);
957
958         XtFree( (XtPointer)options );
959         DEALLOCATE_LOCAL( search_list );
960 }
961
962 /*      Function Name: XtAppSetFallbackResources
963  *      Description: Sets the fallback resource list that will be loaded
964  *                   at display initialization time.
965  *      Arguments: app_context - the app context.
966  *                 specification_list - the resource specification list.
967  *      Returns: none.
968  */
969
970 void
971 XtAppSetFallbackResources(
972     XtAppContext app_context,
973     String *specification_list)
974 {
975     LOCK_APP(app_context);
976     app_context->fallback_resources = specification_list;
977     UNLOCK_APP(app_context);
978 }
979
980
981 Widget XtOpenApplication(XtAppContext *app_context_return,
982                          _Xconst char *application_class,
983                          XrmOptionDescRec *options, Cardinal num_options,
984                          int *argc_in_out, String *argv_in_out,
985                          String *fallback_resources, WidgetClass widget_class,
986                          ArgList args_in, Cardinal num_args_in)
987 {
988     XtAppContext app_con;
989     Display * dpy;
990     register int saved_argc = *argc_in_out;
991     Widget root;
992     Arg args[3], *merged_args;
993     Cardinal num = 0;
994
995     XtToolkitInitialize(); /* cannot be moved into _XtAppInit */
996
997     dpy = _XtAppInit(&app_con, (String)application_class, options, num_options,
998                      argc_in_out, &argv_in_out, fallback_resources);
999
1000     LOCK_APP(app_con);
1001     XtSetArg(args[num], XtNscreen, DefaultScreenOfDisplay(dpy)); num++;
1002     XtSetArg(args[num], XtNargc, saved_argc);                    num++;
1003     XtSetArg(args[num], XtNargv, argv_in_out);                   num++;
1004
1005     merged_args = XtMergeArgLists(args_in, num_args_in, args, num);
1006     num += num_args_in;
1007
1008     root = XtAppCreateShell(NULL, application_class, widget_class, dpy,
1009                             merged_args, num);
1010
1011     if (app_context_return)
1012         *app_context_return = app_con;
1013
1014     XtFree((XtPointer)merged_args);
1015     XtFree((XtPointer)argv_in_out);
1016     UNLOCK_APP(app_con);
1017     return root;
1018 }
1019
1020
1021 Widget
1022 XtAppInitialize(
1023     XtAppContext * app_context_return,
1024     _Xconst char* application_class,
1025     XrmOptionDescRec *options,
1026     Cardinal num_options,
1027     int *argc_in_out,
1028     String *argv_in_out,
1029     String *fallback_resources,
1030     ArgList args_in,
1031     Cardinal num_args_in)
1032 {
1033     return XtOpenApplication(app_context_return, application_class,
1034                              options, num_options,
1035                              argc_in_out, argv_in_out, fallback_resources,
1036                              applicationShellWidgetClass,
1037                              args_in, num_args_in);
1038 }
1039
1040
1041 /*ARGSUSED*/
1042 Widget
1043 XtInitialize(
1044     _Xconst char* name,
1045     _Xconst char* classname,
1046     XrmOptionDescRec *options,
1047     Cardinal num_options,
1048     int *argc,
1049     String *argv)
1050 {
1051     Widget root;
1052     XtAppContext app_con;
1053     register ProcessContext process = _XtGetProcessContext();
1054
1055     root = XtAppInitialize(&app_con, classname, options, num_options,
1056                            argc, argv, NULL, NULL, (Cardinal) 0);
1057
1058     LOCK_PROCESS;
1059     process->defaultAppContext = app_con;
1060     UNLOCK_PROCESS;
1061     return root;
1062 }