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