1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                        All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1998  The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in this Software without prior written authorization from The Open Group.
68
69*/
70
71#ifdef HAVE_CONFIG_H
72#include <config.h>
73#endif
74#include "IntrinsicI.h"
75#ifndef X_NO_RESOURCE_CONFIGURATION_MANAGEMENT
76#include "ResConfigP.h"
77#endif
78
79#include <stdlib.h>
80
81#ifdef XTHREADS
82void (*_XtProcessLock) (void) = NULL;
83void (*_XtProcessUnlock) (void) = NULL;
84void (*_XtInitAppLock) (XtAppContext) = NULL;
85#endif
86
87static _Xconst _XtString XtNnoPerDisplay = "noPerDisplay";
88
89ProcessContext
90_XtGetProcessContext(void)
91{
92    static ProcessContextRec processContextRec = {
93        (XtAppContext) NULL,
94        (XtAppContext) NULL,
95        (ConverterTable) NULL,
96        {(XtLanguageProc) NULL, (XtPointer) NULL}
97    };
98
99    return &processContextRec;
100}
101
102XtAppContext
103_XtDefaultAppContext(void)
104{
105    ProcessContext process = _XtGetProcessContext();
106    XtAppContext app;
107
108    LOCK_PROCESS;
109    if (process->defaultAppContext == NULL) {
110        process->defaultAppContext = XtCreateApplicationContext();
111    }
112    app = process->defaultAppContext;
113    UNLOCK_PROCESS;
114    return app;
115}
116
117static void
118AddToAppContext(Display *d, XtAppContext app)
119{
120#define DISPLAYS_TO_ADD 4
121
122    if (app->count >= app->max) {
123        app->max = (short) (app->max + DISPLAYS_TO_ADD);
124        app->list = XtReallocArray(app->list,
125                                   (Cardinal) app->max,
126                                   (Cardinal) sizeof(Display *));
127    }
128
129    app->list[app->count++] = d;
130    app->rebuild_fdlist = TRUE;
131#ifdef USE_POLL
132    app->fds.nfds++;
133#else
134    if (ConnectionNumber(d) + 1 > app->fds.nfds) {
135        app->fds.nfds = ConnectionNumber(d) + 1;
136    }
137#endif
138#undef DISPLAYS_TO_ADD
139}
140
141static void
142XtDeleteFromAppContext(const Display *d, register XtAppContext app)
143{
144    register int i;
145
146    for (i = 0; i < app->count; i++)
147        if (app->list[i] == d)
148            break;
149
150    if (i < app->count) {
151        if (i <= app->last && app->last > 0)
152            app->last--;
153        for (i++; i < app->count; i++)
154            app->list[i - 1] = app->list[i];
155        app->count--;
156    }
157    app->rebuild_fdlist = TRUE;
158#ifdef USE_POLL
159    app->fds.nfds--;
160#else
161    if ((ConnectionNumber(d) + 1) == app->fds.nfds)
162        app->fds.nfds--;
163    else                        /* Unnecessary, just to be fool-proof */
164        FD_CLR(ConnectionNumber(d), &app->fds.rmask);
165#endif
166}
167
168static XtPerDisplay
169NewPerDisplay(Display *dpy)
170{
171    PerDisplayTablePtr pd;
172
173    pd = XtNew(PerDisplayTable);
174
175    LOCK_PROCESS;
176    pd->dpy = dpy;
177    pd->next = _XtperDisplayList;
178    _XtperDisplayList = pd;
179    UNLOCK_PROCESS;
180    return &(pd->perDpy);
181}
182
183static XtPerDisplay
184InitPerDisplay(Display *dpy,
185               XtAppContext app,
186               _Xconst char *name,
187               _Xconst char *classname)
188{
189    XtPerDisplay pd;
190
191    AddToAppContext(dpy, app);
192
193    pd = NewPerDisplay(dpy);
194    _XtHeapInit(&pd->heap);
195    pd->destroy_callbacks = NULL;
196    pd->region = XCreateRegion();
197    pd->case_cvt = NULL;
198    pd->defaultKeycodeTranslator = XtTranslateKey;
199    pd->keysyms_serial = 0;
200    pd->keysyms = NULL;
201    XDisplayKeycodes(dpy, &pd->min_keycode, &pd->max_keycode);
202    pd->modKeysyms = NULL;
203    pd->modsToKeysyms = NULL;
204    pd->appContext = app;
205    pd->name = XrmStringToName(name);
206    pd->class = XrmStringToClass(classname);
207    pd->being_destroyed = False;
208    pd->GClist = NULL;
209    pd->pixmap_tab = NULL;
210    pd->language = NULL;
211    pd->rv = False;
212    pd->last_event.xany.serial = 0;
213    pd->last_timestamp = 0;
214    _XtAllocTMContext(pd);
215    pd->mapping_callbacks = NULL;
216
217    pd->pdi.grabList = NULL;
218    pd->pdi.trace = NULL;
219    pd->pdi.traceDepth = 0;
220    pd->pdi.traceMax = 0;
221    pd->pdi.focusWidget = NULL;
222    pd->pdi.activatingKey = 0;
223    pd->pdi.keyboard.grabType = XtNoServerGrab;
224    pd->pdi.pointer.grabType = XtNoServerGrab;
225
226    _XtAllocWWTable(pd);
227    pd->per_screen_db = (XrmDatabase *) __XtCalloc((Cardinal) ScreenCount(dpy),
228                                                   (Cardinal)
229                                                   sizeof(XrmDatabase));
230    pd->cmd_db = (XrmDatabase) NULL;
231    pd->server_db = (XrmDatabase) NULL;
232    pd->dispatcher_list = NULL;
233    pd->ext_select_list = NULL;
234    pd->ext_select_count = 0;
235    pd->hook_object = NULL;
236#if 0
237    pd->hook_object = _XtCreate("hooks", "Hooks", hookObjectClass,
238                                (Widget) NULL,
239                                (Screen *) DefaultScreenOfDisplay(dpy),
240                                (ArgList) NULL, 0, (XtTypedArgList) NULL, 0,
241                                (ConstraintWidgetClass) NULL);
242#endif
243
244#ifndef X_NO_RESOURCE_CONFIGURATION_MANAGEMENT
245    pd->rcm_init = XInternAtom(dpy, RCM_INIT, 0);
246    pd->rcm_data = XInternAtom(dpy, RCM_DATA, 0);
247#endif
248
249    return pd;
250}
251
252#define THIS_FUNC "XtOpenDisplay"
253Display *
254XtOpenDisplay(XtAppContext app,
255              _Xconst _XtString displayName,
256              _Xconst _XtString applName,
257              _Xconst _XtString className,
258              XrmOptionDescRec *urlist,
259              Cardinal num_urs,
260              int *argc,
261              _XtString *argv)
262{
263    Display *d;
264    XrmDatabase db = NULL;
265    String language = NULL;
266
267    LOCK_APP(app);
268    LOCK_PROCESS;
269    /* parse the command line for name, display, and/or language */
270    db = _XtPreparseCommandLine(urlist, num_urs, *argc, argv,
271                                (String *) &applName,
272                                (String *) (displayName ? NULL : &displayName),
273                                (app->process->globalLangProcRec.proc ?
274                                 &language : NULL));
275    UNLOCK_PROCESS;
276    d = XOpenDisplay(displayName);
277    if (d != NULL) {
278        if (ScreenCount(d) <= 0) {
279            XtErrorMsg("nullDisplay",
280                       THIS_FUNC, XtCXtToolkitError,
281                       THIS_FUNC " requires a non-NULL display",
282                       NULL, NULL);
283        }
284        if (DefaultScreen(d) < 0 || DefaultScreen(d) >= ScreenCount(d)) {
285            XtWarningMsg("nullDisplay",
286                         THIS_FUNC, XtCXtToolkitError,
287                         THIS_FUNC " default screen is invalid (ignoring)",
288                         NULL, NULL);
289            DefaultScreen(d) = 0;
290        }
291    }
292
293    if (!applName && !(applName = getenv("RESOURCE_NAME"))) {
294        if (*argc > 0 && argv[0] && *argv[0]) {
295#ifdef WIN32
296            char *ptr = strrchr(argv[0], '\\');
297#else
298            char *ptr = strrchr(argv[0], '/');
299#endif
300
301            if (ptr)
302                applName = ++ptr;
303            else
304                applName = argv[0];
305        }
306        else
307            applName = "main";
308    }
309
310    if (d) {
311        XtPerDisplay pd;
312
313        pd = InitPerDisplay(d, app, applName, className);
314        pd->language = language;
315        _XtDisplayInitialize(d, pd, applName, urlist, num_urs, argc, argv);
316    }
317    else {
318        int len;
319
320        displayName = XDisplayName(displayName);
321        len = (int) strlen(displayName);
322        app->display_name_tried = (_XtString) __XtMalloc((Cardinal) (len + 1));
323        strncpy((char *) app->display_name_tried, displayName,
324                (size_t) (len + 1));
325        app->display_name_tried[len] = '\0';
326    }
327    if (db)
328        XrmDestroyDatabase(db);
329    UNLOCK_APP(app);
330    return d;
331}
332
333Display *
334_XtAppInit(XtAppContext *app_context_return,
335           String application_class,
336           XrmOptionDescRec *options,
337           Cardinal num_options,
338           int *argc_in_out,
339           _XtString **argv_in_out,
340           String *fallback_resources)
341{
342    _XtString *saved_argv;
343    int i;
344    Display *dpy;
345
346    /*
347     * Save away argv and argc so we can set the properties later
348     */
349    saved_argv = XtMallocArray((Cardinal) *argc_in_out + 1,
350                               (Cardinal) sizeof(_XtString));
351
352    for (i = 0; i < *argc_in_out; i++)
353        saved_argv[i] = (*argv_in_out)[i];
354    saved_argv[i] = NULL;       /* NULL terminate that sucker. */
355
356    *app_context_return = XtCreateApplicationContext();
357
358    LOCK_APP((*app_context_return));
359    if (fallback_resources)     /* save a procedure call */
360        XtAppSetFallbackResources(*app_context_return, fallback_resources);
361
362    dpy = XtOpenDisplay(*app_context_return, NULL, NULL,
363                        application_class,
364                        options, num_options, argc_in_out, *argv_in_out);
365
366    if (!dpy) {
367        String param = (*app_context_return)->display_name_tried;
368        Cardinal param_count = 1;
369
370        XtErrorMsg("invalidDisplay", "xtInitialize", XtCXtToolkitError,
371                   "Can't open display: %s", &param, &param_count);
372        XtFree((char *) (*app_context_return)->display_name_tried);
373    }
374    *argv_in_out = saved_argv;
375    UNLOCK_APP((*app_context_return));
376    return dpy;
377}
378
379void
380XtDisplayInitialize(XtAppContext app,
381                    Display *dpy,
382                    _Xconst _XtString name,
383                    _Xconst _XtString classname,
384                    XrmOptionDescRec *urlist,
385                    Cardinal num_urs,
386                    int *argc,
387                    _XtString *argv)
388{
389    XtPerDisplay pd;
390    XrmDatabase db = NULL;
391
392    LOCK_APP(app);
393    pd = InitPerDisplay(dpy, app, name, classname);
394    LOCK_PROCESS;
395    if (app->process->globalLangProcRec.proc)
396        /* pre-parse the command line for the language resource */
397        db = _XtPreparseCommandLine(urlist, num_urs, *argc, argv, NULL, NULL,
398                                    &pd->language);
399    UNLOCK_PROCESS;
400    _XtDisplayInitialize(dpy, pd, name, urlist, num_urs, argc, argv);
401    if (db)
402        XrmDestroyDatabase(db);
403    UNLOCK_APP(app);
404}
405
406XtAppContext
407XtCreateApplicationContext(void)
408{
409    XtAppContext app = XtNew(XtAppStruct);
410
411#ifdef XTHREADS
412    app->lock_info = NULL;
413    app->lock = NULL;
414    app->unlock = NULL;
415    app->yield_lock = NULL;
416    app->restore_lock = NULL;
417    app->free_lock = NULL;
418#endif
419    INIT_APP_LOCK(app);
420    LOCK_APP(app);
421    LOCK_PROCESS;
422    app->process = _XtGetProcessContext();
423    app->next = app->process->appContextList;
424    app->process->appContextList = app;
425    app->langProcRec.proc = app->process->globalLangProcRec.proc;
426    app->langProcRec.closure = app->process->globalLangProcRec.closure;
427    app->destroy_callbacks = NULL;
428    app->list = NULL;
429    app->count = app->max = app->last = 0;
430    app->timerQueue = NULL;
431    app->workQueue = NULL;
432    app->signalQueue = NULL;
433    app->input_list = NULL;
434    app->outstandingQueue = NULL;
435    app->errorDB = NULL;
436    _XtSetDefaultErrorHandlers(&app->errorMsgHandler,
437                               &app->warningMsgHandler, &app->errorHandler,
438                               &app->warningHandler);
439    app->action_table = NULL;
440    _XtSetDefaultSelectionTimeout(&app->selectionTimeout);
441    _XtSetDefaultConverterTable(&app->converterTable);
442    app->sync = app->being_destroyed = app->error_inited = FALSE;
443    app->in_phase2_destroy = NULL;
444#ifndef USE_POLL
445    FD_ZERO(&app->fds.rmask);
446    FD_ZERO(&app->fds.wmask);
447    FD_ZERO(&app->fds.emask);
448#endif
449    app->fds.nfds = 0;
450    app->input_count = app->input_max = 0;
451    _XtHeapInit(&app->heap);
452    app->fallback_resources = NULL;
453    _XtPopupInitialize(app);
454    app->action_hook_list = NULL;
455    app->block_hook_list = NULL;
456    app->destroy_list_size = app->destroy_count = app->dispatch_level = 0;
457    app->destroy_list = NULL;
458#ifndef NO_IDENTIFY_WINDOWS
459    app->identify_windows = False;
460#endif
461    app->free_bindings = NULL;
462    app->display_name_tried = NULL;
463    app->dpy_destroy_count = 0;
464    app->dpy_destroy_list = NULL;
465    app->exit_flag = FALSE;
466    app->rebuild_fdlist = TRUE;
467    UNLOCK_PROCESS;
468    UNLOCK_APP(app);
469    return app;
470}
471
472void
473XtAppSetExitFlag(XtAppContext app)
474{
475    LOCK_APP(app);
476    app->exit_flag = TRUE;
477    UNLOCK_APP(app);
478}
479
480Boolean
481XtAppGetExitFlag(XtAppContext app)
482{
483    Boolean retval;
484
485    LOCK_APP(app);
486    retval = app->exit_flag;
487    UNLOCK_APP(app);
488    return retval;
489}
490
491static void
492DestroyAppContext(XtAppContext app)
493{
494    XtAppContext *prev_app;
495
496    prev_app = &app->process->appContextList;
497    while (app->count-- > 0)
498        XtCloseDisplay(app->list[app->count]);
499    if (app->list != NULL)
500        XtFree((char *) app->list);
501    _XtFreeConverterTable(app->converterTable);
502    _XtCacheFlushTag(app, (XtPointer) &app->heap);
503    _XtFreeActions(app->action_table);
504    if (app->destroy_callbacks != NULL) {
505        XtCallCallbackList((Widget) NULL,
506                           (XtCallbackList) app->destroy_callbacks,
507                           (XtPointer) app);
508        _XtRemoveAllCallbacks(&app->destroy_callbacks);
509    }
510    while (app->timerQueue)
511        XtRemoveTimeOut((XtIntervalId) app->timerQueue);
512    while (app->workQueue)
513        XtRemoveWorkProc((XtWorkProcId) app->workQueue);
514    while (app->signalQueue)
515        XtRemoveSignal((XtSignalId) app->signalQueue);
516    if (app->input_list)
517        _XtRemoveAllInputs(app);
518    XtFree((char *) app->destroy_list);
519    _XtHeapFree(&app->heap);
520    while (*prev_app != app)
521        prev_app = &(*prev_app)->next;
522    *prev_app = app->next;
523    if (app->process->defaultAppContext == app)
524        app->process->defaultAppContext = NULL;
525    if (app->free_bindings)
526        _XtDoFreeBindings(app);
527    FREE_APP_LOCK(app);
528    XtFree((char *) app);
529}
530
531static XtAppContext *appDestroyList = NULL;
532int _XtAppDestroyCount = 0;
533
534void
535XtDestroyApplicationContext(XtAppContext app)
536{
537    LOCK_APP(app);
538    if (app->being_destroyed) {
539        UNLOCK_APP(app);
540        return;
541    }
542
543    if (_XtSafeToDestroy(app)) {
544        LOCK_PROCESS;
545        DestroyAppContext(app);
546        UNLOCK_PROCESS;
547    }
548    else {
549        app->being_destroyed = TRUE;
550        LOCK_PROCESS;
551        _XtAppDestroyCount++;
552        appDestroyList = XtReallocArray(appDestroyList,
553                                        (Cardinal) _XtAppDestroyCount,
554                                        (Cardinal) sizeof(XtAppContext));
555        appDestroyList[_XtAppDestroyCount - 1] = app;
556        UNLOCK_PROCESS;
557        UNLOCK_APP(app);
558    }
559}
560
561void
562_XtDestroyAppContexts(void)
563{
564    int i, ii;
565    XtAppContext apps[8];
566    XtAppContext *pApps;
567
568    pApps =
569        XtStackAlloc(sizeof(XtAppContext) * (size_t) _XtAppDestroyCount, apps);
570
571    for (i = ii = 0; i < _XtAppDestroyCount; i++) {
572        if (_XtSafeToDestroy(appDestroyList[i]))
573            DestroyAppContext(appDestroyList[i]);
574        else
575            pApps[ii++] = appDestroyList[i];
576    }
577    _XtAppDestroyCount = ii;
578    if (_XtAppDestroyCount == 0) {
579        XtFree((char *) appDestroyList);
580        appDestroyList = NULL;
581    }
582    else {
583        for (i = 0; i < ii; i++)
584            appDestroyList[i] = pApps[i];
585    }
586    XtStackFree((XtPointer) pApps, apps);
587}
588
589XrmDatabase
590XtDatabase(Display *dpy)
591{
592    XrmDatabase retval;
593
594    DPY_TO_APPCON(dpy);
595
596    LOCK_APP(app);
597    retval = XrmGetDatabase(dpy);
598    UNLOCK_APP(app);
599    return retval;
600}
601
602PerDisplayTablePtr _XtperDisplayList = NULL;
603
604XtPerDisplay
605_XtSortPerDisplayList(Display *dpy)
606{
607    register PerDisplayTablePtr pd, opd = NULL;
608    XtPerDisplay result = NULL;
609
610    LOCK_PROCESS;
611    for (pd = _XtperDisplayList; pd != NULL && pd->dpy != dpy; pd = pd->next) {
612        opd = pd;
613    }
614
615    if (pd == NULL) {
616        XtErrorMsg(XtNnoPerDisplay, "getPerDisplay", XtCXtToolkitError,
617                   "Couldn't find per display information", NULL, NULL);
618    }
619    else {
620        if (pd != _XtperDisplayList) {  /* move it to the front */
621            /* opd points to the previous one... */
622
623            opd->next = pd->next;
624            pd->next = _XtperDisplayList;
625            _XtperDisplayList = pd;
626        }
627        result = &(pd->perDpy);
628    }
629    UNLOCK_PROCESS;
630    return result;
631}
632
633XtAppContext
634XtDisplayToApplicationContext(Display *dpy)
635{
636    XtAppContext retval;
637
638    retval = _XtGetPerDisplay(dpy)->appContext;
639    return retval;
640}
641
642static void
643CloseDisplay(Display *dpy)
644{
645    register XtPerDisplay xtpd = NULL;
646    register PerDisplayTablePtr pd, opd = NULL;
647    XrmDatabase db;
648
649    XtDestroyWidget(XtHooksOfDisplay(dpy));
650
651    LOCK_PROCESS;
652    for (pd = _XtperDisplayList; pd != NULL && pd->dpy != dpy; pd = pd->next) {
653        opd = pd;
654    }
655
656    if (pd == NULL) {
657        XtErrorMsg(XtNnoPerDisplay, "closeDisplay", XtCXtToolkitError,
658                   "Couldn't find per display information", NULL, NULL);
659    }
660    else {
661
662        if (pd == _XtperDisplayList)
663            _XtperDisplayList = pd->next;
664        else
665            opd->next = pd->next;
666
667        xtpd = &(pd->perDpy);
668    }
669
670    if (xtpd != NULL) {
671        int i;
672
673        if (xtpd->destroy_callbacks != NULL) {
674            XtCallCallbackList((Widget) NULL,
675                               (XtCallbackList) xtpd->destroy_callbacks,
676                               (XtPointer) xtpd);
677            _XtRemoveAllCallbacks(&xtpd->destroy_callbacks);
678        }
679        if (xtpd->mapping_callbacks != NULL)
680            _XtRemoveAllCallbacks(&xtpd->mapping_callbacks);
681        XtDeleteFromAppContext(dpy, xtpd->appContext);
682        if (xtpd->keysyms)
683            XFree((char *) xtpd->keysyms);
684        XtFree((char *) xtpd->modKeysyms);
685        XtFree((char *) xtpd->modsToKeysyms);
686        xtpd->keysyms_per_keycode = 0;
687        xtpd->being_destroyed = FALSE;
688        xtpd->keysyms = NULL;
689        xtpd->modKeysyms = NULL;
690        xtpd->modsToKeysyms = NULL;
691        XDestroyRegion(xtpd->region);
692        _XtCacheFlushTag(xtpd->appContext, (XtPointer) &xtpd->heap);
693        _XtGClistFree(dpy, xtpd);
694        XtFree((char *) xtpd->pdi.trace);
695        _XtHeapFree(&xtpd->heap);
696        _XtFreeWWTable(xtpd);
697        xtpd->per_screen_db[DefaultScreen(dpy)] = (XrmDatabase) NULL;
698        for (i = ScreenCount(dpy); --i >= 0;) {
699            db = xtpd->per_screen_db[i];
700            if (db)
701                XrmDestroyDatabase(db);
702        }
703        XtFree((char *) xtpd->per_screen_db);
704        if ((db = XrmGetDatabase(dpy)))
705            XrmDestroyDatabase(db);
706        if (xtpd->cmd_db)
707            XrmDestroyDatabase(xtpd->cmd_db);
708        if (xtpd->server_db)
709            XrmDestroyDatabase(xtpd->server_db);
710        XtFree((_XtString) xtpd->language);
711        if (xtpd->dispatcher_list != NULL)
712            XtFree((char *) xtpd->dispatcher_list);
713        if (xtpd->ext_select_list != NULL)
714            XtFree((char *) xtpd->ext_select_list);
715    }
716    XtFree((char *) pd);
717    XrmSetDatabase(dpy, (XrmDatabase) NULL);
718    XCloseDisplay(dpy);
719    UNLOCK_PROCESS;
720}
721
722void
723XtCloseDisplay(Display *dpy)
724{
725    XtPerDisplay pd;
726    XtAppContext app = XtDisplayToApplicationContext(dpy);
727
728    LOCK_APP(app);
729    pd = _XtGetPerDisplay(dpy);
730    if (pd->being_destroyed) {
731        UNLOCK_APP(app);
732        return;
733    }
734
735    if (_XtSafeToDestroy(app))
736        CloseDisplay(dpy);
737    else {
738        pd->being_destroyed = TRUE;
739        app->dpy_destroy_count++;
740        app->dpy_destroy_list = XtReallocArray(app->dpy_destroy_list,
741                                               (Cardinal) app->dpy_destroy_count,
742                                               (Cardinal) sizeof(Display *));
743        app->dpy_destroy_list[app->dpy_destroy_count - 1] = dpy;
744    }
745    UNLOCK_APP(app);
746}
747
748void
749_XtCloseDisplays(XtAppContext app)
750{
751    int i;
752
753    LOCK_APP(app);
754    for (i = 0; i < app->dpy_destroy_count; i++) {
755        CloseDisplay(app->dpy_destroy_list[i]);
756    }
757    app->dpy_destroy_count = 0;
758    XtFree((char *) app->dpy_destroy_list);
759    app->dpy_destroy_list = NULL;
760    UNLOCK_APP(app);
761}
762
763XtAppContext
764XtWidgetToApplicationContext(Widget w)
765{
766    XtAppContext retval;
767
768    retval = _XtGetPerDisplay(XtDisplayOfObject(w))->appContext;
769    return retval;
770}
771
772void
773XtGetApplicationNameAndClass(Display *dpy,
774                             String *name_return,
775                             String *class_return)
776{
777    XtPerDisplay pd;
778
779    pd = _XtGetPerDisplay(dpy);
780    *name_return = XrmQuarkToString(pd->name);
781    *class_return = XrmQuarkToString(pd->class);
782}
783
784XtPerDisplay
785_XtGetPerDisplay(Display *display)
786{
787    XtPerDisplay retval;
788
789    LOCK_PROCESS;
790    retval = ((_XtperDisplayList != NULL && _XtperDisplayList->dpy == display)
791              ? &_XtperDisplayList->perDpy : _XtSortPerDisplayList(display));
792
793    UNLOCK_PROCESS;
794    return retval;
795}
796
797XtPerDisplayInputRec *
798_XtGetPerDisplayInput(Display *display)
799{
800    XtPerDisplayInputRec *retval;
801
802    LOCK_PROCESS;
803    retval = ((_XtperDisplayList != NULL && _XtperDisplayList->dpy == display)
804              ? &_XtperDisplayList->perDpy.pdi
805              : &_XtSortPerDisplayList(display)->pdi);
806    UNLOCK_PROCESS;
807    return retval;
808}
809
810void
811XtGetDisplays(XtAppContext app_context,
812              Display ***dpy_return,
813              Cardinal *num_dpy_return)
814{
815    int ii;
816
817    LOCK_APP(app_context);
818    *num_dpy_return = (Cardinal) app_context->count;
819    *dpy_return = XtMallocArray((Cardinal) app_context->count,
820                                (Cardinal) sizeof(Display *));
821    for (ii = 0; ii < app_context->count; ii++)
822        (*dpy_return)[ii] = app_context->list[ii];
823    UNLOCK_APP(app_context);
824}
825