diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:39 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:39 +0000 |
commit | 0117b0b441d8835a11a2886f3c8aed937dcffa9d (patch) | |
tree | f4acfebbb67f382f645fb876acb0278891a6a91a /src |
R6.6 is the Xorg base-lineXORG-MAIN
Diffstat (limited to 'src')
-rw-r--r-- | src/ActionHook.c | 131 | ||||
-rw-r--r-- | src/Alloc.c | 496 | ||||
-rw-r--r-- | src/ArgList.c | 76 | ||||
-rw-r--r-- | src/Callback.c | 738 | ||||
-rw-r--r-- | src/ClickTime.c | 90 | ||||
-rw-r--r-- | src/Composite.c | 283 | ||||
-rw-r--r-- | src/Constraint.c | 131 | ||||
-rw-r--r-- | src/Convert.c | 1169 | ||||
-rw-r--r-- | src/Converters.c | 1870 | ||||
-rw-r--r-- | src/Core.c | 397 | ||||
-rw-r--r-- | src/Create.c | 827 | ||||
-rw-r--r-- | src/Destroy.c | 383 | ||||
-rw-r--r-- | src/Display.c | 866 | ||||
-rw-r--r-- | src/Error.c | 735 | ||||
-rw-r--r-- | src/Event.c | 1846 | ||||
-rw-r--r-- | src/EventUtil.c | 221 | ||||
-rw-r--r-- | src/Functions.c | 228 | ||||
-rw-r--r-- | src/GCManager.c | 350 | ||||
-rw-r--r-- | src/Geometry.c | 826 | ||||
-rw-r--r-- | src/GetActKey.c | 99 | ||||
-rw-r--r-- | src/GetResList.c | 187 | ||||
-rw-r--r-- | src/GetValues.c | 250 | ||||
-rw-r--r-- | src/HookObj.c | 130 | ||||
-rw-r--r-- | src/Hooks.c | 163 | ||||
-rw-r--r-- | src/Initialize.c | 1044 | ||||
-rw-r--r-- | src/Intrinsic.c | 1643 | ||||
-rw-r--r-- | src/Keyboard.c | 854 | ||||
-rw-r--r-- | src/Manage.c | 498 | ||||
-rw-r--r-- | src/NextEvent.c | 1643 | ||||
-rw-r--r-- | src/Object.c | 292 | ||||
-rw-r--r-- | src/PassivGrab.c | 1119 | ||||
-rw-r--r-- | src/Pointer.c | 112 | ||||
-rw-r--r-- | src/Popup.c | 211 | ||||
-rw-r--r-- | src/PopupCB.c | 81 | ||||
-rw-r--r-- | src/RectObj.c | 188 | ||||
-rw-r--r-- | src/ResConfig.c | 1020 | ||||
-rw-r--r-- | src/Resources.c | 1294 | ||||
-rw-r--r-- | src/Selection.c | 2306 | ||||
-rw-r--r-- | src/SetSens.c | 131 | ||||
-rw-r--r-- | src/SetValues.c | 438 | ||||
-rw-r--r-- | src/SetWMCW.c | 152 | ||||
-rw-r--r-- | src/Shell.c | 3416 | ||||
-rw-r--r-- | src/TMaction.c | 1068 | ||||
-rw-r--r-- | src/TMgrab.c | 342 | ||||
-rw-r--r-- | src/TMkey.c | 744 | ||||
-rw-r--r-- | src/TMparse.c | 2128 | ||||
-rw-r--r-- | src/TMprint.c | 889 | ||||
-rw-r--r-- | src/TMstate.c | 2340 | ||||
-rw-r--r-- | src/Threads.c | 473 | ||||
-rw-r--r-- | src/VarCreate.c | 509 | ||||
-rw-r--r-- | src/VarGet.c | 351 | ||||
-rw-r--r-- | src/Varargs.c | 565 | ||||
-rw-r--r-- | src/Vendor.c | 118 | ||||
-rw-r--r-- | src/sharedlib.c | 302 |
54 files changed, 38763 insertions, 0 deletions
diff --git a/src/ActionHook.c b/src/ActionHook.c new file mode 100644 index 0000000..54f8562 --- /dev/null +++ b/src/ActionHook.c @@ -0,0 +1,131 @@ +/* $Xorg: ActionHook.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */ + +/*LINTLIBRARY*/ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* + * Contains XtAppAddActionHook, XtRemoveActionHook + */ + +#include "IntrinsicI.h" + + +/*ARGSUSED*/ +static void FreeActionHookList( widget, closure, call_data ) + Widget widget; /* unused (and invalid) */ + XtPointer closure; /* ActionHook* */ + XtPointer call_data; /* unused */ +{ + ActionHook list = *(ActionHook*)closure; + while (list != NULL) { + ActionHook next = list->next; + XtFree( (XtPointer)list ); + list = next; + } +} + + +XtActionHookId XtAppAddActionHook( app, proc, closure ) + XtAppContext app; + XtActionHookProc proc; + XtPointer closure; +{ + ActionHook hook = XtNew(ActionHookRec); + LOCK_APP(app); + hook->next = app->action_hook_list; + hook->app = app; + hook->proc = proc; + hook->closure = closure; + if (app->action_hook_list == NULL) { + _XtAddCallback( &app->destroy_callbacks, + FreeActionHookList, + (XtPointer)&app->action_hook_list + ); + } + app->action_hook_list = hook; + UNLOCK_APP(app); + return (XtActionHookId)hook; +} + + +void XtRemoveActionHook( id ) + XtActionHookId id; +{ + ActionHook *p, hook = (ActionHook)id; + XtAppContext app = hook->app; + LOCK_APP(app); + for (p = &app->action_hook_list; p != NULL && *p != hook; p = &(*p)->next); + if (p) { + *p = hook->next; + XtFree( (XtPointer)hook ); + if (app->action_hook_list == NULL) + _XtRemoveCallback(&app->destroy_callbacks, FreeActionHookList, + (XtPointer) &app->action_hook_list); + } +#ifdef DEBUG + else { + XtAppWarningMsg(app, "badId", "xtRemoveActionHook", XtCXtToolkitError, + "XtRemoveActionHook called with bad or old hook id", + (String*)NULL, (Cardinal*)NULL); + } +#endif /*DEBUG*/ + UNLOCK_APP(app); +} diff --git a/src/Alloc.c b/src/Alloc.c new file mode 100644 index 0000000..16d922d --- /dev/null +++ b/src/Alloc.c @@ -0,0 +1,496 @@ +/* $Xorg: Alloc.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* + * X Toolkit Memory Allocation Routines + * + * Uses Xlib memory management, which is spec'd to be re-entrant. + */ + +#include "IntrinsicI.h" +#undef _XBCOPYFUNC + +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#else +char *malloc(), *realloc(), *calloc(); +#endif + +#define Xmalloc(size) malloc((size)) +#define Xrealloc(ptr, size) realloc((ptr), (size)) +#define Xcalloc(nelem, elsize) calloc((nelem), (elsize)) +#define Xfree(ptr) free(ptr) + +#ifdef _XNEEDBCOPYFUNC +void _XtBcopy(src, dst, length) + char *src, *dst; + int length; +{ + if (src < dst) { + dst += length; + src += length; + while (length--) + *--dst = *--src; + } else { + while (length--) + *dst++ = *src++; + } +} +#endif + +void _XtAllocError(type) + String type; +{ + Cardinal num_params = 1; + if (type == NULL) type = "local memory allocation"; + XtErrorMsg("allocError", type, XtCXtToolkitError, + "Cannot perform %s", &type, &num_params); +} + +void _XtHeapInit(heap) + Heap* heap; +{ + heap->start = NULL; + heap->bytes_remaining = 0; +} + +#ifndef XTTRACEMEMORY + +char *XtMalloc(size) + unsigned size; +{ + char *ptr; + +#if defined (MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC) + /* preserve this (broken) behavior until everyone fixes their apps */ + if (!size) size = 1; +#endif + if ((ptr = Xmalloc(size)) == NULL) + _XtAllocError("malloc"); + + return(ptr); +} + +char *XtRealloc(ptr, size) + char *ptr; + unsigned size; +{ + if (ptr == NULL) { +#if MALLOC_0_RETURNS_NULL + if (!size) size = 1; +#endif + return(XtMalloc(size)); + } else if ((ptr = Xrealloc(ptr, size)) == NULL +#if MALLOC_0_RETURNS_NULL + && size +#endif + ) + _XtAllocError("realloc"); + + return(ptr); +} + +char *XtCalloc(num, size) + unsigned num, size; +{ + char *ptr; + +#if defined (MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC) + /* preserve this (broken) behavior until everyone fixes their apps */ + if (!size) num = size = 1; +#endif + if ((ptr = Xcalloc(num, size)) == NULL) + _XtAllocError("calloc"); + + return(ptr); +} + +void XtFree(ptr) + char *ptr; +{ + if (ptr != NULL) Xfree(ptr); +} + +char* __XtMalloc(size) + unsigned size; +{ +#ifdef MALLOC_0_RETURNS_NULL + if (!size) size = 1; +#endif + return XtMalloc (size); +} + +char* __XtCalloc(num, size) + unsigned num, size; +{ +#ifdef MALLOC_0_RETURNS_NULL + if (!size) num = size = 1; +#endif + return XtCalloc(num, size); +} + +#ifndef HEAP_SEGMENT_SIZE +#define HEAP_SEGMENT_SIZE 1492 +#endif + +char* _XtHeapAlloc(heap, bytes) + Heap* heap; + Cardinal bytes; +{ + register char* heap_loc; + if (heap == NULL) return XtMalloc(bytes); + if (heap->bytes_remaining < (int)bytes) { + if ((bytes + sizeof(char*)) >= (HEAP_SEGMENT_SIZE>>1)) { + /* preserve current segment; insert this one in front */ +#ifdef _TRACE_HEAP + printf( "allocating large segment (%d bytes) on heap %#x\n", + bytes, heap ); +#endif + heap_loc = XtMalloc(bytes + sizeof(char*)); + if (heap->start) { + *(char**)heap_loc = *(char**)heap->start; + *(char**)heap->start = heap_loc; + } + else { + *(char**)heap_loc = NULL; + heap->start = heap_loc; + } + return heap_loc + sizeof(char*); + } + /* else discard remainder of this segment */ +#ifdef _TRACE_HEAP + printf( "allocating new segment on heap %#x\n", heap ); +#endif + heap_loc = XtMalloc((unsigned)HEAP_SEGMENT_SIZE); + *(char**)heap_loc = heap->start; + heap->start = heap_loc; + heap->current = heap_loc + sizeof(char*); + heap->bytes_remaining = HEAP_SEGMENT_SIZE - sizeof(char*); + } + bytes = (bytes + (sizeof(long) - 1)) & (~(sizeof(long) - 1)); + heap_loc = heap->current; + heap->current += bytes; + heap->bytes_remaining -= bytes; /* can be negative, if rounded */ + return heap_loc; +} + +void _XtHeapFree(heap) + Heap* heap; +{ + char* segment = heap->start; + while (segment != NULL) { + char* next_segment = *(char**)segment; + XtFree(segment); + segment = next_segment; + } + heap->start = NULL; + heap->bytes_remaining = 0; +} + +#else + +/* + * X Toolkit Memory Trace Allocation Routines + */ + +#undef XtMalloc +#undef XtRealloc +#undef XtCalloc +#undef XtFree + +typedef struct _Stats *StatsPtr; +typedef struct _Stats { + StatsPtr prev, next; + char *file; + int line; + unsigned size; + unsigned long seq; + XtPointer heap; +} Stats; + +static StatsPtr XtMemory = (StatsPtr)NULL; +static unsigned long ActiveXtMemory = 0; +static unsigned long XtSeqId = 0; +static unsigned long XtSeqBreakpoint = ~0; + +#define StatsSize(n) ((((n) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) + sizeof(Stats)) +#define ToStats(ptr) ((StatsPtr)(ptr - sizeof(Stats))) +#define ToMem(ptr) (((char *)ptr) + sizeof(Stats)) + +#define CHAIN(ptr,len,hp) \ + ptr->next = XtMemory; \ + if (XtMemory) \ + XtMemory->prev = ptr; \ + XtMemory = ptr; \ + ptr->prev = (StatsPtr)NULL; \ + ptr->file = file; \ + ptr->line = line; \ + ptr->size = len; \ + ptr->heap = hp; \ + if (file) \ + ActiveXtMemory += len; \ + ptr->seq = XtSeqId; \ + if (XtSeqId == XtSeqBreakpoint) \ + _XtBreakpoint(ptr); \ + XtSeqId++ + +/*ARGUSED*/ +static void _XtBreakpoint(mem) + StatsPtr mem; +{ + mem->seq = XtSeqId; /* avoid being optimized out of existence */ +} + +char *_XtMalloc(size, file, line) + unsigned size; + char *file; + int line; +{ + StatsPtr ptr; + unsigned newsize; + char* retval = NULL; + + LOCK_PROCESS; + newsize = StatsSize(size); + if ((ptr = (StatsPtr)Xmalloc(newsize)) == NULL) + _XtAllocError("malloc"); + CHAIN(ptr, size, NULL); + retval = (ToMem(ptr)); + UNLOCK_PROCESS; + return retval; +} + +char *XtMalloc(size) + unsigned size; +{ + return _XtMalloc(size, (char *)NULL, 0); +} + +char *_XtRealloc(ptr, size, file, line) + char *ptr; + unsigned size; + char *file; + int line; +{ + char *newptr; + + LOCK_PROCESS; + newptr = _XtMalloc(size, file, line); + if (ptr) { + unsigned copysize = ToStats(ptr)->size; + if (copysize > size) copysize = size; + memmove(newptr, ptr, copysize); + _XtFree(ptr); + } + UNLOCK_PROCESS; + return(newptr); +} + +char *XtRealloc(ptr, size) + char *ptr; + unsigned size; +{ + return _XtRealloc(ptr, size, (char *)NULL, 0); +} + +char *_XtCalloc(num, size, file, line) + unsigned num, size; + char *file; + int line; +{ + StatsPtr ptr; + unsigned total, newsize; + char* retval = NULL; + + LOCK_PROCESS; + total = num * size; + newsize = StatsSize(total); + if ((ptr = (StatsPtr)Xcalloc(newsize, 1)) == NULL) + _XtAllocError("calloc"); + CHAIN(ptr, total, NULL); + retval = (ToMem(ptr)); + UNLOCK_PROCESS; + return retval; +} + +char *XtCalloc(num, size) + unsigned num, size; +{ + return _XtCalloc(num, size, (char *)NULL, 0); +} + +Boolean _XtIsValidPointer(ptr) + char *ptr; +{ + register StatsPtr mem; + register StatsPtr stp = ToStats(ptr); + + LOCK_PROCESS; + for (mem = XtMemory; mem; mem = mem->next) { + if (mem == stp) { + UNLOCK_PROCESS; + return True; + } + } + UNLOCK_PROCESS; + return False; +} + +Boolean _XtValidateMemory = False; + +void _XtFree(ptr) + char *ptr; +{ + register StatsPtr stp; + + LOCK_PROCESS; + if (ptr) { + if (_XtValidateMemory && !_XtIsValidPointer(ptr)) + abort(); + stp = ToStats(ptr); + if (stp->file) + ActiveXtMemory -= stp->size; + if (stp->prev) + stp->prev->next = stp->next; + else + XtMemory = stp->next; + if (stp->next) + stp->next->prev = stp->prev; + Xfree((char *)stp); + } + UNLOCK_PROCESS; +} + +void XtFree(ptr) + char *ptr; +{ + _XtFree(ptr); +} + +char *_XtHeapMalloc(heap, size, file, line) + Heap *heap; + Cardinal size; + char *file; + int line; +{ + StatsPtr ptr; + unsigned newsize; + XtPointer hp = (XtPointer) heap; + char* retval = NULL; + + LOCK_PROCESS; + newsize = StatsSize(size); + if ((ptr = (StatsPtr)Xmalloc(newsize)) == NULL) + _XtAllocError("malloc"); + CHAIN(ptr, size, hp); + retval = (ToMem(ptr)); + UNLOCK_PROCESS; + return retval; +} + +void _XtHeapFree(heap) + register XtPointer heap; +{ + register StatsPtr mem, next; + + LOCK_PROCESS; + for (mem = XtMemory; mem; mem = next) { + next = mem->next; + if (mem->heap == heap) { + if (mem->file) + ActiveXtMemory -= mem->size; + if (mem->prev) + mem->prev->next = next; + else + XtMemory = next; + if (next) + next->prev = mem->prev; + Xfree((char *)mem); + } + } + UNLOCK_PROCESS; +} + +#include <stdio.h> + +void _XtPrintMemory(filename) +char * filename; +{ + register StatsPtr mem; + FILE *f; + + if (filename == NULL) + f = stderr; + else + f = fopen(filename, "w"); + LOCK_PROCESS; + fprintf(f, "total size: %d\n", ActiveXtMemory); + for (mem = XtMemory; mem; mem = mem->next) { + if (mem->file) + fprintf(f, "size: %6d seq: %5d %12s(%4d) %s\n", + mem->size, mem->seq, + mem->file, mem->line, mem->heap ? "heap" : ""); + } + UNLOCK_PROCESS; + if (filename) fclose(f); +} + +#endif /* XTTRACEMEMORY */ diff --git a/src/ArgList.c b/src/ArgList.c new file mode 100644 index 0000000..5b3e720 --- /dev/null +++ b/src/ArgList.c @@ -0,0 +1,76 @@ +/* $Xorg: ArgList.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */ + +/*********************************************************** + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#include "IntrinsicI.h" +#include <stdio.h> + +/* + * This routine merges two arglists. It does NOT check for duplicate entries. + */ + +ArgList XtMergeArgLists(args1, num_args1, args2, num_args2) + ArgList args1; + Cardinal num_args1; + ArgList args2; + Cardinal num_args2; +{ + ArgList result, args; + + result = (ArgList) __XtCalloc((unsigned) num_args1 + num_args2, + (unsigned) sizeof(Arg)); + + for (args = result; num_args1 != 0; num_args1--) + *args++ = *args1++; + for ( ; num_args2 != 0; num_args2--) + *args++ = *args2++; + + return result; +} + + diff --git a/src/Callback.c b/src/Callback.c new file mode 100644 index 0000000..26213a9 --- /dev/null +++ b/src/Callback.c @@ -0,0 +1,738 @@ +/* $Xorg: Callback.c,v 1.4 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" + +static String XtNinvalidCallbackList = "invalidCallbackList"; +static String XtNxtAddCallback = "xtAddCallback"; +static String XtNxtRemoveCallback = "xtRemoveCallback"; +static String XtNxtRemoveAllCallback = "xtRemoveAllCallback"; +static String XtNxtCallCallback = "xtCallCallback"; + +/* However it doesn't contain a final NULL record */ +#define ToList(p) ((XtCallbackList) ((p)+1)) + +static InternalCallbackList* FetchInternalList(widget, name) + Widget widget; + String name; +{ + XrmQuark quark; + int n; + CallbackTable offsets; + InternalCallbackList* retval = NULL; + + quark = StringToQuark(name); + LOCK_PROCESS; + offsets = (CallbackTable) + widget->core.widget_class->core_class.callback_private; + + for (n = (int) *(offsets++); --n >= 0; offsets++) + if (quark == (*offsets)->xrm_name) { + retval = (InternalCallbackList *) + ((char *) widget - (*offsets)->xrm_offset - 1); + break; + } + UNLOCK_PROCESS; + return retval; +} + + +void _XtAddCallback(callbacks, callback, closure) + InternalCallbackList* callbacks; + XtCallbackProc callback; + XtPointer closure; +{ + register InternalCallbackList icl; + register XtCallbackList cl; + register int count; + + icl = *callbacks; + count = icl ? icl->count : 0; + + if (icl && icl->call_state) { + icl->call_state |= _XtCBFreeAfterCalling; + icl = (InternalCallbackList) + __XtMalloc(sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * (count + 1)); + (void) memmove((char *)ToList(icl), (char *)ToList(*callbacks), + sizeof(XtCallbackRec) * count); + } else { + icl = (InternalCallbackList) + XtRealloc((char *) icl, sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * (count + 1)); + } + *callbacks = icl; + icl->count = count + 1; + icl->is_padded = 0; + icl->call_state = 0; + cl = ToList(icl) + count; + cl->callback = callback; + cl->closure = closure; +} /* _XtAddCallback */ + +void _XtAddCallbackOnce(callbacks, callback, closure) + register InternalCallbackList*callbacks; + XtCallbackProc callback; + XtPointer closure; +{ + register XtCallbackList cl = ToList(*callbacks); + register int i; + + for (i=(*callbacks)->count; --i >= 0; cl++) + if (cl->callback == callback && cl->closure == closure) + return; + + _XtAddCallback(callbacks, callback, closure); +} /* _XtAddCallbackOnce */ + +#if NeedFunctionPrototypes +void XtAddCallback( + Widget widget, + _Xconst char* name, + XtCallbackProc callback, + XtPointer closure + ) +#else +void XtAddCallback(widget, name, callback, closure) + Widget widget; + String name; + XtCallbackProc callback; + XtPointer closure; +#endif +{ + InternalCallbackList *callbacks; + Widget hookobj; + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + callbacks = FetchInternalList(widget, name); + if (!callbacks) { + XtAppWarningMsg(app, + XtNinvalidCallbackList,XtNxtAddCallback,XtCXtToolkitError, + "Cannot find callback list in XtAddCallback", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_APP(app); + return; + } + _XtAddCallback(callbacks, callback, closure); + if (!_XtIsHookObject(widget)) { + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHaddCallback; + call_data.widget = widget; + call_data.event_data = (XtPointer) name; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + } + UNLOCK_APP(app); +} /* XtAddCallback */ + +/* ARGSUSED */ +static void AddCallbacks(widget, callbacks, newcallbacks) + Widget widget; + InternalCallbackList *callbacks; + XtCallbackList newcallbacks; +{ + register InternalCallbackList icl; + register int i, j; + register XtCallbackList cl; + + icl = *callbacks; + i = icl ? icl->count : 0; + for (j=0, cl = newcallbacks; cl->callback; cl++, j++); + if (icl && icl->call_state) { + icl->call_state |= _XtCBFreeAfterCalling; + icl = (InternalCallbackList) __XtMalloc(sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * (i+j)); + (void) memmove((char *)ToList(*callbacks), (char *)ToList(icl), + sizeof(XtCallbackRec) * i); + } else { + icl = (InternalCallbackList) XtRealloc((char *) icl, + sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * (i+j)); + } + *callbacks = icl; + icl->count = i+j; + icl->is_padded = 0; + icl->call_state = 0; + for (cl = ToList(icl) + i; --j >= 0; ) + *cl++ = *newcallbacks++; +} /* AddCallbacks */ + +#if NeedFunctionPrototypes +void XtAddCallbacks( + Widget widget, + _Xconst char* name, + XtCallbackList xtcallbacks + ) +#else +void XtAddCallbacks(widget, name, xtcallbacks) + Widget widget; + String name; + XtCallbackList xtcallbacks; +#endif +{ + InternalCallbackList* callbacks; + Widget hookobj; + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + callbacks = FetchInternalList(widget, name); + if (!callbacks) { + XtAppWarningMsg(app, + XtNinvalidCallbackList,XtNxtAddCallback,XtCXtToolkitError, + "Cannot find callback list in XtAddCallbacks", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_APP(app); + return; + } + AddCallbacks(widget, callbacks, xtcallbacks); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHaddCallbacks; + call_data.widget = widget; + call_data.event_data = (XtPointer) name; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} /* XtAddCallbacks */ + +void _XtRemoveCallback (callbacks, callback, closure) + InternalCallbackList *callbacks; + XtCallbackProc callback; + XtPointer closure; + +{ + register InternalCallbackList icl; + register int i, j; + register XtCallbackList cl, ncl, ocl; + + icl = *callbacks; + if (!icl) return; + + cl = ToList(icl); + for (i=icl->count; --i >= 0; cl++) { + if (cl->callback == callback && cl->closure == closure) { + if (icl->call_state) { + icl->call_state |= _XtCBFreeAfterCalling; + if (icl->count == 1) { + *callbacks = NULL; + } else { + j = icl->count - i - 1; + ocl = ToList(icl); + icl = (InternalCallbackList) + __XtMalloc(sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * (i + j)); + icl->count = i + j; + icl->is_padded = 0; + icl->call_state = 0; + ncl = ToList(icl); + while (--j >= 0) + *ncl++ = *ocl++; + while (--i >= 0) + *ncl++ = *++cl; + *callbacks = icl; + } + } else { + if (--icl->count) { + ncl = cl + 1; + while (--i >= 0) + *cl++ = *ncl++; + icl = (InternalCallbackList) + XtRealloc((char *) icl, sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * icl->count); + icl->is_padded = 0; + *callbacks = icl; + } else { + XtFree((char *) icl); + *callbacks = NULL; + } + } + return; + } + } +} /* _XtRemoveCallback */ + +#if NeedFunctionPrototypes +void XtRemoveCallback ( + Widget widget, + _Xconst char* name, + XtCallbackProc callback, + XtPointer closure + ) +#else +void XtRemoveCallback (widget, name, callback, closure) + Widget widget; + String name; + XtCallbackProc callback; + XtPointer closure; +#endif +{ + InternalCallbackList *callbacks; + Widget hookobj; + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + callbacks = FetchInternalList(widget, name); + if (!callbacks) { + XtAppWarningMsg(app, + XtNinvalidCallbackList,XtNxtRemoveCallback,XtCXtToolkitError, + "Cannot find callback list in XtRemoveCallback", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_APP(app); + return; + } + _XtRemoveCallback(callbacks, callback, closure); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHremoveCallback; + call_data.widget = widget; + call_data.event_data = (XtPointer) name; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} /* XtRemoveCallback */ + + +#if NeedFunctionPrototypes +void XtRemoveCallbacks (widget, name, xtcallbacks) + Widget widget; + _Xconst char* name; + XtCallbackList xtcallbacks; +#else +void XtRemoveCallbacks (widget, name, xtcallbacks) + Widget widget; + String name; + XtCallbackList xtcallbacks; +#endif +{ + InternalCallbackList *callbacks; + Widget hookobj; + int i; + InternalCallbackList icl; + XtCallbackList cl, ccl, rcl; + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + callbacks = FetchInternalList(widget, name); + if (!callbacks) { + XtAppWarningMsg(app, + XtNinvalidCallbackList,XtNxtRemoveCallback,XtCXtToolkitError, + "Cannot find callback list in XtRemoveCallbacks", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_APP(app); + return; + } + + icl = *callbacks; + if (!icl) { + UNLOCK_APP(app); + return; + } + + i = icl->count; + cl = ToList(icl); + if (icl->call_state) { + icl->call_state |= _XtCBFreeAfterCalling; + icl = (InternalCallbackList)__XtMalloc(sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * i); + icl->count = i; + icl->call_state = 0; + } + ccl = ToList(icl); + while (--i >= 0) { + *ccl++ = *cl; + for (rcl=xtcallbacks; rcl->callback; rcl++) { + if (cl->callback == rcl->callback && cl->closure == rcl->closure) { + ccl--; + icl->count--; + break; + } + } + cl++; + } + if (icl->count) { + icl = (InternalCallbackList) + XtRealloc((char *)icl, (sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * icl->count)); + icl->is_padded = 0; + *callbacks = icl; + } else { + XtFree((char *)icl); + *callbacks = NULL; + } + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHremoveCallbacks; + call_data.widget = widget; + call_data.event_data = (XtPointer) name; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} /* XtRemoveCallbacks */ + + +void _XtRemoveAllCallbacks (callbacks) + InternalCallbackList *callbacks; +{ + register InternalCallbackList icl = *callbacks; + + if (icl) { + if (icl->call_state) + icl->call_state |= _XtCBFreeAfterCalling; + else + XtFree((char *) icl); + *callbacks = NULL; + } +} /* _XtRemoveAllCallbacks */ + +#if NeedFunctionPrototypes +void XtRemoveAllCallbacks(widget, name) + Widget widget; + _Xconst char* name; +#else +void XtRemoveAllCallbacks(widget, name) + Widget widget; + String name; +#endif +{ + InternalCallbackList *callbacks; + Widget hookobj; + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + callbacks = FetchInternalList(widget, name); + if (!callbacks) { + XtAppWarningMsg(app, + XtNinvalidCallbackList,XtNxtRemoveAllCallback,XtCXtToolkitError, + "Cannot find callback list in XtRemoveAllCallbacks", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_APP(app); + return; + } + _XtRemoveAllCallbacks(callbacks); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHremoveAllCallbacks; + call_data.widget = widget; + call_data.event_data = (XtPointer) name; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} /* XtRemoveAllCallbacks */ + +InternalCallbackList _XtCompileCallbackList(xtcallbacks) + XtCallbackList xtcallbacks; +{ + register int n; + register XtCallbackList xtcl, cl; + register InternalCallbackList callbacks; + + for (n=0, xtcl=xtcallbacks; xtcl->callback; n++, xtcl++) {}; + if (n == 0) return (InternalCallbackList) NULL; + + callbacks = (InternalCallbackList) __XtMalloc(sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * n); + callbacks->count = n; + callbacks->is_padded = 0; + callbacks->call_state = 0; + cl = ToList(callbacks); + while (--n >= 0) + *cl++ = *xtcallbacks++; + return(callbacks); +} /* _XtCompileCallbackList */ + + +XtCallbackList _XtGetCallbackList(callbacks) + InternalCallbackList *callbacks; +{ + register int i; + register InternalCallbackList icl; + register XtCallbackList cl, ocl; + + icl = *callbacks; + if (!icl) { + static XtCallbackRec emptyList[1] = { {NULL, NULL} }; + return (XtCallbackList)emptyList; + } + if (icl->is_padded) + return ToList(icl); + i = icl->count; + if (icl->call_state) { + icl->call_state |= _XtCBFreeAfterCalling; + ocl = ToList(icl); + icl = (InternalCallbackList) __XtMalloc(sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * (i+1)); + icl->count = i; + icl->call_state = 0; + cl = ToList(icl); + while (--i >= 0) + *cl++ = *ocl++; + } else { + icl = (InternalCallbackList) XtRealloc((char *)icl, + sizeof(InternalCallbackRec) + + sizeof(XtCallbackRec) * (i+1)); + cl = ToList(icl) + i; + } + icl->is_padded = 1; + cl->callback = (XtCallbackProc) NULL; + cl->closure = NULL; + *callbacks = icl; + return ToList(icl); +} + +#if NeedFunctionPrototypes +void XtCallCallbacks( + Widget widget, + _Xconst char* name, + XtPointer call_data + ) +#else +void XtCallCallbacks(widget, name, call_data) + Widget widget; + String name; + XtPointer call_data; +#endif +{ + InternalCallbackList *callbacks; + InternalCallbackList icl; + XtCallbackList cl; + int i; + char ostate; + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + callbacks = FetchInternalList(widget, name); + if (!callbacks) { + XtAppWarningMsg(app, + XtNinvalidCallbackList,XtNxtCallCallback,XtCXtToolkitError, + "Cannot find callback list in XtCallCallbacks", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_APP(app); + return; + } + + icl = *callbacks; + if (!icl) { + UNLOCK_APP(app); + return; + } + cl = ToList(icl); + if (icl->count == 1) { + (*cl->callback) (widget, cl->closure, call_data); + UNLOCK_APP(app); + return; + } + ostate = icl->call_state; + icl->call_state = _XtCBCalling; + for (i = icl->count; --i >= 0; cl++) + (*cl->callback) (widget, cl->closure, call_data); + if (ostate) + icl->call_state |= ostate; + else if (icl->call_state & _XtCBFreeAfterCalling) + XtFree((char *)icl); + else + icl->call_state = ostate; + UNLOCK_APP(app); +} /* XtCallCallbacks */ + + +#if NeedFunctionPrototypes +XtCallbackStatus XtHasCallbacks( + Widget widget, + _Xconst char* callback_name + ) +#else +XtCallbackStatus XtHasCallbacks(widget, callback_name) + Widget widget; + String callback_name; +#endif +{ + InternalCallbackList *callbacks; + XtCallbackStatus retval = XtCallbackHasSome; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + callbacks = FetchInternalList(widget, callback_name); + if (!callbacks) + retval = XtCallbackNoList; + else if (!*callbacks) + retval = XtCallbackHasNone; + UNLOCK_APP(app); + return retval; +} /* XtHasCallbacks */ + + +void XtCallCallbackList(widget, callbacks, call_data) + Widget widget; + XtCallbackList callbacks; + XtPointer call_data; +{ + register InternalCallbackList icl; + register XtCallbackList cl; + register int i; + char ostate; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + if (!callbacks) { + UNLOCK_APP(app); + return; + } + icl = (InternalCallbackList)callbacks; + cl = ToList(icl); + if (icl->count == 1) { + (*cl->callback) (widget, cl->closure, call_data); + UNLOCK_APP(app); + return; + } + ostate = icl->call_state; + icl->call_state = _XtCBCalling; + for (i = icl->count; --i >= 0; cl++) + (*cl->callback) (widget, cl->closure, call_data); + if (ostate) + icl->call_state |= ostate; + else if (icl->call_state & _XtCBFreeAfterCalling) + XtFree((char *)icl); + else + icl->call_state = 0; + UNLOCK_APP(app); +} /* XtCallCallbackList */ + +void _XtPeekCallback(widget, callbacks, callback, closure) + Widget widget; + XtCallbackList callbacks; + XtCallbackProc *callback; + XtPointer *closure; +{ + register InternalCallbackList icl = (InternalCallbackList) callbacks; + register XtCallbackList cl; + + if (!callbacks) { + *callback = (XtCallbackProc) NULL; + return; + } + cl = ToList(icl); + *callback = cl->callback; + *closure = cl->closure; + return; +} + +void _XtCallConditionalCallbackList(widget, callbacks, call_data, cond_proc) + Widget widget; + XtCallbackList callbacks; + XtPointer call_data; + _XtConditionProc cond_proc; +{ + register InternalCallbackList icl; + register XtCallbackList cl; + register int i; + char ostate; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + if (!callbacks) { + UNLOCK_APP(app); + return; + } + icl = (InternalCallbackList)callbacks; + cl = ToList(icl); + if (icl->count == 1) { + (*cl->callback) (widget, cl->closure, call_data); + (void) (*cond_proc)(call_data); + UNLOCK_APP(app); + return; + } + ostate = icl->call_state; + icl->call_state = _XtCBCalling; + for (i = icl->count; --i >= 0; cl++) { + (*cl->callback) (widget, cl->closure, call_data); + if (! (*cond_proc)(call_data)) + break; + } + if (ostate) + icl->call_state |= ostate; + else if (icl->call_state & _XtCBFreeAfterCalling) + XtFree((char *)icl); + else + icl->call_state = 0; + UNLOCK_APP(app); +} diff --git a/src/ClickTime.c b/src/ClickTime.c new file mode 100644 index 0000000..807134f --- /dev/null +++ b/src/ClickTime.c @@ -0,0 +1,90 @@ +/* $Xorg: ClickTime.c,v 1.4 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* + * Contains XtSetMultiClickTime, XtGetMultiClickTime + */ + +#include "IntrinsicI.h" + +void XtSetMultiClickTime( dpy, time ) + Display *dpy; + int time; +{ + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + _XtGetPerDisplay(dpy)->multi_click_time = time; + UNLOCK_APP(app); +} + + +int XtGetMultiClickTime( dpy ) + Display *dpy; +{ + int retval; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + retval = _XtGetPerDisplay(dpy)->multi_click_time; + UNLOCK_APP(app); + return retval; +} diff --git a/src/Composite.c b/src/Composite.c new file mode 100644 index 0000000..6d3ea64 --- /dev/null +++ b/src/Composite.c @@ -0,0 +1,283 @@ +/* $Xorg: Composite.c,v 1.4 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital, or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#define COMPOSITE +#include "IntrinsicI.h" +#include "StringDefs.h" + +static XtResource resources[] = { + {XtNchildren, XtCReadOnly, XtRWidgetList, sizeof(WidgetList), + XtOffsetOf(CompositeRec, composite.children), XtRImmediate, NULL}, + {XtNnumChildren, XtCReadOnly, XtRCardinal, sizeof(Cardinal), + XtOffsetOf(CompositeRec, composite.num_children), XtRImmediate, 0}, + {XtNinsertPosition, XtCInsertPosition, XtRFunction, sizeof(XtOrderProc), + XtOffsetOf(CompositeRec, composite.insert_position), XtRImmediate, NULL}, +}; + +static void CompositeClassPartInitialize(); +static void CompositeInitialize(); +static void CompositeInsertChild(); +static void CompositeDeleteChild(); +static void CompositeDestroy(); + +externaldef(compositeclassrec) CompositeClassRec compositeClassRec = { + { /******* CorePart *******/ + /* superclass */ &widgetClassRec, + /* class_name */ "Composite", + /* widget_size */ sizeof(CompositeRec), + /* class_initialize */ NULL, + /* class_part_initialize*/ CompositeClassPartInitialize, + /* class_inited */ FALSE, + /* initialize */ CompositeInitialize, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ FALSE, + /* visible_interest */ FALSE, + /* destroy */ CompositeDestroy, + /* resize */ NULL, + /* expose */ NULL, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + }, + { /**** CompositePart *****/ + /* geometry_handler */ NULL, + /* change_managed */ NULL, + /* insert_child */ CompositeInsertChild, + /* delete_child */ CompositeDeleteChild, + /* extension */ NULL + } +}; + +externaldef(compositewidgetclass) WidgetClass compositeWidgetClass = (WidgetClass) &compositeClassRec; + +static void InheritAllowsChangeManagedSet(widget_class) + WidgetClass widget_class; +{ + CompositeWidgetClass cc = (CompositeWidgetClass) widget_class; + CompositeClassExtension ext, super_ext, new_ext; + + ext = (CompositeClassExtension) + XtGetClassExtension(widget_class, + XtOffsetOf(CompositeClassRec, composite_class.extension), + NULLQUARK, 1L, 0); + + if (ext && ext->version == XtCompositeExtensionVersion) + return; + + super_ext = (CompositeClassExtension) + XtGetClassExtension(cc->core_class.superclass, + XtOffsetOf(CompositeClassRec, composite_class.extension), + NULLQUARK, 1L, 0); + + LOCK_PROCESS; + if (super_ext && super_ext->version == XtCompositeExtensionVersion && + super_ext->record_size == sizeof(CompositeClassExtensionRec) && + super_ext->allows_change_managed_set) { + + new_ext = (CompositeClassExtension) + __XtCalloc(1, sizeof(CompositeClassExtensionRec)); + + /* Be careful to inherit only what is appropriate */ + new_ext->next_extension = cc->composite_class.extension; + new_ext->record_type = NULLQUARK; + new_ext->version = XtCompositeExtensionVersion; + new_ext->record_size = sizeof(CompositeClassExtensionRec); + new_ext->accepts_objects = (ext ? ext->accepts_objects : False); + new_ext->allows_change_managed_set = True; + cc->composite_class.extension = (XtPointer) new_ext; + } + UNLOCK_PROCESS; +} + +static void CompositeClassPartInitialize(widgetClass) + WidgetClass widgetClass; +{ + register CompositePartPtr wcPtr; + register CompositePartPtr superPtr; + + wcPtr = (CompositePartPtr) + &(((CompositeWidgetClass)widgetClass)->composite_class); + + if (widgetClass != compositeWidgetClass) + /* don't compute possible bogus pointer */ + superPtr = (CompositePartPtr)&(((CompositeWidgetClass)widgetClass + ->core_class.superclass)->composite_class); +#ifdef lint + else + superPtr = NULL; +#endif + + /* We don't need to check for null super since we'll get to composite + eventually, and it had better define them! */ + + LOCK_PROCESS; + if (wcPtr->geometry_manager == XtInheritGeometryManager) { + wcPtr->geometry_manager = + superPtr->geometry_manager; + } + + if (wcPtr->change_managed == XtInheritChangeManaged) { + wcPtr->change_managed = + superPtr->change_managed; + InheritAllowsChangeManagedSet(widgetClass); + } + + if (wcPtr->insert_child == XtInheritInsertChild) { + wcPtr->insert_child = superPtr->insert_child; + } + + if (wcPtr->delete_child == XtInheritDeleteChild) { + wcPtr->delete_child = superPtr->delete_child; + } + UNLOCK_PROCESS; +} + +static void CompositeDestroy(w) + Widget w; +{ + register CompositeWidget cw = (CompositeWidget) w; + + XtFree((char *) cw->composite.children); +} + +static void CompositeInsertChild(w) + Widget w; +{ + register Cardinal position; + register Cardinal i; + register CompositeWidget cw; + register WidgetList children; + + cw = (CompositeWidget) w->core.parent; + children = cw->composite.children; + + if (cw->composite.insert_position != NULL) + position = (*(cw->composite.insert_position))(w); + else + position = cw->composite.num_children; + + if (cw->composite.num_children == cw->composite.num_slots) { + /* Allocate more space */ + cw->composite.num_slots += (cw->composite.num_slots / 2) + 2; + cw->composite.children = children = + (WidgetList) XtRealloc((XtPointer) children, + (unsigned) (cw->composite.num_slots) * sizeof(Widget)); + } + /* Ripple children up one space from "position" */ + for (i = cw->composite.num_children; i > position; i--) { + children[i] = children[i-1]; + } + children[position] = w; + cw->composite.num_children++; +} + +static void CompositeDeleteChild(w) + Widget w; +{ + register Cardinal position; + register Cardinal i; + register CompositeWidget cw; + + cw = (CompositeWidget) w->core.parent; + + for (position = 0; position < cw->composite.num_children; position++) { + if (cw->composite.children[position] == w) { + break; + } + } + if (position == cw->composite.num_children) return; + + /* Ripple children down one space from "position" */ + cw->composite.num_children--; + for (i = position; i < cw->composite.num_children; i++) { + cw->composite.children[i] = cw->composite.children[i+1]; + } +} + +/* ARGSUSED */ +static void CompositeInitialize(requested_widget, new_widget, args, num_args) + Widget new_widget, requested_widget; + ArgList args; + Cardinal *num_args; +{ + register CompositeWidget cw; + + cw = (CompositeWidget) new_widget; + cw->composite.num_children = 0; + cw->composite.children = NULL; + cw->composite.num_slots = 0; +} diff --git a/src/Constraint.c b/src/Constraint.c new file mode 100644 index 0000000..90b62bd --- /dev/null +++ b/src/Constraint.c @@ -0,0 +1,131 @@ +/* $Xorg: Constraint.c,v 1.4 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#define CONSTRAINT +#include "IntrinsicI.h" +#include "StringDefs.h" + +static void ConstraintPartInitialize(); +externaldef(constraintclassrec) ConstraintClassRec constraintClassRec = { + { /******* CorePart *******/ + /* superclass */ (WidgetClass) &compositeClassRec, + /* class_name */ "Constraint", + /* widget_size */ sizeof(ConstraintRec), + /* class_initialize */ NULL, + /* class_part_initialize*/ ConstraintPartInitialize, + /* class_inited */ FALSE, + /* initialize */ NULL, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ NULL, + /* num_resources */ 0, + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ FALSE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ NULL, + /* expose */ NULL, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + },{ /**** CompositePart *****/ + /* geometry_handler */ NULL, + /* change_managed */ NULL, + /* insert_child */ XtInheritInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ NULL + },{ /**** ConstraintPart ****/ + /* resources */ NULL, + /* num_resources */ 0, + /* constraint_size */ 0, + /* initialize */ NULL, + /* destroy */ NULL, + /* set_values */ NULL, + /* extension */ NULL + } +}; + +externaldef(constraintwidgetclass) WidgetClass constraintWidgetClass = + (WidgetClass) &constraintClassRec; + + +static void ConstraintPartInitialize(wc) + WidgetClass wc; +{ + ConstraintWidgetClass cwc = (ConstraintWidgetClass)wc; + if (cwc->constraint_class.resources) + _XtCompileResourceList(cwc->constraint_class.resources, + cwc->constraint_class.num_resources); + + _XtConstraintResDependencies((ConstraintWidgetClass)wc); +} diff --git a/src/Convert.c b/src/Convert.c new file mode 100644 index 0000000..08d461f --- /dev/null +++ b/src/Convert.c @@ -0,0 +1,1169 @@ +/* $Xorg: Convert.c,v 1.5 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "StringDefs.h" + +/* Conversion procedure hash table */ + +#define CONVERTHASHSIZE ((unsigned)256) +#define CONVERTHASHMASK 255 +#define ProcHash(from_type, to_type) (2 * (from_type) + to_type) + +typedef struct _ConverterRec *ConverterPtr; +typedef struct _ConverterRec { + ConverterPtr next; + XrmRepresentation from, to; + XtTypeConverter converter; + XtDestructor destructor; + unsigned short num_args; + unsigned int do_ref_count:1; + unsigned int new_style:1; + unsigned int global:1; + char cache_type; +} ConverterRec; + +#define ConvertArgs(p) ((XtConvertArgList)((p)+1)) + +/* used for old-style type converter cache only */ +static Heap globalHeap = {NULL, NULL, 0}; + +void _XtSetDefaultConverterTable(table) + ConverterTable *table; +{ + register ConverterTable globalConverterTable; + + LOCK_PROCESS; + globalConverterTable = _XtGetProcessContext()->globalConverterTable; + + *table = (ConverterTable) + __XtCalloc(CONVERTHASHSIZE, (unsigned)sizeof(ConverterPtr)); + _XtAddDefaultConverters(*table); + + if (globalConverterTable) { + ConverterPtr rec; + int i; + XtCacheType cache_type; + for (i = CONVERTHASHSIZE; --i >= 0; ) { + for (rec = *globalConverterTable++; rec; rec = rec->next) { + cache_type = rec->cache_type; + if (rec->do_ref_count) + cache_type |= XtCacheRefCount; + _XtTableAddConverter(*table, rec->from, rec->to, rec->converter, + ConvertArgs(rec), rec->num_args, + rec->new_style, cache_type, + rec->destructor, True); + } + } + } + UNLOCK_PROCESS; +} + +void _XtFreeConverterTable(table) + ConverterTable table; +{ + register int i; + register ConverterPtr p; + + for (i = 0; i < CONVERTHASHSIZE; i++) { + for (p = table[i]; p; ) { + register ConverterPtr next = p->next; + XtFree((char*)p); + p = next; + } + } + XtFree((char*)table); +} + +/* Data cache hash table */ + +typedef struct _CacheRec *CachePtr; + +typedef struct _CacheRec { + CachePtr next; + XtPointer tag; + int hash; + XtTypeConverter converter; + unsigned short num_args; + unsigned int conversion_succeeded:1; + unsigned int has_ext:1; + unsigned int is_refcounted:1; + unsigned int must_be_freed:1; + unsigned int from_is_value:1; + unsigned int to_is_value:1; + XrmValue from; + XrmValue to; +} CacheRec; + +typedef struct _CacheRecExt { + CachePtr *prev; + XtDestructor destructor; + XtPointer closure; + long ref_count; +} CacheRecExt; + +#define CEXT(p) ((CacheRecExt *)((p)+1)) +#define CARGS(p) ((p)->has_ext ? (XrmValue *)(CEXT(p)+1) : (XrmValue *)((p)+1)) + +#define CACHEHASHSIZE 256 +#define CACHEHASHMASK 255 +typedef CachePtr CacheHashTable[CACHEHASHSIZE]; + +static CacheHashTable cacheHashTable; + +#if NeedFunctionPrototypes +void _XtTableAddConverter( + ConverterTable table, + XrmRepresentation from_type, + XrmRepresentation to_type, + XtTypeConverter converter, + XtConvertArgList convert_args, + Cardinal num_args, + _XtBoolean new_style, + XtCacheType cache_type, + XtDestructor destructor, + _XtBoolean global) +#else +void _XtTableAddConverter(table, from_type, to_type, converter, convert_args, + num_args, new_style, cache_type, destructor, global) + ConverterTable table; + XrmRepresentation from_type, to_type; + XtTypeConverter converter; + XtConvertArgList convert_args; + Cardinal num_args; + Boolean new_style; + XtCacheType cache_type; + XtDestructor destructor; + Boolean global; +#endif +{ + register ConverterPtr *pp; + register ConverterPtr p; + XtConvertArgList args; + + pp= &table[ProcHash(from_type, to_type) & CONVERTHASHMASK]; + while ((p = *pp) && (p->from != from_type || p->to != to_type)) + pp = &p->next; + + if (p) { + *pp = p->next; + XtFree((char *)p); + } + + p = (ConverterPtr) __XtMalloc(sizeof(ConverterRec) + + sizeof(XtConvertArgRec) * num_args); + p->next = *pp; + *pp = p; + p->from = from_type; + p->to = to_type; + p->converter = converter; + p->destructor = destructor; + p->num_args = num_args; + p->global = global; + args = ConvertArgs(p); + while (num_args--) + *args++ = *convert_args++; + p->new_style = new_style; + p->do_ref_count = False; + if (destructor || (cache_type & 0xff)) { + p->cache_type = cache_type & 0xff; + if (cache_type & XtCacheRefCount) + p->do_ref_count = True; + } else { + p->cache_type = XtCacheNone; + } +} + +#if NeedFunctionPrototypes +void XtSetTypeConverter( + register _Xconst char* from_type, + register _Xconst char* to_type, + XtTypeConverter converter, + XtConvertArgList convert_args, + Cardinal num_args, + XtCacheType cache_type, + XtDestructor destructor + ) +#else +void XtSetTypeConverter(from_type, to_type, converter, convert_args, num_args, cache_type, destructor) + register String from_type, to_type; + XtTypeConverter converter; + XtConvertArgList convert_args; + Cardinal num_args; + XtCacheType cache_type; + XtDestructor destructor; +#endif +{ + ProcessContext process; + XtAppContext app; + XrmRepresentation from; + XrmRepresentation to; + + LOCK_PROCESS; + process = _XtGetProcessContext(); + app = process->appContextList; + from = XrmStringToRepresentation(from_type); + to = XrmStringToRepresentation(to_type); + + if (!process->globalConverterTable) { + process->globalConverterTable = (ConverterTable) + __XtCalloc(CONVERTHASHSIZE, (unsigned)sizeof(ConverterPtr)); + } + _XtTableAddConverter(process->globalConverterTable, from, to, + converter, convert_args, + num_args, True, cache_type, destructor, True); + while (app) { + _XtTableAddConverter(app->converterTable, from, to, + converter, convert_args, + num_args, True, cache_type, destructor, True); + app = app->next; + } + UNLOCK_PROCESS; +} + +#if NeedFunctionPrototypes +void XtAppSetTypeConverter( + XtAppContext app, + register _Xconst char* from_type, + register _Xconst char* to_type, + XtTypeConverter converter, + XtConvertArgList convert_args, + Cardinal num_args, + XtCacheType cache_type, + XtDestructor destructor + ) +#else +void XtAppSetTypeConverter(app, from_type, to_type, converter, convert_args, num_args, cache_type, destructor) + XtAppContext app; + register String from_type, to_type; + XtTypeConverter converter; + XtConvertArgList convert_args; + Cardinal num_args; + XtCacheType cache_type; + XtDestructor destructor; +#endif +{ + LOCK_PROCESS; + _XtTableAddConverter(app->converterTable, + XrmStringToRepresentation(from_type), + XrmStringToRepresentation(to_type), + converter, convert_args, num_args, + True, cache_type, destructor, False); + UNLOCK_PROCESS; +} + +/* old interface */ +#if NeedFunctionPrototypes +void XtAddConverter( + register _Xconst char* from_type, + register _Xconst char* to_type, + XtConverter converter, + XtConvertArgList convert_args, + Cardinal num_args + ) +#else +void XtAddConverter(from_type, to_type, converter, convert_args, num_args) + register String from_type, to_type; + XtConverter converter; + XtConvertArgList convert_args; + Cardinal num_args; +#endif +{ + ProcessContext process; + XtAppContext app; + XrmRepresentation from; + XrmRepresentation to; + + LOCK_PROCESS; + process = _XtGetProcessContext(); + app = process->appContextList; + from = XrmStringToRepresentation(from_type); + to = XrmStringToRepresentation(to_type); + + if (!process->globalConverterTable) { + process->globalConverterTable = (ConverterTable) + __XtCalloc(CONVERTHASHSIZE, (unsigned)sizeof(ConverterPtr)); + } + _XtTableAddConverter(process->globalConverterTable, from, to, + (XtTypeConverter)converter, convert_args, num_args, + False, XtCacheAll, (XtDestructor)NULL, True); + while (app) { + _XtTableAddConverter(app->converterTable, from, to, + (XtTypeConverter)converter, convert_args, + num_args, False, XtCacheAll, (XtDestructor)NULL, + True); + app = app->next; + } + UNLOCK_PROCESS; +} + +/* old interface */ +#if NeedFunctionPrototypes +void XtAppAddConverter( + XtAppContext app, + register _Xconst char* from_type, + register _Xconst char* to_type, + XtConverter converter, + XtConvertArgList convert_args, + Cardinal num_args + ) +#else +void XtAppAddConverter(app, from_type, to_type, converter, convert_args, num_args) + XtAppContext app; + register String from_type, to_type; + XtConverter converter; + XtConvertArgList convert_args; + Cardinal num_args; +#endif +{ + LOCK_PROCESS; + _XtTableAddConverter(app->converterTable, + XrmStringToRepresentation(from_type), + XrmStringToRepresentation(to_type), + (XtTypeConverter)converter, convert_args, num_args, + False, XtCacheAll, (XtDestructor)NULL, False); + UNLOCK_PROCESS; +} + +static CachePtr +CacheEnter(heap, converter, args, num_args, from, to, succeeded, hash, + do_ref, do_free, destructor, closure) + Heap* heap; + register XtTypeConverter converter; + register XrmValuePtr args; + Cardinal num_args; + XrmValuePtr from; + XrmValuePtr to; + Boolean succeeded; + register int hash; + Boolean do_ref; + Boolean do_free; + XtDestructor destructor; + XtPointer closure; +{ + register CachePtr *pHashEntry; + register CachePtr p; + register Cardinal i; + + LOCK_PROCESS; + pHashEntry = &cacheHashTable[hash & CACHEHASHMASK]; + + if ((succeeded && destructor) || do_ref) { + p = (CachePtr) _XtHeapAlloc(heap, (sizeof(CacheRec) + + sizeof(CacheRecExt) + + num_args * sizeof(XrmValue))); + CEXT(p)->prev = pHashEntry; + CEXT(p)->destructor = succeeded ? destructor : NULL; + CEXT(p)->closure = closure; + CEXT(p)->ref_count = 1; + p->has_ext = True; + } + else { + p = (CachePtr)_XtHeapAlloc(heap, (sizeof(CacheRec) + + num_args * sizeof(XrmValue))); + p->has_ext = False; + } + if (!to->addr) + succeeded = False; + p->conversion_succeeded = succeeded; + p->is_refcounted = do_ref; + p->must_be_freed = do_free; + p->next = *pHashEntry; + if (p->next && p->next->has_ext) + CEXT(p->next)->prev = &p->next; + + *pHashEntry = p; + p->tag = (XtPointer)heap; + p->hash = hash; + p->converter = converter; + p->from.size = from->size; + if (from->size <= sizeof(p->from.addr)) { + p->from_is_value = True; + XtMemmove(&p->from.addr, from->addr, from->size); + } else { + p->from_is_value = False; + p->from.addr = (XPointer)_XtHeapAlloc(heap, from->size); + (void) memmove((char *)p->from.addr, (char *)from->addr, from->size); + } + p->num_args = num_args; + if (num_args) { + XrmValue *pargs = CARGS(p); + for (i = 0; i < num_args; i++) { + pargs[i].size = args[i].size; + pargs[i].addr = (XPointer)_XtHeapAlloc(heap, args[i].size); + XtMemmove(pargs[i].addr, args[i].addr, args[i].size); + } + } + p->to.size = to->size; + if (!succeeded) { + p->to_is_value = False; + p->to.addr = NULL; + } else if (to->size <= sizeof(p->to.addr)) { + p->to_is_value = True; + XtMemmove(&p->to.addr, to->addr, to->size); + } else { + p->to_is_value = False; + p->to.addr = (XPointer)_XtHeapAlloc(heap, to->size); + (void) memmove((char *)p->to.addr, (char *)to->addr, to->size); + } + UNLOCK_PROCESS; + return p; +} + +static void FreeCacheRec(app, p, prev) + XtAppContext app; + CachePtr p; + CachePtr *prev; +{ + LOCK_PROCESS; + if (p->has_ext) { + if (CEXT(p)->destructor) { + Cardinal num_args = p->num_args; + XrmValue *args = NULL; + XrmValue toc; + if (num_args) + args = CARGS(p); + toc.size = p->to.size; + if (p->to_is_value) + toc.addr = (XPointer)&p->to.addr; + else + toc.addr = p->to.addr; + (*CEXT(p)->destructor) (app, &toc, CEXT(p)->closure, args, + &num_args); + } + *(CEXT(p)->prev) = p->next; + if (p->next && p->next->has_ext) + CEXT(p->next)->prev = CEXT(p)->prev; + } else { + *prev = p->next; + if (p->next && p->next->has_ext) + CEXT(p->next)->prev = prev; + } + if (p->must_be_freed) { + register int i; + if (!p->from_is_value) + XtFree(p->from.addr); + if ((i = p->num_args)) { + XrmValue *pargs = CARGS(p); + while (i--) + XtFree(pargs[i].addr); + } + if (!p->to_is_value) + XtFree(p->to.addr); + XtFree((char*)p); + } + /* else on private heap; will free entire heap later */ + UNLOCK_PROCESS; +} + + +void _XtCacheFlushTag(app, tag) + XtAppContext app; + XtPointer tag; +{ + int i; + register CachePtr *prev; + register CachePtr rec; + + LOCK_PROCESS; + for (i = CACHEHASHSIZE; --i >= 0;) { + prev = &cacheHashTable[i]; + while ((rec = *prev)) { + if (rec->tag == tag) + FreeCacheRec(app, rec, prev); + else + prev = &rec->next; + } + } + UNLOCK_PROCESS; +} + +#ifdef DEBUG +#include <stdio.h> + +void _XtConverterCacheStats() +{ + register Cardinal i; + register CachePtr p; + register Cardinal entries; + + LOCK_PROCESS; + for (i = 0; i < CACHEHASHSIZE; i++) { + p = cacheHashTable[i]; + if (p) { + for (entries = 0; p; p = p->next) { + entries++; + } + (void) fprintf(stdout, "Index: %4d Entries: %d\n", i, entries); + for (p = cacheHashTable[i]; p; p = p->next) { + (void) fprintf(stdout, " Size: %3d Refs: %3d '", + p->from.size, + p->has_ext ? CEXT(p)->ref_count : 0); + (void) fprintf(stdout, "'\n"); + } + (void) fprintf(stdout, "\n"); + } + } + UNLOCK_PROCESS; +} +#endif /*DEBUG*/ + +static Boolean ResourceQuarkToOffset(widget_class, name, offset) + WidgetClass widget_class; + XrmName name; + Cardinal *offset; +{ + register WidgetClass wc; + register Cardinal i; + register XrmResourceList res, *resources; + + for (wc = widget_class; wc; wc = wc->core_class.superclass) { + resources = (XrmResourceList*) wc->core_class.resources; + for (i = 0; i < wc->core_class.num_resources; i++, resources++) { + res = *resources; + if (res->xrm_name == name) { + *offset = -res->xrm_offset - 1; + return True; + } + } /* for i in resources */ + } /* for wc in widget classes */ + (*offset) = 0; + return False; +} + + +static void ComputeArgs(widget, convert_args, num_args, args) + Widget widget; + XtConvertArgList convert_args; + Cardinal num_args; + XrmValuePtr args; +{ + register Cardinal i; + Cardinal offset; + String params[1]; + Cardinal num_params = 1; + Widget ancestor = NULL; + + for (i = 0; i < num_args; i++) { + args[i].size = convert_args[i].size; + switch (convert_args[i].address_mode) { + case XtAddress: + args[i].addr = convert_args[i].address_id; + break; + + case XtBaseOffset: +#if defined(CRAY1) && !defined(__STDC__) + args[i].addr = + (XPointer)((int)widget + (int)convert_args[i].address_id); +#else + args[i].addr = (XPointer)((char *)widget + (int)convert_args[i].address_id); +#endif + break; + + case XtWidgetBaseOffset: + if (!ancestor) { + if (XtIsWidget(widget)) + ancestor = widget; + else + ancestor = _XtWindowedAncestor(widget); + } + +#if defined(CRAY1) && !defined(__STDC__) + args[i].addr = + (XPointer)((int)ancestor + (int)convert_args[i].address_id); +#else + args[i].addr = + (XPointer)((char *)ancestor + (int)convert_args[i].address_id); +#endif + break; + + case XtImmediate: + args[i].addr = (XPointer) &(convert_args[i].address_id); + break; + + case XtProcedureArg: + (*(XtConvertArgProc)convert_args[i].address_id) + (widget, &convert_args[i].size, &args[i]); + break; + + case XtResourceString: + /* Convert in place for next usage */ + convert_args[i].address_mode = XtResourceQuark; + convert_args[i].address_id = + (XtPointer)XrmStringToQuark((String)convert_args[i].address_id); + /* Fall through */ + + case XtResourceQuark: + if (! ResourceQuarkToOffset(widget->core.widget_class, + (XrmQuark) convert_args[i].address_id, &offset)) { + params[0]= + XrmQuarkToString((XrmQuark) convert_args[i].address_id); + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidResourceName","computeArgs",XtCXtToolkitError, + "Cannot find resource name %s as argument to conversion", + params,&num_params); + offset = 0; + } +#if defined(CRAY1) && !defined(__STDC__) + args[i].addr = (XPointer)((int)widget + offset); +#else + args[i].addr = (XPointer)((char *)widget + offset); +#endif + break; + default: + params[0] = XtName(widget); + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidAddressMode", "computeArgs", XtCXtToolkitError, + "Conversion arguments for widget '%s' contain an unsupported address mode", + params,&num_params); + args[i].addr = NULL; + args[i].size = 0; + } /* switch */ + } /* for */ +} /* ComputeArgs */ + +void XtDirectConvert(converter, args, num_args, from, to) + XtConverter converter; + XrmValuePtr args; + Cardinal num_args; + register XrmValuePtr from; + XrmValuePtr to; +{ + register CachePtr p; + register int hash; + register Cardinal i; + + LOCK_PROCESS; + /* Try to find cache entry for conversion */ + hash = ((int)(converter) >> 2) + from->size + *((char *) from->addr); + if (from->size > 1) hash += ((char *) from->addr)[1]; + + for (p = cacheHashTable[hash & CACHEHASHMASK]; p; p = p->next) { + if ((p->hash == hash) + && (p->converter == (XtTypeConverter)converter) + && (p->from.size == from->size) + && !(p->from_is_value ? + XtMemcmp(&p->from.addr, from->addr, from->size) : + memcmp((char *)p->from.addr, (char *)from->addr, from->size)) + && (p->num_args == num_args)) { + if ((i = num_args)) { + XrmValue *pargs = CARGS(p); + /* Are all args the same data ? */ + while (i) { + i--; /* do not move to while test, broken compilers */ + if (pargs[i].size != args[i].size || + XtMemcmp(pargs[i].addr, args[i].addr, args[i].size)) { + i++; + break; + } + } + } + if (!i) { + /* Perfect match */ + to->size = p->to.size; + if (p->to_is_value) + to->addr = (XPointer)&p->to.addr; + else + to->addr = p->to.addr; + UNLOCK_PROCESS; + return; + } + } + } + + /* Didn't find it, call converter procedure and entry result in cache */ + (*to).size = 0; + (*to).addr = NULL; + (*converter)(args, &num_args, from, to); + /* This memory can never be freed since we don't know the Display + * or app context from which to compute the persistance */ + { + CacheEnter(&globalHeap, (XtTypeConverter)converter, args, num_args, + from, to, (to->addr != NULL), hash, False, False, + (XtDestructor)NULL, NULL); + } + UNLOCK_PROCESS; +} + + +static ConverterPtr GetConverterEntry( app, converter ) + XtAppContext app; + XtTypeConverter converter; +{ + int entry; + register ConverterPtr cP; + ConverterTable converterTable; + + LOCK_PROCESS; + converterTable = app->converterTable; + cP = NULL; + for (entry = 0; (entry < CONVERTHASHSIZE) && !cP; entry++) { + cP = converterTable[entry]; + while (cP && (cP->converter != converter)) cP = cP->next; + } + UNLOCK_PROCESS; + return cP; +} + + +static Boolean +CallConverter(dpy, converter, + args, num_args, from, to, cache_ref_return, cP) + Display* dpy; + XtTypeConverter converter; + XrmValuePtr args; + Cardinal num_args; + register XrmValuePtr from; + XrmValuePtr to; + XtCacheRef *cache_ref_return; + register ConverterPtr cP; +{ + CachePtr p; + int hash; + Cardinal i; + Boolean retval; + + if (!cP || ((cP->cache_type == XtCacheNone) && !cP->destructor)) { + XtPointer closure; + if (cache_ref_return) *cache_ref_return = NULL; + retval = (*(XtTypeConverter)converter) + (dpy, args, &num_args, from, to, &closure); + return retval; + } + + LOCK_PROCESS; + /* Try to find cache entry for conversion */ + hash = ((int)(converter) >> 2) + from->size + *((char *) from->addr); + if (from->size > 1) hash += ((char *) from->addr)[1]; + + if (cP->cache_type != XtCacheNone) { + for (p = cacheHashTable[hash & CACHEHASHMASK]; p; p = p->next){ + if ((p->hash == hash) + && (p->converter == converter) + && (p->from.size == from->size) + && !(p->from_is_value ? + XtMemcmp(&p->from.addr, from->addr, from->size) : + memcmp((char *)p->from.addr, (char *)from->addr, from->size)) + && (p->num_args == num_args)) { + if ((i = num_args)) { + XrmValue *pargs = CARGS(p); + /* Are all args the same data ? */ + while (i) { + i--; /* do not move to while test, broken compilers */ + if (pargs[i].size != args[i].size || + XtMemcmp(pargs[i].addr, args[i].addr, args[i].size)){ + i++; + break; + } + } + } + if (!i) { + /* Perfect match */ + if (p->conversion_succeeded) { + if (to->addr) { /* new-style call */ + if (to->size < p->to.size) { + to->size = p->to.size; + UNLOCK_PROCESS; + return False; + } + to->size = p->to.size; + if (p->to_is_value) { + XtMemmove(to->addr, &p->to.addr, + to->size); + } else { + (void) memmove((char *)to->addr, + (char *)p->to.addr, to->size); + } + } else { /* old-style call */ + to->size = p->to.size; + if (p->to_is_value) + to->addr = (XPointer)&p->to.addr; + else + to->addr = p->to.addr; + } + } + if (p->is_refcounted) { + CEXT(p)->ref_count++; + if (cache_ref_return) + *cache_ref_return = (XtCacheRef)p; + else + p->is_refcounted = False; + } + else { + if (cache_ref_return) + *cache_ref_return = NULL; + } + retval = (p->conversion_succeeded); + UNLOCK_PROCESS; + return retval; + } + } + } + } + + /* No cache entry, call converter procedure and enter result in cache */ + { + Heap *heap; + XtPointer closure = NULL; + unsigned int supplied_size = to->size; + Boolean do_ref = cP->do_ref_count && cache_ref_return; + Boolean do_free = False; + Boolean retval = + (*(XtTypeConverter)converter)(dpy, args, &num_args, from, to, &closure); + + if (retval == False && supplied_size < to->size) { + /* programmer error: caller must allocate sufficient storage */ + if (cache_ref_return) + *cache_ref_return = NULL; + UNLOCK_PROCESS; + return False; + } + + if ((cP->cache_type == XtCacheNone) || do_ref) { + heap = NULL; + do_free = True; + } + else if (cP->cache_type == XtCacheByDisplay) + heap = &_XtGetPerDisplay(dpy)->heap; + else if (cP->global) + heap = &globalHeap; + else + heap = &XtDisplayToApplicationContext(dpy)->heap; + + p = CacheEnter(heap, converter, args, num_args, from, to, retval, + hash, do_ref, do_free, cP->destructor, closure); + if (do_ref) + *cache_ref_return = (XtCacheRef)p; + else if (cache_ref_return) + *cache_ref_return = NULL; + UNLOCK_PROCESS; + return retval; + } +} + +Boolean +XtCallConverter(dpy, converter, args, num_args, from, to, cache_ref_return) + Display* dpy; + XtTypeConverter converter; + XrmValuePtr args; + Cardinal num_args; + register XrmValuePtr from; + XrmValuePtr to; + XtCacheRef *cache_ref_return; +{ + ConverterPtr cP; + Boolean retval; + XtAppContext app = XtDisplayToApplicationContext(dpy); + + LOCK_APP(app); + if ((cP = GetConverterEntry(app, converter)) == NULL) { + XtAppSetTypeConverter(XtDisplayToApplicationContext(dpy), + "_XtUnk1", "_XtUnk2", + converter, NULL, 0, + XtCacheAll, NULL); + cP = GetConverterEntry(app, converter); + } + retval = CallConverter(dpy, converter, args, num_args, from, to, + cache_ref_return, cP); + UNLOCK_APP(app); + return retval; +} + +Boolean _XtConvert(widget, from_type, from, to_type, to, cache_ref_return) + Widget widget; + register XrmRepresentation from_type; + XrmValuePtr from; + register XrmRepresentation to_type; + register XrmValuePtr to; + XtCacheRef *cache_ref_return; +{ + XtAppContext app = XtWidgetToApplicationContext(widget); + register ConverterPtr p; + Cardinal num_args; + XrmValue *args; + + /* Look for type converter */ + LOCK_PROCESS; + p = app->converterTable[ProcHash(from_type, to_type) & CONVERTHASHMASK]; + for (; p; p = p->next) { + if (from_type == p->from && to_type == p->to) { + Boolean retval = False; + /* Compute actual arguments from widget and arg descriptor */ + num_args = p->num_args; + if (num_args != 0) { + args = (XrmValue*) + ALLOCATE_LOCAL( num_args * sizeof (XrmValue) ); + if (!args) _XtAllocError("alloca"); + ComputeArgs(widget, ConvertArgs(p), num_args, args); + } else args = NULL; + if (p->new_style) { + retval = + CallConverter(XtDisplayOfObject(widget), + p->converter, args, num_args, + from, to, cache_ref_return, p); + } + else { /* is old-style (non-display) converter */ + XrmValue tempTo; + XtDirectConvert((XtConverter)p->converter, args, num_args, + from, &tempTo); + if (cache_ref_return) + *cache_ref_return = NULL; + if (tempTo.addr) { + if (to->addr) { /* new-style caller */ + if (to->size >= tempTo.size) { + if (to_type == _XtQString) + *(String*)(to->addr) = tempTo.addr; + else { + XtMemmove(to->addr, tempTo.addr, + tempTo.size); + } + retval = True; + } + to->size = tempTo.size; + } else { /* old-style caller */ + *to = tempTo; + retval = True; + } + } + } + if (args) DEALLOCATE_LOCAL( (XtPointer)args ); + UNLOCK_PROCESS; + return retval; + } + } + + { + String params[2]; + Cardinal num_params = 2; + params[0] = XrmRepresentationToString(from_type); + params[1] = XrmRepresentationToString(to_type); + XtAppWarningMsg(app, "typeConversionError", "noConverter", XtCXtToolkitError, + "No type converter registered for '%s' to '%s' conversion.", + params, &num_params); + } + UNLOCK_PROCESS; + return False; +} + +#if NeedFunctionPrototypes +void XtConvert( + Widget widget, + _Xconst char* from_type_str, + XrmValuePtr from, + _Xconst char* to_type_str, + XrmValuePtr to + ) +#else +void XtConvert(widget, from_type_str, from, to_type_str, to) + Widget widget; + String from_type_str; + XrmValuePtr from; + String to_type_str; + XrmValuePtr to; +#endif +{ + XrmQuark from_type, to_type; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + from_type = XrmStringToRepresentation(from_type_str); + to_type = XrmStringToRepresentation(to_type_str); + if (from_type != to_type) { + /* It's not safe to ref count these resources, 'cause we + don't know what older clients may have assumed about + the resource lifetimes. + XtCacheRef ref; + */ + to->addr = NULL; + to->size = 0; + _XtConvert(widget, from_type, from, to_type, to, /*&ref*/ NULL); + /* + if (ref) { + XtAddCallback( widget, XtNdestroyCallback, + XtCallbackReleaseCacheRef, (XtPointer)ref ); + } + */ + } + else + (*to) = *from; + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +Boolean XtConvertAndStore( + Widget object, + _Xconst char* from_type_str, + XrmValuePtr from, + _Xconst char* to_type_str, + XrmValuePtr to + ) +#else +Boolean XtConvertAndStore(object, from_type_str, from, to_type_str, to) + Widget object; + String from_type_str; + XrmValuePtr from; + String to_type_str; + XrmValuePtr to; +#endif +{ + XrmQuark from_type, to_type; + WIDGET_TO_APPCON(object); + + LOCK_APP(app); + LOCK_PROCESS; + from_type = XrmStringToRepresentation(from_type_str); + to_type = XrmStringToRepresentation(to_type_str); + if (from_type != to_type) { + static XtPointer local_valueP = NULL; + static Cardinal local_valueS = 128; + XtCacheRef ref; + Boolean local = False; + do { + if (!to->addr) { + if (!local_valueP) + local_valueP = _XtHeapAlloc(&globalHeap, local_valueS); + to->addr = local_valueP; + to->size = local_valueS; + local = True; + } + if (!_XtConvert(object, from_type, from, to_type, to, &ref)) { + if (local && (to->size > local_valueS)) { + to->addr = + local_valueP = _XtHeapAlloc(&globalHeap, to->size); + local_valueS = to->size; + continue; + } else { + if (local) { + to->addr = NULL; + to->size = 0; + } + UNLOCK_PROCESS; + UNLOCK_APP(app); + return False; + } + } + if (ref) { + XtAddCallback( object, XtNdestroyCallback, + XtCallbackReleaseCacheRef, (XtPointer)ref ); + } + UNLOCK_PROCESS; + UNLOCK_APP(app); + return True; + } while (local /* && local_valueS < to->size */); + } + if (to->addr) { + if (to->size < from->size) { + to->size = from->size; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return False; + } + (void) memmove(to->addr, from->addr, from->size ); + to->size = from->size; + } else /* from_type == to_type */ + *to = *from; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return True; +} + +void XtAppReleaseCacheRefs(app, refs) + XtAppContext app; + XtCacheRef *refs; +{ + register CachePtr *r; + register CachePtr p; + + LOCK_APP(app); + LOCK_PROCESS; + for (r = (CachePtr*)refs; (p = *r); r++) { + if (p->is_refcounted && --(CEXT(p)->ref_count) == 0) { + FreeCacheRec(app, p, NULL); + } + } + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + + +/* ARGSUSED */ +void XtCallbackReleaseCacheRefList(widget, closure, call_data) + Widget widget; /* unused */ + XtPointer closure; + XtPointer call_data; /* unused */ +{ + XtAppReleaseCacheRefs( XtWidgetToApplicationContext(widget), + (XtCacheRef*)closure ); + XtFree(closure); +} + + +/* ARGSUSED */ +void XtCallbackReleaseCacheRef(widget, closure, call_data) + Widget widget; /* unused */ + XtPointer closure; + XtPointer call_data; /* unused */ +{ + XtCacheRef cache_refs[2]; + cache_refs[0] = (XtCacheRef)closure; + cache_refs[1] = NULL; + XtAppReleaseCacheRefs( XtWidgetToApplicationContext(widget), cache_refs ); +} diff --git a/src/Converters.c b/src/Converters.c new file mode 100644 index 0000000..deaed4a --- /dev/null +++ b/src/Converters.c @@ -0,0 +1,1870 @@ +/* $Xorg: Converters.c,v 1.5 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/*LINTLIBRARY*/ +/* Conversion.c - implementations of resource type conversion procs */ + +#include "IntrinsicI.h" +#include "StringDefs.h" +#include "Shell.h" +#include <stdio.h> +#include <X11/cursorfont.h> +#include <X11/keysym.h> +#include <X11/Xlocale.h> +#include <errno.h> /* for StringToDirectoryString */ + +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif + +#ifdef __STDC__ +#define Const const +#else +#define Const /**/ +#endif + +static Const String XtNwrongParameters = "wrongParameters"; +static Const String XtNconversionError = "conversionError"; +static Const String XtNmissingCharsetList = "missingCharsetList"; + +/* Representation types */ + +#define XtQAtom XrmPermStringToQuark(XtRAtom) +#define XtQCommandArgArray XrmPermStringToQuark(XtRCommandArgArray) +#define XtQCursor XrmPermStringToQuark(XtRCursor) +#define XtQDirectoryString XrmPermStringToQuark(XtRDirectoryString) +#define XtQDisplay XrmPermStringToQuark(XtRDisplay) +#define XtQFile XrmPermStringToQuark(XtRFile) +#define XtQFloat XrmPermStringToQuark(XtRFloat) +#define XtQInitialState XrmPermStringToQuark(XtRInitialState) +#define XtQPixmap XrmPermStringToQuark(XtRPixmap) +#define XtQRestartStyle XrmPermStringToQuark(XtRRestartStyle) +#define XtQShort XrmPermStringToQuark(XtRShort) +#define XtQUnsignedChar XrmPermStringToQuark(XtRUnsignedChar) +#define XtQVisual XrmPermStringToQuark(XtRVisual) + +static XrmQuark XtQBool; +static XrmQuark XtQBoolean; +static XrmQuark XtQColor; +static XrmQuark XtQDimension; +static XrmQuark XtQFont; +static XrmQuark XtQFontSet; +static XrmQuark XtQFontStruct; +static XrmQuark XtQGravity; +static XrmQuark XtQInt; +static XrmQuark XtQPixel; +static XrmQuark XtQPosition; +XrmQuark _XtQString; + +void _XtConvertInitialize() +{ + XtQBool = XrmPermStringToQuark(XtRBool); + XtQBoolean = XrmPermStringToQuark(XtRBoolean); + XtQColor = XrmPermStringToQuark(XtRColor); + XtQDimension = XrmPermStringToQuark(XtRDimension); + XtQFont = XrmPermStringToQuark(XtRFont); + XtQFontSet = XrmPermStringToQuark(XtRFontSet); + XtQFontStruct = XrmPermStringToQuark(XtRFontStruct); + XtQGravity = XrmPermStringToQuark(XtRGravity); + XtQInt = XrmPermStringToQuark(XtRInt); + XtQPixel = XrmPermStringToQuark(XtRPixel); + XtQPosition = XrmPermStringToQuark(XtRPosition); + _XtQString = XrmPermStringToQuark(XtRString); +} + +#define donestr(type, value, tstr) \ + { \ + if (toVal->addr != NULL) { \ + if (toVal->size < sizeof(type)) { \ + toVal->size = sizeof(type); \ + XtDisplayStringConversionWarning(dpy, \ + (char*) fromVal->addr, tstr); \ + return False; \ + } \ + *(type*)(toVal->addr) = (value); \ + } \ + else { \ + static type static_val; \ + static_val = (value); \ + toVal->addr = (XPointer)&static_val; \ + } \ + toVal->size = sizeof(type); \ + return True; \ + } + +#define done(type, value) \ + { \ + if (toVal->addr != NULL) { \ + if (toVal->size < sizeof(type)) { \ + toVal->size = sizeof(type); \ + return False; \ + } \ + *(type*)(toVal->addr) = (value); \ + } \ + else { \ + static type static_val; \ + static_val = (value); \ + toVal->addr = (XPointer)&static_val; \ + } \ + toVal->size = sizeof(type); \ + return True; \ + } + +#if NeedFunctionPrototypes +void XtDisplayStringConversionWarning( + Display* dpy, + _Xconst char* from, + _Xconst char* toType + ) +#else +void XtDisplayStringConversionWarning(dpy, from, toType) + Display* dpy; + String from, toType; +#endif +{ +#ifndef NO_MIT_HACKS + /* Allow suppression of conversion warnings. %%% Not specified. */ + + static enum {Check, Report, Ignore} report_it = Check; + XtAppContext app = XtDisplayToApplicationContext(dpy); + + LOCK_APP(app); + LOCK_PROCESS; + if (report_it == Check) { + XrmDatabase rdb = XtDatabase(dpy); + XrmName xrm_name[2]; + XrmClass xrm_class[2]; + XrmRepresentation rep_type; + XrmValue value; + xrm_name[0] = XrmPermStringToQuark( "stringConversionWarnings" ); + xrm_name[1] = 0; + xrm_class[0] = XrmPermStringToQuark( "StringConversionWarnings" ); + xrm_class[1] = 0; + if (XrmQGetResource( rdb, xrm_name, xrm_class, + &rep_type, &value )) + { + if (rep_type == XtQBoolean) + report_it = *(Boolean*)value.addr ? Report : Ignore; + else if (rep_type == _XtQString) { + XrmValue toVal; + Boolean report; + toVal.addr = (XPointer)&report; + toVal.size = sizeof(Boolean); + if (XtCallConverter(dpy, XtCvtStringToBoolean, (XrmValuePtr)NULL, + (Cardinal)0, &value, &toVal, + (XtCacheRef*)NULL)) + report_it = report ? Report : Ignore; + } + else report_it = Report; + } + else report_it = Report; + } + + if (report_it == Report) { +#endif /* ifndef NO_MIT_HACKS */ + String params[2]; + Cardinal num_params = 2; + params[0] = (String)from; + params[1] = (String)toType; + XtAppWarningMsg(app, + XtNconversionError,"string",XtCXtToolkitError, + "Cannot convert string \"%s\" to type %s", + params,&num_params); +#ifndef NO_MIT_HACKS + } +#endif /* ifndef NO_MIT_HACKS */ + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtStringConversionWarning( + _Xconst char* from, + _Xconst char* toType + ) +#else +void XtStringConversionWarning(from, toType) + String from, toType; +#endif +{ + String params[2]; + Cardinal num_params = 2; + params[0] = (String)from; + params[1] = (String)toType; + XtWarningMsg(XtNconversionError,"string",XtCXtToolkitError, + "Cannot convert string \"%s\" to type %s", + params,&num_params); +} + +static int CompareISOLatin1(); + + +static Boolean IsInteger(string, value) + String string; + int *value; +{ + Boolean foundDigit = False; + Boolean isNegative = False; + Boolean isPositive = False; + int val = 0; + char ch; + /* skip leading whitespace */ + while ((ch = *string) == ' ' || ch == '\t') string++; + while ((ch = *string++)) { + if (ch >= '0' && ch <= '9') { + val *= 10; + val += ch - '0'; + foundDigit = True; + continue; + } + if (ch == ' ' || ch == '\t') { + if (!foundDigit) return False; + /* make sure only trailing whitespace */ + while ((ch = *string++)) { + if (ch != ' ' && ch != '\t') + return False; + } + break; + } + if (ch == '-' && !foundDigit && !isNegative && !isPositive) { + isNegative = True; + continue; + } + if (ch == '+' && !foundDigit && !isNegative && !isPositive) { + isPositive = True; + continue; + } + return False; + } + if (ch == '\0') { + if (isNegative) + *value = -val; + else + *value = val; + return True; + } + return False; +} + + +/*ARGSUSED*/ +Boolean XtCvtIntToBoolean(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtIntToBoolean",XtCXtToolkitError, + "Integer to Boolean conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + done(Boolean, (*(int *)fromVal->addr != 0)); +} + + +/*ARGSUSED*/ +Boolean XtCvtIntToShort(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtIntToShort",XtCXtToolkitError, + "Integer to Short conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + done(short, (*(int *)fromVal->addr)); +} + + +/*ARGSUSED*/ +Boolean XtCvtStringToBoolean(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + String str = (String)fromVal->addr; + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToBoolean",XtCXtToolkitError, + "String to Boolean conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + + if ( (CompareISOLatin1(str, "true") == 0) + || (CompareISOLatin1(str, "yes") == 0) + || (CompareISOLatin1(str, "on") == 0) + || (CompareISOLatin1(str, "1") == 0)) donestr( Boolean, True, XtRBoolean ); + + if ( (CompareISOLatin1(str, "false") == 0) + || (CompareISOLatin1(str, "no") == 0) + || (CompareISOLatin1(str, "off") == 0) + || (CompareISOLatin1(str, "0") == 0)) donestr( Boolean, False, XtRBoolean ); + + XtDisplayStringConversionWarning(dpy, str, XtRBoolean); + return False; +} + + +/*ARGSUSED*/ +Boolean XtCvtIntToBool(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtIntToBool",XtCXtToolkitError, + "Integer to Bool conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + done(Bool, (*(int *)fromVal->addr != 0)); +} + + +/*ARGSUSED*/ +Boolean XtCvtStringToBool(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + String str = (String)fromVal->addr; + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToBool", + XtCXtToolkitError, + "String to Bool conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + + if ( (CompareISOLatin1(str, "true") == 0) + || (CompareISOLatin1(str, "yes") == 0) + || (CompareISOLatin1(str, "on") == 0) + || (CompareISOLatin1(str, "1") == 0)) donestr( Bool, True, XtRBool ); + + if ( (CompareISOLatin1(str, "false") == 0) + || (CompareISOLatin1(str, "no") == 0) + || (CompareISOLatin1(str, "off") == 0) + || (CompareISOLatin1(str, "0") == 0)) donestr( Bool, False, XtRBool ); + + XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRBool); + return False; +} + +XtConvertArgRec Const colorConvertArgs[] = { + {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), + sizeof(Screen *)}, + {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap), + sizeof(Colormap)} +}; + + +/* ARGSUSED */ +Boolean XtCvtIntToColor(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + XColor c; + Screen *screen; + Colormap colormap; + + if (*num_args != 2) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtIntOrPixelToXColor",XtCXtToolkitError, + "Pixel to color conversion needs screen and colormap arguments", + (String *)NULL, (Cardinal *)NULL); + return False; + } + screen = *((Screen **) args[0].addr); + colormap = *((Colormap *) args[1].addr); + c.pixel = *(int *)fromVal->addr; + + XQueryColor(DisplayOfScreen(screen), colormap, &c); + done(XColor, c); +} + + +Boolean XtCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + String str = (String)fromVal->addr; + XColor screenColor; + XColor exactColor; + Screen *screen; + XtPerDisplay pd = _XtGetPerDisplay(dpy); + Colormap colormap; + Status status; + String params[1]; + Cardinal num_params=1; + + if (*num_args != 2) { + XtAppWarningMsg(pd->appContext, XtNwrongParameters, "cvtStringToPixel", + XtCXtToolkitError, + "String to pixel conversion needs screen and colormap arguments", + (String *)NULL, (Cardinal *)NULL); + return False; + } + + screen = *((Screen **) args[0].addr); + colormap = *((Colormap *) args[1].addr); + + if (CompareISOLatin1(str, XtDefaultBackground) == 0) { + *closure_ret = False; + if (pd->rv) donestr(Pixel, BlackPixelOfScreen(screen), XtRPixel) + else donestr(Pixel, WhitePixelOfScreen(screen), XtRPixel); + } + if (CompareISOLatin1(str, XtDefaultForeground) == 0) { + *closure_ret = False; + if (pd->rv) donestr(Pixel, WhitePixelOfScreen(screen), XtRPixel) + else donestr(Pixel, BlackPixelOfScreen(screen), XtRPixel); + } + + status = XAllocNamedColor(DisplayOfScreen(screen), colormap, + (char*)str, &screenColor, &exactColor); + if (status == 0) { + String msg, type; + params[0] = str; + /* Server returns a specific error code but Xlib discards it. Ugh */ + if (XLookupColor(DisplayOfScreen(screen), colormap, (char*)str, + &exactColor, &screenColor)) { + type = "noColormap"; + msg = "Cannot allocate colormap entry for \"%s\""; + } + else { + type = "badValue"; + msg = "Color name \"%s\" is not defined"; + } + + XtAppWarningMsg(pd->appContext, type, "cvtStringToPixel", + XtCXtToolkitError, msg, params, &num_params); + *closure_ret = False; + return False; + } else { + *closure_ret = (char*)True; + donestr(Pixel, screenColor.pixel, XtRPixel); + } +} + +/* ARGSUSED */ +static void FreePixel(app, toVal, closure, args, num_args) + XtAppContext app; + XrmValuePtr toVal; + XtPointer closure; + XrmValuePtr args; + Cardinal *num_args; +{ + Screen *screen; + Colormap colormap; + + if (*num_args != 2) { + XtAppWarningMsg(app, XtNwrongParameters,"freePixel",XtCXtToolkitError, + "Freeing a pixel requires screen and colormap arguments", + (String *)NULL, (Cardinal *)NULL); + return; + } + + screen = *((Screen **) args[0].addr); + colormap = *((Colormap *) args[1].addr); + + if (closure) { + XFreeColors( DisplayOfScreen(screen), colormap, + (unsigned long*)toVal->addr, 1, (unsigned long)0 + ); + } +} + + +/* no longer used by Xt, but it's in the spec */ +XtConvertArgRec Const screenConvertArg[] = { + {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), + sizeof(Screen *)} +}; + +/*ARGSUSED*/ +static void FetchDisplayArg(widget, size, value) + Widget widget; + Cardinal *size; + XrmValue* value; +{ + if (widget == NULL) + XtErrorMsg("missingWidget", "fetchDisplayArg", XtCXtToolkitError, + "FetchDisplayArg called without a widget to reference", + (String*)NULL, (Cardinal*)NULL); + /* can't return any useful Display and caller will de-ref NULL, + so aborting is the only useful option */ + + value->size = sizeof(Display*); + value->addr = (XPointer)&DisplayOfScreen(XtScreenOfObject(widget)); +} + +static XtConvertArgRec Const displayConvertArg[] = { + {XtProcedureArg, (XtPointer)FetchDisplayArg, 0}, +}; + +/*ARGSUSED*/ +Boolean XtCvtStringToCursor(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + + XtPointer *closure_ret; +{ + static Const struct _CursorName { + Const char *name; + unsigned int shape; + } cursor_names[] = { + {"X_cursor", XC_X_cursor}, + {"arrow", XC_arrow}, + {"based_arrow_down", XC_based_arrow_down}, + {"based_arrow_up", XC_based_arrow_up}, + {"boat", XC_boat}, + {"bogosity", XC_bogosity}, + {"bottom_left_corner", XC_bottom_left_corner}, + {"bottom_right_corner", XC_bottom_right_corner}, + {"bottom_side", XC_bottom_side}, + {"bottom_tee", XC_bottom_tee}, + {"box_spiral", XC_box_spiral}, + {"center_ptr", XC_center_ptr}, + {"circle", XC_circle}, + {"clock", XC_clock}, + {"coffee_mug", XC_coffee_mug}, + {"cross", XC_cross}, + {"cross_reverse", XC_cross_reverse}, + {"crosshair", XC_crosshair}, + {"diamond_cross", XC_diamond_cross}, + {"dot", XC_dot}, + {"dotbox", XC_dotbox}, + {"double_arrow", XC_double_arrow}, + {"draft_large", XC_draft_large}, + {"draft_small", XC_draft_small}, + {"draped_box", XC_draped_box}, + {"exchange", XC_exchange}, + {"fleur", XC_fleur}, + {"gobbler", XC_gobbler}, + {"gumby", XC_gumby}, + {"hand1", XC_hand1}, + {"hand2", XC_hand2}, + {"heart", XC_heart}, + {"icon", XC_icon}, + {"iron_cross", XC_iron_cross}, + {"left_ptr", XC_left_ptr}, + {"left_side", XC_left_side}, + {"left_tee", XC_left_tee}, + {"leftbutton", XC_leftbutton}, + {"ll_angle", XC_ll_angle}, + {"lr_angle", XC_lr_angle}, + {"man", XC_man}, + {"middlebutton", XC_middlebutton}, + {"mouse", XC_mouse}, + {"pencil", XC_pencil}, + {"pirate", XC_pirate}, + {"plus", XC_plus}, + {"question_arrow", XC_question_arrow}, + {"right_ptr", XC_right_ptr}, + {"right_side", XC_right_side}, + {"right_tee", XC_right_tee}, + {"rightbutton", XC_rightbutton}, + {"rtl_logo", XC_rtl_logo}, + {"sailboat", XC_sailboat}, + {"sb_down_arrow", XC_sb_down_arrow}, + {"sb_h_double_arrow", XC_sb_h_double_arrow}, + {"sb_left_arrow", XC_sb_left_arrow}, + {"sb_right_arrow", XC_sb_right_arrow}, + {"sb_up_arrow", XC_sb_up_arrow}, + {"sb_v_double_arrow", XC_sb_v_double_arrow}, + {"shuttle", XC_shuttle}, + {"sizing", XC_sizing}, + {"spider", XC_spider}, + {"spraycan", XC_spraycan}, + {"star", XC_star}, + {"target", XC_target}, + {"tcross", XC_tcross}, + {"top_left_arrow", XC_top_left_arrow}, + {"top_left_corner", XC_top_left_corner}, + {"top_right_corner", XC_top_right_corner}, + {"top_side", XC_top_side}, + {"top_tee", XC_top_tee}, + {"trek", XC_trek}, + {"ul_angle", XC_ul_angle}, + {"umbrella", XC_umbrella}, + {"ur_angle", XC_ur_angle}, + {"watch", XC_watch}, + {"xterm", XC_xterm}, + }; + Const struct _CursorName *nP; + char *name = (char *)fromVal->addr; + register int i; + + if (*num_args != 1) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToCursor",XtCXtToolkitError, + "String to cursor conversion needs display argument", + (String *)NULL, (Cardinal *)NULL); + return False; + } + + for (i=0, nP=cursor_names; i < XtNumber(cursor_names); i++, nP++ ) { + if (strcmp(name, nP->name) == 0) { + Display *display = *(Display**)args[0].addr; + Cursor cursor = XCreateFontCursor(display, nP->shape ); + donestr(Cursor, cursor, XtRCursor); + } + } + XtDisplayStringConversionWarning(dpy, name, XtRCursor); + return False; +} + +/* ARGSUSED */ +static void FreeCursor(app, toVal, closure, args, num_args) + XtAppContext app; + XrmValuePtr toVal; + XtPointer closure; /* unused */ + XrmValuePtr args; + Cardinal *num_args; +{ + Display* display; + + if (*num_args != 1) { + XtAppWarningMsg(app, + XtNwrongParameters,"freeCursor",XtCXtToolkitError, + "Free Cursor requires display argument", + (String *)NULL, (Cardinal *)NULL); + return; + } + + display = *(Display**)args[0].addr; + XFreeCursor( display, *(Cursor*)toVal->addr ); +} + +/*ARGSUSED*/ +Boolean XtCvtStringToDisplay(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + Display *d; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToDisplay",XtCXtToolkitError, + "String to Display conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + + d = XOpenDisplay((char *)fromVal->addr); + if (d != NULL) + donestr(Display*, d, XtRDisplay); + + XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRDisplay); + return False; +} + + +/*ARGSUSED*/ +Boolean XtCvtStringToFile(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + FILE *f; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToFile",XtCXtToolkitError, + "String to File conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + + f = fopen((char *)fromVal->addr, "r"); + if (f != NULL) + donestr(FILE*, f, XtRFile); + + XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRFile); + return False; +} + +/* ARGSUSED */ +static void FreeFile(app, toVal, closure, args, num_args) + XtAppContext app; + XrmValuePtr toVal; + XtPointer closure; /* unused */ + XrmValuePtr args; /* unused */ + Cardinal *num_args; +{ + if (*num_args != 0) + XtAppWarningMsg(app, + XtNwrongParameters,"freeFile",XtCXtToolkitError, + "Free File requires no extra arguments", + (String *) NULL, (Cardinal *)NULL); + + fclose( *(FILE**)toVal->addr ); +} + +/*ARGSUSED*/ +Boolean XtCvtIntToFloat(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtIntToFloat",XtCXtToolkitError, + "Integer to Float conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + done(float, (*(int *)fromVal->addr)); +} + +/*ARGSUSED*/ +Boolean XtCvtStringToFloat(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + int ret; + float f, nan; + + /* depending on the system this may or may not do anything useful */ + (void) sscanf ("NaNS", "%g", + toVal->addr != NULL ? (float*) toVal->addr : &nan); + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToFloat",XtCXtToolkitError, + "String to Float conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + + ret = sscanf (fromVal->addr, "%g", &f); + if (ret == 0) { + if (toVal->addr != NULL && toVal->size == sizeof nan) + *(float*)toVal->addr = nan; + XtDisplayStringConversionWarning (dpy, (char*) fromVal->addr, XtRFloat); + return False; + } + donestr(float, f, XtRFloat); +} + +/*ARGSUSED*/ +Boolean XtCvtStringToFont(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + Font f; + Display* display; + + if (*num_args != 1) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToFont",XtCXtToolkitError, + "String to font conversion needs display argument", + (String *) NULL, (Cardinal *)NULL); + return False; + } + + display = *(Display**)args[0].addr; + + if (CompareISOLatin1((String)fromVal->addr, XtDefaultFont) != 0) { + f = XLoadFont(display, (char *)fromVal->addr); + if (f != 0) { + Done: donestr( Font, f, XtRFont ); + } + XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRFont); + } + /* try and get the default font */ + + { + XrmName xrm_name[2]; + XrmClass xrm_class[2]; + XrmRepresentation rep_type; + XrmValue value; + + xrm_name[0] = XrmPermStringToQuark ("xtDefaultFont"); + xrm_name[1] = 0; + xrm_class[0] = XrmPermStringToQuark ("XtDefaultFont"); + xrm_class[1] = 0; + if (XrmQGetResource(XtDatabase(display), xrm_name, xrm_class, + &rep_type, &value)) { + if (rep_type == _XtQString) { + f = XLoadFont(display, (char *)value.addr); + if (f != 0) + goto Done; + else + XtDisplayStringConversionWarning(dpy, (char *)value.addr, + XtRFont); + } else if (rep_type == XtQFont) { + f = *(Font*)value.addr; + goto Done; + } else if (rep_type == XtQFontStruct) { + f = ((XFontStruct*)value.addr)->fid; + goto Done; + } + } + } + /* Should really do XListFonts, but most servers support this */ + f = XLoadFont(display, "-*-*-*-R-*-*-*-120-*-*-*-*-ISO8859-1"); + if (f != 0) + goto Done; + + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "noFont","cvtStringToFont",XtCXtToolkitError, + "Unable to load any usable ISO8859-1 font", + (String *) NULL, (Cardinal *)NULL); + + return False; +} + +/* ARGSUSED */ +static void FreeFont(app, toVal, closure, args, num_args) + XtAppContext app; + XrmValuePtr toVal; + XtPointer closure; /* unused */ + XrmValuePtr args; + Cardinal *num_args; +{ + Display *display; + if (*num_args != 1) { + XtAppWarningMsg(app, + XtNwrongParameters,"freeFont",XtCXtToolkitError, + "Free Font needs display argument", + (String *) NULL, (Cardinal *)NULL); + return; + } + + display = *(Display**)args[0].addr; + XUnloadFont( display, *(Font*)toVal->addr ); +} + +/*ARGSUSED*/ +Boolean XtCvtIntToFont(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtIntToFont",XtCXtToolkitError, + "Integer to Font conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + done(Font, *(int*)fromVal->addr); +} + +/*ARGSUSED*/ +Boolean XtCvtStringToFontSet(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + XFontSet f; + Display* display; + char** missing_charset_list; + int missing_charset_count; + char* def_string; + + if (*num_args != 2) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToFontSet",XtCXtToolkitError, + "String to FontSet conversion needs display and locale arguments", + (String *) NULL, (Cardinal *)NULL); + return False; + } + + display = *(Display**)args[0].addr; + + if (CompareISOLatin1((String)fromVal->addr, XtDefaultFontSet) != 0) { + f = XCreateFontSet(display, (char *)fromVal->addr, + &missing_charset_list, &missing_charset_count, &def_string); + /* Free any returned missing charset list */ + if (missing_charset_count) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNmissingCharsetList,"cvtStringToFontSet",XtCXtToolkitError, + "Missing charsets in String to FontSet conversion", + (String *) NULL, (Cardinal *)NULL); + XFreeStringList(missing_charset_list); + } + if (f != NULL) { + Done: donestr( XFontSet, f, XtRFontSet ); + } + XtDisplayStringConversionWarning(dpy, (char *)fromVal->addr, XtRFontSet); + } + /* try and get the default fontset */ + + { + XrmName xrm_name[2]; + XrmClass xrm_class[2]; + XrmRepresentation rep_type; + XrmValue value; + + xrm_name[0] = XrmPermStringToQuark ("xtDefaultFontSet"); + xrm_name[1] = 0; + xrm_class[0] = XrmPermStringToQuark ("XtDefaultFontSet"); + xrm_class[1] = 0; + if (XrmQGetResource(XtDatabase(display), xrm_name, xrm_class, + &rep_type, &value)) { + if (rep_type == _XtQString) { + + f = XCreateFontSet(display, (char *)value.addr, + &missing_charset_list, &missing_charset_count, + &def_string); + /* Free any returned missing charset list */ + if (missing_charset_count) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNmissingCharsetList,"cvtStringToFontSet", + XtCXtToolkitError, + "Missing charsets in String to FontSet conversion", + (String *) NULL, (Cardinal *)NULL); + XFreeStringList(missing_charset_list); + } + if (f != NULL) + goto Done; + else + XtDisplayStringConversionWarning(dpy, (char *)value.addr, + XtRFontSet); + } else if (rep_type == XtQFontSet) { + f = *(XFontSet*)value.addr; + goto Done; + } + } + } + + /* Should really do XListFonts, but most servers support this */ + f = XCreateFontSet(display, "-*-*-*-R-*-*-*-120-*-*-*-*", + &missing_charset_list, &missing_charset_count, &def_string); + + /* Free any returned missing charset list */ + if (missing_charset_count) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNmissingCharsetList,"cvtStringToFontSet",XtCXtToolkitError, + "Missing charsets in String to FontSet conversion", + (String *) NULL, (Cardinal *)NULL); + XFreeStringList(missing_charset_list); + } + if (f != NULL) + goto Done; + + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "noFont","cvtStringToFontSet",XtCXtToolkitError, + "Unable to load any usable fontset", + (String *) NULL, (Cardinal *)NULL); + + return False; +} + +/*ARGSUSED*/ +static void FreeFontSet(app, toVal, closure, args, num_args) + XtAppContext app; + XrmValuePtr toVal; + XtPointer closure; /* unused */ + XrmValuePtr args; + Cardinal *num_args; +{ + Display *display; + if (*num_args != 2) { + XtAppWarningMsg(app, + XtNwrongParameters,"freeFontSet",XtCXtToolkitError, + "FreeFontSet needs display and locale arguments", + (String *) NULL, (Cardinal *)NULL); + return; + } + + display = *(Display**)args[0].addr; + XFreeFontSet( display, *(XFontSet*)toVal->addr ); +} + +/*ARGSUSED*/ +static void FetchLocaleArg(widget, size, value ) + Widget widget; /* unused */ + Cardinal *size; /* unused */ + XrmValue *value; +{ + static XrmString locale; + + locale = XrmQuarkToString(XrmStringToQuark + (setlocale(LC_CTYPE, (char*)NULL))); + value->size = sizeof(XrmString); + value->addr = (XPointer)&locale; +} + +static XtConvertArgRec Const localeDisplayConvertArgs[] = { + {XtProcedureArg, (XtPointer)FetchDisplayArg, 0}, + {XtProcedureArg, (XtPointer)FetchLocaleArg, 0}, +}; + + +/*ARGSUSED*/ +Boolean +XtCvtStringToFontStruct(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + XFontStruct *f; + Display* display; + + if (*num_args != 1) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToFontStruct",XtCXtToolkitError, + "String to font conversion needs display argument", + (String *) NULL, (Cardinal *)NULL); + return False; + } + + display = *(Display**)args[0].addr; + + if (CompareISOLatin1((String)fromVal->addr, XtDefaultFont) != 0) { + f = XLoadQueryFont(display, (char *)fromVal->addr); + if (f != NULL) { + Done: donestr( XFontStruct*, f, XtRFontStruct); + } + + XtDisplayStringConversionWarning(dpy, (char*)fromVal->addr, + XtRFontStruct); + } + + /* try and get the default font */ + + { + XrmName xrm_name[2]; + XrmClass xrm_class[2]; + XrmRepresentation rep_type; + XrmValue value; + + xrm_name[0] = XrmPermStringToQuark ("xtDefaultFont"); + xrm_name[1] = 0; + xrm_class[0] = XrmPermStringToQuark ("XtDefaultFont"); + xrm_class[1] = 0; + if (XrmQGetResource(XtDatabase(display), xrm_name, xrm_class, + &rep_type, &value)) { + if (rep_type == _XtQString) { + f = XLoadQueryFont(display, (char*)value.addr); + if (f != NULL) + goto Done; + else + XtDisplayStringConversionWarning(dpy, (char*)value.addr, + XtRFontStruct); + } else if (rep_type == XtQFont) { + f = XQueryFont(display, *(Font*)value.addr ); + if (f != NULL) goto Done; + } else if (rep_type == XtQFontStruct) { + f = (XFontStruct*)value.addr; + goto Done; + } + } + } + /* Should really do XListFonts, but most servers support this */ + f = XLoadQueryFont(display, "-*-*-*-R-*-*-*-120-*-*-*-*-ISO8859-1"); + if (f != NULL) + goto Done; + + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "noFont","cvtStringToFontStruct",XtCXtToolkitError, + "Unable to load any usable ISO8859-1 font", + (String *) NULL, (Cardinal *)NULL); + + return False; +} + +/* ARGSUSED */ +static void FreeFontStruct(app, toVal, closure, args, num_args) + XtAppContext app; + XrmValuePtr toVal; + XtPointer closure; /* unused */ + XrmValuePtr args; + Cardinal *num_args; +{ + Display *display; + if (*num_args != 1) { + XtAppWarningMsg(app, + XtNwrongParameters,"freeFontStruct",XtCXtToolkitError, + "Free FontStruct requires display argument", + (String *) NULL, (Cardinal *)NULL); + return; + } + + display = *(Display**)args[0].addr; + XFreeFont( display, *(XFontStruct**)toVal->addr ); +} + +/*ARGSUSED*/ +Boolean XtCvtStringToInt(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + int i; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToInt",XtCXtToolkitError, + "String to Integer conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + if (IsInteger((String)fromVal->addr, &i)) + donestr(int, i, XtRInt); + + XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRInt); + return False; +} + +/*ARGSUSED*/ +Boolean XtCvtStringToShort(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + int i; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToShort",XtCXtToolkitError, + "String to Integer conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + if (IsInteger((String)fromVal->addr, &i)) + donestr(short, (short)i, XtRShort); + + XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRShort); + return False; +} + +/*ARGSUSED*/ +Boolean XtCvtStringToDimension(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + int i; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToDimension",XtCXtToolkitError, + "String to Dimension conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + if (IsInteger((String)fromVal->addr, &i)) { + if ( i < 0 ) + XtDisplayStringConversionWarning(dpy, (char*)fromVal->addr, + XtRDimension); + donestr(Dimension, (Dimension)i, XtRDimension); + } + XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, XtRDimension); + return False; +} + +/*ARGSUSED*/ +Boolean XtCvtIntToUnsignedChar(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtIntToUnsignedChar",XtCXtToolkitError, + "Integer to UnsignedChar conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + done(unsigned char, (*(int *)fromVal->addr)); +} + + +/*ARGSUSED*/ +Boolean XtCvtStringToUnsignedChar(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + int i; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToUnsignedChar",XtCXtToolkitError, + "String to Integer conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + if (IsInteger((String)fromVal->addr, &i)) { + if ( i < 0 || i > 255 ) + XtDisplayStringConversionWarning(dpy, (char*)fromVal->addr, + XtRUnsignedChar); + donestr(unsigned char, i, XtRUnsignedChar); + } + XtDisplayStringConversionWarning(dpy, (char*)fromVal->addr, + XtRUnsignedChar); + return False; +} + + +/*ARGSUSED*/ +Boolean XtCvtColorToPixel(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtXColorToPixel",XtCXtToolkitError, + "Color to Pixel conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + done(Pixel, ((XColor *)fromVal->addr)->pixel); +} + +/*ARGSUSED*/ +Boolean XtCvtIntToPixel(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtIntToPixel",XtCXtToolkitError, + "Integer to Pixel conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + done(Pixel, *(int*)fromVal->addr); +} + +/*ARGSUSED*/ +Boolean XtCvtIntToPixmap(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtIntToPixmap",XtCXtToolkitError, + "Integer to Pixmap conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + done(Pixmap, *(Pixmap*)fromVal->addr); +} + +#ifdef MOTIFBC +void LowerCase(source, dest) + register char *source, *dest; +{ + register char ch; + int i; + + for (i = 0; (ch = *source) != 0 && i < 999; source++, dest++, i++) { + if ('A' <= ch && ch <= 'Z') + *dest = ch - 'A' + 'a'; + else + *dest = ch; + } + *dest = 0; +} +#endif + +static int CompareISOLatin1 (first, second) + char *first, *second; +{ + register unsigned char *ap, *bp; + + for (ap = (unsigned char *) first, bp = (unsigned char *) second; + *ap && *bp; ap++, bp++) { + register unsigned char a, b; + + if ((a = *ap) != (b = *bp)) { + /* try lowercasing and try again */ + + if ((a >= XK_A) && (a <= XK_Z)) + a += (XK_a - XK_A); + else if ((a >= XK_Agrave) && (a <= XK_Odiaeresis)) + a += (XK_agrave - XK_Agrave); + else if ((a >= XK_Ooblique) && (a <= XK_Thorn)) + a += (XK_oslash - XK_Ooblique); + + if ((b >= XK_A) && (b <= XK_Z)) + b += (XK_a - XK_A); + else if ((b >= XK_Agrave) && (b <= XK_Odiaeresis)) + b += (XK_agrave - XK_Agrave); + else if ((b >= XK_Ooblique) && (b <= XK_Thorn)) + b += (XK_oslash - XK_Ooblique); + + if (a != b) break; + } + } + return (((int) *bp) - ((int) *ap)); +} + +static void CopyISOLatin1Lowered(dst, src) + char *dst, *src; +{ + unsigned char *dest, *source; + + dest = (unsigned char *) dst; source = (unsigned char *) src; + + for ( ; *source; source++, dest++) { + if (*source >= XK_A && *source <= XK_Z) + *dest = *source + (XK_a - XK_A); + else if (*source >= XK_Agrave && *source <= XK_Odiaeresis) + *dest = *source + (XK_agrave - XK_Agrave); + else if (*source >= XK_Ooblique && *source <= XK_Thorn) + *dest = *source + (XK_oslash - XK_Ooblique); + else + *dest = *source; + } + *dest = '\0'; +} + +/*ARGSUSED*/ +Boolean +XtCvtStringToInitialState(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + String str = (String)fromVal->addr; + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToInitialState",XtCXtToolkitError, + "String to InitialState conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + + if (CompareISOLatin1(str, "NormalState") == 0) donestr(int, NormalState, XtRInitialState); + if (CompareISOLatin1(str, "IconicState") == 0) donestr(int, IconicState, XtRInitialState); + { + int val; + if (IsInteger(str, &val)) donestr( int, val, XtRInitialState ); + } + XtDisplayStringConversionWarning(dpy, str, XtRInitialState); + return False; +} + +static XtConvertArgRec Const visualConvertArgs[] = { + {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen), + sizeof(Screen *)}, + {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.depth), + sizeof(Cardinal)} +}; + +/*ARGSUSED*/ +Boolean XtCvtStringToVisual(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; /* Screen, depth */ + Cardinal *num_args; /* 2 */ + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; /* unused */ +{ + String str = (String)fromVal->addr; + int vc; + XVisualInfo vinfo; + if (*num_args != 2) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToVisual",XtCXtToolkitError, + "String to Visual conversion needs screen and depth arguments", + (String *) NULL, (Cardinal *)NULL); + return False; + } + + if (CompareISOLatin1(str, "StaticGray") == 0) vc = StaticGray; + else if (CompareISOLatin1(str, "StaticColor") == 0) vc = StaticColor; + else if (CompareISOLatin1(str, "TrueColor") == 0) vc = TrueColor; + else if (CompareISOLatin1(str, "GrayScale") == 0) vc = GrayScale; + else if (CompareISOLatin1(str, "PseudoColor") == 0) vc = PseudoColor; + else if (CompareISOLatin1(str, "DirectColor") == 0) vc = DirectColor; + else if (!IsInteger(str, &vc)) { + XtDisplayStringConversionWarning(dpy, str, "Visual class name"); + return False; + } + + if (XMatchVisualInfo( XDisplayOfScreen((Screen*)*(Screen**)args[0].addr), + XScreenNumberOfScreen((Screen*)*(Screen**)args[0].addr), + (int)*(int*)args[1].addr, + vc, + &vinfo) ) { + donestr( Visual*, vinfo.visual, XtRVisual ); + } + else { + String params[2]; + Cardinal num_params = 2; + params[0] = str; + params[1] = + DisplayString(XDisplayOfScreen((Screen*)*(Screen**)args[0].addr)); + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNconversionError, "stringToVisual", XtCXtToolkitError, + "Cannot find Visual of class %s for display %s", + params, &num_params ); + return False; + } +} + + +/*ARGSUSED*/ +Boolean XtCvtStringToAtom(dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + Atom atom; + if (*num_args != 1) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToAtom",XtCXtToolkitError, + "String to Atom conversion needs Display argument", + (String *) NULL, (Cardinal *)NULL); + return False; + } + + atom = XInternAtom( *(Display**)args->addr, (char*)fromVal->addr, False ); + donestr(Atom, atom, XtRAtom); +} + +/*ARGSUSED*/ +Boolean XtCvtStringToDirectoryString(dpy, args, num_args, fromVal, toVal, + closure_ret) + Display *dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + String str; + char directory[PATH_MAX+1]; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToDirectoryString",XtCXtToolkitError, + "String to DirectoryString conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + + str = (String)fromVal->addr; + if (CompareISOLatin1(str, "XtCurrentDirectory") == 0) { + /* uglier, but does not depend on compiler knowing return type */ +#if !defined(X_NOT_POSIX) || defined(SYSV) || defined(WIN32) + if (getcwd(directory, PATH_MAX + 1)) + str = directory; +#else + if (getwd(directory)) + str = directory; +#endif + if (!str) { + if (errno == EACCES) + errno = 0; /* reset errno */ + XtDisplayStringConversionWarning(dpy, (char *) fromVal->addr, + XtRDirectoryString); + return False; + } + } + + /* Since memory from the resource database or from static buffers of + * system libraries may be freed or overwritten, allocate memory. + * The memory is freed when all cache references are released. + */ + str = XtNewString(str); + donestr(String, str, XtRDirectoryString); +} + +/*ARGSUSED*/ +static void FreeDirectoryString(app, toVal, closure, args, num_args) + XtAppContext app; + XrmValuePtr toVal; + XtPointer closure; /* unused */ + XrmValuePtr args; + Cardinal *num_args; +{ + if (*num_args != 0) + XtAppWarningMsg(app, + XtNwrongParameters,"freeDirectoryString",XtCXtToolkitError, + "Free Directory String requires no extra arguments", + (String *) NULL, (Cardinal *) NULL); + + XtFree((char *) toVal->addr); +} + +/*ARGSUSED*/ +Boolean XtCvtStringToRestartStyle(dpy, args, num_args, fromVal, toVal, + closure_ret) + Display *dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + String str = (String)fromVal->addr; + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToRestartStyle",XtCXtToolkitError, + "String to RestartStyle conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + + if (CompareISOLatin1(str, "RestartIfRunning") == 0) + donestr(unsigned char, SmRestartIfRunning, XtRRestartStyle); + if (CompareISOLatin1(str, "RestartAnyway") == 0) + donestr(unsigned char, SmRestartAnyway, XtRRestartStyle); + if (CompareISOLatin1(str, "RestartImmediately") == 0) + donestr(unsigned char, SmRestartImmediately, XtRRestartStyle); + if (CompareISOLatin1(str, "RestartNever") == 0) + donestr(unsigned char, SmRestartNever, XtRRestartStyle); + XtDisplayStringConversionWarning(dpy, str, XtRRestartStyle); + return False; +} + +/*ARGSUSED*/ +Boolean XtCvtStringToCommandArgArray(dpy, args, num_args, fromVal, toVal, + closure_ret) + Display *dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + String *strarray, *ptr; + char *src, *src_str; + char *dst, *dst_str; + char *start; + int tokens, len; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + XtNwrongParameters,"cvtStringToCommandArgArray",XtCXtToolkitError, + "String to CommandArgArray conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + + src = src_str = fromVal->addr; + dst = dst_str = __XtMalloc((unsigned) strlen(src) + 1); + tokens = 0; + + while (*src != '\0') { + /* skip whitespace */ + while (*src == ' ' || *src == '\t' || *src == '\n') + src++; + /* test for end of string */ + if (*src == '\0') + break; + + /* start new token */ + tokens++; + start = src; + while (*src != '\0' && *src != ' ' && *src != '\t' && *src != '\n') { + if (*src == '\\' && + (*(src+1) == ' ' || *(src+1) == '\t' || *(src+1) == '\n')) { + len = src - start; + if (len) { + /* copy preceeding part of token */ + memcpy(dst, start, len); + dst += len; + } + /* skip backslash */ + src++; + /* next part of token starts at whitespace */ + start = src; + } + src++; + } + len = src - start; + if (len) { + /* copy last part of token */ + memcpy(dst, start, len); + dst += len; + } + *dst = '\0'; + if (*src != '\0') + dst++; + } + + ptr = strarray = (String*) __XtMalloc((Cardinal)(tokens+1) * sizeof(String)); + src = dst_str; + while (--tokens >= 0) { + *ptr = src; + ptr++; + if (tokens) { + len = strlen(src); + src = src + len + 1; + } + } + *ptr = NULL; + + *closure_ret = (XtPointer) strarray; + donestr(char**, strarray, XtRCommandArgArray) +} + +/*ARGSUSED*/ +static void ArgArrayDestructor(app, toVal, closure, args, num_args) + XtAppContext app; + XrmValuePtr toVal; + XtPointer closure; + XrmValuePtr args; + Cardinal *num_args; +{ + String *strarray; + + if (closure) { + strarray = (String*) closure; + XtFree(*strarray); + XtFree((char *) strarray); + } +} + +/*ARGSUSED*/ +Boolean XtCvtStringToGravity (dpy, args, num_args, fromVal, toVal, closure_ret) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr fromVal; + XrmValuePtr toVal; + XtPointer *closure_ret; +{ + static struct _namepair { + XrmQuark quark; + char *name; + int gravity; + } names[] = { + { NULLQUARK, "forget", ForgetGravity }, + { NULLQUARK, "northwest", NorthWestGravity }, + { NULLQUARK, "north", NorthGravity }, + { NULLQUARK, "northeast", NorthEastGravity }, + { NULLQUARK, "west", WestGravity }, + { NULLQUARK, "center", CenterGravity }, + { NULLQUARK, "east", EastGravity }, + { NULLQUARK, "southwest", SouthWestGravity }, + { NULLQUARK, "south", SouthGravity }, + { NULLQUARK, "southeast", SouthEastGravity }, + { NULLQUARK, "static", StaticGravity }, + { NULLQUARK, "unmap", UnmapGravity }, + { NULLQUARK, "0", ForgetGravity }, + { NULLQUARK, "1", NorthWestGravity }, + { NULLQUARK, "2", NorthGravity }, + { NULLQUARK, "3", NorthEastGravity }, + { NULLQUARK, "4", WestGravity }, + { NULLQUARK, "5", CenterGravity }, + { NULLQUARK, "6", EastGravity }, + { NULLQUARK, "7", SouthWestGravity }, + { NULLQUARK, "8", SouthGravity }, + { NULLQUARK, "9", SouthEastGravity }, + { NULLQUARK, "10", StaticGravity }, + { NULLQUARK, NULL, ForgetGravity } + }; + static Boolean haveQuarks = FALSE; + char lowerName[40]; + XrmQuark q; + char *s; + struct _namepair *np; + + if (*num_args != 0) { + XtAppWarningMsg(XtDisplayToApplicationContext (dpy), + "wrongParameters","cvtStringToGravity","XtToolkitError", + "String to Gravity conversion needs no extra arguments", + (String *) NULL, (Cardinal *)NULL); + return False; + } + if (!haveQuarks) { + for (np = names; np->name; np++) { + np->quark = XrmPermStringToQuark (np->name); + } + haveQuarks = TRUE; + } + s = (char *) fromVal->addr; + if (strlen(s) < sizeof lowerName) { + CopyISOLatin1Lowered (lowerName, s); + q = XrmStringToQuark (lowerName); + for (np = names; np->name; np++) + if (np->quark == q) donestr(int, np->gravity, XtRGravity); + } + XtDisplayStringConversionWarning(dpy, (char *)fromVal->addr, XtRGravity); + return False; +} + +void _XtAddDefaultConverters(table) + ConverterTable table; +{ +#define Add(from, to, proc, convert_args, num_args, cache) \ + _XtTableAddConverter(table, from, to, proc, \ + (XtConvertArgList) convert_args, (Cardinal)num_args, \ + True, cache, (XtDestructor)NULL, True) + +#define Add2(from, to, proc, convert_args, num_args, cache, destructor) \ + _XtTableAddConverter(table, from, to, proc, \ + (XtConvertArgList) convert_args, (Cardinal)num_args, \ + True, cache, destructor, True) + + Add(XtQColor, XtQPixel, XtCvtColorToPixel, NULL, 0, XtCacheNone); + + Add(XtQInt, XtQBool, XtCvtIntToBool, NULL, 0, XtCacheNone); + Add(XtQInt, XtQBoolean, XtCvtIntToBoolean, NULL, 0, XtCacheNone); + Add(XtQInt, XtQColor, XtCvtIntToColor, + colorConvertArgs, XtNumber(colorConvertArgs), XtCacheByDisplay); + Add(XtQInt, XtQDimension, XtCvtIntToShort, NULL, 0, XtCacheNone); + Add(XtQInt, XtQFloat, XtCvtIntToFloat, NULL, 0, XtCacheNone); + Add(XtQInt, XtQFont, XtCvtIntToFont, NULL, 0, XtCacheNone); + Add(XtQInt, XtQPixel, XtCvtIntToPixel, NULL, 0, XtCacheNone); + Add(XtQInt, XtQPixmap, XtCvtIntToPixmap, NULL, 0, XtCacheNone); + Add(XtQInt, XtQPosition, XtCvtIntToShort, NULL, 0, XtCacheNone); + Add(XtQInt, XtQShort, XtCvtIntToShort, NULL, 0, XtCacheNone); + Add(XtQInt, XtQUnsignedChar,XtCvtIntToUnsignedChar,NULL, 0, XtCacheNone); + + Add(XtQPixel, XtQColor, XtCvtIntToColor, + colorConvertArgs, XtNumber(colorConvertArgs), XtCacheByDisplay); + + Add(_XtQString, XtQAtom, XtCvtStringToAtom, + displayConvertArg, XtNumber(displayConvertArg), XtCacheNone); + Add(_XtQString, XtQBool, XtCvtStringToBool, NULL, 0, XtCacheNone); + Add(_XtQString, XtQBoolean, XtCvtStringToBoolean, NULL, 0, XtCacheNone); + Add2(_XtQString, XtQCommandArgArray, XtCvtStringToCommandArgArray, + NULL, 0, XtCacheNone | XtCacheRefCount, ArgArrayDestructor); + Add2(_XtQString, XtQCursor, XtCvtStringToCursor, + displayConvertArg, XtNumber(displayConvertArg), + XtCacheByDisplay, FreeCursor); + Add(_XtQString, XtQDimension, XtCvtStringToDimension,NULL, 0, XtCacheNone); + Add2(_XtQString, XtQDirectoryString, XtCvtStringToDirectoryString, NULL, 0, + XtCacheNone | XtCacheRefCount, FreeDirectoryString); + Add(_XtQString, XtQDisplay, XtCvtStringToDisplay, NULL, 0, XtCacheAll); + Add2(_XtQString, XtQFile, XtCvtStringToFile, NULL, 0, + XtCacheAll | XtCacheRefCount, FreeFile); + Add(_XtQString, XtQFloat, XtCvtStringToFloat, NULL, 0, XtCacheNone); + + Add2(_XtQString, XtQFont, XtCvtStringToFont, + displayConvertArg, XtNumber(displayConvertArg), + XtCacheByDisplay, FreeFont); + Add2(_XtQString, XtQFontSet, XtCvtStringToFontSet, + localeDisplayConvertArgs, XtNumber(localeDisplayConvertArgs), + XtCacheByDisplay, FreeFontSet); + Add2(_XtQString, XtQFontStruct,XtCvtStringToFontStruct, + displayConvertArg, XtNumber(displayConvertArg), + XtCacheByDisplay, FreeFontStruct); + + Add(_XtQString, XtQGravity, XtCvtStringToGravity, NULL, 0, XtCacheNone); + Add(_XtQString, XtQInitialState, XtCvtStringToInitialState, NULL, 0, + XtCacheNone); + Add(_XtQString, XtQInt, XtCvtStringToInt, NULL, 0, XtCacheAll); + Add2(_XtQString, XtQPixel, XtCvtStringToPixel, + colorConvertArgs, XtNumber(colorConvertArgs), + XtCacheByDisplay, FreePixel); + Add(_XtQString, XtQPosition, XtCvtStringToShort, NULL, 0, XtCacheAll); + Add(_XtQString, XtQRestartStyle, XtCvtStringToRestartStyle, NULL, 0, + XtCacheNone); + Add(_XtQString, XtQShort, XtCvtStringToShort, NULL, 0, XtCacheAll); + Add(_XtQString, XtQUnsignedChar, XtCvtStringToUnsignedChar, + NULL, 0, XtCacheAll); + Add2(_XtQString, XtQVisual, XtCvtStringToVisual, + visualConvertArgs, XtNumber(visualConvertArgs), + XtCacheByDisplay, NULL); + + _XtAddTMConverters(table); +} diff --git a/src/Core.c b/src/Core.c new file mode 100644 index 0000000..343204b --- /dev/null +++ b/src/Core.c @@ -0,0 +1,397 @@ +/* $Xorg: Core.c,v 1.4 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#define _XT_CORE_C + +#include "IntrinsicP.h" +#include "EventI.h" +#include "ConvertI.h" +#include "TranslateI.h" +#include "ResourceI.h" +#include "RectObj.h" +#include "RectObjP.h" +#include "ThreadsI.h" +#include "StringDefs.h" + +/****************************************************************** + * + * CoreWidget Resources + * + ******************************************************************/ + +externaldef(xtinherittranslations) int _XtInheritTranslations = 0; +extern String XtCXtToolkitError; /* from IntrinsicI.h */ +static void XtCopyScreen(); + +static XtResource resources[] = { + {XtNscreen, XtCScreen, XtRScreen, sizeof(Screen*), + XtOffsetOf(CoreRec,core.screen), XtRCallProc, (XtPointer)XtCopyScreen}, +/*_XtCopyFromParent does not work for screen because the Display +parameter is not passed through to the XtRCallProc routines */ + {XtNdepth, XtCDepth, XtRInt,sizeof(int), + XtOffsetOf(CoreRec,core.depth), + XtRCallProc, (XtPointer)_XtCopyFromParent}, + {XtNcolormap, XtCColormap, XtRColormap, sizeof(Colormap), + XtOffsetOf(CoreRec,core.colormap), + XtRCallProc,(XtPointer)_XtCopyFromParent}, + {XtNbackground, XtCBackground, XtRPixel,sizeof(Pixel), + XtOffsetOf(CoreRec,core.background_pixel), + XtRString, (XtPointer)"XtDefaultBackground"}, + {XtNbackgroundPixmap, XtCPixmap, XtRPixmap, sizeof(Pixmap), + XtOffsetOf(CoreRec,core.background_pixmap), + XtRImmediate, (XtPointer)XtUnspecifiedPixmap}, + {XtNborderColor, XtCBorderColor, XtRPixel,sizeof(Pixel), + XtOffsetOf(CoreRec,core.border_pixel), + XtRString,(XtPointer)"XtDefaultForeground"}, + {XtNborderPixmap, XtCPixmap, XtRPixmap, sizeof(Pixmap), + XtOffsetOf(CoreRec,core.border_pixmap), + XtRImmediate, (XtPointer)XtUnspecifiedPixmap}, + {XtNmappedWhenManaged, XtCMappedWhenManaged, XtRBoolean, sizeof(Boolean), + XtOffsetOf(CoreRec,core.mapped_when_managed), + XtRImmediate, (XtPointer)True}, + {XtNtranslations, XtCTranslations, XtRTranslationTable, + sizeof(XtTranslations), XtOffsetOf(CoreRec,core.tm.translations), + XtRTranslationTable, (XtPointer)NULL}, + {XtNaccelerators, XtCAccelerators, XtRAcceleratorTable, + sizeof(XtTranslations), XtOffsetOf(CoreRec,core.accelerators), + XtRTranslationTable, (XtPointer)NULL} + }; + +static void CoreInitialize(); +static void CoreClassPartInitialize(); +static void CoreDestroy(); +static void CoreRealize(); +static Boolean CoreSetValues(); +static void CoreSetValuesAlmost(); + +static RectObjClassRec unNamedObjClassRec = { + { + /* superclass */ (WidgetClass)&rectObjClassRec, + /* class_name */ "UnNamedObj", + /* widget_size */ 0, + /* class_initialize */ NULL, + /* class_part_initialize*/ NULL, + /* class_inited */ FALSE, + /* initialize */ NULL, + /* initialize_hook */ NULL, + /* realize */ (XtProc)XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ NULL, + /* num_resources */ 0, + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ FALSE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ NULL, + /* expose */ NULL, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + } +}; + + +externaldef(widgetclassrec) WidgetClassRec widgetClassRec = { +{ + /* superclass */ (WidgetClass)&unNamedObjClassRec, + /* class_name */ "Core", + /* widget_size */ sizeof(WidgetRec), + /* class_initialize */ NULL, + /* class_part_initialize*/ CoreClassPartInitialize, + /* class_inited */ FALSE, + /* initialize */ CoreInitialize, + /* initialize_hook */ NULL, + /* realize */ CoreRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ CoreDestroy, + /* resize */ NULL, + /* expose */ NULL, + /* set_values */ CoreSetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ CoreSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + } +}; +externaldef (WidgetClass) WidgetClass widgetClass = &widgetClassRec; + +externaldef (WidgetClass) WidgetClass coreWidgetClass = &widgetClassRec; + + +/*ARGSUSED*/ +static void XtCopyScreen(widget, offset, value) + Widget widget; + int offset; + XrmValue *value; +{ + value->addr = (XPointer)(&widget->core.screen); +} + +/* + * Start of Core methods + */ + +static void CoreClassPartInitialize(wc) + register WidgetClass wc; +{ + /* We don't need to check for null super since we'll get to object + eventually, and it had better define them! */ + + register WidgetClass super = wc->core_class.superclass; + + LOCK_PROCESS; + if (wc->core_class.realize == XtInheritRealize) { + wc->core_class.realize = super->core_class.realize; + } + + if (wc->core_class.accept_focus == XtInheritAcceptFocus) { + wc->core_class.accept_focus = super->core_class.accept_focus; + } + + if (wc->core_class.display_accelerator == XtInheritDisplayAccelerator) { + wc->core_class.display_accelerator = + super->core_class.display_accelerator; + } + + if (wc->core_class.tm_table == (char *) XtInheritTranslations) { + wc->core_class.tm_table = + wc->core_class.superclass->core_class.tm_table; + } else if (wc->core_class.tm_table != NULL) { + wc->core_class.tm_table = + (String)XtParseTranslationTable(wc->core_class.tm_table); + } + + if (wc->core_class.actions != NULL) { + Boolean inPlace; + + if (wc->core_class.version == XtVersionDontCheck) + inPlace = True; + else + inPlace = (wc->core_class.version < XtVersion) ? False : True; + + /* Compile the action table into a more efficient form */ + wc->core_class.actions = (XtActionList) _XtInitializeActionData( + wc->core_class.actions, wc->core_class.num_actions, inPlace); + } + UNLOCK_PROCESS; +} +/* ARGSUSED */ +static void CoreInitialize(requested_widget, new_widget, args, num_args) + Widget requested_widget; + register Widget new_widget; + ArgList args; + Cardinal *num_args; +{ + XtTranslations save1, save2; + new_widget->core.event_table = NULL; + new_widget->core.tm.proc_table = NULL; + new_widget->core.tm.lastEventTime = 0; + /* magic semi-resource fetched by GetResources */ + save1 = (XtTranslations)new_widget->core.tm.current_state; + new_widget->core.tm.current_state = NULL; + save2 = new_widget->core.tm.translations; + LOCK_PROCESS; + new_widget->core.tm.translations = + (XtTranslations)new_widget->core.widget_class->core_class.tm_table; + UNLOCK_PROCESS; + if (save1) + _XtMergeTranslations(new_widget, save1, save1->operation); + if (save2) + _XtMergeTranslations(new_widget, save2, save2->operation); +} + +static void CoreRealize(widget, value_mask, attributes) + Widget widget; + XtValueMask *value_mask; + XSetWindowAttributes *attributes; +{ + XtCreateWindow(widget, (unsigned int) InputOutput, + (Visual *) CopyFromParent, *value_mask, attributes); +} /* CoreRealize */ + +static void CoreDestroy (widget) + Widget widget; +{ + _XtFreeEventTable(&widget->core.event_table); + _XtDestroyTMData(widget); + XtUnregisterDrawable(XtDisplay(widget), widget->core.window); + + if (widget->core.popup_list != NULL) + XtFree((char *)widget->core.popup_list); + +} /* CoreDestroy */ + +/* ARGSUSED */ +static Boolean CoreSetValues(old, reference, new, args, num_args) + Widget old, reference, new; + ArgList args; + Cardinal *num_args; +{ + Boolean redisplay; + Mask window_mask; + XSetWindowAttributes attributes; + XtTranslations save; + + redisplay = FALSE; + if (old->core.tm.translations != new->core.tm.translations) { + save = new->core.tm.translations; + new->core.tm.translations = old->core.tm.translations; + _XtMergeTranslations(new, save, XtTableReplace); + } + + /* Check everything that depends upon window being realized */ + if (XtIsRealized(old)) { + window_mask = 0; + /* Check window attributes */ + if (old->core.background_pixel != new->core.background_pixel + && new->core.background_pixmap == XtUnspecifiedPixmap) { + attributes.background_pixel = new->core.background_pixel; + window_mask |= CWBackPixel; + redisplay = TRUE; + } + if (old->core.background_pixmap != new->core.background_pixmap) { + if (new->core.background_pixmap == XtUnspecifiedPixmap) { + window_mask |= CWBackPixel; + attributes.background_pixel = new->core.background_pixel; + } + else { + attributes.background_pixmap = new->core.background_pixmap; + window_mask &= ~CWBackPixel; + window_mask |= CWBackPixmap; + } + redisplay = TRUE; + } + if (old->core.border_pixel != new->core.border_pixel + && new->core.border_pixmap == XtUnspecifiedPixmap) { + attributes.border_pixel = new->core.border_pixel; + window_mask |= CWBorderPixel; + } + if (old->core.border_pixmap != new->core.border_pixmap) { + if (new->core.border_pixmap == XtUnspecifiedPixmap) { + window_mask |= CWBorderPixel; + attributes.border_pixel = new->core.border_pixel; + } + else { + attributes.border_pixmap = new->core.border_pixmap; + window_mask &= ~CWBorderPixel; + window_mask |= CWBorderPixmap; + } + } + if (old->core.depth != new->core.depth) { + XtAppWarningMsg(XtWidgetToApplicationContext(old), + "invalidDepth","setValues",XtCXtToolkitError, + "Can't change widget depth", (String *)NULL, (Cardinal *)NULL); + new->core.depth = old->core.depth; + } + if (old->core.colormap != new->core.colormap) { + window_mask |= CWColormap; + attributes.colormap = new->core.colormap; + } + if (window_mask != 0) { + /* Actually change X window attributes */ + XChangeWindowAttributes( + XtDisplay(new), XtWindow(new), window_mask, &attributes); + } + + if (old->core.mapped_when_managed != new->core.mapped_when_managed) { + Boolean mapped_when_managed = new->core.mapped_when_managed; + new->core.mapped_when_managed = !mapped_when_managed; + XtSetMappedWhenManaged(new, mapped_when_managed); + } + } /* if realized */ + + return redisplay; +} /* CoreSetValues */ + +/*ARGSUSED*/ +static void CoreSetValuesAlmost(old, new, request, reply) + Widget old; + Widget new; + XtWidgetGeometry *request; + XtWidgetGeometry *reply; +{ + *request = *reply; +} diff --git a/src/Create.c b/src/Create.c new file mode 100644 index 0000000..212ebd8 --- /dev/null +++ b/src/Create.c @@ -0,0 +1,827 @@ +/* $Xorg: Create.c,v 1.4 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "VarargsI.h" +#include "ShellP.h" +#ifndef X_NO_RESOURCE_CONFIGURATION_MANAGEMENT +#include "ResConfigP.h" +#endif +#include <stdio.h> + +static String XtNxtCreateWidget = "xtCreateWidget"; +static String XtNxtCreatePopupShell = "xtCreatePopupShell"; + +static void +CallClassPartInit(ancestor, wc) + WidgetClass ancestor, wc; +{ + if (ancestor->core_class.superclass != NULL) { + CallClassPartInit(ancestor->core_class.superclass, wc); + } + if (ancestor->core_class.class_part_initialize != NULL) { + (*(ancestor->core_class.class_part_initialize)) (wc); + } +} + +void +XtInitializeWidgetClass(wc) + WidgetClass wc; +{ + XtEnum inited; + LOCK_PROCESS; + if (wc->core_class.class_inited) { + UNLOCK_PROCESS; + return; + } + inited = 0x01; + { + WidgetClass pc; +#define LeaveIfClass(c, d) if (pc == c) { inited = d; break; } + for (pc = wc; pc; pc = pc->core_class.superclass) { + LeaveIfClass(rectObjClass, 0x01 | + RectObjClassFlag); + LeaveIfClass(coreWidgetClass, 0x01 | + RectObjClassFlag | + WidgetClassFlag); + LeaveIfClass(compositeWidgetClass, 0x01 | + RectObjClassFlag | + WidgetClassFlag | + CompositeClassFlag); + LeaveIfClass(constraintWidgetClass, 0x01 | + RectObjClassFlag | + WidgetClassFlag | + CompositeClassFlag | + ConstraintClassFlag); + LeaveIfClass(shellWidgetClass, 0x01 | + RectObjClassFlag | + WidgetClassFlag | + CompositeClassFlag | + ShellClassFlag); + LeaveIfClass(wmShellWidgetClass, 0x01 | + RectObjClassFlag | + WidgetClassFlag | + CompositeClassFlag | + ShellClassFlag | + WMShellClassFlag); + LeaveIfClass(topLevelShellWidgetClass, 0x01 | + RectObjClassFlag | + WidgetClassFlag | + CompositeClassFlag | + ShellClassFlag | + WMShellClassFlag | + TopLevelClassFlag); + } +#undef LeaveIfClass + } + if (wc->core_class.version != XtVersion && + wc->core_class.version != XtVersionDontCheck) { + String param[3]; + String mismatch = "Widget class %s version mismatch (recompilation needed):\n widget %d vs. intrinsics %d."; + String recompile = "Widget class %s must be re-compiled."; + Cardinal num_params; + + param[0] = wc->core_class.class_name; + param[1] = (String) wc->core_class.version; + param[2] = (String) XtVersion; + + if (wc->core_class.version == (11 * 1000 + 5) || /* MIT X11R5 */ + wc->core_class.version == (11 * 1000 + 4)) { /* MIT X11R4 */ + if ((inited & WMShellClassFlag) && + (sizeof(Boolean) != sizeof(char) || + sizeof(Atom) != sizeof(Widget) || + sizeof(Atom) != sizeof(String))) { + num_params=3; + XtWarningMsg("versionMismatch","widget",XtCXtToolkitError, + mismatch, param, &num_params); + num_params=1; + XtErrorMsg("R4orR5versionMismatch","widget",XtCXtToolkitError, + recompile, param, &num_params); + + } + } + else if (wc->core_class.version == (11 * 1000 + 3)) { /* MIT X11R3 */ + if (inited & ShellClassFlag) { + num_params=1; + XtWarningMsg("r3versionMismatch","widget",XtCXtToolkitError, + "Shell Widget class %s binary compiled for R3", + param,&num_params); + XtErrorMsg("R3versionMismatch","widget",XtCXtToolkitError, + recompile, param, &num_params); + } + } + else { + num_params=3; + XtWarningMsg("versionMismatch","widget",XtCXtToolkitError, + mismatch, param, &num_params); + if (wc->core_class.version == (2 * 1000 + 2)) /* MIT X11R2 */ { + num_params=1; + XtErrorMsg("r2versionMismatch","widget",XtCXtToolkitError, + recompile, param, &num_params); + } + } + } + + if ((wc->core_class.superclass != NULL) + && (!(wc->core_class.superclass->core_class.class_inited))) + XtInitializeWidgetClass(wc->core_class.superclass); + + if (wc->core_class.class_initialize != NULL) + (*(wc->core_class.class_initialize))(); + CallClassPartInit(wc, wc); + wc->core_class.class_inited = inited; + UNLOCK_PROCESS; +} + +static void +CallInitialize (class, req_widget, new_widget, args, num_args) + WidgetClass class; + Widget req_widget; + Widget new_widget; + ArgList args; + Cardinal num_args; +{ + WidgetClass superclass; + XtInitProc initialize; + XtArgsProc initialize_hook; + + LOCK_PROCESS; + superclass = class->core_class.superclass; + UNLOCK_PROCESS; + if (superclass) + CallInitialize (superclass, req_widget, new_widget, args, num_args); + LOCK_PROCESS; + initialize = class->core_class.initialize; + UNLOCK_PROCESS; + if (initialize) + (*initialize) (req_widget, new_widget, args, &num_args); + LOCK_PROCESS; + initialize_hook = class->core_class.initialize_hook; + UNLOCK_PROCESS; + if (initialize_hook) + (*initialize_hook) (new_widget, args, &num_args); +} + +static void +CallConstraintInitialize (class, req_widget, new_widget, args, num_args) + ConstraintWidgetClass class; + Widget req_widget, new_widget; + ArgList args; + Cardinal num_args; +{ + WidgetClass superclass; + XtInitProc initialize; + + LOCK_PROCESS; + superclass = class->core_class.superclass; + UNLOCK_PROCESS; + if (superclass != constraintWidgetClass) + CallConstraintInitialize((ConstraintWidgetClass) superclass, + req_widget, new_widget, args, num_args); + LOCK_PROCESS; + initialize = class->constraint_class.initialize; + UNLOCK_PROCESS; + if (initialize) + (*initialize) (req_widget, new_widget, args, &num_args); +} + +static Widget +xtWidgetAlloc(widget_class, parent_constraint_class, parent, name, + args, num_args, typed_args, num_typed_args) + WidgetClass widget_class; + ConstraintWidgetClass parent_constraint_class; + Widget parent; + String name; + ArgList args; /* must be NULL if typed_args is non-NULL */ + Cardinal num_args; + XtTypedArgList typed_args; /* must be NULL if args is non-NULL */ + Cardinal num_typed_args; +{ + Widget widget; + Cardinal wsize, csize = 0; + ObjectClassExtension ext; + + LOCK_PROCESS; + if (! (widget_class->core_class.class_inited)) + XtInitializeWidgetClass(widget_class); + ext = (ObjectClassExtension) + XtGetClassExtension(widget_class, + XtOffsetOf(ObjectClassRec, object_class.extension), + NULLQUARK, XtObjectExtensionVersion, + sizeof(ObjectClassExtensionRec)); + if (parent_constraint_class) + csize = parent_constraint_class->constraint_class.constraint_size; + if (ext && ext->allocate) { + XtAllocateProc allocate; + Cardinal extra = 0; + Cardinal nargs = num_args; + Cardinal ntyped = num_typed_args; + allocate = ext->allocate; + UNLOCK_PROCESS; + (*allocate)(widget_class, &csize, &extra, args, &nargs, + typed_args, &ntyped, &widget, NULL); + } else { + wsize = widget_class->core_class.widget_size; + UNLOCK_PROCESS; + if (csize) { + if (sizeof(struct {char a; double b;}) != + (sizeof(struct {char a; unsigned long b;}) - + sizeof(unsigned long) + sizeof(double))) { + if (csize && !(csize & (sizeof(double) - 1))) + wsize = (wsize + sizeof(double) - 1) & ~(sizeof(double)-1); + } + } + widget = (Widget) __XtMalloc((unsigned)(wsize + csize)); + widget->core.constraints = + (csize ? (XtPointer)((char *)widget + wsize) : NULL); + } + widget->core.self = widget; + widget->core.parent = parent; + widget->core.widget_class = widget_class; + widget->core.xrm_name = StringToName((name != NULL) ? name : ""); + widget->core.being_destroyed = + (parent != NULL ? parent->core.being_destroyed : FALSE); + return widget; +} + +static void +CompileCallbacks(widget) + Widget widget; +{ + CallbackTable offsets; + InternalCallbackList* cl; + int i; + + LOCK_PROCESS; + offsets = (CallbackTable) + widget->core.widget_class->core_class.callback_private; + + for (i = (int) *(offsets++); --i >= 0; offsets++) { + cl = (InternalCallbackList *) + ((char *) widget - (*offsets)->xrm_offset - 1); + if (*cl) + *cl = _XtCompileCallbackList((XtCallbackList) *cl); + } + UNLOCK_PROCESS; +} + +static Widget +xtCreate(name, class, widget_class, parent, default_screen, + args, num_args, typed_args, num_typed_args, parent_constraint_class, + post_proc) + char *name, *class; + WidgetClass widget_class; + Widget parent; + Screen* default_screen; /* undefined when creating a nonwidget */ + ArgList args; /* must be NULL if typed_args is non-NULL */ + Cardinal num_args; + XtTypedArgList typed_args; /* must be NULL if args is non-NULL */ + Cardinal num_typed_args; + ConstraintWidgetClass parent_constraint_class; + /* NULL if not a subclass of Constraint or if child is popup shell */ + XtWidgetProc post_proc; +{ + /* need to use strictest alignment rules possible in next two decls. */ + double widget_cache[100]; + double constraint_cache[20]; + Widget req_widget; + XtPointer req_constraints; + Cardinal wsize, csize; + Widget widget; + XtCacheRef *cache_refs; + int i; + XtCreateHookDataRec call_data; + + widget = xtWidgetAlloc(widget_class, parent_constraint_class, parent, + name, args, num_args, typed_args, num_typed_args); + + if (XtIsRectObj(widget)) { + widget->core.managed = FALSE; + } + if (XtIsWidget(widget)) { + widget->core.name = XrmNameToString(widget->core.xrm_name); + widget->core.screen = default_screen; + widget->core.tm.translations = NULL; + widget->core.window = (Window) 0; + widget->core.visible = TRUE; + widget->core.popup_list = NULL; + widget->core.num_popups = 0; + }; + LOCK_PROCESS; + if (XtIsApplicationShell(widget)) { + ApplicationShellWidget a = (ApplicationShellWidget) widget; + if (class != NULL) + a->application.xrm_class = StringToClass(class); + else + a->application.xrm_class = widget_class->core_class.xrm_class; + a->application.class = XrmQuarkToString(a->application.xrm_class); + } + UNLOCK_PROCESS; + + /* fetch resources */ + cache_refs = _XtGetResources(widget, args, num_args, + typed_args, &num_typed_args); + + /* Convert typed arg list to arg list */ + if (typed_args != NULL && num_typed_args > 0) { + args = (ArgList)ALLOCATE_LOCAL(sizeof(Arg) * num_typed_args); + if (args == NULL) _XtAllocError(NULL); + for (i = 0; i < num_typed_args; i++) { + args[i].name = typed_args[i].name; + args[i].value = typed_args[i].value; + } + num_args = num_typed_args; + } + + CompileCallbacks(widget); + + if (cache_refs != NULL) { + XtAddCallback(widget, XtNdestroyCallback, + XtCallbackReleaseCacheRefList, (XtPointer)cache_refs ); + } + + wsize = widget_class->core_class.widget_size; + csize = 0; + req_widget = (Widget) XtStackAlloc(wsize, widget_cache); + (void) memmove ((char *) req_widget, (char *) widget, (int) wsize); + CallInitialize (XtClass(widget), req_widget, widget, args, num_args); + if (parent_constraint_class != NULL) { + csize = parent_constraint_class->constraint_class.constraint_size; + if (csize) { + req_constraints = XtStackAlloc(csize, constraint_cache); + (void) memmove((char*)req_constraints, widget->core.constraints, + (int)csize); + req_widget->core.constraints = req_constraints; + } else req_widget->core.constraints = NULL; + CallConstraintInitialize(parent_constraint_class, req_widget, widget, + args, num_args); + if (csize) XtStackFree(req_constraints, constraint_cache); + } + XtStackFree((XtPointer)req_widget, widget_cache); + if (post_proc != (XtWidgetProc) NULL) { + Widget hookobj; + (*post_proc)(widget); + hookobj = XtHooksOfDisplay((default_screen != (Screen*) NULL) ? + default_screen->display : + XtDisplayOfObject(parent)); + if (XtHasCallbacks(hookobj, XtNcreateHook) == XtCallbackHasSome) { + + call_data.type = XtHcreate; + call_data.widget = widget; + call_data.args = args; + call_data.num_args = num_args; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.createhook_callbacks, + (XtPointer)&call_data); + } + } + if (typed_args != NULL) { + while (num_typed_args-- > 0) { + + /* In GetResources we may have dynamically alloc'd store to hold */ + /* a copy of a resource which was larger then sizeof(XtArgVal). */ + /* We must free this store now in order to prevent a memory leak */ + /* A typed arg that has a converted value in dynamic store has a */ + /* negated size field. */ + + if (typed_args->type != NULL && typed_args->size < 0) { + XtFree((char*)typed_args->value); + typed_args->size = -(typed_args->size); + } + typed_args++; + } + DEALLOCATE_LOCAL((char*)args); + } + return (widget); +} + +static void +widgetPostProc(w) + Widget w; +{ + XtWidgetProc insert_child; + Widget parent = XtParent(w); + String param = XtName(w); + Cardinal num_params = 1; + + if (XtIsComposite(parent)) { + LOCK_PROCESS; + insert_child = ((CompositeWidgetClass) parent->core.widget_class)-> + composite_class.insert_child; + UNLOCK_PROCESS; + } else { + return; + } + if (insert_child == NULL) { + XtAppErrorMsg(XtWidgetToApplicationContext(parent), + "nullProc","insertChild",XtCXtToolkitError, + "\"%s\" parent has NULL insert_child method", + ¶m, &num_params); + } else { + (*insert_child) (w); + } +} + +Widget +_XtCreateWidget(name, widget_class, parent, + args, num_args, typed_args, num_typed_args) + String name; + WidgetClass widget_class; + Widget parent; + ArgList args; + Cardinal num_args; + XtTypedArgList typed_args; + Cardinal num_typed_args; +{ + register Widget widget; + ConstraintWidgetClass cwc; + Screen* default_screen; + XtEnum class_inited; + String params[3]; + Cardinal num_params; + + params[0] = name; + num_params = 1; + + if (parent == NULL) { + XtErrorMsg("invalidParent", XtNxtCreateWidget, XtCXtToolkitError, + "XtCreateWidget \"%s\" requires non-NULL parent", + params, &num_params); + } else if (widget_class == NULL) { + XtAppErrorMsg(XtWidgetToApplicationContext(parent), + "invalidClass", XtNxtCreateWidget, XtCXtToolkitError, + "XtCreateWidget \"%s\" requires non-NULL widget class", + params, &num_params); + } + LOCK_PROCESS; + if (!widget_class->core_class.class_inited) + XtInitializeWidgetClass(widget_class); + class_inited = widget_class->core_class.class_inited; + UNLOCK_PROCESS; + if ((class_inited & WidgetClassFlag) == 0) { + /* not a widget */ + default_screen = NULL; + if (XtIsComposite(parent)) { + CompositeClassExtension ext; + ext = (CompositeClassExtension) + XtGetClassExtension(XtClass(parent), + XtOffsetOf(CompositeClassRec, composite_class.extension), + NULLQUARK, 1L, (Cardinal) 0); + LOCK_PROCESS; + if (ext && + (ext->version > XtCompositeExtensionVersion || + ext->record_size > sizeof(CompositeClassExtensionRec))) { + params[1] = XtClass(parent)->core_class.class_name; + num_params = 2; + XtAppWarningMsg(XtWidgetToApplicationContext(parent), + "invalidExtension", XtNxtCreateWidget, + XtCXtToolkitError, + "widget \"%s\" class %s has invalid CompositeClassExtension record", + params, &num_params); + } + if (!ext || !ext->accepts_objects) { + params[1] = XtName(parent); + num_params = 2; + XtAppErrorMsg(XtWidgetToApplicationContext(parent), + "nonWidget", XtNxtCreateWidget,XtCXtToolkitError, +"attempt to add non-widget child \"%s\" to parent \"%s\" which supports only widgets", + params, &num_params); + } + UNLOCK_PROCESS; + } + } else { + default_screen = parent->core.screen; + } + + if (XtIsConstraint(parent)) { + cwc = (ConstraintWidgetClass) parent->core.widget_class; + } else { + cwc = NULL; + } + widget = xtCreate(name, (char *)NULL, widget_class, parent, + default_screen, args, num_args, + typed_args, num_typed_args, cwc, widgetPostProc); + return (widget); +} + +#if NeedFunctionPrototypes +Widget +XtCreateWidget( + _Xconst char* name, + WidgetClass widget_class, + Widget parent, + ArgList args, + Cardinal num_args + ) +#else +Widget +XtCreateWidget(name, widget_class, parent, args, num_args) + String name; + WidgetClass widget_class; + Widget parent; + ArgList args; + Cardinal num_args; +#endif +{ + Widget retval; + WIDGET_TO_APPCON(parent); + + LOCK_APP(app); + retval = _XtCreateWidget(name, widget_class, parent, args, num_args, + (XtTypedArgList)NULL, (Cardinal)0); + UNLOCK_APP(app); + return retval; +} + + +#if NeedFunctionPrototypes +Widget +XtCreateManagedWidget( + _Xconst char* name, + WidgetClass widget_class, + Widget parent, + ArgList args, + Cardinal num_args + ) +#else +Widget +XtCreateManagedWidget(name, widget_class, parent, args, num_args) + String name; + WidgetClass widget_class; + Widget parent; + ArgList args; + Cardinal num_args; +#endif +{ + register Widget widget; + WIDGET_TO_APPCON(parent); + + LOCK_APP(app); + XtCheckSubclass(parent, compositeWidgetClass, "in XtCreateManagedWidget"); + widget = _XtCreateWidget(name, widget_class, parent, args, num_args, + (XtTypedArgList)NULL, (Cardinal) 0); + XtManageChild(widget); + UNLOCK_APP(app); + return widget; +} + +static void +popupPostProc(w) + Widget w; +{ + Widget parent = XtParent(w); + + parent->core.popup_list = + (WidgetList) XtRealloc((char*) parent->core.popup_list, + (unsigned) (parent->core.num_popups+1) * sizeof(Widget)); + parent->core.popup_list[parent->core.num_popups++] = w; +} + +Widget +_XtCreatePopupShell(name, widget_class, parent, args, num_args, + typed_args, num_typed_args) + String name; + WidgetClass widget_class; + Widget parent; + ArgList args; + Cardinal num_args; + XtTypedArgList typed_args; + Cardinal num_typed_args; +{ + register Widget widget; + Screen* default_screen; + + if (parent == NULL) { + XtErrorMsg("invalidParent",XtNxtCreatePopupShell,XtCXtToolkitError, + "XtCreatePopupShell requires non-NULL parent", + (String *)NULL, (Cardinal *)NULL); + } else if (widget_class == NULL) { + XtAppErrorMsg(XtWidgetToApplicationContext(parent), + "invalidClass",XtNxtCreatePopupShell,XtCXtToolkitError, + "XtCreatePopupShell requires non-NULL widget class", + (String *)NULL, (Cardinal *)NULL); + } + XtCheckSubclass(parent, coreWidgetClass, "in XtCreatePopupShell"); + default_screen = parent->core.screen; + widget = xtCreate(name, (char *)NULL, widget_class, parent, + default_screen, args, num_args, typed_args, + num_typed_args, (ConstraintWidgetClass)NULL, + popupPostProc); + +#ifndef X_NO_RESOURCE_CONFIGURATION_MANAGEMENT + XtAddEventHandler (widget, (EventMask) PropertyChangeMask, FALSE, + (XtEventHandler) _XtResourceConfigurationEH, NULL); +#endif + return(widget); +} + +#if NeedFunctionPrototypes +Widget +XtCreatePopupShell( + _Xconst char* name, + WidgetClass widget_class, + Widget parent, + ArgList args, + Cardinal num_args + ) +#else +Widget +XtCreatePopupShell(name, widget_class, parent, args, num_args) + String name; + WidgetClass widget_class; + Widget parent; + ArgList args; + Cardinal num_args; +#endif +{ + Widget retval; + WIDGET_TO_APPCON(parent); + + LOCK_APP(app); + retval = _XtCreatePopupShell(name, widget_class, parent, args, num_args, + (XtTypedArgList)NULL, (Cardinal)0); + UNLOCK_APP(app); + return retval; +} + +Widget +_XtAppCreateShell(name, class, widget_class, display, args, num_args, + typed_args, num_typed_args) + String name, class; + WidgetClass widget_class; + Display* display; + ArgList args; + Cardinal num_args; + XtTypedArgList typed_args; + Cardinal num_typed_args; +{ + Widget shell; + + if (widget_class == NULL) { + XtAppErrorMsg(XtDisplayToApplicationContext(display), + "invalidClass","xtAppCreateShell",XtCXtToolkitError, + "XtAppCreateShell requires non-NULL widget class", + (String *)NULL, (Cardinal *)NULL); + } + if (name == NULL) + name = XrmNameToString(_XtGetPerDisplay(display)->name); + shell = xtCreate(name, class, widget_class, (Widget)NULL, + (Screen*)DefaultScreenOfDisplay(display), + args, num_args, typed_args, num_typed_args, + (ConstraintWidgetClass) NULL, _XtAddShellToHookObj); + +#ifndef X_NO_RESOURCE_CONFIGURATION_MANAGEMENT + XtAddEventHandler (shell, (EventMask) PropertyChangeMask, FALSE, + (XtEventHandler) _XtResourceConfigurationEH, NULL); +#endif + + return shell; +} + +#if NeedFunctionPrototypes +Widget +XtAppCreateShell( + _Xconst char* name, + _Xconst char* class, + WidgetClass widget_class, + Display *display, + ArgList args, + Cardinal num_args + ) +#else +Widget +XtAppCreateShell(name, class, widget_class, display, args, num_args) + String name, class; + WidgetClass widget_class; + Display *display; + ArgList args; + Cardinal num_args; +#endif +{ + Widget retval; + DPY_TO_APPCON(display); + + LOCK_APP(app); + retval = _XtAppCreateShell(name, class, widget_class, display, args, + num_args, (XtTypedArgList)NULL, (Cardinal)0); + UNLOCK_APP(app); + return retval; +} + +/* ARGSUSED */ +#if NeedFunctionPrototypes +Widget +XtCreateApplicationShell( + _Xconst char* name, /* unused in R3 and later */ + WidgetClass widget_class, + ArgList args, + Cardinal num_args + ) +#else +Widget +XtCreateApplicationShell(name, widget_class, args, num_args) + String name; /* unused in R3 and later */ + WidgetClass widget_class; + ArgList args; + Cardinal num_args; +#endif +{ + Widget retval; + Display* dpy; + XrmClass class; + XtAppContext app = _XtDefaultAppContext(); + + LOCK_APP(app); + dpy = app->list[0]; + class = _XtGetPerDisplay(dpy)->class; + + retval = _XtAppCreateShell((String)NULL, XrmQuarkToString((XrmQuark)class), + widget_class, dpy, args, num_args, + (XtTypedArgList)NULL, (Cardinal)0); + UNLOCK_APP(app); + return retval; +} + +Widget +_XtCreateHookObj(screen) + Screen* screen; +{ + Widget req_widget; + double widget_cache[100]; + Cardinal wsize = 0; + Widget hookobj = xtWidgetAlloc(hookObjectClass, + (ConstraintWidgetClass)NULL, + (Widget)NULL, "hooks", + (ArgList)NULL, (Cardinal)0, + (XtTypedArgList)NULL, (Cardinal)0); + + ((HookObject)hookobj)->hooks.screen = screen; + (void) _XtGetResources(hookobj, (ArgList)NULL, 0, + (XtTypedArgList)NULL, &wsize); + CompileCallbacks(hookobj); + wsize = hookObjectClass->core_class.widget_size; + req_widget = (Widget) XtStackAlloc(wsize, widget_cache); + (void) memmove ((char *) req_widget, (char *) hookobj, (int) wsize); + CallInitialize (hookObjectClass, req_widget, hookobj, + (ArgList)NULL, (Cardinal) 0); + XtStackFree((XtPointer)req_widget, widget_cache); + return hookobj; +} diff --git a/src/Destroy.c b/src/Destroy.c new file mode 100644 index 0000000..aed7cc7 --- /dev/null +++ b/src/Destroy.c @@ -0,0 +1,383 @@ +/* $Xorg: Destroy.c,v 1.4 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" + +struct _DestroyRec { + int dispatch_level; + Widget widget; +}; + +static void Recursive(widget, proc) + Widget widget; + XtWidgetProc proc; +{ + register int i; + CompositePart *cwp; + + /* Recurse down normal children */ + if (XtIsComposite(widget)) { + cwp = &(((CompositeWidget) widget)->composite); + for (i = 0; i < cwp->num_children; i++) { + Recursive(cwp->children[i], proc); + } + } + + /* Recurse down popup children */ + if (XtIsWidget(widget)) { + for (i = 0; i < widget->core.num_popups; i++) { + Recursive(widget->core.popup_list[i], proc); + } + } + + /* Finally, apply procedure to this widget */ + (*proc) (widget); +} /* Recursive */ + +static void Phase1Destroy (widget) + Widget widget; +{ + Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + + widget->core.being_destroyed = TRUE; + if (XtHasCallbacks(hookobj, XtNdestroyHook) == XtCallbackHasSome) { + XtDestroyHookDataRec call_data; + + call_data.type = XtHdestroy; + call_data.widget = widget; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.destroyhook_callbacks, + (XtPointer) &call_data); + } +} /* Phase1Destroy */ + +static void Phase2Callbacks(widget) + Widget widget; +{ + if (widget->core.destroy_callbacks != NULL) { + XtCallCallbackList(widget, + widget->core.destroy_callbacks, (XtPointer) NULL); + } +} /* Phase2Callbacks */ + +static void Phase2Destroy(widget) + register Widget widget; +{ + register WidgetClass class; + register ConstraintWidgetClass cwClass; + ObjectClassExtension ext; + + /* Call constraint destroy procedures */ + if (XtParent(widget) != NULL && !XtIsShell(widget) && XtIsConstraint(XtParent(widget))) { + LOCK_PROCESS; + cwClass = (ConstraintWidgetClass)XtParent(widget)->core.widget_class; + UNLOCK_PROCESS; + for (;;) { + XtWidgetProc destroy; + + LOCK_PROCESS; + destroy = cwClass->constraint_class.destroy; + UNLOCK_PROCESS; + if (destroy) + (*destroy) (widget); + if (cwClass == (ConstraintWidgetClass)constraintWidgetClass) break; + LOCK_PROCESS; + cwClass = (ConstraintWidgetClass) cwClass->core_class.superclass; + UNLOCK_PROCESS; + } + } + + /* Call widget destroy procedures */ + LOCK_PROCESS; + for (class = widget->core.widget_class; + class != NULL; + class = class->core_class.superclass) { + XtWidgetProc destroy; + + destroy = class->core_class.destroy; + UNLOCK_PROCESS; + if (destroy) + (*destroy) (widget); + LOCK_PROCESS; + } + + /* Call widget deallocate procedure */ + ext = (ObjectClassExtension) + XtGetClassExtension(widget->core.widget_class, + XtOffsetOf(CoreClassPart, extension), + NULLQUARK, XtObjectExtensionVersion, + sizeof(ObjectClassExtensionRec)); + if (ext && ext->deallocate) { + XtDeallocateProc deallocate; + deallocate = ext->deallocate; + UNLOCK_PROCESS; + (*deallocate)(widget, NULL); + } else { + UNLOCK_PROCESS; + XtFree((char *)widget); + } +} /* Phase2Destroy */ + +static Boolean IsDescendant(widget, root) + register Widget widget, root; +{ + while ((widget = XtParent(widget)) != root) { + if (widget == NULL) return False; + } + return True; +} + +static void XtPhase2Destroy (widget) + register Widget widget; +{ + Display *display; + Window window; + Widget parent; + XtAppContext app = XtWidgetToApplicationContext(widget); + Widget outerInPhase2Destroy = app->in_phase2_destroy; + int starting_count = app->destroy_count; + Boolean isPopup = False; + + /* invalidate focus trace cache for this display */ + _XtGetPerDisplay(XtDisplayOfObject(widget))->pdi.traceDepth = 0; + + parent = widget->core.parent; + + if (parent && XtIsWidget(parent) && parent->core.num_popups) { + int i; + for (i = 0; i < parent->core.num_popups; i++) { + if (parent->core.popup_list[i] == widget) { + isPopup = True; + break; + } + } + } + + if (!isPopup && parent && XtIsComposite(parent)) { + XtWidgetProc delete_child; + + LOCK_PROCESS; + delete_child = + ((CompositeWidgetClass) parent->core.widget_class)-> + composite_class.delete_child; + UNLOCK_PROCESS; + if (XtIsRectObj(widget)) { + XtUnmanageChild(widget); + } + if (delete_child == NULL) { + String param; + Cardinal num_params = 1; + + LOCK_PROCESS; + param = parent->core.widget_class->core_class.class_name; + UNLOCK_PROCESS; + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidProcedure","deleteChild",XtCXtToolkitError, + "null delete_child procedure for class %s in XtDestroy", + ¶m, &num_params); + } else { + (*delete_child) (widget); + } + } + + /* widget is freed in Phase2Destroy, so retrieve window now. + * Shells destroy their own windows, to prevent window leaks in + * popups; this test is practical only when XtIsShell() is cheap. + */ + if (XtIsShell(widget) || !XtIsWidget(widget)) { + window = 0; +#ifdef lint + display = 0; +#endif + } + else { + display = XtDisplay(widget); + window = widget->core.window; + } + + Recursive(widget, Phase2Callbacks); + if (app->destroy_count > starting_count) { + int i = starting_count; + while (i < app->destroy_count) { + + DestroyRec * dr = app->destroy_list + i; + if (IsDescendant(dr->widget, widget)) { + Widget descendant = dr->widget; + register int j; + app->destroy_count--; + for (j = app->destroy_count - i; --j >= 0; dr++) + *dr = *(dr + 1); + XtPhase2Destroy(descendant); + } + else i++; + } + } + + app->in_phase2_destroy = widget; + Recursive(widget, Phase2Destroy); + app->in_phase2_destroy = outerInPhase2Destroy; + + if (isPopup) { + int i; + for (i = 0; i < parent->core.num_popups; i++) + if (parent->core.popup_list[i] == widget) { + parent->core.num_popups--; + while (i < parent->core.num_popups) { + parent->core.popup_list[i] = parent->core.popup_list[i+1]; + i++; + } + break; + } + } + + /* %%% the following parent test hides a more serious problem, + but it avoids breaking those who depended on the old bug + until we have time to fix it properly. */ + + if (window && (parent == NULL || !parent->core.being_destroyed)) + XDestroyWindow(display, window); +} /* XtPhase2Destroy */ + + +void _XtDoPhase2Destroy(app, dispatch_level) + XtAppContext app; + int dispatch_level; +{ + /* Phase 2 must occur in fifo order. List is not necessarily + * contiguous in dispatch_level. + */ + + int i = 0; + while (i < app->destroy_count) { + + /* XtPhase2Destroy can result in calls to XtDestroyWidget, + * and these could cause app->destroy_list to be reallocated. + */ + + DestroyRec* dr = app->destroy_list + i; + if (dr->dispatch_level >= dispatch_level) { + Widget w = dr->widget; + register int j; + app->destroy_count--; + for (j = app->destroy_count - i; --j >=0; dr++) + *dr = *(dr + 1); + XtPhase2Destroy(w); + } + else i++; + } +} + + +void XtDestroyWidget (widget) + Widget widget; +{ + XtAppContext app; + DestroyRec *dr, *dr2; + + app = XtWidgetToApplicationContext(widget); + LOCK_APP(app); + if (widget->core.being_destroyed) { + UNLOCK_APP(app); + return; + } + Recursive(widget, Phase1Destroy); + + if (app->in_phase2_destroy && + IsDescendant(widget, app->in_phase2_destroy)) + { + XtPhase2Destroy(widget); + UNLOCK_APP(app); + return; + } + + if (app->destroy_count == app->destroy_list_size) { + app->destroy_list_size += 10; + app->destroy_list = (DestroyRec*) + XtRealloc( (char*)app->destroy_list, + (unsigned)sizeof(DestroyRec)*app->destroy_list_size + ); + } + dr = app->destroy_list + app->destroy_count++; + dr->dispatch_level = app->dispatch_level; + dr->widget = widget; + + if (app->dispatch_level > 1) { + int i; + for (i = app->destroy_count - 1; i;) { + /* this handles only one case of nesting difficulties */ + dr = app->destroy_list + (--i); + if (dr->dispatch_level < app->dispatch_level && + IsDescendant(dr->widget, widget)) { + dr2 = app->destroy_list + (app->destroy_count-1); + dr2->dispatch_level = dr->dispatch_level; + break; + } + } + } + + if (_XtSafeToDestroy(app)) { + app->dispatch_level = 1; /* avoid nested _XtDoPhase2Destroy */ + _XtDoPhase2Destroy(app, 0); + app->dispatch_level = 0; + } + UNLOCK_APP(app); + +} /* XtDestroyWidget */ diff --git a/src/Display.c b/src/Display.c new file mode 100644 index 0000000..a0f1ba0 --- /dev/null +++ b/src/Display.c @@ -0,0 +1,866 @@ +/* $Xorg: Display.c,v 1.6 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#ifndef X_NO_RESOURCE_CONFIGURATION_MANAGEMENT +#include "ResConfigP.h" +#endif + +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#else +extern char* getenv(); +#endif + +#ifdef XTHREADS +void (*_XtProcessLock)() = NULL; +void (*_XtProcessUnlock)() = NULL; +void (*_XtInitAppLock)() = NULL; +#endif + +static String XtNnoPerDisplay = "noPerDisplay"; + +extern void _XtHeapInit(); +extern void _XtHeapFree(); +extern XrmDatabase _XtPreparseCommandLine(); + +ProcessContext _XtGetProcessContext() +{ + static ProcessContextRec processContextRec = { + (XtAppContext)NULL, + (XtAppContext)NULL, + (ConverterTable)NULL, + {(XtLanguageProc)NULL, (XtPointer)NULL} + }; + + return &processContextRec; +} + + +XtAppContext _XtDefaultAppContext() +{ + ProcessContext process = _XtGetProcessContext(); + XtAppContext app; + + LOCK_PROCESS; + if (process->defaultAppContext == NULL) { + process->defaultAppContext = XtCreateApplicationContext(); + } + app = process->defaultAppContext; + UNLOCK_PROCESS; + return app; +} + +static void AddToAppContext(d, app) + Display *d; + XtAppContext app; +{ +#define DISPLAYS_TO_ADD 4 + + if (app->count >= app->max) { + app->max += DISPLAYS_TO_ADD; + app->list = (Display **) XtRealloc((char *)app->list, + (unsigned) app->max * sizeof(Display *)); + } + + app->list[app->count++] = d; + app->rebuild_fdlist = TRUE; +#ifndef USE_POLL + if (ConnectionNumber(d) + 1 > app->fds.nfds) { + app->fds.nfds = ConnectionNumber(d) + 1; + } +#else + app->fds.nfds++; +#endif +#undef DISPLAYS_TO_ADD +} + +static void XtDeleteFromAppContext(d, app) + Display *d; + register XtAppContext app; +{ + register int i; + + LOCK_APP(app); + + for (i = 0; i < app->count; i++) if (app->list[i] == d) break; + + if (i < app->count) { + if (i <= app->last && app->last > 0) app->last--; + for (i++; i < app->count; i++) app->list[i-1] = app->list[i]; + app->count--; + } + app->rebuild_fdlist = TRUE; + +#ifndef USE_POLL + + { + int display; + int source; + + /* + * Search through list[] for largest connection number + */ + + app->fds.nfds = 0; + + for (display = 0; display < app->count; display++) { + if ((ConnectionNumber(app->list[display]) + 1) > app->fds.nfds) { + app->fds.nfds = ConnectionNumber(app->list[display]) + 1; + } + } + + /* + * Search through input_list[] for largest input source, i.e. + * file descriptor + */ + + for (source = (app->input_max - 1); ((source >= 0) && ((source + 1) > app->fds.nfds)); source--) { + if (app->input_list[source] != (InputEvent *) NULL) { + app->fds.nfds = (source + 1); + break; + } + } + } + +#else + + app->fds.nfds--; + +#endif + + UNLOCK_APP(app); +} + +static XtPerDisplay NewPerDisplay(dpy) + Display *dpy; +{ + PerDisplayTablePtr pd; + + pd = XtNew(PerDisplayTable); + LOCK_PROCESS; + pd->dpy = dpy; + pd->next = _XtperDisplayList; + _XtperDisplayList = pd; + UNLOCK_PROCESS; + return &(pd->perDpy); +} + +static XtPerDisplay InitPerDisplay(dpy, app, name, classname) + Display *dpy; + XtAppContext app; + String name; + String classname; +{ + extern void _XtAllocTMContext(); + XtPerDisplay pd; + + AddToAppContext(dpy, app); + + pd = NewPerDisplay(dpy); + _XtHeapInit(&pd->heap); + pd->destroy_callbacks = NULL; + pd->region = XCreateRegion(); + pd->case_cvt = NULL; + pd->defaultKeycodeTranslator = XtTranslateKey; + pd->keysyms_serial = 0; + pd->keysyms = NULL; + XDisplayKeycodes(dpy, &pd->min_keycode, &pd->max_keycode); + pd->modKeysyms = NULL; + pd->modsToKeysyms = NULL; + pd->appContext = app; + pd->name = XrmStringToName(name); + pd->class = XrmStringToClass(classname); + pd->being_destroyed = False; + pd->GClist = NULL; + pd->pixmap_tab = NULL; + pd->language = NULL; + pd->rv = False; + pd->last_event.xany.serial = 0; + pd->last_timestamp = 0; + _XtAllocTMContext(pd); + pd->mapping_callbacks = NULL; + + pd->pdi.grabList = NULL; + pd->pdi.trace = NULL; + pd->pdi.traceDepth = 0; + pd->pdi.traceMax = 0; + pd->pdi.focusWidget = NULL; + pd->pdi.activatingKey = 0; + pd->pdi.keyboard.grabType = XtNoServerGrab; + pd->pdi.pointer.grabType = XtNoServerGrab; + _XtAllocWWTable(pd); + pd->per_screen_db = (XrmDatabase *)__XtCalloc(ScreenCount(dpy), + sizeof(XrmDatabase)); + pd->cmd_db = (XrmDatabase)NULL; + pd->server_db = (XrmDatabase)NULL; + pd->dispatcher_list = NULL; + pd->ext_select_list = NULL; + pd->ext_select_count = 0; + pd->hook_object = NULL; +#if 0 + pd->hook_object = _XtCreate("hooks", "Hooks", hookObjectClass, + (Widget)NULL, (Screen*)DefaultScreenOfDisplay(dpy), + (ArgList)NULL, 0, (XtTypedArgList)NULL, 0, + (ConstraintWidgetClass)NULL); +#endif + +#ifndef X_NO_RESOURCE_CONFIGURATION_MANAGEMENT + pd->rcm_init = XInternAtom (dpy, RCM_INIT, 0); + pd->rcm_data = XInternAtom (dpy, RCM_DATA, 0); +#endif + + return pd; +} + +#if NeedFunctionPrototypes +Display *XtOpenDisplay( + XtAppContext app, + _Xconst char* displayName, + _Xconst char* applName, + _Xconst char* className, + XrmOptionDescRec *urlist, + Cardinal num_urs, + int *argc, + String *argv + ) +#else +Display *XtOpenDisplay(app, displayName, applName, className, + urlist, num_urs, argc, argv) + XtAppContext app; + String displayName, applName, className; + XrmOptionDescRec *urlist; + Cardinal num_urs; + int *argc; + String *argv; +#endif +{ + Display *d; + XrmDatabase db = 0; + XtPerDisplay pd; + String language = NULL; + + LOCK_APP(app); + LOCK_PROCESS; + /* parse the command line for name, display, and/or language */ + db = _XtPreparseCommandLine(urlist, num_urs, *argc, argv, &applName, + (displayName ? NULL : &displayName), + (app->process->globalLangProcRec.proc ? + &language : NULL)); + UNLOCK_PROCESS; + d = XOpenDisplay(displayName); + + if (! applName && !(applName = getenv("RESOURCE_NAME"))) { + if (*argc > 0 && argv[0] && *argv[0]) { +#ifdef WIN32 + char *ptr = strrchr(argv[0], '\\'); +#else + char *ptr = strrchr(argv[0], '/'); +#endif + if (ptr) applName = ++ptr; + else applName = argv[0]; + } else + applName = "main"; + } + + if (d) { + pd = InitPerDisplay(d, app, applName, className); + pd->language = language; + _XtDisplayInitialize(d, pd, applName, urlist, num_urs, argc, argv); + } else { + int len; + displayName = XDisplayName(displayName); + len = strlen (displayName); + app->display_name_tried = (String) __XtMalloc (len + 1); + strncpy ((char*) app->display_name_tried, displayName, len + 1); + app->display_name_tried[len] = '\0'; + } + if (db) XrmDestroyDatabase(db); + UNLOCK_APP(app); + return d; +} + +Display * +_XtAppInit(app_context_return, application_class, options, num_options, + argc_in_out, argv_in_out, fallback_resources) +XtAppContext * app_context_return; +String application_class; +XrmOptionDescRec *options; +Cardinal num_options; +int *argc_in_out; +String **argv_in_out, * fallback_resources; +{ + String *saved_argv; + int i; + Display *dpy; + +/* + * Save away argv and argc so we can set the properties later + */ + + saved_argv = (String *) + __XtMalloc( (Cardinal)((*argc_in_out + 1) * sizeof(String)) ); + + for (i = 0 ; i < *argc_in_out ; i++) saved_argv[i] = (*argv_in_out)[i]; + saved_argv[i] = NULL; /* NULL terminate that sucker. */ + + + *app_context_return = XtCreateApplicationContext(); + + LOCK_APP((*app_context_return)); + if (fallback_resources) /* save a procedure call */ + XtAppSetFallbackResources(*app_context_return, fallback_resources); + + dpy = XtOpenDisplay(*app_context_return, (String) NULL, NULL, + application_class, + options, num_options, argc_in_out, *argv_in_out); + + if (!dpy) { + String param = (*app_context_return)->display_name_tried; + Cardinal param_count = 1; + XtErrorMsg("invalidDisplay","xtInitialize",XtCXtToolkitError, + "Can't open display: %s", ¶m, ¶m_count); + XtFree((char *) (*app_context_return)->display_name_tried); + } + *argv_in_out = saved_argv; + UNLOCK_APP((*app_context_return)); + return dpy; +} + +#if NeedFunctionPrototypes +void +XtDisplayInitialize( + XtAppContext app, + Display *dpy, + _Xconst char* name, + _Xconst char* classname, + XrmOptionDescRec *urlist, + Cardinal num_urs, + int *argc, + String *argv + ) +#else +void +XtDisplayInitialize(app, dpy, name, classname, urlist, num_urs, argc, argv) + XtAppContext app; + Display *dpy; + String name, classname; + XrmOptionDescRec *urlist; + Cardinal num_urs; + int *argc; + String *argv; +#endif +{ + XtPerDisplay pd; + XrmDatabase db = 0; + + LOCK_APP(app); + pd = InitPerDisplay(dpy, app, name, classname); + LOCK_PROCESS; + if (app->process->globalLangProcRec.proc) + /* pre-parse the command line for the language resource */ + db = _XtPreparseCommandLine(urlist, num_urs, *argc, argv, NULL, NULL, + &pd->language); + UNLOCK_PROCESS; + _XtDisplayInitialize(dpy, pd, name, urlist, num_urs, argc, argv); + if (db) XrmDestroyDatabase(db); + UNLOCK_APP(app); +} + +XtAppContext XtCreateApplicationContext() +{ + XtAppContext app = XtNew(XtAppStruct); +#ifdef XTHREADS + app->lock_info = NULL; + app->lock = NULL; + app->unlock = NULL; + app->yield_lock = NULL; + app->restore_lock = NULL; + app->free_lock = NULL; +#endif + INIT_APP_LOCK(app); + LOCK_APP(app); + LOCK_PROCESS; + app->process = _XtGetProcessContext(); + app->next = app->process->appContextList; + app->process->appContextList = app; + app->langProcRec.proc = app->process->globalLangProcRec.proc; + app->langProcRec.closure = app->process->globalLangProcRec.closure; + app->destroy_callbacks = NULL; + app->list = NULL; + app->count = app->max = app->last = 0; + app->timerQueue = NULL; + app->workQueue = NULL; + app->signalQueue = NULL; + app->input_list = NULL; + app->outstandingQueue = NULL; + app->errorDB = NULL; + _XtSetDefaultErrorHandlers(&app->errorMsgHandler, + &app->warningMsgHandler, &app->errorHandler, + &app->warningHandler); + app->action_table = NULL; + _XtSetDefaultSelectionTimeout(&app->selectionTimeout); + _XtSetDefaultConverterTable(&app->converterTable); + app->sync = app->being_destroyed = app->error_inited = FALSE; + app->in_phase2_destroy = NULL; +#ifndef USE_POLL + FD_ZERO(&app->fds.rmask); + FD_ZERO(&app->fds.wmask); + FD_ZERO(&app->fds.emask); +#endif + app->fds.nfds = 0; + app->input_count = app->input_max = 0; + _XtHeapInit(&app->heap); + app->fallback_resources = NULL; + _XtPopupInitialize(app); + app->action_hook_list = NULL; + app->block_hook_list = NULL; + app->destroy_list_size = app->destroy_count = app->dispatch_level = 0; + app->destroy_list = NULL; +#ifndef NO_IDENTIFY_WINDOWS + app->identify_windows = False; +#endif + app->free_bindings = NULL; + app->display_name_tried = NULL; + app->dpy_destroy_count = 0; + app->dpy_destroy_list = NULL; + app->exit_flag = FALSE; + app->rebuild_fdlist = TRUE; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return app; +} + +#if NeedFunctionPrototypes +void XtAppSetExitFlag ( + XtAppContext app) +#else +void XtAppSetExitFlag (app) + XtAppContext app; +#endif +{ + LOCK_APP(app); + app->exit_flag = TRUE; + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +Boolean XtAppGetExitFlag ( + XtAppContext app) +#else +Boolean XtAppGetExitFlag (app) + XtAppContext app; +#endif +{ + Boolean retval; + LOCK_APP(app); + retval = app->exit_flag; + UNLOCK_APP(app); + return retval; +} + +static void DestroyAppContext(app) + XtAppContext app; +{ + XtAppContext* prev_app; + + prev_app = &app->process->appContextList; + while (app->count-- > 0) XtCloseDisplay(app->list[app->count]); + if (app->list != NULL) XtFree((char *)app->list); + _XtFreeConverterTable(app->converterTable); + _XtCacheFlushTag(app, (XtPointer)&app->heap); + _XtFreeActions(app->action_table); + if (app->destroy_callbacks != NULL) { + XtCallCallbackList((Widget) NULL, + (XtCallbackList)app->destroy_callbacks, + (XtPointer)app); + _XtRemoveAllCallbacks(&app->destroy_callbacks); + } + while (app->timerQueue) XtRemoveTimeOut((XtIntervalId)app->timerQueue); + while (app->workQueue) XtRemoveWorkProc((XtWorkProcId)app->workQueue); + while (app->signalQueue) XtRemoveSignal((XtSignalId)app->signalQueue); + if (app->input_list) _XtRemoveAllInputs(app); + XtFree((char*)app->destroy_list); + _XtHeapFree(&app->heap); + while (*prev_app != app) prev_app = &(*prev_app)->next; + *prev_app = app->next; + if (app->process->defaultAppContext == app) + app->process->defaultAppContext = NULL; + if (app->free_bindings) _XtDoFreeBindings (app); + FREE_APP_LOCK(app); + XtFree((char *)app); +} + +static XtAppContext* appDestroyList = NULL; +int _XtAppDestroyCount = 0; + +void XtDestroyApplicationContext(app) + XtAppContext app; +{ + LOCK_APP(app); + if (app->being_destroyed) { + UNLOCK_APP(app); + return; + } + + if (_XtSafeToDestroy(app)) { + LOCK_PROCESS; + DestroyAppContext(app); + UNLOCK_PROCESS; + } else { + app->being_destroyed = TRUE; + LOCK_PROCESS; + _XtAppDestroyCount++; + appDestroyList = + (XtAppContext *) XtRealloc((char *) appDestroyList, + (unsigned) (_XtAppDestroyCount * sizeof(XtAppContext))); + appDestroyList[_XtAppDestroyCount-1] = app; + UNLOCK_PROCESS; + UNLOCK_APP(app); + } +} + +void _XtDestroyAppContexts() +{ + int i,ii; + XtAppContext apps[8]; + XtAppContext* pApps; + + pApps = XtStackAlloc (sizeof (XtAppContext) * _XtAppDestroyCount, apps); + + for (i = ii = 0; i < _XtAppDestroyCount; i++) { + if (_XtSafeToDestroy(appDestroyList[i])) + DestroyAppContext(appDestroyList[i]); + else + pApps[ii++] = appDestroyList[i]; + } + _XtAppDestroyCount = ii; + if (_XtAppDestroyCount == 0) { + XtFree((char *) appDestroyList); + appDestroyList = NULL; + } else { + for (i = 0; i < ii; i++) + appDestroyList[i] = pApps[i]; + } + XtStackFree ((XtPointer) pApps, apps); +} + +XrmDatabase XtDatabase(dpy) + Display *dpy; +{ + XrmDatabase retval; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + retval = XrmGetDatabase(dpy); + UNLOCK_APP(app); + return retval; +} + +PerDisplayTablePtr _XtperDisplayList = NULL; + +XtPerDisplay _XtSortPerDisplayList(dpy) + Display *dpy; +{ + register PerDisplayTablePtr pd, opd; + +#ifdef lint + opd = NULL; +#endif + LOCK_PROCESS; + for (pd = _XtperDisplayList; + pd != NULL && pd->dpy != dpy; + pd = pd->next) { + opd = pd; + } + + if (pd == NULL) { + XtErrorMsg(XtNnoPerDisplay, "getPerDisplay", XtCXtToolkitError, + "Couldn't find per display information", + (String *) NULL, (Cardinal *)NULL); + } + + if (pd != _XtperDisplayList) { /* move it to the front */ + /* opd points to the previous one... */ + + opd->next = pd->next; + pd->next = _XtperDisplayList; + _XtperDisplayList = pd; + } + UNLOCK_PROCESS; + return &(pd->perDpy); +} + +XtAppContext XtDisplayToApplicationContext(dpy) + Display *dpy; +{ + XtAppContext retval; + + retval = _XtGetPerDisplay(dpy)->appContext; + return retval; +} + +static void CloseDisplay(dpy) + Display *dpy; +{ + register XtPerDisplay xtpd; + register PerDisplayTablePtr pd, opd; + XrmDatabase db; + int i; + +#ifdef lint + opd = NULL; +#endif + XtDestroyWidget(XtHooksOfDisplay(dpy)); + + LOCK_PROCESS; + for (pd = _XtperDisplayList; + pd != NULL && pd->dpy != dpy; + pd = pd->next){ + opd = pd; + } + + if (pd == NULL) { + XtErrorMsg(XtNnoPerDisplay, "closeDisplay", XtCXtToolkitError, + "Couldn't find per display information", + (String *) NULL, (Cardinal *)NULL); + } + + if (pd == _XtperDisplayList) _XtperDisplayList = pd->next; + else opd->next = pd->next; + + xtpd = &(pd->perDpy); + + if (xtpd != NULL) { + extern void _XtGClistFree(); + if (xtpd->destroy_callbacks != NULL) { + XtCallCallbackList((Widget) NULL, + (XtCallbackList)xtpd->destroy_callbacks, + (XtPointer)xtpd); + _XtRemoveAllCallbacks(&xtpd->destroy_callbacks); + } + if (xtpd->mapping_callbacks != NULL) + _XtRemoveAllCallbacks(&xtpd->mapping_callbacks); + XtDeleteFromAppContext(dpy, xtpd->appContext); + if (xtpd->keysyms) + XFree((char *) xtpd->keysyms); + XtFree((char *) xtpd->modKeysyms); + XtFree((char *) xtpd->modsToKeysyms); + xtpd->keysyms_per_keycode = 0; + xtpd->being_destroyed = FALSE; + xtpd->keysyms = NULL; + xtpd->modKeysyms = NULL; + xtpd->modsToKeysyms = NULL; + XDestroyRegion(xtpd->region); + _XtCacheFlushTag(xtpd->appContext, (XtPointer)&xtpd->heap); + _XtGClistFree(dpy, xtpd); + XtFree((char*)xtpd->pdi.trace); + _XtHeapFree(&xtpd->heap); + _XtFreeWWTable(xtpd); + xtpd->per_screen_db[DefaultScreen(dpy)] = (XrmDatabase)NULL; + for (i = ScreenCount(dpy); --i >= 0; ) { + db = xtpd->per_screen_db[i]; + if (db) + XrmDestroyDatabase(db); + } + XtFree((char *)xtpd->per_screen_db); + if ((db = XrmGetDatabase(dpy))) + XrmDestroyDatabase(db); + if (xtpd->cmd_db) + XrmDestroyDatabase(xtpd->cmd_db); + if (xtpd->server_db) + XrmDestroyDatabase(xtpd->server_db); + XtFree(xtpd->language); + if (xtpd->dispatcher_list != NULL) + XtFree((char *) xtpd->dispatcher_list); + if (xtpd->ext_select_list != NULL) + XtFree((char *) xtpd->ext_select_list); + } + XtFree((char*)pd); + XrmSetDatabase(dpy, (XrmDatabase)NULL); + XCloseDisplay(dpy); + UNLOCK_PROCESS; +} + +void XtCloseDisplay(dpy) + Display *dpy; +{ + XtPerDisplay pd; + XtAppContext app = XtDisplayToApplicationContext(dpy); + + LOCK_APP(app); + pd = _XtGetPerDisplay(dpy); + if (pd->being_destroyed) { + UNLOCK_APP(app); + return; + } + + if (_XtSafeToDestroy(app)) CloseDisplay(dpy); + else { + pd->being_destroyed = TRUE; + app->dpy_destroy_count++; + app->dpy_destroy_list = (Display **) + XtRealloc((char *) app->dpy_destroy_list, + (unsigned) (app->dpy_destroy_count * sizeof(Display *))); + app->dpy_destroy_list[app->dpy_destroy_count-1] = dpy; + } + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void _XtCloseDisplays( + XtAppContext app) +#else +void _XtCloseDisplays(app) + XtAppContext app; +#endif +{ + int i; + + LOCK_APP(app); + for (i = 0; i < app->dpy_destroy_count; i++) { + CloseDisplay(app->dpy_destroy_list[i]); + } + app->dpy_destroy_count = 0; + XtFree((char *) app->dpy_destroy_list); + app->dpy_destroy_list = NULL; + UNLOCK_APP(app); +} + +XtAppContext XtWidgetToApplicationContext(w) + Widget w; +{ + XtAppContext retval; + + retval = _XtGetPerDisplay(XtDisplayOfObject(w))->appContext; + return retval; +} + + +void XtGetApplicationNameAndClass(dpy, name_return, class_return) + Display *dpy; + String *name_return; + String *class_return; +{ + XtPerDisplay pd; + + pd = _XtGetPerDisplay(dpy); + *name_return = XrmQuarkToString(pd->name); + *class_return = XrmQuarkToString(pd->class); +} + +#if NeedFunctionPrototypes +XtPerDisplay _XtGetPerDisplay ( + Display* display) +#else +XtPerDisplay _XtGetPerDisplay (display) + Display* display; +#endif +{ + XtPerDisplay retval; + + LOCK_PROCESS; + retval = ((_XtperDisplayList != NULL && + _XtperDisplayList->dpy == display) + ? &_XtperDisplayList->perDpy + : _XtSortPerDisplayList(display)); + UNLOCK_PROCESS; + return retval; +} + +#if NeedFunctionPrototypes +XtPerDisplayInputRec* _XtGetPerDisplayInput( + Display* display) +#else +XtPerDisplayInputRec* _XtGetPerDisplayInput(display) + Display* display; +#endif +{ + XtPerDisplayInputRec* retval; + LOCK_PROCESS; + retval = ((_XtperDisplayList != NULL && + _XtperDisplayList->dpy == display) + ? &_XtperDisplayList->perDpy.pdi + : &_XtSortPerDisplayList(display)->pdi); + UNLOCK_PROCESS; + return retval; +} + +#if NeedFunctionPrototypes +void XtGetDisplays( + XtAppContext app_context, + Display*** dpy_return, + Cardinal* num_dpy_return) +#else +void XtGetDisplays(app_context, dpy_return, num_dpy_return) + XtAppContext app_context; + Display*** dpy_return; + Cardinal* num_dpy_return; +#endif +{ + int ii; + LOCK_APP(app_context); + *num_dpy_return = app_context->count; + *dpy_return = (Display**)__XtMalloc(app_context->count * sizeof(Display*)); + for (ii = 0; ii < app_context->count; ii++) + *dpy_return[ii] = app_context->list[ii]; + UNLOCK_APP(app_context); +} diff --git a/src/Error.c b/src/Error.c new file mode 100644 index 0000000..27186d6 --- /dev/null +++ b/src/Error.c @@ -0,0 +1,735 @@ +/* $Xorg: Error.c,v 1.5 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include <stdio.h> + +/* The error handlers in the application context aren't used since we can't + come up with a uniform way of using them. If you can, define + GLOBALERRORS to be FALSE (or 0). */ + +#ifndef GLOBALERRORS +#define GLOBALERRORS 1 +#endif + +static void InitErrorHandling(); +#if GLOBALERRORS +static XrmDatabase errorDB = NULL; +static Boolean error_inited = FALSE; +void _XtDefaultErrorMsg(), _XtDefaultWarningMsg(), + _XtDefaultError(), _XtDefaultWarning(); +static XtErrorMsgHandler errorMsgHandler = _XtDefaultErrorMsg; +static XtErrorMsgHandler warningMsgHandler = _XtDefaultWarningMsg; +static XtErrorHandler errorHandler = _XtDefaultError; +static XtErrorHandler warningHandler = _XtDefaultWarning; +#endif /* GLOBALERRORS */ + +XrmDatabase *XtGetErrorDatabase() +{ + XrmDatabase* retval; +#if GLOBALERRORS + LOCK_PROCESS; + retval = &errorDB; + UNLOCK_PROCESS; +#else + retval = XtAppGetErrorDatabase(_XtDefaultAppContext()); +#endif /* GLOBALERRORS */ + return retval; +} + +XrmDatabase *XtAppGetErrorDatabase(app) + XtAppContext app; +{ + XrmDatabase* retval; +#if GLOBALERRORS + LOCK_PROCESS; + retval = &errorDB; + UNLOCK_PROCESS; +#else + LOCK_APP(app); + retval= &app->errorDB; + UNLOCK_APP(app); +#endif /* GLOBALERRORS */ + return retval; +} + +#if NeedFunctionPrototypes +void XtGetErrorDatabaseText( + register _Xconst char* name, + register _Xconst char* type, + register _Xconst char* class, + _Xconst char* defaultp, + String buffer, + int nbytes + ) +#else +void XtGetErrorDatabaseText(name,type,class,defaultp, buffer, nbytes) + register String name, type, class; + String defaultp; + String buffer; + int nbytes; +#endif +{ +#if GLOBALERRORS + XtAppGetErrorDatabaseText(NULL, + name,type,class,defaultp, buffer, nbytes, NULL); +#else + XtAppGetErrorDatabaseText(_XtDefaultAppContext(), + name,type,class,defaultp, buffer, nbytes, NULL); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +void XtAppGetErrorDatabaseText( + XtAppContext app, + register _Xconst char* name, + register _Xconst char* type, + register _Xconst char* class, + _Xconst char* defaultp, + String buffer, + int nbytes, + XrmDatabase db + ) +#else +void XtAppGetErrorDatabaseText(app, name,type,class,defaultp, + buffer, nbytes, db) + XtAppContext app; + register String name, type, class; + String defaultp; + String buffer; + int nbytes; + XrmDatabase db; +#endif +{ + String str_class; + String type_str; + XrmValue result; + char *str_name = NULL; + char *temp = NULL; + +#if GLOBALERRORS + LOCK_PROCESS; + if (error_inited == FALSE) { + InitErrorHandling (&errorDB); + error_inited = TRUE; + } +#else + LOCK_APP(app); + if (app->error_inited == FALSE) { + InitErrorHandling (&app->errorDB); + app->error_inited = TRUE; + } +#endif /* GLOBALERRORS */ + if (!(str_name = ALLOCATE_LOCAL(strlen(name) + strlen(type) + 2))) + _XtAllocError(NULL); + (void) sprintf(str_name, "%s.%s", name, type); + /* XrmGetResource requires the name and class to be fully qualified + * and to have the same number of components. */ + str_class = (char *)class; + if (! strchr(class, '.')) { + if (!(temp = ALLOCATE_LOCAL(2 * strlen(class) + 2))) + _XtAllocError(NULL); + (void) sprintf(temp, "%s.%s", class, class); + str_class = temp; + } + if (db == NULL) { +#if GLOBALERRORS + (void) XrmGetResource(errorDB, str_name, str_class, &type_str, + &result); +#else + (void) XrmGetResource(app->errorDB, str_name, str_class, &type_str, + &result); +#endif /* GLOBALERRORS */ + } else (void) XrmGetResource(db, str_name, str_class, &type_str, &result); + if (result.addr) { + (void) strncpy (buffer, result.addr, nbytes); + if (result.size > nbytes) buffer[nbytes-1] = 0; + } else { + int len = strlen(defaultp); + if (len >= nbytes) len = nbytes-1; + (void) memmove(buffer, defaultp, len); + buffer[len] = '\0'; + } + if (str_name) + DEALLOCATE_LOCAL(str_name); + if (temp) + DEALLOCATE_LOCAL(temp); +#if GLOBALERRORS + UNLOCK_PROCESS; +#else + UNLOCK_APP(app); +#endif +} + +static void InitErrorHandling (db) + XrmDatabase *db; +{ + XrmDatabase errordb; + + errordb = XrmGetFileDatabase(ERRORDB); + XrmMergeDatabases(errordb, db); +} + +static void DefaultMsg (name,type,class,defaultp,params,num_params,error,fn) + String name,type,class,defaultp; + String* params; + Cardinal* num_params; + Bool error; + void (*fn)(String); +{ +#define BIGBUF 1024 +#ifdef notyet /* older versions don't, might want to wait until more do */ +#if defined(__linux__) || defined(CSRG_BASED) /* everyone else needs to get with the program */ +#define USE_SNPRINTF +#endif +#endif + char buffer[BIGBUF]; + char* message; + XtGetErrorDatabaseText(name,type,class,defaultp, buffer, BIGBUF); +/*need better solution here, perhaps use lower level printf primitives? */ + if (params == NULL || num_params == NULL || *num_params == 0) + (*fn)(buffer); +#ifndef WIN32 /* and OS/2 */ + else if ((getuid () != geteuid ()) || getuid() == 0) { + if ((error && errorHandler == _XtDefaultError) || + (!error && warningHandler == _XtDefaultWarning)) { + /* + * if it's just going to go to stderr anyway, then we'll + * fprintf to stderr ourselves and skip the insecure sprintf. + */ + int i = *num_params; + String par[10]; + if (i > 10) i = 10; + (void) memmove((char*)par, (char*)params, i * sizeof(String) ); + bzero( &par[i], (10-i) * sizeof(String) ); + (void) fprintf (stderr, "%s%s", + error ? XTERROR_PREFIX : XTWARNING_PREFIX, + error ? "Error: " : "Warning: "); + (void) fprintf (stderr, buffer, + par[0], par[1], par[2], par[3], par[4], + par[5], par[6], par[7], par[8], par[9]); + (void) fprintf (stderr, "%c", '\n'); + if (i != *num_params) + (*fn) ( "Some arguments in previous message were lost" ); + else if (error) exit (1); + } else { + /* + * can't tell what it might do, so we'll play it safe + */ + XtWarning ("\ +This program is an suid-root program or is being run by the root user.\n\ +The full text of the error or warning message cannot be safely formatted\n\ +in this environment. You may get a more descriptive message by running the\n\ +program as a non-root user or by removing the suid bit on the executable."); + (*fn)(buffer); /* if *fn is an ErrorHandler it should exit */ + } + } +#endif + else { + /* + * If you have snprintf the worst thing that could happen is you'd + * lose some information. Without snprintf you're probably going to + * scramble your heap and perhaps SEGV -- sooner or later. + * If it hurts when you go like this then don't go like this! :-) + */ + int i = *num_params; + String par[10]; + if (i > 10) i = 10; + (void) memmove((char*)par, (char*)params, i * sizeof(String) ); + bzero( &par[i], (10-i) * sizeof(String) ); + if (i != *num_params) + XtWarning( "Some arguments in following message were lost" ); + /* + * resist any temptation you might have to make `message' a + * local buffer on the stack. Doing so is a security hole + * in programs executing as root. Error and Warning + * messages shouldn't be called frequently enough for this + * to be a performance issue. + */ + if ((message = __XtMalloc (BIGBUF))) { +#ifndef USE_SNPRINTF + message[BIGBUF-1] = 0; + (void) sprintf (message, buffer, +#else + (void) snprintf (message, BIGBUF, buffer, +#endif + par[0], par[1], par[2], par[3], par[4], + par[5], par[6], par[7], par[8], par[9]); +#ifndef USE_SNPRINTF + if (message[BIGBUF-1] != '\0') + XtWarning ("Possible heap corruption in Xt{Error,Warning}MsgHandler"); +#endif + (*fn)(message); + XtFree(message); + } else { + XtWarning ("Memory allocation failed, arguments in the following message were lost"); + (*fn)(buffer); + } + } +} + +void _XtDefaultErrorMsg (name,type,class,defaultp,params,num_params) + String name,type,class,defaultp; + String* params; + Cardinal* num_params; +{ + DefaultMsg (name,type,class,defaultp,params,num_params,True,XtError); +} + +void _XtDefaultWarningMsg (name,type,class,defaultp,params,num_params) + String name,type,class,defaultp; + String* params; + Cardinal* num_params; +{ + DefaultMsg (name,type,class,defaultp,params,num_params,False,XtWarning); +} + +#if NeedFunctionPrototypes +void XtErrorMsg( + _Xconst char* name, + _Xconst char* type, + _Xconst char* class, + _Xconst char* defaultp, + String* params, + Cardinal* num_params + ) +#else +void XtErrorMsg(name,type,class,defaultp,params,num_params) + String name,type,class,defaultp; + String* params; + Cardinal* num_params; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + (*errorMsgHandler)((String)name,(String)type,(String)class, + (String)defaultp,params,num_params); + UNLOCK_PROCESS; +#else + XtAppErrorMsg(_XtDefaultAppContext(),name,type,class, + defaultp,params,num_params); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +void XtAppErrorMsg( + XtAppContext app, + _Xconst char* name, + _Xconst char* type, + _Xconst char* class, + _Xconst char* defaultp, + String* params, + Cardinal* num_params + ) +#else +void XtAppErrorMsg(app, name,type,class,defaultp,params,num_params) + XtAppContext app; + String name,type,class,defaultp; + String* params; + Cardinal* num_params; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + (*errorMsgHandler)((String)name,(String)type,(String)class, + (String)defaultp,params,num_params); + UNLOCK_PROCESS; +#else + LOCK_APP(app); + (*app->errorMsgHandler)(name,type,class,defaultp,params,num_params); + UNLOCK_APP(app); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +void XtWarningMsg( + _Xconst char* name, + _Xconst char* type, + _Xconst char* class, + _Xconst char* defaultp, + String* params, + Cardinal* num_params + ) +#else +void XtWarningMsg(name,type,class,defaultp,params,num_params) + String name,type,class,defaultp; + String* params; + Cardinal* num_params; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + (*warningMsgHandler)((String)name,(String)type,(String)class, + (String)defaultp,params,num_params); + UNLOCK_PROCESS; +#else + XtAppWarningMsg(_XtDefaultAppContext(),name,type,class, + defaultp,params,num_params); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +void XtAppWarningMsg( + XtAppContext app, + _Xconst char* name, + _Xconst char* type, + _Xconst char* class, + _Xconst char* defaultp, + String* params, + Cardinal* num_params + ) +#else +void XtAppWarningMsg(app,name,type,class,defaultp,params,num_params) + XtAppContext app; + String name,type,class,defaultp; + String* params; + Cardinal* num_params; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + (*warningMsgHandler)((String)name,(String)type,(String)class, + (String)defaultp,params,num_params); + UNLOCK_PROCESS; +#else + LOCK_APP(app); + (*app->warningMsgHandler)(name,type,class,defaultp,params,num_params); + UNLOCK_APP(app); +#endif /* GLOBALERRORS */ +} + +void XtSetErrorMsgHandler(handler) + XtErrorMsgHandler handler; +{ +#if GLOBALERRORS + LOCK_PROCESS; + if (handler != NULL) errorMsgHandler = handler; + else errorMsgHandler = _XtDefaultErrorMsg; + UNLOCK_PROCESS; +#else + XtAppSetErrorMsgHandler(_XtDefaultAppContext(), handler); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +XtErrorMsgHandler XtAppSetErrorMsgHandler( + XtAppContext app, + XtErrorMsgHandler handler) +#else +XtErrorMsgHandler XtAppSetErrorMsgHandler(app,handler) + XtAppContext app; + XtErrorMsgHandler handler; +#endif +{ + XtErrorMsgHandler old; +#if GLOBALERRORS + LOCK_PROCESS; + old = errorMsgHandler; + if (handler != NULL) errorMsgHandler = handler; + else errorMsgHandler = _XtDefaultErrorMsg; + UNLOCK_PROCESS; +#else + LOCK_APP(app); + old = app->errorMsgHandler; + if (handler != NULL) app->errorMsgHandler = handler; + else app->errorMsgHandler = _XtDefaultErrorMsg; + UNLOCK_APP(app); +#endif /* GLOBALERRORS */ + return old; +} + +void XtSetWarningMsgHandler(handler) + XtErrorMsgHandler handler; +{ +#if GLOBALERRORS + LOCK_PROCESS; + if (handler != NULL) warningMsgHandler = handler; + else warningMsgHandler = _XtDefaultWarningMsg; + UNLOCK_PROCESS; +#else + XtAppSetWarningMsgHandler(_XtDefaultAppContext(),handler); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +XtErrorMsgHandler XtAppSetWarningMsgHandler( + XtAppContext app, + XtErrorMsgHandler handler) +#else +XtErrorMsgHandler XtAppSetWarningMsgHandler(app,handler) + XtAppContext app; + XtErrorMsgHandler handler; +#endif +{ + XtErrorMsgHandler old; +#if GLOBALERRORS + LOCK_PROCESS; + old = warningMsgHandler; + if (handler != NULL) warningMsgHandler = handler; + else warningMsgHandler = _XtDefaultWarningMsg; + UNLOCK_PROCESS; +#else + LOCK_APP(app); + old = app->warningMsgHandler; + if (handler != NULL) app->warningMsgHandler = handler; + else app->warningMsgHandler = _XtDefaultWarningMsg; + UNLOCK_APP(app); +#endif /* GLOBALERRORS */ + return old; +} + +void _XtDefaultError(message) + String message; +{ + if (message && *message) + (void)fprintf(stderr, "%sError: %s\n", XTERROR_PREFIX, message); + exit(1); +} + +void _XtDefaultWarning(message) + String message; +{ + if (message && *message) + (void)fprintf(stderr, "%sWarning: %s\n", XTWARNING_PREFIX, message); + return; +} + +#if NeedFunctionPrototypes +void XtError( + _Xconst char* message + ) +#else +void XtError(message) + String message; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + (*errorHandler)((String)message); + UNLOCK_PROCESS; +#else + XtAppError(_XtDefaultAppContext(),message); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +void XtAppError( + XtAppContext app, + _Xconst char* message + ) +#else +void XtAppError(app,message) + XtAppContext app; + String message; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + (*errorHandler)((String)message); + UNLOCK_PROCESS; +#else + LOCK_APP(app); + (*app->errorHandler)(message); + UNLOCK_APP(app); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +void XtWarning( + _Xconst char* message + ) +#else +void XtWarning(message) + String message; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + (*warningHandler)((String)message); + UNLOCK_PROCESS; +#else + XtAppWarning(_XtDefaultAppContext(),message); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +void XtAppWarning( + XtAppContext app, + _Xconst char* message + ) +#else +void XtAppWarning(app,message) + XtAppContext app; + String message; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + (*warningHandler)((String)message); + UNLOCK_PROCESS; +#else + LOCK_APP(app); + (*app->warningHandler)(message); + UNLOCK_APP(app); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +void XtSetErrorHandler(XtErrorHandler handler) +#else +void XtSetErrorHandler(handler) + XtErrorHandler handler; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + if (handler != NULL) errorHandler = handler; + else errorHandler = _XtDefaultError; + UNLOCK_PROCESS; +#else + XtAppSetErrorHandler(_XtDefaultAppContext(),handler); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +XtErrorHandler XtAppSetErrorHandler( + XtAppContext app, + XtErrorHandler handler) +#else +XtErrorHandler XtAppSetErrorHandler(app,handler) + XtAppContext app; + XtErrorHandler handler; +#endif +{ + XtErrorHandler old; +#if GLOBALERRORS + LOCK_PROCESS; + old = errorHandler; + if (handler != NULL) errorHandler = handler; + else errorHandler = _XtDefaultError; + UNLOCK_PROCESS; +#else + LOCK_APP(app); + old = app->errorHandler; + if (handler != NULL) app->errorHandler = handler; + else app->errorHandler = _XtDefaultError; + UNLOCK_APP(app); +#endif /* GLOBALERRORS */ + return old; +} + +#if NeedFunctionPrototypes +void XtSetWarningHandler(XtErrorHandler handler) +#else +void XtSetWarningHandler(handler) + XtErrorHandler handler; +#endif +{ +#if GLOBALERRORS + LOCK_PROCESS; + if (handler != NULL) warningHandler = handler; + else warningHandler = _XtDefaultWarning; + UNLOCK_PROCESS; +#else + XtAppSetWarningHandler(_XtDefaultAppContext(),handler); +#endif /* GLOBALERRORS */ +} + +#if NeedFunctionPrototypes +XtErrorHandler XtAppSetWarningHandler( + XtAppContext app, + XtErrorHandler handler) +#else +XtErrorHandler XtAppSetWarningHandler(app,handler) + XtAppContext app; + XtErrorHandler handler; +#endif +{ + XtErrorHandler old; +#if GLOBALERRORS + LOCK_PROCESS; + old = warningHandler; + if (handler != NULL) warningHandler = handler; + else warningHandler = _XtDefaultWarning; + UNLOCK_PROCESS; +#else + LOCK_APP(app); + old = app->warningHandler; + if (handler != NULL) app->warningHandler = handler; + else app->warningHandler = _XtDefaultWarning; + UNLOCK_APP(app); +#endif /* GLOBALERRORS */ + return old; +} + +void _XtSetDefaultErrorHandlers(errMsg, warnMsg, err, warn) + XtErrorMsgHandler *errMsg, *warnMsg; + XtErrorHandler *err, *warn; +{ +#ifndef GLOBALERRORS + LOCK_PROCESS; + *errMsg = _XtDefaultErrorMsg; + *warnMsg = _XtDefaultWarningMsg; + *err = _XtDefaultError; + *warn = _XtDefaultWarning; + UNLOCK_PROCESS; +#endif /* GLOBALERRORS */ +} diff --git a/src/Event.c b/src/Event.c new file mode 100644 index 0000000..47d1e43 --- /dev/null +++ b/src/Event.c @@ -0,0 +1,1846 @@ +/* $Xorg: Event.c,v 1.5 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "Shell.h" +#include "StringDefs.h" + +#ifdef __STDC__ +#define Const const +#else +#define Const /**/ +#endif + +typedef struct _XtEventRecExt { + int type; + XtPointer select_data[1]; /* actual dimension is [mask] */ +} XtEventRecExt; + +#define EXT_TYPE(p) (((XtEventRecExt*) ((p)+1))->type) +#define EXT_SELECT_DATA(p,n) (((XtEventRecExt*) ((p)+1))->select_data[n]) + +#define NonMaskableMask ((EventMask)0x80000000L) + +/* + * These are definitions to make the code that handles exposure compresssion + * easier to read. + * + * COMP_EXPOSE - The compression exposure field of "widget" + * COMP_EXPOSE_TYPE - The type of compression (lower 4 bits of COMP_EXPOSE. + * GRAPHICS_EXPOSE - TRUE if the widget wants graphics expose events + * dispatched. + * NO_EXPOSE - TRUE if the widget wants No expose events dispatched. + */ + +#define COMP_EXPOSE (widget->core.widget_class->core_class.compress_exposure) +#define COMP_EXPOSE_TYPE (COMP_EXPOSE & 0x0f) +#define GRAPHICS_EXPOSE ((XtExposeGraphicsExpose & COMP_EXPOSE) || \ + (XtExposeGraphicsExposeMerged & COMP_EXPOSE)) +#define NO_EXPOSE (XtExposeNoExpose & COMP_EXPOSE) + +EventMask XtBuildEventMask(widget) + Widget widget; +{ + XtEventTable ev; + EventMask mask = 0L; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + for (ev = widget->core.event_table; ev != NULL; ev = ev->next) + if (ev->select) { + if (!ev->has_type_specifier) + mask |= ev->mask; + else { + if (EXT_TYPE(ev) < LASTEvent) { + int i; + for (i = 0; i < ev->mask; i++) + if (EXT_SELECT_DATA(ev, i)) + mask |= *(EventMask*)EXT_SELECT_DATA(ev, i); + } + } + } + LOCK_PROCESS; + if (widget->core.widget_class->core_class.expose != NULL) + mask |= ExposureMask; + if (widget->core.widget_class->core_class.visible_interest) + mask |= VisibilityChangeMask; + UNLOCK_PROCESS; + if (widget->core.tm.translations) + mask |= widget->core.tm.translations->eventMask; + + mask = mask & ~NonMaskableMask; + UNLOCK_APP(app); + return mask; +} + +static void CallExtensionSelector(widget, rec, forceCall) + Widget widget; + ExtSelectRec* rec; + Boolean forceCall; +{ + XtEventRec* p; + XtPointer* data; + int* types; + int i, count = 0; + + for (p = widget->core.event_table; p != NULL; p = p->next) + if (p->has_type_specifier && + EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max) + count += p->mask; + + if (count == 0 && !forceCall) return; + + data = (XtPointer *) ALLOCATE_LOCAL(count * sizeof (XtPointer)); + types = (int *) ALLOCATE_LOCAL(count * sizeof (int)); + count = 0; + + for (p = widget->core.event_table; p != NULL; p = p->next) + if (p->has_type_specifier && + EXT_TYPE(p) >= rec->min && EXT_TYPE(p) <= rec->max) + for (i =0; i < p->mask; i++) { + types[count] = EXT_TYPE(p); + data[count++] = EXT_SELECT_DATA(p, i); + } + + (*rec->proc)(widget, types, data, count, rec->client_data); + DEALLOCATE_LOCAL((char*) types); + DEALLOCATE_LOCAL((char*) data); +} + +static void +RemoveEventHandler(widget, select_data, type, has_type_specifier, other, + proc, closure, raw) + Widget widget; + XtPointer select_data; + int type; + Boolean has_type_specifier, other; + XtEventHandler proc; + XtPointer closure; + Boolean raw; +{ + XtEventRec *p, **pp; + EventMask eventMask, oldMask = XtBuildEventMask(widget); + + if (raw) raw = 1; + pp = &widget->core.event_table; + while ((p = *pp) && + (p->proc != proc || p->closure != closure || p->select == raw || + has_type_specifier != p->has_type_specifier || + (has_type_specifier && EXT_TYPE(p) != type))) + pp = &p->next; + if (!p) return; + + /* un-register it */ + if (!has_type_specifier) { + eventMask = *(EventMask*)select_data; + eventMask &= ~NonMaskableMask; + if (other) + eventMask |= NonMaskableMask; + p->mask &= ~eventMask; + } else { + int i; + /* p->mask specifies count of EXT_SELECT_DATA(p,i) + * search through the list of selection data, if not found + * dont remove this handler + */ + for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p,i);) i++; + if (i == p->mask) return; + if (p->mask == 1) p->mask = 0; + else { + p->mask--; + while (i < p->mask) { + EXT_SELECT_DATA(p,i) = EXT_SELECT_DATA(p, i+1); + i++; + } + } + } + + if (!p->mask) { /* delete it entirely */ + *pp = p->next; + XtFree((char *)p); + } + + /* Reset select mask if realized and not raw. */ + if ( !raw && XtIsRealized(widget) && !widget->core.being_destroyed) { + EventMask mask = XtBuildEventMask(widget); + Display* dpy = XtDisplay (widget); + + if (oldMask != mask) + XSelectInput(dpy, XtWindow(widget), mask); + + if (has_type_specifier) { + XtPerDisplay pd = _XtGetPerDisplay(dpy); + int i; + for (i = 0; i < pd->ext_select_count; i++) { + if (type >= pd->ext_select_list[i].min && + type <= pd->ext_select_list[i].max) { + CallExtensionSelector(widget, pd->ext_select_list+i, TRUE); + break; + } + if (type < pd->ext_select_list[i].min) break; + } + } + } +} + +/* Function Name: AddEventHandler + * Description: An Internal routine that does the actual work of + * adding the event handlers. + * Arguments: widget - widget to register an event handler for. + * eventMask - events to mask for. + * other - pass non maskable events to this proceedure. + * proc - proceedure to register. + * closure - data to pass to the event hander. + * position - where to add this event handler. + * force_new_position - If the element is already in the + * list, this will force it to the + * beginning or end depending on position. + * raw - If FALSE call XSelectInput for events in mask. + * Returns: none + */ + +static void +AddEventHandler(widget, select_data, type, has_type_specifier, other, proc, + closure, position, force_new_position, raw) + Widget widget; + XtPointer select_data; + int type; + Boolean has_type_specifier, other, force_new_position, raw; + XtEventHandler proc; + XtPointer closure; + XtListPosition position; +{ + register XtEventRec *p, **pp; + EventMask oldMask, eventMask; + + if (!has_type_specifier) { + eventMask = *(EventMask*)select_data & ~NonMaskableMask; + if (other) eventMask |= NonMaskableMask; + if (!eventMask) return; + } else if (!type) return; + + if (XtIsRealized(widget) && !raw) oldMask = XtBuildEventMask(widget); + + if (raw) raw = 1; + pp = &widget->core.event_table; + while ((p = *pp) && + (p->proc != proc || p->closure != closure || p->select == raw || + has_type_specifier != p->has_type_specifier || + (has_type_specifier && EXT_TYPE(p) != type))) + pp = &p->next; + + if (!p) { /* New proc to add to list */ + if (has_type_specifier) { + p = (XtEventRec*) __XtMalloc(sizeof(XtEventRec) + + sizeof(XtEventRecExt)); + EXT_TYPE(p) = type; + EXT_SELECT_DATA(p,0) = select_data; + p->mask = 1; + p->has_type_specifier = True; + } else { + p = (XtEventRec*) __XtMalloc(sizeof(XtEventRec)); + p->mask = eventMask; + p->has_type_specifier = False; + } + p->proc = proc; + p->closure = closure; + p->select = ! raw; + + if (position == XtListHead) { + p->next = widget->core.event_table; + widget->core.event_table = p; + pp = &widget->core.event_table; + } else { + *pp = p; + p->next = NULL; + } + } + else { + if (force_new_position) { + *pp = p->next; + + if (position == XtListHead) { + p->next = widget->core.event_table; + widget->core.event_table = p; + } else { + /* + * Find the last element in the list. + */ + while (*pp) + pp = &(*pp)->next; + *pp = p; + p->next = NULL; + } + } + + if (!has_type_specifier) + p->mask |= eventMask; + else { + int i; + /* p->mask specifies count of EXT_SELECT_DATA(p,i) */ + for (i = 0; i < p->mask && select_data != EXT_SELECT_DATA(p,i); ) + i++; + if (i == p->mask) { + p = (XtEventRec*) XtRealloc((char*)p, + sizeof(XtEventRec) + + sizeof(XtEventRecExt) + + p->mask * sizeof(XtPointer)); + EXT_SELECT_DATA(p,i) = select_data; + p->mask++; + *pp = p; + } + } + } + + if (XtIsRealized(widget) && !raw) { + EventMask mask = XtBuildEventMask(widget); + Display* dpy = XtDisplay (widget); + + if (oldMask != mask) + XSelectInput(dpy, XtWindow(widget), mask); + + if (has_type_specifier) { + XtPerDisplay pd = _XtGetPerDisplay (dpy); + int i; + for (i = 0; i < pd->ext_select_count; i++) { + if (type >= pd->ext_select_list[i].min && + type <= pd->ext_select_list[i].max) { + CallExtensionSelector(widget, pd->ext_select_list+i, FALSE); + break; + } + if (type < pd->ext_select_list[i].min) break; + } + } + } +} + +#if NeedFunctionPrototypes +void XtRemoveEventHandler( + Widget widget, + EventMask eventMask, + _XtBoolean other, + XtEventHandler proc, + XtPointer closure + ) +#else +void XtRemoveEventHandler(widget, eventMask, other, proc, closure) + Widget widget; + EventMask eventMask; + Boolean other; + XtEventHandler proc; + XtPointer closure; +#endif +{ + WIDGET_TO_APPCON(widget); + LOCK_APP(app); + RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, + other, proc, closure, FALSE); + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtAddEventHandler( + Widget widget, + EventMask eventMask, + _XtBoolean other, + XtEventHandler proc, + XtPointer closure + ) +#else +void XtAddEventHandler(widget, eventMask, other, proc, closure) + Widget widget; + EventMask eventMask; + Boolean other; + XtEventHandler proc; + XtPointer closure; +#endif +{ + WIDGET_TO_APPCON(widget); + LOCK_APP(app); + AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, other, + proc, closure, XtListTail, FALSE, FALSE); + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtInsertEventHandler( + Widget widget, + EventMask eventMask, + _XtBoolean other, + XtEventHandler proc, + XtPointer closure, + XtListPosition position + ) +#else +void XtInsertEventHandler(widget, eventMask, other, proc, closure, position) + Widget widget; + EventMask eventMask; + Boolean other; + XtEventHandler proc; + XtPointer closure; + XtListPosition position; +#endif +{ + WIDGET_TO_APPCON(widget); + LOCK_APP(app); + AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, other, + proc, closure, position, TRUE, FALSE); + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtRemoveRawEventHandler( + Widget widget, + EventMask eventMask, + _XtBoolean other, + XtEventHandler proc, + XtPointer closure + ) +#else +void XtRemoveRawEventHandler(widget, eventMask, other, proc, closure) + Widget widget; + EventMask eventMask; + Boolean other; + XtEventHandler proc; + XtPointer closure; +#endif +{ + WIDGET_TO_APPCON(widget); + LOCK_APP(app); + RemoveEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, + other, proc, closure, TRUE); + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtInsertRawEventHandler( + Widget widget, + EventMask eventMask, + _XtBoolean other, + XtEventHandler proc, + XtPointer closure, + XtListPosition position + ) +#else +void XtInsertRawEventHandler(widget, eventMask, other, proc, closure, position) + Widget widget; + EventMask eventMask; + Boolean other; + XtEventHandler proc; + XtPointer closure; + XtListPosition position; +#endif +{ + WIDGET_TO_APPCON(widget); + LOCK_APP(app); + AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, other, + proc, closure, position, TRUE, TRUE); + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtAddRawEventHandler( + Widget widget, + EventMask eventMask, + _XtBoolean other, + XtEventHandler proc, + XtPointer closure + ) +#else +void XtAddRawEventHandler(widget, eventMask, other, proc, closure) + Widget widget; + EventMask eventMask; + Boolean other; + XtEventHandler proc; + XtPointer closure; +#endif +{ + WIDGET_TO_APPCON(widget); + LOCK_APP(app); + AddEventHandler(widget, (XtPointer) &eventMask, 0, FALSE, other, + proc, closure, XtListTail, FALSE, TRUE); + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtRemoveEventTypeHandler( + Widget widget, + int type, + XtPointer select_data, + XtEventHandler proc, + XtPointer closure) +#else +void XtRemoveEventTypeHandler(widget, type, select_data, proc, closure) + Widget widget; + int type; + XtPointer select_data; + XtEventHandler proc; + XtPointer closure; +#endif +{ + WIDGET_TO_APPCON(widget); + LOCK_APP(app); + RemoveEventHandler(widget, select_data, type, TRUE, + FALSE, proc, closure, FALSE); + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtInsertEventTypeHandler( + Widget widget, + int type, + XtPointer select_data, + XtEventHandler proc, + XtPointer closure, + XtListPosition position) +#else +void XtInsertEventTypeHandler(widget, type, select_data, proc, closure, position) + Widget widget; + int type; + XtPointer select_data; + XtEventHandler proc; + XtPointer closure; + XtListPosition position; +#endif +{ + WIDGET_TO_APPCON(widget); + LOCK_APP(app); + AddEventHandler(widget, select_data, type, TRUE, FALSE, + proc, closure, position, TRUE, FALSE); + UNLOCK_APP(app); +} + +typedef struct _WWPair { + struct _WWPair *next; + Window window; + Widget widget; +} *WWPair; + +typedef struct _WWTable { + unsigned int mask; /* size of hash table - 1 */ + unsigned int rehash; /* mask - 2 */ + unsigned int occupied; /* number of occupied entries */ + unsigned int fakes; /* number occupied by WWfake */ + Widget *entries; /* the entries */ + WWPair pairs; /* bogus entries */ +} *WWTable; + +static Const WidgetRec WWfake; /* placeholder for deletions */ + +#define WWHASH(tab,win) ((win) & tab->mask) +#define WWREHASHVAL(tab,win) ((((win) % tab->rehash) + 2) | 1) +#define WWREHASH(tab,idx,rehash) ((idx + rehash) & tab->mask) +#define WWTABLE(display) (_XtGetPerDisplay(display)->WWtable) + +static void ExpandWWTable(); + +void XtRegisterDrawable(display, drawable, widget) + Display* display; + Drawable drawable; + Widget widget; +{ + WWTable tab; + int idx, rehash; + Widget entry; + Window window = (Window) drawable; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + LOCK_PROCESS; + tab = WWTABLE(display); + if (window != XtWindow(widget)) { + WWPair pair; + pair = XtNew(struct _WWPair); + pair->next = tab->pairs; + pair->window = window; + pair->widget = widget; + tab->pairs = pair; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return; + } + if ((tab->occupied + (tab->occupied >> 2)) > tab->mask) + ExpandWWTable(tab); + + idx = WWHASH(tab, window); + if ((entry = tab->entries[idx]) && entry != &WWfake) { + rehash = WWREHASHVAL(tab, window); + do { + idx = WWREHASH(tab, idx, rehash); + } while ((entry = tab->entries[idx]) && entry != &WWfake); + } + if (!entry) + tab->occupied++; + else if (entry == &WWfake) + tab->fakes--; + tab->entries[idx] = widget; + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +void XtUnregisterDrawable(display, drawable) + Display* display; + Drawable drawable; +{ + WWTable tab; + int idx, rehash; + Widget entry; + Window window = (Window) drawable; + Widget widget = XtWindowToWidget (display, window); + DPY_TO_APPCON(display); + + if (widget == NULL) return; + + LOCK_APP(app); + LOCK_PROCESS; + tab = WWTABLE(display); + if (window != XtWindow(widget)) { + WWPair *prev, pair; + + prev = &tab->pairs; + while ((pair = *prev) && pair->window != window) + prev = &pair->next; + if (pair) { + *prev = pair->next; + XtFree((char *)pair); + } + UNLOCK_PROCESS; + UNLOCK_APP(app); + return; + } + idx = WWHASH(tab, window); + if ((entry = tab->entries[idx])) { + if (entry != widget) { + rehash = WWREHASHVAL(tab, window); + do { + idx = WWREHASH(tab, idx, rehash); + if (!(entry = tab->entries[idx])) { + UNLOCK_PROCESS; + UNLOCK_APP(app); + return; + } + } while (entry != widget); + } + tab->entries[idx] = (Widget)&WWfake; + tab->fakes++; + } + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +static void ExpandWWTable(tab) + register WWTable tab; +{ + unsigned int oldmask; + register Widget *oldentries, *entries; + register int oldidx, newidx, rehash; + register Widget entry; + + LOCK_PROCESS; + oldmask = tab->mask; + oldentries = tab->entries; + tab->occupied -= tab->fakes; + tab->fakes = 0; + if ((tab->occupied + (tab->occupied >> 2)) > tab->mask) { + tab->mask = (tab->mask << 1) + 1; + tab->rehash = tab->mask - 2; + } + entries = tab->entries = (Widget *) __XtCalloc(tab->mask+1, sizeof(Widget)); + for (oldidx = 0; oldidx <= oldmask; oldidx++) { + if ((entry = oldentries[oldidx]) && entry != &WWfake) { + newidx = WWHASH(tab, XtWindow(entry)); + if (entries[newidx]) { + rehash = WWREHASHVAL(tab, XtWindow(entry)); + do { + newidx = WWREHASH(tab, newidx, rehash); + } while (entries[newidx]); + } + entries[newidx] = entry; + } + } + XtFree((char *)oldentries); + UNLOCK_PROCESS; +} + +Widget XtWindowToWidget(display, window) + register Display *display; + register Window window; +{ + register WWTable tab; + register int idx, rehash; + register Widget entry; + WWPair pair; + DPY_TO_APPCON(display); + + if (!window) return NULL; + + LOCK_APP(app); + LOCK_PROCESS; + tab = WWTABLE(display); + idx = WWHASH(tab, window); + if ((entry = tab->entries[idx]) && XtWindow(entry) != window) { + rehash = WWREHASHVAL(tab, window); + do { + idx = WWREHASH(tab, idx, rehash); + } while ((entry = tab->entries[idx]) && XtWindow(entry) != window); + } + if (entry) { + UNLOCK_PROCESS; + UNLOCK_APP(app); + return entry; + } + for (pair = tab->pairs; pair; pair = pair->next) { + if (pair->window == window) { + entry = pair->widget; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return entry; + } + } + UNLOCK_PROCESS; + UNLOCK_APP(app); + return NULL; +} + +void _XtAllocWWTable(pd) + XtPerDisplay pd; +{ + register WWTable tab; + + tab = (WWTable) __XtMalloc(sizeof(struct _WWTable)); + tab->mask = 0x7f; + tab->rehash = tab->mask - 2; + tab->entries = (Widget *) __XtCalloc(tab->mask+1, sizeof(Widget)); + tab->occupied = 0; + tab->fakes = 0; + tab->pairs = NULL; + pd->WWtable = tab; +} + +void _XtFreeWWTable(pd) + register XtPerDisplay pd; +{ + register WWPair pair, next; + + for (pair = pd->WWtable->pairs; pair; pair = next) { + next = pair->next; + XtFree((char *)pair); + } + XtFree((char *)pd->WWtable->entries); + XtFree((char *)pd->WWtable); +} + +#define EHMAXSIZE 25 /* do not make whopping big */ + +static Boolean CallEventHandlers(widget, event, mask) + Widget widget; + XEvent *event; + EventMask mask; +{ + register XtEventRec *p; + XtEventHandler *proc; + XtPointer *closure; + XtEventHandler procs[EHMAXSIZE]; + XtPointer closures[EHMAXSIZE]; + Boolean cont_to_disp = True; + int i, numprocs; + + /* Have to copy the procs into an array, because one of them might + * call XtRemoveEventHandler, which would break our linked list. */ + + numprocs = 0; + for (p=widget->core.event_table; p; p = p->next) { + if ((!p->has_type_specifier && (mask & p->mask)) || + (p->has_type_specifier && event->type == EXT_TYPE(p))) + numprocs++; + } + if (numprocs > EHMAXSIZE) { + proc = (XtEventHandler *)__XtMalloc(numprocs * (sizeof(XtEventHandler) + + sizeof(XtPointer))); + closure = (XtPointer *)(proc + numprocs); + } else { + proc = procs; + closure = closures; + } + numprocs = 0; + for (p=widget->core.event_table; p; p = p->next) { + if ((!p->has_type_specifier && (mask & p->mask)) || + (p->has_type_specifier && event->type == EXT_TYPE(p))) { + proc[numprocs] = p->proc; + closure[numprocs] = p->closure; + numprocs++; + } + } +/* FUNCTIONS CALLED THROUGH POINTER proc: + Selection.c:ReqCleanup, + "Shell.c":EventHandler, + PassivGrab.c:ActiveHandler, + PassivGrab.c:RealizeHandler, + Keyboard.c:QueryEventMask, + _XtHandleFocus, + Selection.c:HandleSelectionReplies, + Selection.c:HandleGetIncrement, + Selection.c:HandleIncremental, + Selection.c:HandlePropertyGone, + Selection.c:HandleSelectionEvents + */ + for (i = 0; i < numprocs && cont_to_disp; i++) + (*(proc[i]))(widget, closure[i], event, &cont_to_disp); + if (numprocs > EHMAXSIZE) + XtFree((char *)proc); + return cont_to_disp; +} + +static void CompressExposures(); + +#define KnownButtons (Button1MotionMask|Button2MotionMask|Button3MotionMask|\ + Button4MotionMask|Button5MotionMask) + +/* keep this SMALL to avoid blowing stack cache! */ +/* because some compilers allocate all local locals on procedure entry */ +#define EHSIZE 4 + +#if NeedFunctionPrototypes +Boolean XtDispatchEventToWidget( + Widget widget, + XEvent* event) +#else +Boolean XtDispatchEventToWidget(widget, event) + Widget widget; + XEvent* event; +#endif +{ + register XtEventRec *p; + Boolean was_dispatched = False; + Boolean call_tm = False; + Boolean cont_to_disp; + EventMask mask; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + + mask = _XtConvertTypeToMask(event->type); + if (event->type == MotionNotify) + mask |= (event->xmotion.state & KnownButtons); + + LOCK_PROCESS; + if ( (mask == ExposureMask) || + ((event->type == NoExpose) && NO_EXPOSE) || + ((event->type == GraphicsExpose) && GRAPHICS_EXPOSE) ) { + + if (widget->core.widget_class->core_class.expose != NULL ) { + + /* We need to mask off the bits that could contain the information + * about whether or not we desire Graphics and NoExpose events. */ + + if ( (COMP_EXPOSE_TYPE == XtExposeNoCompress) || + (event->type == NoExpose) ) + + (*widget->core.widget_class->core_class.expose) + (widget, event, (Region)NULL); + else { + CompressExposures(event, widget); + } + was_dispatched = True; + } + } + + if ((mask == VisibilityChangeMask) && + XtClass(widget)->core_class.visible_interest) { + was_dispatched = True; + /* our visibility just changed... */ + switch (((XVisibilityEvent *)event)->state) { + case VisibilityUnobscured: + widget->core.visible = TRUE; + break; + + case VisibilityPartiallyObscured: + /* what do we want to say here? */ + /* well... some of us is visible */ + widget->core.visible = TRUE; + break; + + case VisibilityFullyObscured: + widget->core.visible = FALSE; + /* do we want to mark our children obscured? */ + break; + } + } + UNLOCK_PROCESS; + + /* to maintain "copy" semantics we check TM now but call later */ + if (widget->core.tm.translations && + (mask & widget->core.tm.translations->eventMask)) + call_tm = True; + + cont_to_disp = True; + p=widget->core.event_table; + if (p) { + if (p->next) { + XtEventHandler proc[EHSIZE]; + XtPointer closure[EHSIZE]; + int numprocs = 0; + + /* Have to copy the procs into an array, because one of them might + * call XtRemoveEventHandler, which would break our linked list. */ + + for (; p; p = p->next) { + if ((!p->has_type_specifier && (mask & p->mask)) || + (p->has_type_specifier && event->type == EXT_TYPE(p))) { + if (numprocs >= EHSIZE) + break; + proc[numprocs] = p->proc; + closure[numprocs] = p->closure; + numprocs++; + } + } + if (numprocs) { + if (p) { + cont_to_disp = CallEventHandlers(widget, event, mask); + } else { + int i; + for (i = 0; i < numprocs && cont_to_disp; i++) + (*(proc[i]))(widget, closure[i], event, &cont_to_disp); +/* FUNCTIONS CALLED THROUGH POINTER proc: + Selection.c:ReqCleanup, + "Shell.c":EventHandler, + PassivGrab.c:ActiveHandler, + PassivGrab.c:RealizeHandler, + Keyboard.c:QueryEventMask, + _XtHandleFocus, + Selection.c:HandleSelectionReplies, + Selection.c:HandleGetIncrement, + Selection.c:HandleIncremental, + Selection.c:HandlePropertyGone, + Selection.c:HandleSelectionEvents + */ + } + was_dispatched = True; + } + } else if ((!p->has_type_specifier && (mask & p->mask)) || + (p->has_type_specifier && event->type == EXT_TYPE(p))) { + (*p->proc)(widget, p->closure, event, &cont_to_disp); + was_dispatched = True; + } + } + if (call_tm && cont_to_disp) + _XtTranslateEvent(widget, event); + UNLOCK_APP(app); + return (was_dispatched|call_tm); +} + +/* + * This structure is passed into the check exposure proc. + */ + +typedef struct _CheckExposeInfo { + int type1, type2; /* Types of events to check for. */ + Boolean maximal; /* Ignore non-exposure events? */ + Boolean non_matching; /* Was there an event that did not + match either type? */ + Window window; /* Window to match. */ +} CheckExposeInfo; + +#define GetCount(ev) (((XExposeEvent *)(ev))->count) + +static void SendExposureEvent(); +static Bool CheckExposureEvent(); +static void AddExposureToRectangularRegion(); + +/* Function Name: CompressExposures + * Description: Handles all exposure compression + * Arguments: event - the xevent that is to be dispatched + * widget - the widget that this event occured in. + * Returns: none. + * + * NOTE: Event must be of type Expose or GraphicsExpose. + */ + +static void +CompressExposures(event, widget) +Widget widget; +XEvent * event; +{ + CheckExposeInfo info; + int count; + Display* dpy = XtDisplay (widget); + XtPerDisplay pd = _XtGetPerDisplay(dpy); + XtEnum comp_expose; + XtEnum comp_expose_type; + Boolean no_region; + + LOCK_PROCESS; + comp_expose = COMP_EXPOSE; + UNLOCK_PROCESS; + comp_expose_type = comp_expose & 0x0f; + no_region = ((comp_expose & XtExposeNoRegion) ? True : False); + + if (no_region) + AddExposureToRectangularRegion(event, pd->region); + else + XtAddExposureToRegion(event, pd->region); + + if ( GetCount(event) != 0 ) + return; + + if ((comp_expose_type == XtExposeCompressSeries) || + (XEventsQueued(dpy, QueuedAfterReading) == 0)) { + SendExposureEvent(event, widget, pd); + return; + } + + if (comp_expose & XtExposeGraphicsExposeMerged) { + info.type1 = Expose; + info.type2 = GraphicsExpose; + } + else { + info.type1 = event->type; + info.type2 = 0; + } + info.maximal = (comp_expose_type == XtExposeCompressMaximal); + info.non_matching = FALSE; + info.window = XtWindow(widget); + +/* + * We have to be very careful here not to hose down the processor + * when blocking until count gets to zero. + * + * First, check to see if there are any events in the queue for this + * widget, and of the correct type. + * + * Once we cannot find any more events, check to see that count is zero. + * If it is not then block until we get another exposure event. + * + * If we find no more events, and count on the last one we saw was zero we + * we can be sure that all events have been processed. + * + * Unfortunately, we wind up having to look at the entire queue + * event if we're not doing Maximal compression, due to the + * semantics of XCheckIfEvent (we can't abort without re-ordering + * the event queue as a side-effect). + */ + + count = 0; + while (TRUE) { + XEvent event_return; + + if (XCheckIfEvent(dpy, &event_return, + CheckExposureEvent, (char *) &info)) { + + count = GetCount(&event_return); + if (no_region) + AddExposureToRectangularRegion(&event_return, pd->region); + else + XtAddExposureToRegion(&event_return, pd->region); + } + else if (count != 0) { + XIfEvent(dpy, &event_return, + CheckExposureEvent, (char *) &info); + count = GetCount(&event_return); + if (no_region) + AddExposureToRectangularRegion(&event_return, pd->region); + else + XtAddExposureToRegion(&event_return, pd->region); + } + else /* count == 0 && XCheckIfEvent Failed. */ + break; + } + + SendExposureEvent(event, widget, pd); +} + +void XtAddExposureToRegion(event, region) + XEvent *event; + Region region; +{ + XRectangle rect; + XExposeEvent *ev = (XExposeEvent *) event; + /* These Expose and GraphicsExpose fields are at identical offsets */ + + if (event->type == Expose || event->type == GraphicsExpose) { + rect.x = ev->x; + rect.y = ev->y; + rect.width = ev->width; + rect.height = ev->height; + XUnionRectWithRegion(&rect, region, region); + } +} + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +static void AddExposureToRectangularRegion(event, region) + XEvent *event; /* when called internally, type is always appropriate */ + Region region; +{ + XRectangle rect; + XExposeEvent *ev = (XExposeEvent *) event; + /* These Expose and GraphicsExpose fields are at identical offsets */ + + rect.x = ev->x; + rect.y = ev->y; + rect.width = ev->width; + rect.height = ev->height; + + if (XEmptyRegion(region)) { + XUnionRectWithRegion(&rect, region, region); + } else { + XRectangle merged, bbox; + + XClipBox(region, &bbox); + merged.x = MIN(rect.x, bbox.x); + merged.y = MIN(rect.y, bbox.y); + merged.width = MAX(rect.x + rect.width, + bbox.x + bbox.width) - merged.x; + merged.height = MAX(rect.y + rect.height, + bbox.y + bbox.height) - merged.y; + XUnionRectWithRegion(&merged, region, region); + } +} + +static Region nullRegion; +/* READ-ONLY VARIABLES: nullRegion */ + +void _XtEventInitialize() +{ +#ifndef __lock_lint + nullRegion = XCreateRegion(); +#endif +} + +/* Function Name: SendExposureEvent + * Description: Sets the x, y, width, and height of the event + * to be the clip box of Expose Region. + * Arguments: event - the X Event to mangle; Expose or GraphicsExpose. + * widget - the widget that this event occured in. + * pd - the per display information for this widget. + * Returns: none. + */ + +static void +SendExposureEvent(event, widget, pd) +XEvent * event; +Widget widget; +XtPerDisplay pd; +{ + XtExposeProc expose; + XRectangle rect; + XtEnum comp_expose; + XExposeEvent *ev = (XExposeEvent *) event; + + XClipBox(pd->region, &rect); + ev->x = rect.x; + ev->y = rect.y; + ev->width = rect.width; + ev->height = rect.height; + + LOCK_PROCESS; + comp_expose = COMP_EXPOSE; + expose = widget->core.widget_class->core_class.expose; + UNLOCK_PROCESS; + if (comp_expose & XtExposeNoRegion) + (*expose)(widget, event, NULL); + else + (*expose)(widget, event, pd->region); + (void) XIntersectRegion(nullRegion, pd->region, pd->region); +} + +/* Function Name: CheckExposureEvent + * Description: Checks the event queue for an expose event + * Arguments: display - the display connection. + * event - the event to check. + * arg - a pointer to the exposure info structure. + * Returns: TRUE if we found an event of the correct type + * with the right window. + * + * NOTE: The only valid types (info.type1 and info.type2) are Expose + * and GraphicsExpose. + */ + +/* ARGSUSED */ +static Bool +CheckExposureEvent(disp, event, arg) +Display * disp; +XEvent * event; +char * arg; +{ + CheckExposeInfo * info = ((CheckExposeInfo *) arg); + + if ( (info->type1 == event->type) || (info->type2 == event->type)) { + if (!info->maximal && info->non_matching) return FALSE; + if (event->type == GraphicsExpose) + return(event->xgraphicsexpose.drawable == info->window); + return(event->xexpose.window == info->window); + } + info->non_matching = TRUE; + return(FALSE); +} + +static EventMask Const masks[] = { + 0, /* Error, should never see */ + 0, /* Reply, should never see */ + KeyPressMask, /* KeyPress */ + KeyReleaseMask, /* KeyRelease */ + ButtonPressMask, /* ButtonPress */ + ButtonReleaseMask, /* ButtonRelease */ + PointerMotionMask /* MotionNotify */ + | ButtonMotionMask, + EnterWindowMask, /* EnterNotify */ + LeaveWindowMask, /* LeaveNotify */ + FocusChangeMask, /* FocusIn */ + FocusChangeMask, /* FocusOut */ + KeymapStateMask, /* KeymapNotify */ + ExposureMask, /* Expose */ + NonMaskableMask, /* GraphicsExpose, in GC */ + NonMaskableMask, /* NoExpose, in GC */ + VisibilityChangeMask, /* VisibilityNotify */ + SubstructureNotifyMask, /* CreateNotify */ + StructureNotifyMask /* DestroyNotify */ + | SubstructureNotifyMask, + StructureNotifyMask /* UnmapNotify */ + | SubstructureNotifyMask, + StructureNotifyMask /* MapNotify */ + | SubstructureNotifyMask, + SubstructureRedirectMask, /* MapRequest */ + StructureNotifyMask /* ReparentNotify */ + | SubstructureNotifyMask, + StructureNotifyMask /* ConfigureNotify */ + | SubstructureNotifyMask, + SubstructureRedirectMask, /* ConfigureRequest */ + StructureNotifyMask /* GravityNotify */ + | SubstructureNotifyMask, + ResizeRedirectMask, /* ResizeRequest */ + StructureNotifyMask /* CirculateNotify */ + | SubstructureNotifyMask, + SubstructureRedirectMask, /* CirculateRequest */ + PropertyChangeMask, /* PropertyNotify */ + NonMaskableMask, /* SelectionClear */ + NonMaskableMask, /* SelectionRequest */ + NonMaskableMask, /* SelectionNotify */ + ColormapChangeMask, /* ColormapNotify */ + NonMaskableMask, /* ClientMessage */ + NonMaskableMask /* MappingNotify */ +}; + +EventMask _XtConvertTypeToMask (eventType) + int eventType; +{ + if (eventType < XtNumber(masks)) + return masks[eventType]; + else + return NoEventMask; +} + +Boolean _XtOnGrabList(widget, grabList) + register Widget widget; + XtGrabRec *grabList; +{ + register XtGrabRec* gl; + for (; widget != NULL; widget = (Widget)widget->core.parent) { + for (gl = grabList; gl != NULL; gl = gl->next) { + if (gl->widget == widget) return TRUE; + if (gl->exclusive) break; + } + } + return FALSE; +} + +static Widget LookupSpringLoaded(grabList) + XtGrabList grabList; +{ + XtGrabList gl; + + for (gl = grabList; gl != NULL; gl = gl->next) { + if (gl->spring_loaded) + if (XtIsSensitive(gl->widget)) + return gl->widget; + else + return NULL; + if (gl->exclusive) break; + } + return NULL; +} + +static Boolean DispatchEvent(event, widget) + XEvent* event; + Widget widget; +{ + + if (event->type == EnterNotify && + event->xcrossing.mode == NotifyNormal && + widget->core.widget_class->core_class.compress_enterleave) { + if (XPending(event->xcrossing.display)) { + XEvent nextEvent; + XPeekEvent(event->xcrossing.display, &nextEvent); + if (nextEvent.type == LeaveNotify && + event->xcrossing.window == nextEvent.xcrossing.window && + nextEvent.xcrossing.mode == NotifyNormal && + (event->xcrossing.detail != NotifyInferior && + nextEvent.xcrossing.detail != NotifyInferior || + event->xcrossing.detail == NotifyInferior && + nextEvent.xcrossing.detail == NotifyInferior)) { + /* skip the enter/leave pair */ + XNextEvent(event->xcrossing.display, &nextEvent); + return False; + } + } + } + + if (event->type == MotionNotify && + widget->core.widget_class->core_class.compress_motion) { + while (XPending(event->xmotion.display)) { + XEvent nextEvent; + XPeekEvent(event->xmotion.display, &nextEvent); + if (nextEvent.type == MotionNotify && + event->xmotion.window == nextEvent.xmotion.window && + event->xmotion.subwindow == nextEvent.xmotion.subwindow) { + /* replace the current event with the next one */ + XNextEvent(event->xmotion.display, event); + } else break; + } + } + + return XtDispatchEventToWidget(widget, event); +} + +typedef enum _GrabType {pass, ignore, remap} GrabType; + +#if !defined(AIXV3) || !defined(AIXSHLIB) +static /* AIX shared libraries are broken */ +#endif +Boolean _XtDefaultDispatcher(event) + XEvent *event; +{ + register Widget widget; + GrabType grabType; + XtPerDisplayInput pdi; + XtGrabList grabList; + Boolean was_dispatched = False; + DPY_TO_APPCON(event->xany.display); + + /* the default dispatcher discards all extension events */ + if (event->type >= LASTEvent) + return False; + + LOCK_APP(app); + + switch (event->type) { + case KeyPress: + case KeyRelease: + case ButtonPress: + case ButtonRelease: grabType = remap; break; + case MotionNotify: + case EnterNotify: grabType = ignore; break; + default: grabType = pass; break; + } + + widget = XtWindowToWidget (event->xany.display, event->xany.window); + pdi = _XtGetPerDisplayInput(event->xany.display); + grabList = *_XtGetGrabList(pdi); + + if (widget == NULL) { + if (grabType == remap + && (widget = LookupSpringLoaded(grabList)) != NULL) { + /* event occurred in a non-widget window, but we've promised also + to dispatch it to the nearest accessible spring_loaded widget */ + was_dispatched = (XFilterEvent(event, XtWindow(widget)) + || XtDispatchEventToWidget(widget, event)); + } + else was_dispatched = XFilterEvent(event, None); + } + else if (grabType == pass) { + if (event->type == LeaveNotify || + event->type == FocusIn || + event->type == FocusOut) { + if (XtIsSensitive (widget)) + was_dispatched = (XFilterEvent(event, XtWindow(widget)) || + XtDispatchEventToWidget(widget, event)); + } else was_dispatched = (XFilterEvent(event, XtWindow(widget)) || + XtDispatchEventToWidget(widget, event)); + } + else if (grabType == ignore) { + if ((grabList == NULL || _XtOnGrabList(widget, grabList)) + && XtIsSensitive(widget)) { + was_dispatched = (XFilterEvent(event, XtWindow(widget)) + || DispatchEvent(event, widget)); + } + } + else if (grabType == remap) { + EventMask mask = _XtConvertTypeToMask(event->type); + Widget dspWidget; + Boolean was_filtered = False; + extern Widget _XtFindRemapWidget(); + extern void _XtUngrabBadGrabs(); + + dspWidget = _XtFindRemapWidget(event, widget, mask, pdi); + + if ((grabList == NULL ||_XtOnGrabList(dspWidget, grabList)) + && XtIsSensitive(dspWidget)) { + if ((was_filtered = XFilterEvent(event, XtWindow(dspWidget)))) { + /* If this event activated a device grab, release it. */ + _XtUngrabBadGrabs(event, widget, mask, pdi); + was_dispatched = True; + } else + was_dispatched = XtDispatchEventToWidget(dspWidget, event); + } + else _XtUngrabBadGrabs(event, widget, mask, pdi); + + if (!was_filtered) { + /* Also dispatch to nearest accessible spring_loaded. */ + /* Fetch this afterward to reflect modal list changes */ + grabList = *_XtGetGrabList(pdi); + widget = LookupSpringLoaded(grabList); + if (widget != NULL && widget != dspWidget) { + was_dispatched = (XFilterEvent(event, XtWindow(widget)) + || XtDispatchEventToWidget(widget, event) + || was_dispatched); + } + } + } + UNLOCK_APP(app); + return was_dispatched; +} + +Boolean XtDispatchEvent (event) + XEvent *event; +{ + Boolean was_dispatched, safe; + int dispatch_level; + int starting_count; + XtPerDisplay pd; + Time time = 0; + XtEventDispatchProc dispatch = _XtDefaultDispatcher; + XtAppContext app = XtDisplayToApplicationContext(event->xany.display); + + LOCK_APP(app); + dispatch_level = ++app->dispatch_level; + starting_count = app->destroy_count; + + switch (event->type) { + case KeyPress: + case KeyRelease: time = event->xkey.time; break; + case ButtonPress: + case ButtonRelease: time = event->xbutton.time; break; + case MotionNotify: time = event->xmotion.time; break; + case EnterNotify: + case LeaveNotify: time = event->xcrossing.time; break; + case PropertyNotify: time = event->xproperty.time; break; + case SelectionClear: time = event->xselectionclear.time; break; + + case MappingNotify: _XtRefreshMapping(event, True); break; + } + pd = _XtGetPerDisplay(event->xany.display); + if (time) pd->last_timestamp = time; + pd->last_event = *event; + + if (pd->dispatcher_list) { + dispatch = pd->dispatcher_list[event->type]; + if (dispatch == NULL) dispatch = _XtDefaultDispatcher; + } + was_dispatched = (*dispatch)(event); + + /* + * To make recursive XtDispatchEvent work, we need to do phase 2 destroys + * only on those widgets destroyed by this particular dispatch. + * + */ + + if (app->destroy_count > starting_count) + _XtDoPhase2Destroy(app, dispatch_level); + + app->dispatch_level = dispatch_level - 1; + + if ((safe = _XtSafeToDestroy(app))) { + if (app->dpy_destroy_count != 0) _XtCloseDisplays(app); + if (app->free_bindings) _XtDoFreeBindings(app); + } + UNLOCK_APP(app); + LOCK_PROCESS; + if (_XtAppDestroyCount != 0 && safe) _XtDestroyAppContexts(); + UNLOCK_PROCESS; + return was_dispatched; +} + +/* ARGSUSED */ +static void GrabDestroyCallback(widget, closure, call_data) + Widget widget; + XtPointer closure; + XtPointer call_data; +{ + /* Remove widget from grab list if it destroyed */ + XtRemoveGrab(widget); +} + +static XtGrabRec *NewGrabRec(widget, exclusive, spring_loaded) + Widget widget; + Boolean exclusive; + Boolean spring_loaded; +{ + register XtGrabList gl; + + gl = XtNew(XtGrabRec); + gl->next = NULL; + gl->widget = widget; + gl->exclusive = exclusive; + gl->spring_loaded = spring_loaded; + + return gl; +} + +#if NeedFunctionPrototypes +void XtAddGrab( + Widget widget, + _XtBoolean exclusive, + _XtBoolean spring_loaded + ) +#else +void XtAddGrab(widget, exclusive, spring_loaded) + Widget widget; + Boolean exclusive; + Boolean spring_loaded; +#endif +{ + register XtGrabList gl; + XtGrabList *grabListPtr; + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + LOCK_PROCESS; + grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget))); + + if (spring_loaded && !exclusive) { + XtAppWarningMsg(app, + "grabError", "xtAddGrab", XtCXtToolkitError, + "XtAddGrab requires exclusive grab if spring_loaded is TRUE", + (String *) NULL, (Cardinal *) NULL); + exclusive = TRUE; + } + + gl = NewGrabRec(widget, exclusive, spring_loaded); + gl->next = *grabListPtr; + *grabListPtr = gl; + + XtAddCallback (widget, XtNdestroyCallback, + GrabDestroyCallback, (XtPointer) NULL); + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +void XtRemoveGrab(widget) + Widget widget; +{ + register XtGrabList gl; + register Boolean done; + XtGrabList *grabListPtr; + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + LOCK_PROCESS; + + grabListPtr = _XtGetGrabList(_XtGetPerDisplayInput(XtDisplay(widget))); + + for (gl = *grabListPtr; gl != NULL; gl = gl->next) { + if (gl->widget == widget) break; + } + + if (gl == NULL) { + XtAppWarningMsg(app, + "grabError","xtRemoveGrab",XtCXtToolkitError, + "XtRemoveGrab asked to remove a widget not on the list", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_PROCESS; + UNLOCK_APP(app); + return; + } + + do { + gl = *grabListPtr; + done = (gl->widget == widget); + *grabListPtr = gl->next; + XtRemoveCallback(gl->widget, XtNdestroyCallback, + GrabDestroyCallback, (XtPointer)NULL); + XtFree((char *)gl); + } while (! done); + UNLOCK_PROCESS; + UNLOCK_APP(app); + return; +} + +void XtMainLoop() +{ + XtAppMainLoop(_XtDefaultAppContext()); +} + +void XtAppMainLoop(app) + XtAppContext app; +{ + XEvent event; + + LOCK_APP(app); + do { + XtAppNextEvent(app, &event); +#ifdef XTHREADS + /* assert(app == XtDisplayToApplicationContext(event.xany.display)); */ +#endif + XtDispatchEvent(&event); + } while(app->exit_flag == FALSE); + UNLOCK_APP(app); +} + +void _XtFreeEventTable(event_table) + XtEventTable *event_table; +{ + register XtEventTable event; + + event = *event_table; + while (event != NULL) { + register XtEventTable next = event->next; + XtFree((char *) event); + event = next; + } +} + +Time XtLastTimestampProcessed(dpy) + Display *dpy; +{ + Time time; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + LOCK_PROCESS; + time = _XtGetPerDisplay(dpy)->last_timestamp; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return(time); +} + +XEvent* XtLastEventProcessed(dpy) + Display* dpy; +{ + XEvent* le = NULL; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + le = &_XtGetPerDisplay(dpy)->last_event; + if (!le->xany.serial) + le = NULL; + UNLOCK_APP(app); + return le; +} + +void _XtSendFocusEvent(child, type) + Widget child; + int type; +{ + child = XtIsWidget(child) ? child : _XtWindowedAncestor(child); + if (XtIsSensitive(child) && !child->core.being_destroyed + && XtIsRealized(child) + && (XtBuildEventMask(child) & FocusChangeMask)) + { + XFocusChangeEvent event; + Display* dpy = XtDisplay (child); + + event.type = type; + event.serial = LastKnownRequestProcessed(dpy); + event.send_event = True; + event.display = dpy; + event.window = XtWindow(child); + event.mode = NotifyNormal; + event.detail = NotifyAncestor; + if (XFilterEvent((XEvent*)&event, XtWindow(child))) + return; + XtDispatchEventToWidget(child, (XEvent*)&event); + } +} + +static XtEventDispatchProc* NewDispatcherList() +{ + XtEventDispatchProc* l = + (XtEventDispatchProc*) __XtCalloc((Cardinal) 128, + (Cardinal)sizeof(XtEventDispatchProc)); + return l; +} + +#if NeedFunctionPrototypes +XtEventDispatchProc XtSetEventDispatcher( + Display *dpy, + int event_type, + XtEventDispatchProc proc + ) +#else +XtEventDispatchProc XtSetEventDispatcher(dpy, event_type, proc) + Display *dpy; + int event_type; + XtEventDispatchProc proc; +#endif +{ + XtEventDispatchProc *list; + XtEventDispatchProc old_proc; + register XtPerDisplay pd; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + LOCK_PROCESS; + pd = _XtGetPerDisplay(dpy); + + list = pd->dispatcher_list; + if (!list) { + if (proc) list = pd->dispatcher_list = NewDispatcherList(); + else return _XtDefaultDispatcher; + } + old_proc = list[event_type]; + list[event_type] = proc; + if (old_proc == NULL) old_proc = _XtDefaultDispatcher; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return old_proc; +} + +#if NeedFunctionPrototypes +void XtRegisterExtensionSelector( + Display *dpy, + int min_event_type, + int max_event_type, + XtExtensionSelectProc proc, + XtPointer client_data + ) +#else +void XtRegisterExtensionSelector(dpy, min_event_type, max_event_type, + proc, client_data) + Display *dpy; + int min_event_type; + int max_event_type; + XtExtensionSelectProc proc; + XtPointer client_data; +#endif +{ + ExtSelectRec *e; + XtPerDisplay pd; + int i; + DPY_TO_APPCON(dpy); + + if (dpy == NULL) XtErrorMsg("nullDisplay", + "xtRegisterExtensionSelector", XtCXtToolkitError, + "XtRegisterExtensionSelector requires a non-NULL display", + (String *) NULL, (Cardinal *) NULL); + + LOCK_APP(app); + LOCK_PROCESS; + pd = _XtGetPerDisplay(dpy); + + for (i = 0; i < pd->ext_select_count; i++) { + e = &pd->ext_select_list[i]; + if (e->min == min_event_type && e->max == max_event_type) { + e->proc = proc; + e->client_data = client_data; + return; + } + if ((min_event_type >= e->min && min_event_type <= e->max) || + (max_event_type >= e->min && max_event_type <= e->max)) { + XtErrorMsg("rangeError", "xtRegisterExtensionSelector", + XtCXtToolkitError, + "Attempt to register multiple selectors for one extension event type", + (String *) NULL, (Cardinal *) NULL); + UNLOCK_PROCESS; + UNLOCK_APP(app); + return; + } + } + pd->ext_select_count++; + pd->ext_select_list = + (ExtSelectRec *) XtRealloc((char *) pd->ext_select_list, + pd->ext_select_count * sizeof(ExtSelectRec)); + for (i = pd->ext_select_count - 1; i > 0; i--) { + if (pd->ext_select_list[i-1].min > min_event_type) { + pd->ext_select_list[i] = pd->ext_select_list[i-1]; + } else break; + } + pd->ext_select_list[i].min = min_event_type; + pd->ext_select_list[i].max = max_event_type; + pd->ext_select_list[i].proc = proc; + pd->ext_select_list[i].client_data = client_data; + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +void _XtExtensionSelect(widget) + Widget widget; +{ + int i; + XtPerDisplay pd; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + LOCK_PROCESS; + + pd = _XtGetPerDisplay(XtDisplay(widget)); + + for (i = 0; i < pd->ext_select_count; i++) { + CallExtensionSelector(widget, pd->ext_select_list+i, FALSE); + } + UNLOCK_PROCESS; + UNLOCK_APP(app); +} diff --git a/src/EventUtil.c b/src/EventUtil.c new file mode 100644 index 0000000..54bdfc0 --- /dev/null +++ b/src/EventUtil.c @@ -0,0 +1,221 @@ +/* $Xorg: EventUtil.c,v 1.4 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/******************************************************** + +Copyright 1988 by Hewlett-Packard Company +Copyright 1987, 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the names of +Hewlett-Packard, Digital, or Sun not be used in advertising or +publicity pertaining to distribution of the software without specific, +written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +********************************************************/ + +/* + +Copyright 1987, 1988, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "PassivGraI.h" +#include "StringDefs.h" + +static XContext perWidgetInputContext = 0; + +void _XtFreePerWidgetInput(w, pwi) + Widget w; + XtPerWidgetInput pwi; +{ + LOCK_PROCESS; + XDeleteContext(XtDisplay(w), + (Window)w, + perWidgetInputContext); + + XtFree((char *)pwi); + UNLOCK_PROCESS; +} + +/* + * This routine gets the passive list associated with the widget + * from the context manager. + */ +#if NeedFunctionPrototypes +XtPerWidgetInput _XtGetPerWidgetInput( + Widget widget, + _XtBoolean create + ) +#else +XtPerWidgetInput _XtGetPerWidgetInput(widget, create) + Widget widget; + Boolean create; +#endif +{ + XtPerWidgetInput pwi = NULL; + Display *dpy = widget->core.screen->display; + + LOCK_PROCESS; + if (! perWidgetInputContext) + perWidgetInputContext = XUniqueContext(); + + if (XFindContext(dpy, + (Window)widget, + perWidgetInputContext, + (XPointer *)&pwi) && + create) + { + pwi = (XtPerWidgetInput) + __XtMalloc((unsigned) sizeof(XtPerWidgetInputRec)); + + pwi->focusKid = NULL; + pwi->queryEventDescendant = NULL; + pwi->focalPoint = XtUnrelated; + pwi->keyList = + pwi->ptrList = NULL; + + pwi->haveFocus = + pwi->map_handler_added = + pwi->realize_handler_added = + pwi->active_handler_added = FALSE; + + XtAddCallback(widget, XtNdestroyCallback, + _XtDestroyServerGrabs, (XtPointer)pwi); + + (void) XSaveContext(dpy, + (Window)widget, + perWidgetInputContext, + (char *) pwi); + } + UNLOCK_PROCESS; + return pwi; +} + + +void _XtFillAncestorList(listPtr, maxElemsPtr, numElemsPtr, start, breakWidget) + Widget **listPtr; + int *maxElemsPtr, *numElemsPtr; + Widget start, breakWidget; +{ +#define CACHESIZE 16 + Cardinal i; + Widget w; + Widget *trace = *listPtr; + + /* First time in, allocate the ancestor list */ + if (trace == NULL) + { + trace = (Widget *) __XtMalloc(CACHESIZE * sizeof(Widget)); + *maxElemsPtr = CACHESIZE; + } + /* First fill in the ancestor list */ + + trace[0] = start; + + for (i = 1, w = XtParent(start); + w != NULL && !XtIsShell(trace[i-1]) && trace[i-1] != breakWidget; + w = XtParent(w), i++) { + if (i == *maxElemsPtr) { + /* This should rarely happen, but if it does it'll probably + happen again, so grow the ancestor list */ + *maxElemsPtr += CACHESIZE; + trace = (Widget *) XtRealloc((char*)trace, + sizeof(Widget) * (*maxElemsPtr)); + } + trace[i] = w; + } + *listPtr = trace; + *numElemsPtr = i; +#undef CACHESIZE +} + + +Widget _XtFindRemapWidget(event, widget, mask, pdi) + XEvent *event; + Widget widget; + EventMask mask; + XtPerDisplayInput pdi; +{ + Widget dspWidget = widget; + + if (!pdi->traceDepth || !(widget == pdi->trace[0])) + { + _XtFillAncestorList(&pdi->trace, &pdi->traceMax, + &pdi->traceDepth, widget, NULL); + pdi->focusWidget = NULL; /* invalidate the focus + cache */ + } + if (mask & (KeyPressMask | KeyReleaseMask)) + dspWidget = _XtProcessKeyboardEvent((XKeyEvent*)event, widget, pdi); + else if (mask &(ButtonPressMask | ButtonReleaseMask)) + dspWidget = _XtProcessPointerEvent((XButtonEvent*)event, widget,pdi); + + return dspWidget; +} + +void _XtUngrabBadGrabs(event, widget, mask, pdi) + XEvent *event; + Widget widget; + EventMask mask; + XtPerDisplayInput pdi; +{ + XKeyEvent * ke = (XKeyEvent *) event; + + if (mask & (KeyPressMask | KeyReleaseMask)) + { + if (IsServerGrab(pdi->keyboard.grabType) && + !_XtOnGrabList(pdi->keyboard.grab.widget, + pdi->grabList)) + XtUngrabKeyboard(widget, ke->time); + + } + else + { + if (IsServerGrab(pdi->pointer.grabType) && + !_XtOnGrabList(pdi->pointer.grab.widget, + pdi->grabList)) + XtUngrabPointer(widget, ke->time); + } +} diff --git a/src/Functions.c b/src/Functions.c new file mode 100644 index 0000000..3fc4d18 --- /dev/null +++ b/src/Functions.c @@ -0,0 +1,228 @@ +/* $Xorg: Functions.c,v 1.4 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/* + +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +/* + +Copyright 1985, 1986, 1987, 1988, 1989, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include <X11/Shell.h> +#include <X11/Vendor.h> + +/* + * This file defines functional equivalents to all macros defined + * in Intrinsic.h + * + */ + +#undef XtIsRectObj +Boolean XtIsRectObj(object) + Widget object; +{ + return _XtCheckSubclassFlag(object, 0x02); +} + + +#undef XtIsWidget +Boolean XtIsWidget(object) + Widget object; +{ + return _XtCheckSubclassFlag(object, 0x04); +} + + +#undef XtIsComposite +Boolean XtIsComposite(object) + Widget object; +{ + return _XtCheckSubclassFlag(object, 0x08); +} + + +#undef XtIsConstraint +Boolean XtIsConstraint(object) + Widget object; +{ + return _XtCheckSubclassFlag(object, 0x10); +} + + +#undef XtIsShell +Boolean XtIsShell(object) + Widget object; +{ + return _XtCheckSubclassFlag(object, 0x20); +} + + +#undef XtIsOverrideShell +Boolean XtIsOverrideShell(object) + Widget object; +{ + return _XtIsSubclassOf(object, (WidgetClass)overrideShellWidgetClass, + (WidgetClass)shellWidgetClass, 0x20); +} + + +#undef XtIsWMShell +Boolean XtIsWMShell(object) + Widget object; +{ + return _XtCheckSubclassFlag(object, 0x40); +} + + +#undef XtIsVendorShell +Boolean XtIsVendorShell(object) + Widget object; +{ + Boolean retval; + + LOCK_PROCESS; + retval = _XtIsSubclassOf(object, +#ifdef notdef +/* + * We don't refer to vendorShell directly, because some shared libraries + * bind local references tightly. + */ + (WidgetClass)vendorShellWidgetClass, +#endif + transientShellWidgetClass->core_class.superclass, + (WidgetClass)wmShellWidgetClass, 0x40); + UNLOCK_PROCESS; + return retval; +} + + +#undef XtIsTransientShell +Boolean XtIsTransientShell(object) + Widget object; +{ + return _XtIsSubclassOf(object, (WidgetClass)transientShellWidgetClass, + (WidgetClass)wmShellWidgetClass, 0x40); +} + + +#undef XtIsTopLevelShell +Boolean XtIsTopLevelShell(object) + Widget object; +{ + return _XtCheckSubclassFlag(object, 0x80); +} + + +#undef XtIsApplicationShell +Boolean XtIsApplicationShell(object) + Widget object; +{ + return _XtIsSubclassOf(object, (WidgetClass)applicationShellWidgetClass, + (WidgetClass)topLevelShellWidgetClass, 0x80); +} + +#undef XtIsSessionShell +Boolean XtIsSessionShell(object) + Widget object; +{ + return _XtIsSubclassOf(object, (WidgetClass)sessionShellWidgetClass, + (WidgetClass)topLevelShellWidgetClass, 0x80); +} + +#undef XtMapWidget +void XtMapWidget(w) + Widget w; +{ + Widget hookobj; + WIDGET_TO_APPCON(w); + + LOCK_APP(app); + XMapWindow(XtDisplay(w), XtWindow(w)); + hookobj = XtHooksOfDisplay(XtDisplay(w)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHmapWidget; + call_data.widget = w; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} + + +#undef XtUnmapWidget +void XtUnmapWidget(w) + Widget w; +{ + Widget hookobj; + WIDGET_TO_APPCON(w); + + LOCK_APP(app); + XUnmapWindow(XtDisplay(w), XtWindow(w)); + hookobj = XtHooksOfDisplay(XtDisplay(w)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHunmapWidget; + call_data.widget = w; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} + + +#undef XtNewString +String XtNewString(str) + String str; +{ + if (str == NULL) + return NULL; + else + return strcpy(__XtMalloc((unsigned)strlen(str) + 1), str); +} diff --git a/src/GCManager.c b/src/GCManager.c new file mode 100644 index 0000000..e80c758 --- /dev/null +++ b/src/GCManager.c @@ -0,0 +1,350 @@ +/* $Xorg: GCManager.c,v 1.5 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988, 1990 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1990, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" + + +typedef struct _GCrec { + unsigned char screen; /* Screen for GC */ + unsigned char depth; /* Depth for GC */ + char dashes; /* Dashes value */ + Pixmap clip_mask; /* Clip_mask value */ + Cardinal ref_count; /* # of shareholders */ + GC gc; /* The GC itself. */ + XtGCMask dynamic_mask; /* Writable values */ + XtGCMask unused_mask; /* Unused values */ + struct _GCrec *next; /* Next GC for this widgetkind. */ +} GCrec, *GCptr; + +#define GCVAL(bit,mask,val,default) ((bit&mask) ? val : default) + +#define CHECK(bit,comp,default) \ + if ((checkMask & bit) && \ + (GCVAL(bit,valueMask,v->comp,default) != gcv.comp)) return False + +#define ALLGCVALS (GCFunction | GCPlaneMask | GCForeground | \ + GCBackground | GCLineWidth | GCLineStyle | \ + GCCapStyle | GCJoinStyle | GCFillStyle | \ + GCFillRule | GCTile | GCStipple | \ + GCTileStipXOrigin | GCTileStipYOrigin | \ + GCFont | GCSubwindowMode | GCGraphicsExposures | \ + GCClipXOrigin | GCClipYOrigin | GCDashOffset | \ + GCArcMode) + +static Bool Matches(dpy, ptr, valueMask, v, readOnlyMask, dynamicMask) + Display *dpy; + GCptr ptr; + register XtGCMask valueMask; + register XGCValues *v; + XtGCMask readOnlyMask; + XtGCMask dynamicMask; +{ + XGCValues gcv; + register XtGCMask checkMask; + + if (readOnlyMask & ptr->dynamic_mask) + return False; + if (((ptr->dynamic_mask|ptr->unused_mask) & dynamicMask) != dynamicMask) + return False; + if (!XGetGCValues(dpy, ptr->gc, ALLGCVALS, &gcv)) + return False; + checkMask = readOnlyMask & ~ptr->unused_mask; + CHECK(GCForeground, foreground, 0); + CHECK(GCBackground, background, 1); + CHECK(GCFont, font, ~0L); + CHECK(GCFillStyle, fill_style, FillSolid); + CHECK(GCLineWidth, line_width, 0); + CHECK(GCFunction, function, GXcopy); + CHECK(GCGraphicsExposures, graphics_exposures, True); + CHECK(GCTile, tile, ~0L); + CHECK(GCSubwindowMode, subwindow_mode, ClipByChildren); + CHECK(GCPlaneMask, plane_mask, AllPlanes); + CHECK(GCLineStyle, line_style, LineSolid); + CHECK(GCCapStyle, cap_style, CapButt); + CHECK(GCJoinStyle, join_style, JoinMiter); + CHECK(GCFillRule, fill_rule, EvenOddRule); + CHECK(GCArcMode, arc_mode, ArcPieSlice); + CHECK(GCStipple, stipple, ~0L); + CHECK(GCTileStipXOrigin, ts_x_origin, 0); + CHECK(GCTileStipYOrigin, ts_y_origin, 0); + CHECK(GCClipXOrigin, clip_x_origin, 0); + CHECK(GCClipYOrigin, clip_y_origin, 0); + CHECK(GCDashOffset, dash_offset, 0); + gcv.clip_mask = ptr->clip_mask; + CHECK(GCClipMask, clip_mask, None); + gcv.dashes = ptr->dashes; + CHECK(GCDashList, dashes, 4); + valueMask &= ptr->unused_mask | dynamicMask; + if (valueMask) { + XChangeGC(dpy, ptr->gc, valueMask, v); + if (valueMask & GCDashList) + ptr->dashes = v->dashes; + if (valueMask & GCClipMask) + ptr->clip_mask = v->clip_mask; + } + ptr->unused_mask &= ~(dynamicMask | readOnlyMask); + ptr->dynamic_mask |= dynamicMask; + return True; +} /* Matches */ + +/* Called by CloseDisplay to free the per-display GC list */ +void _XtGClistFree(dpy, pd) + Display *dpy; + register XtPerDisplay pd; +{ + register GCptr GClist, next; + register int i; + + GClist = pd->GClist; + while (GClist) { + next = GClist->next; + XtFree((char*)GClist); + GClist = next; + } + if (pd->pixmap_tab) { + for (i = ScreenCount(dpy); --i >= 0; ) { + if (pd->pixmap_tab[i]) + XtFree((char *)pd->pixmap_tab[i]); + } + XtFree((char *)pd->pixmap_tab); + } +} + + +/* + * Return a GC with the given values and characteristics. + */ + +GC XtAllocateGC(widget, depth, valueMask, values, dynamicMask, unusedMask) + register Widget widget; + Cardinal depth; + XtGCMask valueMask; + XGCValues *values; + XtGCMask dynamicMask; + XtGCMask unusedMask; +{ + register GCptr *prev; + register GCptr cur; + Screen *screen; + register Display *dpy; + register XtPerDisplay pd; + Drawable drawable; + Drawable *pixmaps; + XtGCMask readOnlyMask; + GC retval; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + LOCK_PROCESS; + if (!XtIsWidget(widget)) + widget = _XtWindowedAncestor(widget); + if (!depth) + depth = widget->core.depth; + screen = XtScreen(widget); + dpy = DisplayOfScreen(screen); + pd = _XtGetPerDisplay(dpy); + unusedMask &= ~valueMask; + readOnlyMask = ~(dynamicMask | unusedMask); + + /* Search for existing GC that matches exactly */ + for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) { + if (cur->depth == depth && + ScreenOfDisplay(dpy, cur->screen) == screen && + Matches(dpy, cur, valueMask, values, readOnlyMask, dynamicMask)) { + cur->ref_count++; + /* Move this GC to front of list */ + *prev = cur->next; + cur->next = pd->GClist; + pd->GClist = cur; + retval = cur->gc; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return retval; + } + } + + /* No matches, have to create a new one */ + cur = XtNew(GCrec); + cur->screen = XScreenNumberOfScreen(screen); + cur->depth = depth; + cur->ref_count = 1; + cur->dynamic_mask = dynamicMask; + cur->unused_mask = (unusedMask & ~dynamicMask); + cur->dashes = GCVAL(GCDashList, valueMask, values->dashes, 4); + cur->clip_mask = GCVAL(GCClipMask, valueMask, values->clip_mask, None); + drawable = 0; + if (depth == widget->core.depth) + drawable = XtWindow(widget); + if (!drawable && depth == DefaultDepthOfScreen(screen)) + drawable = RootWindowOfScreen(screen); + if (!drawable) { + if (!pd->pixmap_tab) { + int n; + pd->pixmap_tab = (Drawable **)__XtMalloc((unsigned)ScreenCount(dpy) * + sizeof(Drawable *)); + for (n = 0; n < ScreenCount(dpy); n++) + pd->pixmap_tab[n] = NULL; + } + pixmaps = pd->pixmap_tab[cur->screen]; + if (!pixmaps) { + int max, n, *depths; + depths = XListDepths(dpy, cur->screen, &n); + n--; + max = depths[n]; + while (n--) { + if (depths[n] > max) + max = depths[n]; + } + XFree((char *)depths); + pixmaps = (Drawable *)__XtCalloc((unsigned)max, sizeof(Drawable)); + pd->pixmap_tab[cur->screen] = pixmaps; + } + drawable = pixmaps[cur->depth - 1]; + if (!drawable) { + drawable = XCreatePixmap(dpy, RootWindowOfScreen(screen), 1, 1, + cur->depth); + pixmaps[cur->depth - 1] = drawable; + } + } + cur->gc = XCreateGC(dpy, drawable, valueMask, values); + cur->next = pd->GClist; + pd->GClist = cur; + retval = cur->gc; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return retval; +} /* XtAllocateGC */ + +/* + * Return a read-only GC with the given values. + */ + +GC XtGetGC(widget, valueMask, values) + register Widget widget; + XtGCMask valueMask; + XGCValues *values; +{ + return XtAllocateGC(widget, 0, valueMask, values, 0, 0); +} /* XtGetGC */ + +void XtReleaseGC(widget, gc) + Widget widget; + register GC gc; +{ + register GCptr cur, *prev; + Display* dpy; + XtPerDisplay pd; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + LOCK_PROCESS; + dpy = XtDisplayOfObject(widget); + pd = _XtGetPerDisplay(dpy); + + for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) { + if (cur->gc == gc) { + if (--(cur->ref_count) == 0) { + *prev = cur->next; + XFreeGC(dpy, gc); + XtFree((char *) cur); + } + break; + } + } + UNLOCK_PROCESS; + UNLOCK_APP(app); +} /* XtReleaseGC */ + +/* The following interface is broken and supplied only for backwards + * compatibility. It will work properly in all cases only if there + * is exactly 1 Display created by the application. + */ + +void XtDestroyGC(gc) + register GC gc; +{ + GCptr cur, *prev; + XtAppContext app; + + LOCK_PROCESS; + app = _XtGetProcessContext()->appContextList; + /* This is awful; we have to search through all the lists + to find the GC. */ + for (; app; app = app->next) { + int i; + for (i = app->count; i ;) { + Display *dpy = app->list[--i]; + XtPerDisplay pd = _XtGetPerDisplay(dpy); + for (prev = &pd->GClist; (cur = *prev); prev = &cur->next) { + if (cur->gc == gc) { + if (--(cur->ref_count) == 0) { + *prev = cur->next; + XFreeGC(dpy, gc); + XtFree((char *) cur); + } + UNLOCK_PROCESS; + return; + } + } + } + } + UNLOCK_PROCESS; +} /* XtDestroyGC */ diff --git a/src/Geometry.c b/src/Geometry.c new file mode 100644 index 0000000..1d901eb --- /dev/null +++ b/src/Geometry.c @@ -0,0 +1,826 @@ +/* $Xorg: Geometry.c,v 1.5 2001/02/09 02:03:54 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "ShellP.h" + +static void ClearRectObjAreas(r, old) + RectObj r; + XWindowChanges* old; +{ + Widget pw = _XtWindowedAncestor((Widget)r); + int bw2; + + bw2 = old->border_width << 1; + XClearArea( XtDisplay(pw), XtWindow(pw), + old->x, old->y, + old->width + bw2, old->height + bw2, + TRUE ); + + bw2 = r->rectangle.border_width << 1; + XClearArea( XtDisplay(pw), XtWindow(pw), + (int)r->rectangle.x, (int)r->rectangle.y, + (unsigned int)(r->rectangle.width + bw2), + (unsigned int)(r->rectangle.height + bw2), + TRUE ); +} + +/* + * Internal function used by XtMakeGeometryRequest and XtSetValues. + * Returns more data than the public interface. Does not convert + * XtGeometryDone to XtGeometryYes. + * + * clear_rect_obj - *** RETURNED *** + * TRUE if the rect obj has been cleared, false otherwise. + */ + +XtGeometryResult +_XtMakeGeometryRequest (widget, request, reply, clear_rect_obj) + Widget widget; + XtWidgetGeometry *request, *reply; + Boolean * clear_rect_obj; +{ + XtWidgetGeometry junk; + XtGeometryHandler manager; + XtGeometryResult returnCode; + Widget parent = widget->core.parent; + Boolean managed, parentRealized, rgm = False; + XtConfigureHookDataRec req; + Widget hookobj; + + *clear_rect_obj = FALSE; + + CALLGEOTAT(_XtGeoTrace(widget, + "\"%s\" is making a %sgeometry request to its parent \"%s\".\n", + XtName(widget), + ((request->request_mode & XtCWQueryOnly))? "query only ":"", + (XtParent(widget))?XtName(XtParent(widget)):"Root")); + CALLGEOTAT(_XtGeoTab(1)); + + if (XtIsShell(widget)) { + ShellClassExtension ext; + LOCK_PROCESS; + for (ext = (ShellClassExtension)((ShellWidgetClass)XtClass(widget)) + ->shell_class.extension; + ext != NULL && ext->record_type != NULLQUARK; + ext = (ShellClassExtension)ext->next_extension); + + if (ext != NULL) { + if ( ext->version == XtShellExtensionVersion + && ext->record_size == sizeof(ShellClassExtensionRec)) { + manager = ext->root_geometry_manager; + rgm = True; + } else { + String params[1]; + Cardinal num_params = 1; + params[0] = XtClass(widget)->core_class.class_name; + XtAppErrorMsg(XtWidgetToApplicationContext(widget), + "invalidExtension", "xtMakeGeometryRequest", + XtCXtToolkitError, + "widget class %s has invalid ShellClassExtension record", + params, &num_params); + } + } else { + XtAppErrorMsg(XtWidgetToApplicationContext(widget), + "internalError", "xtMakeGeometryRequest", + XtCXtToolkitError, + "internal error; ShellClassExtension is NULL", + NULL, NULL); + } + managed = True; + parentRealized = TRUE; + UNLOCK_PROCESS; + } else /* not shell */ { + if (parent == NULL) + XtAppErrorMsg(XtWidgetToApplicationContext(widget), + "invalidParent","xtMakeGeometryRequest", + XtCXtToolkitError, + "non-shell has no parent in XtMakeGeometryRequest", + (String *)NULL, (Cardinal *)NULL); + + /* + * This shouldn't ever happen, we only test for this to pass VSW5. + * Normally managing the widget will catch this, but VSW5 does + * some really screwy stuff to get here. + */ + if (!XtIsComposite(parent)) + XtAppErrorMsg(XtWidgetToApplicationContext(widget), + "invalidParent", "xtMakeGeometryRequest", + XtCXtToolkitError, + "XtMakeGeometryRequest - parent not composite", + (String *)NULL, (Cardinal *)NULL); + + managed = XtIsManaged(widget); + parentRealized = XtIsRealized(parent); + LOCK_PROCESS; + manager = ((CompositeWidgetClass) (parent->core.widget_class)) + ->composite_class.geometry_manager; + UNLOCK_PROCESS; + } + + if (managed && manager == (XtGeometryHandler) NULL) { + XtErrorMsg("invalidGeometryManager","xtMakeGeometryRequest", + XtCXtToolkitError, + "XtMakeGeometryRequest - parent has no geometry manager", + (String *)NULL, (Cardinal *)NULL); + } + + if (widget->core.being_destroyed) { + CALLGEOTAT(_XtGeoTab(-1)); + CALLGEOTAT(_XtGeoTrace(widget, + "It is being destroyed, just return XtGeometryNo.\n")); + return XtGeometryNo; + } + + /* see if requesting anything to change */ + req.changeMask = 0; + if (request->request_mode & CWStackMode + && request->stack_mode != XtSMDontChange) { + req.changeMask |= CWStackMode; + CALLGEOTAT(_XtGeoTrace(widget, + "Asking for a change in StackMode!\n")); + if (request->request_mode & CWSibling) { + XtCheckSubclass(request->sibling, rectObjClass, + "XtMakeGeometryRequest"); + req.changeMask |= CWSibling; + } + } + if (request->request_mode & CWX + && widget->core.x != request->x) { + CALLGEOTAT(_XtGeoTrace(widget, + "Asking for a change in x: from %d to %d.\n", + widget->core.x, request->x)); + req.changeMask |= CWX; + } + if (request->request_mode & CWY + && widget->core.y != request->y) { + CALLGEOTAT(_XtGeoTrace(widget, + "Asking for a change in y: from %d to %d.\n", + widget->core.y, request->y)); + req.changeMask |= CWY; + } + if (request->request_mode & CWWidth + && widget->core.width != request->width) { + CALLGEOTAT(_XtGeoTrace(widget,"Asking for a change in width: from %d to %d.\n", + widget->core.width, request->width)); + req.changeMask |= CWWidth; + } + if (request->request_mode & CWHeight + && widget->core.height != request->height) { + CALLGEOTAT(_XtGeoTrace(widget, + "Asking for a change in height: from %d to %d.\n", + widget->core.height, request->height)); + req.changeMask |= CWHeight; + } + if (request->request_mode & CWBorderWidth + && widget->core.border_width != request->border_width){ + CALLGEOTAT(_XtGeoTrace(widget, + "Asking for a change in border_width: from %d to %d.\n", + widget->core.border_width, request->border_width)); + req.changeMask |= CWBorderWidth; + } + if (! req.changeMask) { + CALLGEOTAT(_XtGeoTrace(widget, + "Asking for nothing new,\n")); + CALLGEOTAT(_XtGeoTab(-1)); + CALLGEOTAT(_XtGeoTrace(widget, + "just return XtGeometryYes.\n")); + return XtGeometryYes; + } + req.changeMask |= (request->request_mode & XtCWQueryOnly); + + if ( !(req.changeMask & XtCWQueryOnly) && XtIsRealized(widget) ) { + /* keep record of the current geometry so we know what's changed */ + req.changes.x = widget->core.x ; + req.changes.y = widget->core.y ; + req.changes.width = widget->core.width ; + req.changes.height = widget->core.height ; + req.changes.border_width = widget->core.border_width ; + } + + if (!managed || !parentRealized) { + CALLGEOTAT(_XtGeoTrace(widget, + "Not Managed or Parent not realized.\n")); + /* Don't get parent's manager involved--assume the answer is yes */ + if (req.changeMask & XtCWQueryOnly) { + /* He was just asking, don't change anything, just tell him yes */ + CALLGEOTAT(_XtGeoTrace(widget,"QueryOnly request\n")); + CALLGEOTAT(_XtGeoTab(-1)); + CALLGEOTAT(_XtGeoTrace(widget,"just return XtGeometryYes.\n")); + return XtGeometryYes; + } else { + CALLGEOTAT(_XtGeoTrace(widget, + "Copy values from request to widget.\n")); + /* copy values from request to widget */ + if (request->request_mode & CWX) + widget->core.x = request->x; + if (request->request_mode & CWY) + widget->core.y = request->y; + if (request->request_mode & CWWidth) + widget->core.width = request->width; + if (request->request_mode & CWHeight) + widget->core.height = request->height; + if (request->request_mode & CWBorderWidth) + widget->core.border_width = request->border_width; + if (!parentRealized) { + CALLGEOTAT(_XtGeoTab(-1)); + CALLGEOTAT(_XtGeoTrace(widget,"and return XtGeometryYes.\n")); + return XtGeometryYes; + } + else returnCode = XtGeometryYes; + } + } else { + /* go ask the widget's geometry manager */ + CALLGEOTAT(_XtGeoTrace(widget, + "Go ask the parent geometry manager.\n")); + if (reply == (XtWidgetGeometry *) NULL) { + returnCode = (*manager)(widget, request, &junk); + } else { + returnCode = (*manager)(widget, request, reply); + } + } + + /* + * If Unrealized, not a XtGeometryYes, or a query-only then we are done. + */ + + if ((returnCode != XtGeometryYes) || + (req.changeMask & XtCWQueryOnly) || !XtIsRealized(widget)) { + +#ifdef XT_GEO_TATTLER + switch(returnCode){ + case XtGeometryNo: + CALLGEOTAT(_XtGeoTab(-1)); + CALLGEOTAT(_XtGeoTrace(widget,"\"%s\" returns XtGeometryNo.\n", + (XtParent(widget))?XtName(XtParent(widget)):"Root")); + /* check for no change */ + break ; + case XtGeometryDone: + CALLGEOTAT(_XtGeoTab(-1)); + CALLGEOTAT(_XtGeoTrace(widget,"\"%s\" returns XtGeometryDone.\n", + (XtParent(widget))?XtName(XtParent(widget)):"Root")); + /* check for no change in queryonly */ + break ; + case XtGeometryAlmost: + CALLGEOTAT(_XtGeoTab(-1)); + CALLGEOTAT(_XtGeoTrace(widget,"\"%s\" returns XtGeometryAlmost.\n", + (XtParent(widget))?XtName(XtParent(widget)):"Root")); + CALLGEOTAT(_XtGeoTab(1)); + CALLGEOTAT(_XtGeoTrace(widget,"Proposal: width %d height %d.\n", + (reply)?reply->width:junk.width, + (reply)?reply->height:junk.height)); + CALLGEOTAT(_XtGeoTab(-1)); + + /* check for no change */ + break ; + case XtGeometryYes: + if (req.changeMask & XtCWQueryOnly) { + CALLGEOTAT(_XtGeoTrace(widget, + "QueryOnly specified, no configuration.\n")); + } + if (!XtIsRealized(widget)) { + CALLGEOTAT(_XtGeoTrace(widget, + "\"%s\" not realized, no configuration.\n", + XtName(widget))); + } + CALLGEOTAT(_XtGeoTab(-1)); + CALLGEOTAT(_XtGeoTrace(widget,"\"%s\" returns XtGeometryYes.\n", + (XtParent(widget))?XtName(XtParent(widget)):"Root")); + break ; + } +#endif + return returnCode; + } + + CALLGEOTAT(_XtGeoTab(-1)); + CALLGEOTAT(_XtGeoTrace(widget,"\"%s\" returns XtGeometryYes.\n", + (XtParent(widget))?XtName(XtParent(widget)):"Root")); + + if (XtIsWidget(widget)) { /* reconfigure the window (if needed) */ + + if (rgm) return returnCode; + + if (req.changes.x != widget->core.x) { + req.changeMask |= CWX; + req.changes.x = widget->core.x; + CALLGEOTAT(_XtGeoTrace(widget, + "x changing to %d\n",widget->core.x)); + } + if (req.changes.y != widget->core.y) { + req.changeMask |= CWY; + req.changes.y = widget->core.y; + CALLGEOTAT(_XtGeoTrace(widget, + "y changing to %d\n",widget->core.y)); + } + if (req.changes.width != widget->core.width) { + req.changeMask |= CWWidth; + req.changes.width = widget->core.width; + CALLGEOTAT(_XtGeoTrace(widget, + "width changing to %d\n",widget->core.width)); + } + if (req.changes.height != widget->core.height) { + req.changeMask |= CWHeight; + req.changes.height = widget->core.height; + CALLGEOTAT(_XtGeoTrace(widget, + "height changing to %d\n",widget->core.height)); + } + if (req.changes.border_width != widget->core.border_width) { + req.changeMask |= CWBorderWidth; + req.changes.border_width = widget->core.border_width; + CALLGEOTAT(_XtGeoTrace(widget, + "border_width changing to %d\n", + widget->core.border_width)); + } + if (req.changeMask & CWStackMode) { + req.changes.stack_mode = request->stack_mode; + CALLGEOTAT(_XtGeoTrace(widget,"stack_mode changing\n")); + if (req.changeMask & CWSibling) + if (XtIsWidget(request->sibling)) + req.changes.sibling = XtWindow(request->sibling); + else + req.changeMask &= ~(CWStackMode | CWSibling); + } + +#ifdef XT_GEO_TATTLER + if (req.changeMask) { + CALLGEOTAT(_XtGeoTrace(widget, + "XConfigure \"%s\"'s window.\n", + XtName(widget))); + } else { + CALLGEOTAT(_XtGeoTrace(widget, + "No window configuration needed for \"%s\".\n", + XtName(widget))); + } +#endif + + XConfigureWindow(XtDisplay(widget), XtWindow(widget), + req.changeMask, &req.changes); + } + else { /* RectObj child of realized Widget */ + *clear_rect_obj = TRUE; + CALLGEOTAT(_XtGeoTrace(widget, + "ClearRectObj on \"%s\".\n",XtName(widget))); + + ClearRectObjAreas((RectObj)widget, &req.changes); + } + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));; + if (XtHasCallbacks(hookobj, XtNconfigureHook) == XtCallbackHasSome) { + req.type = XtHconfigure; + req.widget = widget; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.confighook_callbacks, + (XtPointer)&req); + } + + return returnCode; +} /* _XtMakeGeometryRequest */ + + +/* Public routines */ + +XtGeometryResult XtMakeGeometryRequest (widget, request, reply) + Widget widget; + XtWidgetGeometry *request, *reply; +{ + Boolean junk; + XtGeometryResult r; + XtGeometryHookDataRec call_data; + Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + if (XtHasCallbacks(hookobj, XtNgeometryHook) == XtCallbackHasSome) { + call_data.type = XtHpreGeometry; + call_data.widget = widget; + call_data.request = request; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.geometryhook_callbacks, + (XtPointer)&call_data); + call_data.result = r = + _XtMakeGeometryRequest(widget, request, reply, &junk); + call_data.type = XtHpostGeometry; + call_data.reply = reply; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.geometryhook_callbacks, + (XtPointer)&call_data); + } else { + r = _XtMakeGeometryRequest(widget, request, reply, &junk); + } + UNLOCK_APP(app); + + return ((r == XtGeometryDone) ? XtGeometryYes : r); +} + +#if NeedFunctionPrototypes +XtGeometryResult +XtMakeResizeRequest( + Widget widget, + _XtDimension width, + _XtDimension height, + Dimension *replyWidth, + Dimension *replyHeight) +#else +XtGeometryResult +XtMakeResizeRequest (widget, width, height, replyWidth, replyHeight) + Widget widget; + Dimension width, height; + Dimension *replyWidth, *replyHeight; +#endif +{ + XtWidgetGeometry request, reply; + XtGeometryResult r; + XtGeometryHookDataRec call_data; + Boolean junk; + Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + request.request_mode = CWWidth | CWHeight; + request.width = width; + request.height = height; + + if (XtHasCallbacks(hookobj, XtNgeometryHook) == XtCallbackHasSome) { + call_data.type = XtHpreGeometry; + call_data.widget = widget; + call_data.request = &request; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.geometryhook_callbacks, + (XtPointer)&call_data); + call_data.result = r = + _XtMakeGeometryRequest(widget, &request, &reply, &junk); + call_data.type = XtHpostGeometry; + call_data.reply = &reply; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.geometryhook_callbacks, + (XtPointer)&call_data); + } else { + r = _XtMakeGeometryRequest(widget, &request, &reply, &junk); + } + if (replyWidth != NULL) + if (r == XtGeometryAlmost && reply.request_mode & CWWidth) + *replyWidth = reply.width; + else + *replyWidth = width; + if (replyHeight != NULL) + if (r == XtGeometryAlmost && reply.request_mode & CWHeight) + *replyHeight = reply.height; + else + *replyHeight = height; + UNLOCK_APP(app); + return ((r == XtGeometryDone) ? XtGeometryYes : r); +} /* XtMakeResizeRequest */ + +void XtResizeWindow(w) + Widget w; +{ + XtConfigureHookDataRec req; + Widget hookobj; + WIDGET_TO_APPCON(w); + + LOCK_APP(app); + if (XtIsRealized(w)) { + req.changes.width = w->core.width; + req.changes.height = w->core.height; + req.changes.border_width = w->core.border_width; + req.changeMask = CWWidth | CWHeight | CWBorderWidth; + XConfigureWindow(XtDisplay(w), XtWindow(w), + (unsigned) req.changeMask, &req.changes); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(w));; + if (XtHasCallbacks(hookobj, XtNconfigureHook) == XtCallbackHasSome) { + req.type = XtHconfigure; + req.widget = w; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.confighook_callbacks, + (XtPointer)&req); + } + } + UNLOCK_APP(app); +} /* XtResizeWindow */ + +#if NeedFunctionPrototypes +void XtResizeWidget( + Widget w, + _XtDimension width, + _XtDimension height, + _XtDimension borderWidth + ) +#else +void XtResizeWidget(w, width, height, borderWidth) + Widget w; + Dimension width, height, borderWidth; +#endif +{ + XtConfigureWidget(w, w->core.x, w->core.y, width, height, borderWidth); +} /* XtResizeWidget */ + +#if NeedFunctionPrototypes +void XtConfigureWidget( + Widget w, + _XtPosition x, + _XtPosition y, + _XtDimension width, + _XtDimension height, + _XtDimension borderWidth + ) +#else +void XtConfigureWidget(w, x, y, width, height, borderWidth) + Widget w; + Position x, y; + Dimension width, height, borderWidth; +#endif +{ + XtConfigureHookDataRec req; + Widget hookobj; + XWindowChanges old; + WIDGET_TO_APPCON(w); + + CALLGEOTAT(_XtGeoTrace(w, + "\"%s\" is being configured by its parent \"%s\"\n", + XtName(w), + (XtParent(w))?XtName(XtParent(w)):"Root")); + CALLGEOTAT(_XtGeoTab(1)); + + LOCK_APP(app); + req.changeMask = 0; + if ((old.x = w->core.x) != x) { + CALLGEOTAT(_XtGeoTrace(w,"x move from %d to %d\n",w->core.x, x)); + req.changes.x = w->core.x = x; + req.changeMask |= CWX; + } + + if ((old.y = w->core.y) != y) { + CALLGEOTAT(_XtGeoTrace(w,"y move from %d to %d\n",w->core.y, y)); + req.changes.y = w->core.y = y; + req.changeMask |= CWY; + } + + if ((old.width = w->core.width) != width) { + CALLGEOTAT(_XtGeoTrace(w, + "width move from %d to %d\n",w->core.width, width)); + req.changes.width = w->core.width = width; + req.changeMask |= CWWidth; + } + + if ((old.height = w->core.height) != height) { + CALLGEOTAT(_XtGeoTrace(w, + "height move from %d to %d\n",w->core.height, height)); + req.changes.height = w->core.height = height; + req.changeMask |= CWHeight; + } + + if ((old.border_width = w->core.border_width) != borderWidth) { + CALLGEOTAT(_XtGeoTrace(w,"border_width move from %d to %d\n", + w->core.border_width,borderWidth )); + req.changes.border_width = w->core.border_width = borderWidth; + req.changeMask |= CWBorderWidth; + } + + if (req.changeMask != 0) { + if (XtIsRealized(w)) { + if (XtIsWidget(w)) { + CALLGEOTAT(_XtGeoTrace(w, + "XConfigure \"%s\"'s window\n",XtName(w))); + XConfigureWindow(XtDisplay(w), XtWindow(w), + req.changeMask, &req.changes); + } else { + CALLGEOTAT(_XtGeoTrace(w, + "ClearRectObj called on \"%s\"\n",XtName(w))); + ClearRectObjAreas((RectObj)w, &old); + } + } + hookobj = XtHooksOfDisplay(XtDisplayOfObject(w));; + if (XtHasCallbacks(hookobj, XtNconfigureHook) == XtCallbackHasSome) { + req.type = XtHconfigure; + req.widget = w; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.confighook_callbacks, + (XtPointer)&req); + } + { + XtWidgetProc resize; + + LOCK_PROCESS; + resize = XtClass(w)->core_class.resize; + UNLOCK_PROCESS; + if ((req.changeMask & (CWWidth | CWHeight)) && + resize != (XtWidgetProc) NULL) { + CALLGEOTAT(_XtGeoTrace(w,"Resize proc is called.\n")); + (*resize)(w); + } + } + } else { + CALLGEOTAT(_XtGeoTrace(w,"No change in configuration\n")); + } + + CALLGEOTAT(_XtGeoTab(-1)); + UNLOCK_APP(app); +} /* XtConfigureWidget */ + +#if NeedFunctionPrototypes +void XtMoveWidget( + Widget w, + _XtPosition x, + _XtPosition y + ) +#else +void XtMoveWidget(w, x, y) + Widget w; + Position x, y; +#endif +{ + XtConfigureWidget(w, x, y, w->core.width, w->core.height, + w->core.border_width); +} /* XtMoveWidget */ + +#if NeedFunctionPrototypes +void XtTranslateCoords( + register Widget w, + _XtPosition x, + _XtPosition y, + register Position *rootx, /* return */ + register Position *rooty /* return */ + ) +#else +void XtTranslateCoords(w, x, y, rootx, rooty) + register Widget w; + Position x, y; + register Position *rootx, *rooty; /* return */ +#endif +{ + Position garbagex, garbagey; + XtAppContext app = XtWidgetToApplicationContext(w); + + LOCK_APP(app); + if (rootx == NULL) rootx = &garbagex; + if (rooty == NULL) rooty = &garbagey; + + *rootx = x; + *rooty = y; + + for (; w != NULL && ! XtIsShell(w); w = w->core.parent) { + *rootx += w->core.x + w->core.border_width; + *rooty += w->core.y + w->core.border_width; + } + + if (w == NULL) + XtAppWarningMsg(app, + "invalidShell","xtTranslateCoords",XtCXtToolkitError, + "Widget has no shell ancestor", + (String *)NULL, (Cardinal *)NULL); + else { + Position x, y; + extern void _XtShellGetCoordinates(); + _XtShellGetCoordinates( w, &x, &y ); + *rootx += x + w->core.border_width; + *rooty += y + w->core.border_width; + } + UNLOCK_APP(app); +} + +XtGeometryResult XtQueryGeometry(widget, intended, reply) + Widget widget; + register XtWidgetGeometry *intended; /* parent's changes; may be NULL */ + XtWidgetGeometry *reply; /* child's preferred geometry; never NULL */ +{ + XtWidgetGeometry null_intended; + XtGeometryHandler query; + XtGeometryResult result; + WIDGET_TO_APPCON(widget); + + CALLGEOTAT(_XtGeoTrace(widget, + "\"%s\" is asking its preferred geometry to \"%s\".\n", + (XtParent(widget))?XtName(XtParent(widget)):"Root", + XtName(widget))); + CALLGEOTAT(_XtGeoTab(1)); + + LOCK_APP(app); + LOCK_PROCESS; + query = XtClass(widget)->core_class.query_geometry; + UNLOCK_PROCESS; + reply->request_mode = 0; + if (query != NULL) { + if (intended == NULL) { + null_intended.request_mode = 0; + intended = &null_intended; +#ifdef XT_GEO_TATTLER + CALLGEOTAT(_XtGeoTrace(widget,"without any constraint.\n")); + } else { + CALLGEOTAT(_XtGeoTrace(widget, + "with the following constraints:\n")); + + if (intended->request_mode & CWX) { + CALLGEOTAT(_XtGeoTrace(widget," x = %d\n",intended->x)); + } + if (intended->request_mode & CWY) { + CALLGEOTAT(_XtGeoTrace(widget," y = %d\n",intended->y)); + } + if (intended->request_mode & CWWidth) { + CALLGEOTAT(_XtGeoTrace(widget, + " width = %d\n",intended->width)); + } + if (intended->request_mode & CWHeight) { + CALLGEOTAT(_XtGeoTrace(widget, + " height = %d\n",intended->height)); + } + if (intended->request_mode & CWBorderWidth) { + CALLGEOTAT(_XtGeoTrace(widget, + " border_width = %d\n",intended->border_width)); + } +#endif + } + + result = (*query) (widget, intended, reply); + } + else { + CALLGEOTAT(_XtGeoTrace(widget,"\"%s\" has no QueryGeometry proc, return the current state\n",XtName(widget))); + + result = XtGeometryYes; + } + +#ifdef XT_GEO_TATTLER +#define FillIn(mask, field) \ + if (!(reply->request_mode & mask)) {\ + reply->field = widget->core.field;\ + _XtGeoTrace(widget," using core %s = %d.\n","field",\ + widget->core.field);\ + } else {\ + _XtGeoTrace(widget," replied %s = %d\n","field",\ + reply->field);\ + } +#else +#define FillIn(mask, field) \ + if (!(reply->request_mode & mask)) reply->field = widget->core.field; +#endif + + FillIn(CWX, x); + FillIn(CWY, y); + FillIn(CWWidth, width); + FillIn(CWHeight, height); + FillIn(CWBorderWidth, border_width); + + CALLGEOTAT(_XtGeoTab(-1)); +#undef FillIn + + if (!(reply->request_mode & CWStackMode)) + reply->stack_mode = XtSMDontChange; + UNLOCK_APP(app); + return result; +} diff --git a/src/GetActKey.c b/src/GetActKey.c new file mode 100644 index 0000000..7e08a92 --- /dev/null +++ b/src/GetActKey.c @@ -0,0 +1,99 @@ +/* $Xorg: GetActKey.c,v 1.4 2001/02/09 02:03:55 xorgcvs Exp $ */ + +/*LINTLIBRARY*/ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" + +KeySym XtGetActionKeysym(event, modifiers_return) + XEvent *event; + Modifiers *modifiers_return; +{ + TMKeyContext tm_context; + Modifiers modifiers; + KeySym keysym, retval; + + LOCK_PROCESS; + tm_context= _XtGetPerDisplay(event->xany.display)->tm_context; + if (event->xany.type != KeyPress && event->xany.type != KeyRelease) { + UNLOCK_PROCESS; + return NoSymbol; + } + if (tm_context != NULL + && event == tm_context->event + && event->xany.serial == tm_context->serial ) { + + if (modifiers_return != NULL) + *modifiers_return = tm_context->modifiers; + retval = tm_context->keysym; + UNLOCK_PROCESS; + return retval; + } + + XtTranslateKeycode( event->xany.display, (KeyCode)event->xkey.keycode, + event->xkey.state, &modifiers, &keysym ); + + if (modifiers_return != NULL) + *modifiers_return = event->xkey.state & modifiers; + + UNLOCK_PROCESS; + return keysym; +} diff --git a/src/GetResList.c b/src/GetResList.c new file mode 100644 index 0000000..7def21e --- /dev/null +++ b/src/GetResList.c @@ -0,0 +1,187 @@ +/* $Xorg: GetResList.c,v 1.4 2001/02/09 02:03:55 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" + +/* + * XtGetResourceList(), XtGetConstraintResourceList() + */ + +void XtGetResourceList(widget_class, resources, num_resources) + WidgetClass widget_class; + XtResourceList *resources; + Cardinal *num_resources; +{ + int size; + register int i, dest = 0; + register XtResourceList *list, dlist; + + LOCK_PROCESS; + size = widget_class->core_class.num_resources * sizeof(XtResource); + *resources = (XtResourceList) __XtMalloc((unsigned) size); + + if (!widget_class->core_class.class_inited) { + /* Easy case */ + + (void) memmove((char *) *resources, + (char *)widget_class->core_class.resources, size); + *num_resources = widget_class->core_class.num_resources; + UNLOCK_PROCESS; + return; + } + + /* Nope, it's the hard case */ + + list = (XtResourceList *) widget_class->core_class.resources; + dlist = *resources; + for (i = 0; i < widget_class->core_class.num_resources; i++) { + if (list[i] != NULL) { + dlist[dest].resource_name = (String) + XrmQuarkToString((XrmQuark) list[i]->resource_name); + dlist[dest].resource_class = (String) + XrmQuarkToString((XrmQuark) list[i]->resource_class); + dlist[dest].resource_type = (String) + XrmQuarkToString((XrmQuark) list[i]->resource_type); + dlist[dest].resource_size = list[i]->resource_size; + /* trust that resource_offset isn't that big */ + dlist[dest].resource_offset = (Cardinal) + -((int)(list[i]->resource_offset + 1)); + dlist[dest].default_type = (String) + XrmQuarkToString((XrmQuark) list[i]->default_type); + dlist[dest].default_addr = list[i]->default_addr; + dest++; + } + } + *num_resources = dest; + UNLOCK_PROCESS; +} + + +static Boolean ClassIsSubclassOf(class, superclass) + WidgetClass class, superclass; +{ + for (; class != NULL; class = class->core_class.superclass) { + if (class == superclass) return True; + } + return False; +} + +void XtGetConstraintResourceList(widget_class, resources, num_resources) + WidgetClass widget_class; + XtResourceList *resources; + Cardinal *num_resources; +{ + int size; + register int i, dest = 0; + register XtResourceList *list, dlist; + ConstraintWidgetClass class = (ConstraintWidgetClass)widget_class; + + LOCK_PROCESS; + if ( (class->core_class.class_inited && + !(class->core_class.class_inited & ConstraintClassFlag)) + || (!class->core_class.class_inited && + !ClassIsSubclassOf(widget_class, constraintWidgetClass)) + || class->constraint_class.num_resources == 0) { + + *resources = NULL; + *num_resources = 0; + UNLOCK_PROCESS; + return; + } + + size = class->constraint_class.num_resources * sizeof(XtResource); + *resources = (XtResourceList) __XtMalloc((unsigned) size); + + if (!class->core_class.class_inited) { + /* Easy case */ + + (void) memmove((char *) *resources, + (char *)class->constraint_class.resources, size); + *num_resources = class->constraint_class.num_resources; + UNLOCK_PROCESS; + return; + } + + /* Nope, it's the hard case */ + + list = (XtResourceList *) class->constraint_class.resources; + dlist = *resources; + for (i = 0; i < class->constraint_class.num_resources; i++) { + if (list[i] != NULL) { + dlist[dest].resource_name = (String) + XrmQuarkToString((XrmQuark) list[i]->resource_name); + dlist[dest].resource_class = (String) + XrmQuarkToString((XrmQuark) list[i]->resource_class); + dlist[dest].resource_type = (String) + XrmQuarkToString((XrmQuark) list[i]->resource_type); + dlist[dest].resource_size = list[i]->resource_size; + /* trust that resource_offset isn't that big */ + dlist[dest].resource_offset = (Cardinal) + -((int)(list[i]->resource_offset + 1)); + dlist[dest].default_type = (String) + XrmQuarkToString((XrmQuark) list[i]->default_type); + dlist[dest].default_addr = list[i]->default_addr; + dest++; + } + } + *num_resources = dest; + UNLOCK_PROCESS; +} diff --git a/src/GetValues.c b/src/GetValues.c new file mode 100644 index 0000000..19131f7 --- /dev/null +++ b/src/GetValues.c @@ -0,0 +1,250 @@ +/* $Xorg: GetValues.c,v 1.4 2001/02/09 02:03:55 xorgcvs Exp $ */ +/*LINTLIBRARY*/ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "StringDefs.h" + +extern void _XtCopyToArg(); +extern XrmResourceList* _XtCreateIndirectionTable(); + +static int GetValues(base, res, num_resources, args, num_args) + char* base; /* Base address to fetch values from */ + XrmResourceList* res; /* The current resource values. */ + register Cardinal num_resources; /* number of items in resources */ + ArgList args; /* The resource values requested */ + Cardinal num_args; /* number of items in arg list */ +{ + register ArgList arg; + register int i; + register XrmName argName; + register XrmResourceList* xrmres; + int translation_arg_num = -1; + static XrmQuark QCallback = NULLQUARK; + static XrmQuark QTranslationTable = NULLQUARK; + + LOCK_PROCESS; + if (QCallback == NULLQUARK) { + QCallback = XrmPermStringToQuark(XtRCallback); + QTranslationTable = XrmPermStringToQuark(XtRTranslationTable); + } + UNLOCK_PROCESS; + + /* Resource lists should be in compiled form already */ + + for (arg = args ; num_args != 0; num_args--, arg++) { + argName = StringToName(arg->name); + for (xrmres = res, i = 0; i < num_resources; i++, xrmres++) { + if (argName == (*xrmres)->xrm_name) { + /* hack; do special cases here instead of a get_values_hook + * because get_values_hook looses info as to + * whether arg->value == NULL for ancient compatibility + * mode in _XtCopyToArg. It helps performance, too... + */ + if ((*xrmres)->xrm_type == QCallback) { + XtCallbackList callback = _XtGetCallbackList( + (InternalCallbackList *) + (base - (*xrmres)->xrm_offset - 1)); + _XtCopyToArg( + (char*)&callback, &arg->value, + (*xrmres)->xrm_size); + } + else if ((*xrmres)->xrm_type == QTranslationTable) + translation_arg_num = (int) (arg - args); + else { + _XtCopyToArg( + base - (*xrmres)->xrm_offset - 1, + &arg->value, + (*xrmres)->xrm_size); + } + break; + } + } + } + return translation_arg_num; +} /* GetValues */ + +static void CallGetValuesHook(widget_class, w, args, num_args) + WidgetClass widget_class; + Widget w; + ArgList args; + Cardinal num_args; +{ + WidgetClass superclass; + XtArgsProc get_values_hook; + + LOCK_PROCESS; + superclass = widget_class->core_class.superclass; + UNLOCK_PROCESS; + if (superclass != NULL) + CallGetValuesHook (superclass, w, args, num_args); + + LOCK_PROCESS; + get_values_hook = widget_class->core_class.get_values_hook; + UNLOCK_PROCESS; + if (get_values_hook != NULL) + (*get_values_hook) (w, args, &num_args); +} + + + +static void CallConstraintGetValuesHook(widget_class, w, args, num_args) + WidgetClass widget_class; + Widget w; + ArgList args; + Cardinal num_args; +{ + ConstraintClassExtension ext; + + LOCK_PROCESS; + if (widget_class->core_class.superclass + ->core_class.class_inited & ConstraintClassFlag) { + CallConstraintGetValuesHook + (widget_class->core_class.superclass, w, args, num_args); + } + + for (ext = (ConstraintClassExtension)((ConstraintWidgetClass)widget_class) + ->constraint_class.extension; + ext != NULL && ext->record_type != NULLQUARK; + ext = (ConstraintClassExtension)ext->next_extension); + + if (ext != NULL) { + if ( ext->version == XtConstraintExtensionVersion + && ext->record_size == sizeof(ConstraintClassExtensionRec)) { + if (ext->get_values_hook != NULL) + (*(ext->get_values_hook)) (w, args, &num_args); + } else { + String params[1]; + Cardinal num_params = 1; + params[0] = widget_class->core_class.class_name; + XtAppWarningMsg(XtWidgetToApplicationContext(w), + "invalidExtension", "xtCreateWidget", XtCXtToolkitError, + "widget class %s has invalid ConstraintClassExtension record", + params, &num_params); + } + } + UNLOCK_PROCESS; +} + + +void XtGetValues(w, args, num_args) + register Widget w; + register ArgList args; + register Cardinal num_args; +{ + WidgetClass wc; + int targ; + XtAppContext app = XtWidgetToApplicationContext(w); + + if (num_args == 0) return; + if ((args == NULL) && (num_args != 0)) { + XtAppErrorMsg(app, + "invalidArgCount","xtGetValues",XtCXtToolkitError, + "Argument count > 0 on NULL argument list in XtGetValues", + (String *)NULL, (Cardinal *)NULL); + } + + LOCK_APP(app); + wc = XtClass(w); + LOCK_PROCESS; + /* Get widget values */ + targ = GetValues((char*)w, (XrmResourceList *) wc->core_class.resources, + wc->core_class.num_resources, args, num_args); + UNLOCK_PROCESS; + if (targ != -1 && XtIsWidget(w)) { + XtTranslations translations = _XtGetTranslationValue(w); + _XtCopyToArg((char*)&translations, &args[targ].value, + sizeof(XtTranslations)); + } + + /* Get constraint values if necessary */ + /* constraints may be NULL if constraint_size==0 */ + if (XtParent(w) != NULL && !XtIsShell(w) && XtIsConstraint(XtParent(w)) && + w->core.constraints) { + ConstraintWidgetClass cwc + = (ConstraintWidgetClass) XtClass(XtParent(w)); + LOCK_PROCESS; + GetValues((char*)w->core.constraints, + (XrmResourceList *)(cwc->constraint_class.resources), + cwc->constraint_class.num_resources, args, num_args); + UNLOCK_PROCESS; + } + /* Notify any class procedures that we have performed get_values */ + CallGetValuesHook(wc, w, args, num_args); + + /* Notify constraint get_values if necessary */ + if (XtParent(w) != NULL && !XtIsShell(w) && XtIsConstraint(XtParent(w))) + CallConstraintGetValuesHook(XtClass(XtParent(w)), w, args,num_args); + UNLOCK_APP(app); +} /* XtGetValues */ + +void XtGetSubvalues(base, resources, num_resources, args, num_args) + XtPointer base; /* Base address to fetch values from */ + XtResourceList resources; /* The current resource values. */ + Cardinal num_resources; /* number of items in resources */ + ArgList args; /* The resource values requested */ + Cardinal num_args; /* number of items in arg list */ +{ + XrmResourceList* xrmres; + xrmres = _XtCreateIndirectionTable(resources, num_resources); + GetValues((char*)base, xrmres, num_resources, args, num_args); + XtFree((char *)xrmres); +} diff --git a/src/HookObj.c b/src/HookObj.c new file mode 100644 index 0000000..fa95c0c --- /dev/null +++ b/src/HookObj.c @@ -0,0 +1,130 @@ +/* $Xorg: HookObj.c,v 1.4 2001/02/09 02:03:55 xorgcvs Exp $ */ + +/* + +Copyright 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "StringDefs.h" +/****************************************************************** + * + * Hook Object Resources + * + ******************************************************************/ + +static XtResource resources[] = { + { XtNcreateHook, XtCCallback, XtRCallback, sizeof(XtPointer), + XtOffsetOf(HookObjRec, hooks.createhook_callbacks), + XtRCallback, (XtPointer)NULL}, + { XtNchangeHook, XtCCallback, XtRCallback, sizeof(XtPointer), + XtOffsetOf(HookObjRec, hooks.changehook_callbacks), + XtRCallback, (XtPointer)NULL}, + { XtNconfigureHook, XtCCallback, XtRCallback, sizeof(XtPointer), + XtOffsetOf(HookObjRec, hooks.confighook_callbacks), + XtRCallback, (XtPointer)NULL}, + { XtNgeometryHook, XtCCallback, XtRCallback, sizeof(XtPointer), + XtOffsetOf(HookObjRec, hooks.geometryhook_callbacks), + XtRCallback, (XtPointer)NULL}, + { XtNdestroyHook, XtCCallback, XtRCallback, sizeof(XtPointer), + XtOffsetOf(HookObjRec, hooks.destroyhook_callbacks), + XtRCallback, (XtPointer)NULL}, + { XtNshells, XtCReadOnly, XtRWidgetList, sizeof(WidgetList), + XtOffsetOf(HookObjRec, hooks.shells), XtRImmediate, (XtPointer) NULL }, + { XtNnumShells, XtCReadOnly, XtRCardinal, sizeof(Cardinal), + XtOffsetOf(HookObjRec, hooks.num_shells), XtRImmediate, (XtPointer) 0 } +}; + +static void GetValuesHook(), Initialize(); + +externaldef(hookobjclassrec) HookObjClassRec hookObjClassRec = { + { /* Object Class Part */ + /* superclass */ (WidgetClass)&objectClassRec, + /* class_name */ "Hook", + /* widget_size */ sizeof(HookObjRec), + /* class_initialize */ NULL, + /* class_part_initialize*/ NULL, + /* class_inited */ FALSE, + /* initialize */ Initialize, + /* initialize_hook */ NULL, + /* realize */ NULL, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ NULL, + /* expose */ NULL, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ NULL, + /* get_values_hook */ GetValuesHook, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + }, + { /* HookObj Class Part */ + /* unused */ 0 + } +}; + +externaldef(hookObjectClass) WidgetClass hookObjectClass = + (WidgetClass)&hookObjClassRec; + +static void FreeShellList(w, closure, call_data) + Widget w; + XtPointer closure, call_data; +{ + HookObject h = (HookObject)w; + if (h->hooks.shells != NULL) + XtFree((char*)h->hooks.shells); +} + +static void Initialize(req, new, args, num_args) + Widget req, new; + ArgList args; + Cardinal* num_args; +{ + HookObject w = (HookObject) new; + w->hooks.max_shells = 0; + XtAddCallback (new, XtNdestroyCallback, FreeShellList, (XtPointer) NULL); +} + +static void GetValuesHook(widget, args, num_args) + Widget widget; + ArgList args; + Cardinal* num_args; +{ + /* get the XtNshells and XtNnumShells pseudo-resources */ +} + diff --git a/src/Hooks.c b/src/Hooks.c new file mode 100644 index 0000000..5878d61 --- /dev/null +++ b/src/Hooks.c @@ -0,0 +1,163 @@ +/* $Xorg: Hooks.c,v 1.4 2001/02/09 02:03:55 xorgcvs Exp $ */ + +/* + +Copyright 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/*LINTLIBRARY*/ + +#include "IntrinsicI.h" + +static void FreeBlockHookList( widget, closure, call_data ) + Widget widget; /* unused (and invalid) */ + XtPointer closure; /* ActionHook* */ + XtPointer call_data; /* unused */ +{ + BlockHook list = *(BlockHook*)closure; + while (list != NULL) { + BlockHook next = list->next; + XtFree( (XtPointer)list ); + list = next; + } +} + + +XtBlockHookId XtAppAddBlockHook( app, proc, closure ) + XtAppContext app; + XtBlockHookProc proc; + XtPointer closure; +{ + BlockHook hook = XtNew(BlockHookRec); + LOCK_APP(app); + hook->next = app->block_hook_list; + hook->app = app; + hook->proc = proc; + hook->closure = closure; + if (app->block_hook_list == NULL) { + _XtAddCallback( &app->destroy_callbacks, + FreeBlockHookList, + (XtPointer)&app->block_hook_list + ); + } + app->block_hook_list = hook; + UNLOCK_APP(app); + return (XtBlockHookId)hook; +} + + +void XtRemoveBlockHook( id ) + XtBlockHookId id; +{ + BlockHook *p, hook = (BlockHook)id; + XtAppContext app = hook->app; + LOCK_APP(app); + for (p = &app->block_hook_list; p != NULL && *p != hook; p = &(*p)->next); + if (p == NULL) { +#ifdef DEBUG + XtAppWarningMsg(app, "badId", "xtRemoveBlockHook", XtCXtToolkitError, + "XtRemoveBlockHook called with bad or old hook id", + (String*)NULL, (Cardinal*)NULL); +#endif /*DEBUG*/ + UNLOCK_APP(app); + return; + } + *p = hook->next; + XtFree( (XtPointer)hook ); + UNLOCK_APP(app); +} + +static void DeleteShellFromHookObj(shell, closure, call_data) + Widget shell; + XtPointer closure, call_data; +{ + /* app_con is locked when this function is called */ + int ii, jj; + HookObject ho = (HookObject) closure; + + for (ii = 0; ii < ho->hooks.num_shells; ii++) + if (ho->hooks.shells[ii] == shell) { + /* collapse the list */ + for (jj = ii; jj < ho->hooks.num_shells; jj++) { + if ((jj+1) < ho->hooks.num_shells) + ho->hooks.shells[jj] = ho->hooks.shells[jj+1]; + } + break; + } + ho->hooks.num_shells--; +} + +#define SHELL_INCR 4 + +#if NeedFunctionPrototypes +void _XtAddShellToHookObj( + Widget shell) +#else +void _XtAddShellToHookObj(shell) + Widget shell; +#endif +{ + /* app_con is locked when this function is called */ + HookObject ho = (HookObject) XtHooksOfDisplay(XtDisplay(shell)); + + if (ho->hooks.num_shells == ho->hooks.max_shells) { + ho->hooks.max_shells += SHELL_INCR; + ho->hooks.shells = + (WidgetList)XtRealloc((char*)ho->hooks.shells, + ho->hooks.max_shells * sizeof (Widget)); + } + ho->hooks.shells[ho->hooks.num_shells++] = shell; + + XtAddCallback(shell, XtNdestroyCallback, DeleteShellFromHookObj, + (XtPointer)ho); +} + +#if NeedFunctionPrototypes +Boolean _XtIsHookObject( + Widget widget) +#else +Boolean _XtIsHookObject(widget) + Widget widget; +#endif +{ + return (widget->core.widget_class == hookObjectClass); +} + +Widget XtHooksOfDisplay(dpy) + Display* dpy; +{ + extern Widget _XtCreateHookObj(); + Widget retval; + XtPerDisplay pd; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + pd = _XtGetPerDisplay(dpy); + if (pd->hook_object == NULL) + pd->hook_object = + _XtCreateHookObj((Screen*)DefaultScreenOfDisplay(dpy)); + retval = pd->hook_object; + UNLOCK_APP(app); + return retval; +} diff --git a/src/Initialize.c b/src/Initialize.c new file mode 100644 index 0000000..74e9c0b --- /dev/null +++ b/src/Initialize.c @@ -0,0 +1,1044 @@ +/* $Xorg: Initialize.c,v 1.9 2001/03/19 14:27:27 coskrey Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* Make sure all wm properties can make it out of the resource manager */ + +#include "IntrinsicI.h" +#include "StringDefs.h" +#include "CoreP.h" +#include "ShellP.h" +#include <stdio.h> +#include <X11/Xlocale.h> +#ifdef XTHREADS +#include <X11/Xthreads.h> +#endif +#ifndef WIN32 +#define X_INCLUDE_PWD_H +#define XOS_USE_XT_LOCKING +#include <X11/Xos_r.h> +#endif + +#ifdef __STDC__ +#define Const const +#else +#define Const /**/ +#endif + +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#else +extern char *getenv(); +#endif + +extern void _XtConvertInitialize(); + +#if (defined(SUNSHLIB) || defined(AIXSHLIB)) && defined(SHAREDCODE) +/* + * If used as a shared library, generate code under a different name so that + * the stub routines in sharedlib.c get loaded into the application binary. + */ +#define XtToolkitInitialize _XtToolkitInitialize +#define XtOpenApplication _XtOpenApplication +#define XtAppInitialize _XtAppInitialize +#define XtInitialize _XtInitialize +#endif /* (SUNSHLIB || AIXSHLIB) && SHAREDCODE */ + +/* + * hpux + * Hand-patched versions of HP-UX prior to version 7.0 can usefully add + * -DUSE_UNAME in the appropriate config file to get long hostnames. + */ + +#ifdef USG +#define USE_UNAME +#endif + +#ifdef USE_UNAME +#include <sys/utsname.h> +#endif + +/* some unspecified magic number of expected search levels for Xrm */ +#define SEARCH_LIST_SIZE 1000 + +/* + This is a set of default records describing the command line arguments that + Xlib will parse and set into the resource data base. + + This list is applied before the users list to enforce these defaults. This is + policy, which the toolkit avoids but I hate differing programs at this level. +*/ + +static XrmOptionDescRec Const opTable[] = { +{"+rv", "*reverseVideo", XrmoptionNoArg, (XtPointer) "off"}, +{"+synchronous","*synchronous", XrmoptionNoArg, (XtPointer) "off"}, +{"-background", "*background", XrmoptionSepArg, (XtPointer) NULL}, +{"-bd", "*borderColor", XrmoptionSepArg, (XtPointer) NULL}, +{"-bg", "*background", XrmoptionSepArg, (XtPointer) NULL}, +{"-bordercolor","*borderColor", XrmoptionSepArg, (XtPointer) NULL}, +{"-borderwidth",".borderWidth", XrmoptionSepArg, (XtPointer) NULL}, +{"-bw", ".borderWidth", XrmoptionSepArg, (XtPointer) NULL}, +{"-display", ".display", XrmoptionSepArg, (XtPointer) NULL}, +{"-fg", "*foreground", XrmoptionSepArg, (XtPointer) NULL}, +{"-fn", "*font", XrmoptionSepArg, (XtPointer) NULL}, +{"-font", "*font", XrmoptionSepArg, (XtPointer) NULL}, +{"-foreground", "*foreground", XrmoptionSepArg, (XtPointer) NULL}, +{"-geometry", ".geometry", XrmoptionSepArg, (XtPointer) NULL}, +{"-iconic", ".iconic", XrmoptionNoArg, (XtPointer) "on"}, +{"-name", ".name", XrmoptionSepArg, (XtPointer) NULL}, +{"-reverse", "*reverseVideo", XrmoptionNoArg, (XtPointer) "on"}, +{"-rv", "*reverseVideo", XrmoptionNoArg, (XtPointer) "on"}, +{"-selectionTimeout", + ".selectionTimeout", XrmoptionSepArg, (XtPointer) NULL}, +{"-synchronous","*synchronous", XrmoptionNoArg, (XtPointer) "on"}, +{"-title", ".title", XrmoptionSepArg, (XtPointer) NULL}, +{"-xnllanguage",".xnlLanguage", XrmoptionSepArg, (XtPointer) NULL}, +{"-xrm", NULL, XrmoptionResArg, (XtPointer) NULL}, +{"-xtsessionID",".sessionID", XrmoptionSepArg, (XtPointer) NULL}, +}; + + +/* + * GetHostname - emulates gethostname() on non-bsd systems. + */ + +static void GetHostname (buf, maxlen) + char *buf; + int maxlen; +{ + int len; + +#ifdef USE_UNAME + struct utsname name; + + if (maxlen <= 0 || buf == NULL) + return; + + uname (&name); + len = strlen (name.nodename); + if (len >= maxlen) len = maxlen; + (void) strncpy (buf, name.nodename, len-1); + buf[len-1] = '\0'; +#else + if (maxlen <= 0 || buf == NULL) + return; + + buf[0] = '\0'; + (void) gethostname (buf, maxlen); + buf [maxlen - 1] = '\0'; +#endif +} + + +#ifdef SUNSHLIB +void _XtInherit() +{ + extern void __XtInherit(); + __XtInherit(); +} +#define _XtInherit __XtInherit +#endif + +void _XtInherit() +{ + XtErrorMsg("invalidProcedure","inheritanceProc",XtCXtToolkitError, + "Unresolved inheritance operation", + (String *)NULL, (Cardinal *)NULL); +} + + +void XtToolkitInitialize() +{ + extern void _XtResourceListInitialize(); + static Boolean initialized = False; + + LOCK_PROCESS; + if (initialized) { + UNLOCK_PROCESS; + return; + } + initialized = True; + UNLOCK_PROCESS; + /* Resource management initialization */ + XrmInitialize(); + _XtResourceListInitialize(); + + /* Other intrinsic intialization */ + _XtConvertInitialize(); + _XtEventInitialize(); + _XtTranslateInitialize(); +} + + +String _XtGetUserName(dest, len) + String dest; + int len; +{ +#ifdef WIN32 + String ptr = NULL; + + if ((ptr = getenv("USERNAME"))) { + (void) strncpy (dest, ptr, len-1); + dest[len-1] = '\0'; + } else + *dest = '\0'; +#else + _Xgetpwparams pwparams; + struct passwd *pw; + char* ptr; + + if ((ptr = getenv("USER"))) { + (void) strncpy (dest, ptr, len-1); + dest[len-1] = '\0'; + } else { + if ((pw = _XGetpwuid(getuid(),pwparams)) != NULL) { + (void) strncpy (dest, pw->pw_name, len-1); + dest[len-1] = '\0'; + } else + *dest = '\0'; + } +#endif + return dest; +} + + +static String GetRootDirName(dest, len) + String dest; + int len; +{ +#ifdef WIN32 + register char *ptr1; + register char *ptr2; + int len1 = 0, len2 = 0; + + if (ptr1 = getenv("HOME")) { /* old, deprecated */ + len1 = strlen (ptr1); + } else if ((ptr1 = getenv("HOMEDRIVE")) && (ptr2 = getenv("HOMEDIR"))) { + len1 = strlen (ptr1); + len2 = strlen (ptr2); + } else if (ptr2 = getenv("USERNAME")) { + len1 = strlen (ptr1 = "/users/"); + len2 = strlen (ptr2); + } + if ((len1 + len2 + 1) < len) + sprintf (dest, "%s%s", ptr1, (ptr2) ? ptr2 : ""); + else + *dest = '\0'; +#else + _Xgetpwparams pwparams; + struct passwd *pw; + static char *ptr; + + if (len <= 0 || dest == NULL) + return NULL; + + if ((ptr = getenv("HOME"))) { + (void) strncpy (dest, ptr, len-1); + dest[len-1] = '\0'; + } else { + if ((ptr = getenv("USER"))) + pw = _XGetpwnam(ptr,pwparams); + else + pw = _XGetpwuid(getuid(),pwparams); + if (pw != NULL) { + (void) strncpy (dest, pw->pw_dir, len-1); + dest[len-1] = '\0'; + } else + *dest = '\0'; + } +#endif + return dest; +} + +static void CombineAppUserDefaults(dpy, pdb) + Display *dpy; + XrmDatabase *pdb; +{ + char* filename; + char* path; + Boolean deallocate = False; + + if (!(path = getenv("XUSERFILESEARCHPATH"))) { + char *old_path; + char homedir[PATH_MAX]; + GetRootDirName(homedir, PATH_MAX); + if (!(old_path = getenv("XAPPLRESDIR"))) { + char *path_default = "%s/%%L/%%N%%C:%s/%%l/%%N%%C:%s/%%N%%C:%s/%%L/%%N:%s/%%l/%%N:%s/%%N"; + if (!(path = + ALLOCATE_LOCAL(6*strlen(homedir) + strlen(path_default)))) + _XtAllocError(NULL); + sprintf( path, path_default, + homedir, homedir, homedir, homedir, homedir, homedir ); + } else { + 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"; + if (!(path = + ALLOCATE_LOCAL( 6*strlen(old_path) + 2*strlen(homedir) + + strlen(path_default)))) + _XtAllocError(NULL); + sprintf(path, path_default, old_path, old_path, old_path, homedir, + old_path, old_path, old_path, homedir ); + } + deallocate = True; + } + + filename = XtResolvePathname(dpy, NULL, NULL, NULL, path, NULL, 0, NULL); + if (filename) { + (void)XrmCombineFileDatabase(filename, pdb, False); + XtFree(filename); + } + + if (deallocate) DEALLOCATE_LOCAL(path); +} + +static void CombineUserDefaults(dpy, pdb) + Display *dpy; + XrmDatabase *pdb; +{ + char *slashDotXdefaults = "/.Xdefaults"; + char *dpy_defaults = XResourceManagerString(dpy); + + if (dpy_defaults) { + XrmCombineDatabase(XrmGetStringDatabase(dpy_defaults), pdb, False); + } else { + char filename[PATH_MAX]; + (void) GetRootDirName(filename, + PATH_MAX - strlen (slashDotXdefaults) - 1); + (void) strcat(filename, slashDotXdefaults); + (void)XrmCombineFileDatabase(filename, pdb, False); + } +} + +/*ARGSUSED*/ +static Bool StoreDBEntry(db, bindings, quarks, type, value, data) + XrmDatabase *db; + XrmBindingList bindings; + XrmQuarkList quarks; + XrmRepresentation *type; + XrmValuePtr value; + XPointer data; +{ + XrmQPutResource((XrmDatabase *)data, bindings, quarks, *type, value); + return False; +} + +static XrmDatabase CopyDB(db) + XrmDatabase db; +{ + XrmDatabase copy = NULL; + XrmQuark empty = NULLQUARK; + + XrmEnumerateDatabase(db, &empty, &empty, XrmEnumAllLevels, + StoreDBEntry, (XPointer)©); + return copy; +} + +/*ARGSUSED*/ +static String _XtDefaultLanguageProc(dpy, xnl, closure) + Display *dpy; /* unused */ + String xnl; + XtPointer closure; /* unused */ +{ + if (! setlocale(LC_ALL, xnl)) + XtWarning("locale not supported by C library, locale unchanged"); + + if (! XSupportsLocale()) { + XtWarning("locale not supported by Xlib, locale set to C"); + setlocale(LC_ALL, "C"); + } + if (! XSetLocaleModifiers("")) + XtWarning("X locale modifiers not supported, using default"); + + return setlocale(LC_ALL, NULL); /* re-query in case overwritten */ +} + +#if NeedFunctionPrototypes +XtLanguageProc XtSetLanguageProc( + XtAppContext app, + XtLanguageProc proc, + XtPointer closure + ) +#else +XtLanguageProc XtSetLanguageProc(app, proc, closure) + XtAppContext app; + XtLanguageProc proc; + XtPointer closure; +#endif +{ + XtLanguageProc old; + + if (!proc) { + proc = _XtDefaultLanguageProc; + closure = NULL; + } + + if (app) { + LOCK_APP(app); + LOCK_PROCESS; + /* set langProcRec only for this application context */ + old = app->langProcRec.proc; + app->langProcRec.proc = proc; + app->langProcRec.closure = closure; + UNLOCK_PROCESS; + UNLOCK_APP(app); + } else { + /* set langProcRec for all application contexts */ + ProcessContext process; + + LOCK_PROCESS; + process = _XtGetProcessContext(); + old = process->globalLangProcRec.proc; + process->globalLangProcRec.proc = proc; + process->globalLangProcRec.closure = closure; + app = process->appContextList; + while (app) { + app->langProcRec.proc = proc; + app->langProcRec.closure = closure; + app = app->next; + } + UNLOCK_PROCESS; + } + return (old ? old : _XtDefaultLanguageProc); +} + +XrmDatabase XtScreenDatabase(screen) + Screen *screen; +{ + int scrno; + Bool doing_def; + XrmDatabase db, olddb; + XtPerDisplay pd; + Status do_fallback; + char *scr_resources; + Display *dpy = DisplayOfScreen(screen); + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + LOCK_PROCESS; + if (screen == DefaultScreenOfDisplay(dpy)) { + scrno = DefaultScreen(dpy); + doing_def = True; + } else { + scrno = XScreenNumberOfScreen(screen); + doing_def = False; + } + pd = _XtGetPerDisplay(dpy); + if ((db = pd->per_screen_db[scrno])) { + UNLOCK_PROCESS; + UNLOCK_APP(app); + return (doing_def ? XrmGetDatabase(dpy) : db); + } + scr_resources = XScreenResourceString(screen); + + if (ScreenCount(dpy) == 1) { + db = pd->cmd_db; + pd->cmd_db = NULL; + } else { + db = CopyDB(pd->cmd_db); + } + { /* Environment defaults */ + char filenamebuf[PATH_MAX]; + char *filename; + + if (!(filename = getenv("XENVIRONMENT"))) { + int len; + char *slashDotXdefaultsDash = "/.Xdefaults-"; + + (void) GetRootDirName(filename = filenamebuf, + PATH_MAX - strlen (slashDotXdefaultsDash) - 1); + (void) strcat(filename, slashDotXdefaultsDash); + len = strlen(filename); + GetHostname (filename+len, PATH_MAX-len); + } + (void)XrmCombineFileDatabase(filename, &db, False); + } + if (scr_resources) + { /* Screen defaults */ + XrmCombineDatabase(XrmGetStringDatabase(scr_resources), &db, False); + XFree(scr_resources); + } + /* Server or host defaults */ + if (!pd->server_db) + CombineUserDefaults(dpy, &db); + else { + (void) XrmCombineDatabase(pd->server_db, &db, False); + pd->server_db = NULL; + } + + if (!db) + db = XrmGetStringDatabase(""); + pd->per_screen_db[scrno] = db; + olddb = XrmGetDatabase(dpy); + /* set database now, for XtResolvePathname to use */ + XrmSetDatabase(dpy, db); + CombineAppUserDefaults(dpy, &db); + do_fallback = 1; + { /* System app-defaults */ + char *filename; + + if ((filename = XtResolvePathname(dpy, "app-defaults", + NULL, NULL, NULL, NULL, 0, NULL))) { + do_fallback = !XrmCombineFileDatabase(filename, &db, False); + XtFree(filename); + } + } + /* now restore old database, if need be */ + if (!doing_def) + XrmSetDatabase(dpy, olddb); + if (do_fallback && pd->appContext->fallback_resources) + { /* Fallback defaults */ + XrmDatabase fdb = NULL; + String *res; + + for (res = pd->appContext->fallback_resources; *res; res++) + XrmPutLineResource(&fdb, *res); + (void)XrmCombineDatabase(fdb, &db, False); + } + UNLOCK_PROCESS; + UNLOCK_APP(app); + return db; +} + +/* + * Merge two option tables, allowing the second to over-ride the first, + * so that ambiguous abbreviations can be noticed. The merge attempts + * to make the resulting table lexicographically sorted, but succeeds + * only if the first source table is sorted. Though it _is_ recommended + * (for optimizations later in XrmParseCommand), it is not required + * that either source table be sorted. + * + * Caller is responsible for freeing the returned option table. + */ + +static void _MergeOptionTables(src1, num_src1, src2, num_src2, dst, num_dst) + XrmOptionDescRec *src1, *src2; + Cardinal num_src1, num_src2; + XrmOptionDescRec **dst; + Cardinal *num_dst; +{ + XrmOptionDescRec *table, *endP; + register XrmOptionDescRec *opt1, *opt2, *whereP, *dstP; + int i1, i2, dst_len, order; + Boolean found; + enum {Check, NotSorted, IsSorted} sort_order = Check; + + *dst = table = (XrmOptionDescRec*) + __XtMalloc( sizeof(XrmOptionDescRec) * (num_src1 + num_src2) ); + + (void) memmove(table, src1, sizeof(XrmOptionDescRec) * num_src1 ); + if (num_src2 == 0) { + *num_dst = num_src1; + return; + } + endP = &table[dst_len = num_src1]; + for (opt2 = src2, i2= 0; i2 < num_src2; opt2++, i2++) { + found = False; + whereP = endP-1; /* assume new option goes at the end */ + for (opt1 = table, i1 = 0; i1 < dst_len; opt1++, i1++) { + /* have to walk the entire new table so new list is ordered + (if src1 was ordered) */ + if (sort_order == Check && i1 > 0 + && strcmp(opt1->option, (opt1-1)->option) < 0) + sort_order = NotSorted; + if ((order = strcmp(opt1->option, opt2->option)) == 0) { + /* same option names; just overwrite opt1 with opt2 */ + *opt1 = *opt2; + found = True; + break; + } + /* else */ + if (sort_order == IsSorted && order > 0) { + /* insert before opt1 to preserve order */ + /* shift rest of table forward to make room for new entry */ + for (dstP = endP++; dstP > opt1; dstP--) + *dstP = *(dstP-1); + *opt1 = *opt2; + dst_len++; + found = True; + break; + } + /* else */ + if (order < 0) + /* opt2 sorts after opt1, so remember this position */ + whereP = opt1; + } + if (sort_order == Check && i1 == dst_len) + sort_order = IsSorted; + if (!found) { + /* when we get here, whereP points to the last entry in the + destination that sorts before "opt2". Shift rest of table + forward and insert "opt2" after whereP. */ + whereP++; + for (dstP = endP++; dstP > whereP; dstP--) + *dstP = *(dstP-1); + *whereP = *opt2; + dst_len++; + } + } + *num_dst = dst_len; +} + + +/* NOTE: name, class, and type must be permanent strings */ +static Boolean _GetResource(dpy, list, name, class, type, value) + Display *dpy; + XrmSearchList list; + String name, class, type; + XrmValue* value; +{ + XrmRepresentation db_type; + XrmValue db_value; + XrmName Qname = XrmPermStringToQuark(name); + XrmClass Qclass = XrmPermStringToQuark(class); + XrmRepresentation Qtype = XrmPermStringToQuark(type); + + if (XrmQGetSearchResource(list, Qname, Qclass, &db_type, &db_value)) { + if (db_type == Qtype) { + if (Qtype == _XtQString) + *(String*)value->addr = db_value.addr; + else + (void) memmove(value->addr, db_value.addr, value->size ); + return True; + } else { + WidgetRec widget; /* hack, hack */ + bzero( &widget, sizeof(widget) ); + widget.core.self = &widget; + widget.core.widget_class = coreWidgetClass; + widget.core.screen = (Screen*)DefaultScreenOfDisplay(dpy); + XtInitializeWidgetClass(coreWidgetClass); + if (_XtConvert(&widget,db_type,&db_value,Qtype,value,NULL)) { + return True; + } + } + } + return False; +} + +XrmDatabase _XtPreparseCommandLine(urlist, num_urs, argc, argv, applName, + displayName, language) + XrmOptionDescRec *urlist; + Cardinal num_urs; + int argc; + String *argv; + String *applName, *displayName, *language; /* return */ +{ + XrmDatabase db = 0; + XrmOptionDescRec *options; + Cardinal num_options; + XrmName name_list[3]; + XrmName class_list[3]; + XrmRepresentation type; + XrmValue val; + String *targv; + int targc = argc; + + targv = (String *) __XtMalloc(sizeof(char *) * argc); + (void) memmove(targv, argv, sizeof(char *) * argc); + _MergeOptionTables(opTable, XtNumber(opTable), urlist, num_urs, + &options, &num_options); + name_list[0] = class_list[0] = XrmPermStringToQuark("."); + name_list[2] = class_list[2] = NULLQUARK; + XrmParseCommand(&db, options, num_options, ".", &targc, targv); + if (applName) { + name_list[1] = XrmPermStringToQuark("name"); + if (XrmQGetResource(db, name_list, name_list, &type, &val) && + type == _XtQString) + *applName = val.addr; + } + if (displayName) { + name_list[1] = XrmPermStringToQuark("display"); + if (XrmQGetResource(db, name_list, name_list, &type, &val) && + type == _XtQString) + *displayName = val.addr; + } + if (language) { + name_list[1] = XrmPermStringToQuark("xnlLanguage"); + class_list[1] = XrmPermStringToQuark("XnlLanguage"); + if (XrmQGetResource(db, name_list, class_list, &type, &val) && + type == _XtQString) + *language = val.addr; + } + + XtFree((char *)targv); + XtFree((char *)options); + return db; +} + + +static void GetLanguage(dpy, pd) + Display *dpy; + XtPerDisplay pd; +{ + XrmRepresentation type; + XrmValue value; + XrmName name_list[3]; + XrmName class_list[3]; + + LOCK_PROCESS; + if (! pd->language) { + name_list[0] = pd->name; + name_list[1] = XrmPermStringToQuark("xnlLanguage"); + class_list[0] = pd->class; + class_list[1] = XrmPermStringToQuark("XnlLanguage"); + name_list[2] = class_list[2] = NULLQUARK; + if (!pd->server_db) + CombineUserDefaults(dpy, &pd->server_db); + if (pd->server_db && + XrmQGetResource(pd->server_db,name_list,class_list, &type, &value) + && type == _XtQString) + pd->language = (char *) value.addr; + } + + if (pd->appContext->langProcRec.proc) { + if (! pd->language) pd->language = ""; + pd->language = (*pd->appContext->langProcRec.proc) + (dpy, pd->language, pd->appContext->langProcRec.closure); + } + else if (! pd->language || pd->language[0] == '\0') /* R4 compatibility */ + pd->language = getenv("LANG"); + + if (pd->language) pd->language = XtNewString(pd->language); + UNLOCK_PROCESS; +} + +static void ProcessInternalConnection (client_data, fd, id) + XtPointer client_data; + int* fd; + XtInputId* id; +{ + XProcessInternalConnection ((Display *) client_data, *fd); +} + +static void ConnectionWatch (dpy, client_data, fd, opening, watch_data) + Display* dpy; + XPointer client_data; + int fd; + Bool opening; + XPointer* watch_data; +{ + XtInputId* iptr; + XtAppContext app = XtDisplayToApplicationContext(dpy); + + if (opening) { + iptr = (XtInputId *) __XtMalloc(sizeof(XtInputId)); + *iptr = XtAppAddInput(app, fd, (XtPointer) XtInputReadMask, + ProcessInternalConnection, client_data); + *watch_data = (XPointer) iptr; + } else { + iptr = (XtInputId *) *watch_data; + XtRemoveInput(*iptr); + (void) XtFree(*watch_data); + } +} + +#if NeedFunctionPrototypes +void _XtDisplayInitialize( + Display *dpy, + XtPerDisplay pd, + _Xconst char* name, + XrmOptionDescRec *urlist, + Cardinal num_urs, + int *argc, + char **argv) +#else +void _XtDisplayInitialize(dpy, pd, name, urlist, num_urs, argc, argv) + Display *dpy; + XtPerDisplay pd; + String name; + XrmOptionDescRec *urlist; + Cardinal num_urs; + int *argc; + char **argv; +#endif +{ + Boolean tmp_bool; + XrmValue value; + XrmOptionDescRec *options; + Cardinal num_options; + XrmDatabase db; + XrmName name_list[2]; + XrmClass class_list[2]; + XrmHashTable* search_list; + int search_list_size = SEARCH_LIST_SIZE; + + GetLanguage(dpy, pd); + + /* Parse the command line and remove Xt arguments from argv */ + _MergeOptionTables( opTable, XtNumber(opTable), urlist, num_urs, + &options, &num_options ); + XrmParseCommand(&pd->cmd_db, options, num_options, name, argc, argv); + + db = XtScreenDatabase(DefaultScreenOfDisplay(dpy)); + + if (!(search_list = (XrmHashTable*) + ALLOCATE_LOCAL( SEARCH_LIST_SIZE*sizeof(XrmHashTable)))) + _XtAllocError(NULL); + name_list[0] = pd->name; + class_list[0] = pd->class; + name_list[1] = NULLQUARK; + class_list[1] = NULLQUARK; + + while (!XrmQGetSearchList(db, name_list, class_list, + search_list, search_list_size)) { + XrmHashTable* old = search_list; + Cardinal size = (search_list_size*=2)*sizeof(XrmHashTable); + if (!(search_list = (XrmHashTable*)ALLOCATE_LOCAL(size))) + _XtAllocError(NULL); + (void) memmove((char*)search_list, (char*)old, (size>>1) ); + DEALLOCATE_LOCAL(old); + } + + value.size = sizeof(tmp_bool); + value.addr = (XtPointer)&tmp_bool; + if (_GetResource(dpy, search_list, "synchronous", "Synchronous", + XtRBoolean, &value)) { + int i; + Display **dpyP = pd->appContext->list; + pd->appContext->sync = tmp_bool; + for (i = pd->appContext->count; i; dpyP++, i--) { + (void) XSynchronize(*dpyP, (Bool)tmp_bool); + } + } else { + (void) XSynchronize(dpy, (Bool)pd->appContext->sync); + } + + if (_GetResource(dpy, search_list, "reverseVideo", "ReverseVideo", + XtRBoolean, &value) + && tmp_bool) { + pd->rv = True; + } + + value.size = sizeof(pd->multi_click_time); + value.addr = (XtPointer)&pd->multi_click_time; + if (!_GetResource(dpy, search_list, + "multiClickTime", "MultiClickTime", + XtRInt, &value)) { + pd->multi_click_time = 200; + } + + value.size = sizeof(pd->appContext->selectionTimeout); + value.addr = (XtPointer)&pd->appContext->selectionTimeout; + (void)_GetResource(dpy, search_list, + "selectionTimeout", "SelectionTimeout", + XtRInt, &value); + +#ifndef NO_IDENTIFY_WINDOWS + value.size = sizeof(pd->appContext->identify_windows); + value.addr = (XtPointer)&pd->appContext->identify_windows; + (void)_GetResource(dpy, search_list, + "xtIdentifyWindows", "XtDebug", + XtRBoolean, &value); +#endif + + XAddConnectionWatch(dpy, ConnectionWatch, (XPointer) dpy); + + XtFree( (XtPointer)options ); + DEALLOCATE_LOCAL( search_list ); +} + +/* Function Name: XtAppSetFallbackResources + * Description: Sets the fallback resource list that will be loaded + * at display initialization time. + * Arguments: app_context - the app context. + * specification_list - the resource specification list. + * Returns: none. + */ + +#if NeedFunctionPrototypes +void +XtAppSetFallbackResources( +XtAppContext app_context, +String *specification_list +) +#else +void +XtAppSetFallbackResources(app_context, specification_list) +XtAppContext app_context; +String *specification_list; +#endif +{ + LOCK_APP(app_context); + app_context->fallback_resources = specification_list; + UNLOCK_APP(app_context); +} + + +#if NeedFunctionPrototypes +Widget XtOpenApplication(XtAppContext *app_context_return, + _Xconst char *application_class, + XrmOptionDescRec *options, Cardinal num_options, + int *argc_in_out, String *argv_in_out, + String *fallback_resources, WidgetClass widget_class, + ArgList args_in, Cardinal num_args_in) +#else +Widget XtOpenApplication(app_context_return, application_class, + options, num_options, argc_in_out, argv_in_out, + fallback_resources, widget_class, + args_in, num_args_in) + XtAppContext *app_context_return; + String application_class; + XrmOptionDescRec *options; + Cardinal num_options, num_args_in; + int *argc_in_out; + String *argv_in_out, *fallback_resources; + WidgetClass widget_class; + ArgList args_in; +#endif +{ + XtAppContext app_con; + Display * dpy; + register int saved_argc = *argc_in_out; + Widget root; + Arg args[3], *merged_args; + Cardinal num = 0; + + XtToolkitInitialize(); /* cannot be moved into _XtAppInit */ + + dpy = _XtAppInit(&app_con, (String)application_class, options, num_options, + argc_in_out, &argv_in_out, fallback_resources); + + LOCK_APP(app_con); + XtSetArg(args[num], XtNscreen, DefaultScreenOfDisplay(dpy)); num++; + XtSetArg(args[num], XtNargc, saved_argc); num++; + XtSetArg(args[num], XtNargv, argv_in_out); num++; + + merged_args = XtMergeArgLists(args_in, num_args_in, args, num); + num += num_args_in; + + root = XtAppCreateShell(NULL, application_class, widget_class, dpy, + merged_args, num); + + if (app_context_return) + *app_context_return = app_con; + + XtFree((XtPointer)merged_args); + XtFree((XtPointer)argv_in_out); + UNLOCK_APP(app_con); + return root; +} + + +#if NeedFunctionPrototypes +Widget +XtAppInitialize( +XtAppContext * app_context_return, +_Xconst char* application_class, +XrmOptionDescRec *options, +Cardinal num_options, +int *argc_in_out, +String *argv_in_out, +String *fallback_resources, +ArgList args_in, +Cardinal num_args_in +) +#else +Widget +XtAppInitialize(app_context_return, application_class, options, num_options, + argc_in_out, argv_in_out, fallback_resources, + args_in, num_args_in) +XtAppContext * app_context_return; +String application_class; +XrmOptionDescRec *options; +Cardinal num_options, num_args_in; +int *argc_in_out; +String *argv_in_out, * fallback_resources; +ArgList args_in; +#endif +{ + return XtOpenApplication(app_context_return, application_class, + options, num_options, + argc_in_out, argv_in_out, fallback_resources, + applicationShellWidgetClass, + args_in, num_args_in); +} + + +/*ARGSUSED*/ +#if NeedFunctionPrototypes +Widget +XtInitialize( +_Xconst char* name, +_Xconst char* classname, +XrmOptionDescRec *options, +Cardinal num_options, +int *argc, +String *argv +) +#else +Widget +XtInitialize(name, classname, options, num_options, argc, argv) +String name, classname; +XrmOptionDescRec *options; +Cardinal num_options; +String *argv; +int *argc; +#endif +{ + Widget root; + XtAppContext app_con; + register ProcessContext process = _XtGetProcessContext(); + + root = XtAppInitialize(&app_con, classname, options, num_options, + argc, argv, NULL, NULL, (Cardinal) 0); + + LOCK_PROCESS; + process->defaultAppContext = app_con; + UNLOCK_PROCESS; + return root; +} diff --git a/src/Intrinsic.c b/src/Intrinsic.c new file mode 100644 index 0000000..71e5ab4 --- /dev/null +++ b/src/Intrinsic.c @@ -0,0 +1,1643 @@ +/* $Xorg: Intrinsic.c,v 1.4 2001/02/09 02:03:55 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#define INTRINSIC_C + +#include "IntrinsicI.h" +#include "VarargsI.h" /* for geoTattler */ +#ifndef NO_IDENTIFY_WINDOWS +#include <X11/Xatom.h> +#endif +#ifndef VMS +#include <sys/stat.h> +#endif /* VMS */ + +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#else +extern char *getenv(); +#endif + +String XtCXtToolkitError = "XtToolkitError"; + +Boolean XtIsSubclass(widget, widgetClass) + Widget widget; + WidgetClass widgetClass; +{ + register WidgetClass w; + Boolean retval = FALSE; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + LOCK_PROCESS; + for (w = widget->core.widget_class; w != NULL; w = w->core_class.superclass) + if (w == widgetClass) { + retval = TRUE; + break; + } + UNLOCK_PROCESS; + UNLOCK_APP(app); + return retval; +} /* XtIsSubclass */ + + +#if NeedFunctionPrototypes +Boolean _XtCheckSubclassFlag( + Widget object, + _XtXtEnum flag + ) +#else +Boolean _XtCheckSubclassFlag(object, flag) + Widget object; + XtEnum flag; +#endif +{ + Boolean retval; + + LOCK_PROCESS; + if (object->core.widget_class->core_class.class_inited & flag) + retval = TRUE; + else + retval = FALSE; + UNLOCK_PROCESS; + return retval; +} /*_XtVerifySubclass */ + + +#if NeedFunctionPrototypes +Boolean _XtIsSubclassOf( + Widget object, + WidgetClass widgetClass, + WidgetClass superClass, + _XtXtEnum flag + ) +#else +Boolean _XtIsSubclassOf(object, widgetClass, superClass, flag) + Widget object; + WidgetClass widgetClass, superClass; + XtEnum flag; +#endif +{ + LOCK_PROCESS; + if (!(object->core.widget_class->core_class.class_inited & flag)) { + UNLOCK_PROCESS; + return False; + } else { + register WidgetClass c = object->core.widget_class; + while (c != superClass) { + if (c == widgetClass) { + UNLOCK_PROCESS; + return True; + } + c = c->core_class.superclass; + } + UNLOCK_PROCESS; + return False; + } +} /*_XtIsSubclassOf */ + + +#if NeedFunctionPrototypes +XtPointer XtGetClassExtension( + WidgetClass object_class, + Cardinal byte_offset, + XrmQuark type, + long version, + Cardinal record_size + ) +#else +XtPointer XtGetClassExtension(object_class, byte_offset, type, version, + record_size) + WidgetClass object_class; + Cardinal byte_offset; + XrmQuark type; + long version; + Cardinal record_size; +#endif +{ + ObjectClassExtension ext; + LOCK_PROCESS; + + ext = *(ObjectClassExtension *)((char *)object_class + byte_offset); + while (ext && (ext->record_type != type || ext->version < version + || ext->record_size < record_size)) { + ext = (ObjectClassExtension) ext->next_extension; + } + + UNLOCK_PROCESS; + return (XtPointer) ext; +} + + +static void ComputeWindowAttributes(widget,value_mask,values) + Widget widget; + XtValueMask *value_mask; + XSetWindowAttributes *values; +{ + XtExposeProc expose; + + *value_mask = CWEventMask | CWColormap; + (*values).event_mask = XtBuildEventMask(widget); + (*values).colormap = widget->core.colormap; + if (widget->core.background_pixmap != XtUnspecifiedPixmap) { + *value_mask |= CWBackPixmap; + (*values).background_pixmap = widget->core.background_pixmap; + } else { + *value_mask |= CWBackPixel; + (*values).background_pixel = widget->core.background_pixel; + } + if (widget->core.border_pixmap != XtUnspecifiedPixmap) { + *value_mask |= CWBorderPixmap; + (*values).border_pixmap = widget->core.border_pixmap; + } else { + *value_mask |= CWBorderPixel; + (*values).border_pixel = widget->core.border_pixel; + } + LOCK_PROCESS; + expose = widget->core.widget_class->core_class.expose; + UNLOCK_PROCESS; + if (expose == (XtExposeProc) NULL) { + /* Try to avoid redisplay upon resize by making bit_gravity the same + as the default win_gravity */ + *value_mask |= CWBitGravity; + (*values).bit_gravity = NorthWestGravity; + } +} /* ComputeWindowAttributes */ + +static void CallChangeManaged(widget) + register Widget widget; +{ + register Cardinal i; + XtWidgetProc change_managed; + register WidgetList children; + int managed_children = 0; + + register CompositePtr cpPtr; + register CompositePartPtr clPtr; + + if (XtIsComposite (widget)) { + cpPtr = (CompositePtr)&((CompositeWidget) widget)->composite; + clPtr = (CompositePartPtr)&((CompositeWidgetClass) + widget->core.widget_class)->composite_class; + } else return; + + children = cpPtr->children; + LOCK_PROCESS; + change_managed = clPtr->change_managed; + UNLOCK_PROCESS; + + /* CallChangeManaged for all children */ + for (i = cpPtr->num_children; i != 0; --i) { + CallChangeManaged (children[i-1]); + if (XtIsManaged(children[i-1])) managed_children++; + } + + if (change_managed != NULL && managed_children != 0) { + CALLGEOTAT(_XtGeoTrace(widget,"Call \"%s\"[%d,%d]'s changemanaged\n", + XtName(widget), + widget->core.width, widget->core.height)); + (*change_managed) (widget); + } +} /* CallChangeManaged */ + + +static void MapChildren(cwp) + CompositePart *cwp; +{ + Cardinal i; + WidgetList children; + register Widget child; + + children = cwp->children; + for (i = 0; i < cwp->num_children; i++) { + child = children[i]; + if (XtIsWidget (child)){ + if (child->core.managed && child->core.mapped_when_managed) { + XtMapWidget (children[i]); + } + } + } +} /* MapChildren */ + + +static Boolean ShouldMapAllChildren(cwp) + CompositePart *cwp; +{ + Cardinal i; + WidgetList children; + register Widget child; + + children = cwp->children; + for (i = 0; i < cwp->num_children; i++) { + child = children[i]; + if (XtIsWidget(child)) { + if (XtIsRealized(child) && (! (child->core.managed + && child->core.mapped_when_managed))){ + return False; + } + } + } + + return True; +} /* ShouldMapAllChildren */ + + +static void RealizeWidget(widget) + Widget widget; +{ + XtValueMask value_mask; + XSetWindowAttributes values; + XtRealizeProc realize; + Window window; + Display* display; + String class_name; + Widget hookobj; + + if (!XtIsWidget(widget) || XtIsRealized(widget)) return; + display = XtDisplay(widget); + _XtInstallTranslations(widget); + + ComputeWindowAttributes (widget, &value_mask, &values); + LOCK_PROCESS; + realize = widget->core.widget_class->core_class.realize; + class_name = widget->core.widget_class->core_class.class_name; + UNLOCK_PROCESS; + if (realize == NULL) + XtAppErrorMsg(XtWidgetToApplicationContext(widget), + "invalidProcedure","realizeProc",XtCXtToolkitError, + "No realize class procedure defined", + (String *)NULL, (Cardinal *)NULL); + else { + CALLGEOTAT(_XtGeoTrace(widget,"Call \"%s\"[%d,%d]'s realize proc\n", + XtName(widget), + widget->core.width, widget->core.height)); + (*realize) (widget, &value_mask, &values); + } + window = XtWindow(widget); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj,XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHrealizeWidget; + call_data.widget = widget; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } +#ifndef NO_IDENTIFY_WINDOWS + if (_XtGetPerDisplay(display)->appContext->identify_windows) { + int len_nm, len_cl; + char *s; + + len_nm = widget->core.name ? strlen(widget->core.name) : 0; + len_cl = strlen(class_name); + s = __XtMalloc((unsigned) (len_nm + len_cl + 2)); + s[0] = '\0'; + if (len_nm) + strcpy(s, widget->core.name); + strcpy(s + len_nm + 1, class_name); + XChangeProperty(display, window, + XInternAtom(display, "_MIT_OBJ_CLASS", + False), + XA_STRING, 8, PropModeReplace, (unsigned char *) s, + len_nm + len_cl + 2); + XtFree(s); + } +#endif +#ifdef notdef + _XtRegisterAsyncHandlers(widget); +#endif + /* (re)register any grabs extant in the translations */ + _XtRegisterGrabs(widget); + /* reregister any grabs added with XtGrab{Button,Key} */ + _XtRegisterPassiveGrabs(widget); + XtRegisterDrawable (display, window, widget); + _XtExtensionSelect(widget); + + if (XtIsComposite (widget)) { + Cardinal i; + CompositePart *cwp = &(((CompositeWidget)widget)->composite); + WidgetList children = cwp->children; + /* Realize all children */ + for (i = cwp->num_children; i != 0; --i) { + RealizeWidget (children[i-1]); + } + /* Map children that are managed and mapped_when_managed */ + + if (cwp->num_children != 0) { + if (ShouldMapAllChildren(cwp)) { + XMapSubwindows (display, window); + } else { + MapChildren(cwp); + } + } + } + + /* If this is the application's popup shell, map it */ + if (widget->core.parent == NULL && widget->core.mapped_when_managed) { + XtMapWidget (widget); + } +} /* RealizeWidget */ + +void XtRealizeWidget (widget) + Widget widget; +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + if (XtIsRealized (widget)) { + UNLOCK_APP(app); + return; + } + CallChangeManaged(widget); + RealizeWidget(widget); + UNLOCK_APP(app); +} /* XtRealizeWidget */ + + +static void UnrealizeWidget(widget) + Widget widget; +{ + CompositeWidget cw; + Cardinal i; + WidgetList children; + + if (!XtIsWidget(widget) || !XtIsRealized(widget)) return; + + /* If this is the application's popup shell, unmap it? */ + /* no, the window is being destroyed */ + + /* Recurse on children */ + if (XtIsComposite (widget)) { + cw = (CompositeWidget) widget; + children = cw->composite.children; + /* Unrealize all children */ + for (i = cw->composite.num_children; i != 0; --i) { + UnrealizeWidget (children[i-1]); + } + /* Unmap children that are managed and mapped_when_managed? */ + /* No, it's ok to be managed and unrealized as long as your parent */ + /* is unrealized. XtUnrealize widget makes sure the "top" widget */ + /* is unmanaged, we can ignore all descendents */ + } + + if (XtHasCallbacks(widget, XtNunrealizeCallback) == XtCallbackHasSome) + XtCallCallbacks(widget, XtNunrealizeCallback, NULL); + + /* Unregister window */ + XtUnregisterDrawable(XtDisplay(widget), XtWindow(widget)); + + /* Remove Event Handlers */ + /* remove grabs. Happens automatically when window is destroyed. */ + + /* Destroy X Window, done at outer level with one request */ + widget->core.window = None; + + /* Removing the event handler here saves having to keep track if + * the translation table is changed while the widget is unrealized. + */ + _XtRemoveTranslations(widget); +} /* UnrealizeWidget */ + + +void XtUnrealizeWidget (widget) + Widget widget; +{ + Window window; + Widget hookobj; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + window = XtWindow(widget); + if (! XtIsRealized (widget)) { + UNLOCK_APP(app); + return; + } + if (widget->core.managed && widget->core.parent != NULL) + XtUnmanageChild(widget); + UnrealizeWidget(widget); + if (window != None) + XDestroyWindow(XtDisplay(widget), window); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHunrealizeWidget; + call_data.widget = widget; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} /* XtUnrealizeWidget */ + + +void XtCreateWindow(widget, window_class, visual, value_mask, attributes) + Widget widget; + unsigned int window_class; + Visual *visual; + XtValueMask value_mask; + XSetWindowAttributes *attributes; +{ + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + if (widget->core.window == None) { + if (widget->core.width == 0 || widget->core.height == 0) { + Cardinal count = 1; + XtAppErrorMsg(app, + "invalidDimension", "xtCreateWindow", XtCXtToolkitError, + "Widget %s has zero width and/or height", + &widget->core.name, &count); + } + widget->core.window = + XCreateWindow ( + XtDisplay (widget), + (widget->core.parent ? + widget->core.parent->core.window : + widget->core.screen->root), + (int)widget->core.x, (int)widget->core.y, + (unsigned)widget->core.width, (unsigned)widget->core.height, + (unsigned)widget->core.border_width, (int) widget->core.depth, + window_class, visual, value_mask, attributes); + } + UNLOCK_APP(app); +} /* XtCreateWindow */ + + +/* ---------------- XtNameToWidget ----------------- */ + +static Widget NameListToWidget(); + +typedef Widget (*NameMatchProc)(); + +static Widget MatchExactChildren(names, bindings, children, num, + in_depth, out_depth, found_depth) + XrmNameList names; + XrmBindingList bindings; + register WidgetList children; + register int num; + int in_depth, *out_depth, *found_depth; +{ + register Cardinal i; + register XrmName name = *names; + Widget w, result = NULL; + int d, min = 10000; + + for (i = 0; i < num; i++) { + if (name == children[i]->core.xrm_name) { + w = NameListToWidget(children[i], &names[1], &bindings[1], + in_depth+1, &d, found_depth); + if (w != NULL && d < min) {result = w; min = d;} + } + } + *out_depth = min; + return result; +} + +static Widget MatchWildChildren(names, bindings, children, num, + in_depth, out_depth, found_depth) + XrmNameList names; + XrmBindingList bindings; + register WidgetList children; + register int num; + int in_depth, *out_depth, *found_depth; +{ + register Cardinal i; + Widget w, result = NULL; + int d, min = 10000; + + for (i = 0; i < num; i++) { + w = NameListToWidget(children[i], names, bindings, + in_depth+1, &d, found_depth); + if (w != NULL && d < min) {result = w; min = d;} + } + *out_depth = min; + return result; +} + +static Widget SearchChildren(root, names, bindings, matchproc, + in_depth, out_depth, found_depth) + Widget root; + XrmNameList names; + XrmBindingList bindings; + NameMatchProc matchproc; + int in_depth, *out_depth, *found_depth; +{ + Widget w1, w2; + int d1, d2; + + if (XtIsComposite(root)) { + w1 = (*matchproc)(names, bindings, + ((CompositeWidget) root)->composite.children, + ((CompositeWidget) root)->composite.num_children, + in_depth, &d1, found_depth); + } else d1 = 10000; + w2 = (*matchproc)(names, bindings, root->core.popup_list, + root->core.num_popups, in_depth, &d2, found_depth); + *out_depth = (d1 < d2 ? d1 : d2); + return (d1 < d2 ? w1 : w2); +} + +static Widget NameListToWidget(root, names, bindings, + in_depth, out_depth, found_depth) + register Widget root; + XrmNameList names; + XrmBindingList bindings; + int in_depth, *out_depth, *found_depth; +{ + Widget w1, w2; + int d1, d2; + + if (in_depth >= *found_depth) { + *out_depth = 10000; + return NULL; + } + + if (names[0] == NULLQUARK) { + *out_depth = *found_depth = in_depth; + return root; + } + + if (! XtIsWidget(root)) { + *out_depth = 10000; + return NULL; + } + + if (*bindings == XrmBindTightly) { + return SearchChildren(root, names, bindings, MatchExactChildren, + in_depth, out_depth, found_depth); + + } else { /* XrmBindLoosely */ + w1 = SearchChildren(root, names, bindings, MatchExactChildren, + in_depth, &d1, found_depth); + w2 = SearchChildren(root, names, bindings, MatchWildChildren, + in_depth, &d2, found_depth); + *out_depth = (d1 < d2 ? d1 : d2); + return (d1 < d2 ? w1 : w2); + } +} /* NameListToWidget */ + +#if NeedFunctionPrototypes +Widget XtNameToWidget( + Widget root, + _Xconst char* name + ) +#else +Widget XtNameToWidget(root, name) + Widget root; + String name; +#endif +{ + XrmName *names; + XrmBinding *bindings; + int len, depth, found = 10000; + Widget result; + WIDGET_TO_APPCON(root); + + len = strlen(name); + if (len == 0) return NULL; + + LOCK_APP(app); + names = (XrmName *) ALLOCATE_LOCAL((unsigned) (len+1) * sizeof(XrmName)); + bindings = (XrmBinding *) + ALLOCATE_LOCAL((unsigned) (len+1) * sizeof(XrmBinding)); + if (names == NULL || bindings == NULL) _XtAllocError(NULL); + + XrmStringToBindingQuarkList(name, bindings, names); + if (names[0] == NULLQUARK) { + DEALLOCATE_LOCAL((char *) bindings); + DEALLOCATE_LOCAL((char *) names); + UNLOCK_APP(app); + return NULL; + } + + result = NameListToWidget(root, names, bindings, 0, &depth, &found); + + DEALLOCATE_LOCAL((char *) bindings); + DEALLOCATE_LOCAL((char *) names); + UNLOCK_APP(app); + return result; +} /* XtNameToWidget */ + +/* Define user versions of intrinsics macros */ + +#undef XtDisplayOfObject +Display *XtDisplayOfObject(object) + Widget object; +{ + /* Attempts to LockApp() here will generate endless recursive loops */ + if (XtIsSubclass(object, hookObjectClass)) + return DisplayOfScreen(((HookObject)object)->hooks.screen); + return XtDisplay(XtIsWidget(object) ? object : _XtWindowedAncestor(object)); +} + +#undef XtDisplay +Display *XtDisplay(widget) + Widget widget; +{ + /* Attempts to LockApp() here will generate endless recursive loops */ + return DisplayOfScreen(widget->core.screen); +} + +#undef XtScreenOfObject +Screen *XtScreenOfObject(object) + Widget object; +{ + /* Attempts to LockApp() here will generate endless recursive loops */ + if (XtIsSubclass(object, hookObjectClass)) + return ((HookObject)object)->hooks.screen; + return XtScreen(XtIsWidget(object) ? object : _XtWindowedAncestor(object)); +} + +#undef XtScreen +Screen *XtScreen(widget) + Widget widget; +{ + /* Attempts to LockApp() here will generate endless recursive loops */ + return widget->core.screen; +} + +#undef XtWindowOfObject +Window XtWindowOfObject(object) + Widget object; +{ + return XtWindow(XtIsWidget(object) ? object : _XtWindowedAncestor(object)); +} + + +#undef XtWindow +Window XtWindow(widget) + Widget widget; +{ + return widget->core.window; +} + +#undef XtSuperclass +WidgetClass XtSuperclass(widget) + Widget widget; +{ + WidgetClass retval; + + LOCK_PROCESS; + retval = XtClass(widget)->core_class.superclass; + UNLOCK_PROCESS; + return retval; +} + +#undef XtClass +WidgetClass XtClass(widget) + Widget widget; +{ + WidgetClass retval; + + LOCK_PROCESS; + retval = widget->core.widget_class; + UNLOCK_PROCESS; + return retval; +} + +#undef XtIsManaged +Boolean XtIsManaged(object) + Widget object; +{ + Boolean retval; + WIDGET_TO_APPCON(object); + + LOCK_APP(app); + if (XtIsRectObj(object)) + retval = object->core.managed; + else + retval = False; + UNLOCK_APP(app); + return retval; +} + +#undef XtIsRealized +Boolean XtIsRealized (object) + Widget object; +{ + Boolean retval; + WIDGET_TO_APPCON(object); + + LOCK_APP(app); + retval = XtWindowOfObject(object) != None; + UNLOCK_APP(app); + return retval; +} /* XtIsRealized */ + +#undef XtIsSensitive +Boolean XtIsSensitive(object) + Widget object; +{ + Boolean retval; + WIDGET_TO_APPCON(object); + + LOCK_APP(app); + if (XtIsRectObj(object)) + retval = object->core.sensitive && object->core.ancestor_sensitive; + else + retval = False; + UNLOCK_APP(app); + return retval; +} + +/* + * Internal routine; must be called only after XtIsWidget returns false + */ +Widget _XtWindowedAncestor(object) + register Widget object; +{ + Widget obj = object; + for (object = XtParent(object); object && !XtIsWidget(object);) + object = XtParent(object); + + if (object == NULL) { + String params = XtName(obj); + Cardinal num_params = 1; + XtErrorMsg("noWidgetAncestor", "windowedAncestor", XtCXtToolkitError, + "Object \"%s\" does not have windowed ancestor", + ¶ms, &num_params); + } + + return object; +} + +#undef XtParent +Widget XtParent(widget) + Widget widget; +{ + /* Attempts to LockApp() here will generate endless recursive loops */ + return widget->core.parent; +} + +#undef XtName +String XtName(object) + Widget object; +{ + /* Attempts to LockApp() here will generate endless recursive loops */ + return XrmQuarkToString(object->core.xrm_name); +} + + +Boolean XtIsObject(object) + Widget object; +{ + WidgetClass wc; + String class_name; + + /* perform basic sanity checks */ + if (object->core.self != object || object->core.xrm_name == NULLQUARK) + return False; + + LOCK_PROCESS; + wc = object->core.widget_class; + if (wc->core_class.class_name == NULL || + wc->core_class.xrm_class == NULLQUARK || + (class_name = XrmClassToString(wc->core_class.xrm_class)) == NULL || + strcmp(wc->core_class.class_name, class_name) != 0) { + UNLOCK_PROCESS; + return False; + } + UNLOCK_PROCESS; + + if (XtIsWidget(object)) { + if (object->core.name == NULL || + (class_name = XrmNameToString(object->core.xrm_name)) == NULL || + strcmp(object->core.name, class_name) != 0) + return False; + } + return True; +} + +#if defined(WIN32) || defined(__EMX__) +static int access_file (path, pathbuf, len_pathbuf, pathret) + char* path; + char* pathbuf; + int len_pathbuf; + char** pathret; +{ + if (access (path, F_OK) == 0) { + if (strlen (path) < len_pathbuf) + *pathret = pathbuf; + else + *pathret = XtMalloc (strlen (path)); + if (*pathret) { + strcpy (*pathret, path); + return 1; + } + } + return 0; +} + +static int AccessFile (path, pathbuf, len_pathbuf, pathret) + char* path; + char* pathbuf; + int len_pathbuf; + char** pathret; +{ + unsigned long drives; + int i, len; + char* drive; + char buf[MAX_PATH]; + char* bufp; + + /* just try the "raw" name first and see if it works */ + if (access_file (path, pathbuf, len_pathbuf, pathret)) + return 1; + + /* try the places set in the environment */ + drive = getenv ("_XBASEDRIVE"); +#ifdef __EMX__ + if (!drive) + drive = getenv ("X11ROOT"); +#endif + if (!drive) + drive = "C:"; + len = strlen (drive) + strlen (path); + bufp = XtStackAlloc (len + 1, buf); + strcpy (bufp, drive); + strcat (bufp, path); + if (access_file (bufp, pathbuf, len_pathbuf, pathret)) { + XtStackFree (bufp, buf); + return 1; + } + +#ifndef __EMX__ + /* one last place to look */ + drive = getenv ("HOMEDRIVE"); + if (drive) { + len = strlen (drive) + strlen (path); + bufp = XtStackAlloc (len + 1, buf); + strcpy (bufp, drive); + strcat (bufp, path); + if (access_file (bufp, pathbuf, len_pathbuf, pathret)) { + XtStackFree (bufp, buf); + return 1; + } + } + + /* does OS/2 (with or with gcc-emx) have getdrives()? */ + /* tried everywhere else, go fishing */ + drives = _getdrives (); +#define C_DRIVE ('C' - 'A') +#define Z_DRIVE ('Z' - 'A') + for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */ + if ((1 << i) & drives) { + len = 2 + strlen (path); + bufp = XtStackAlloc (len + 1, buf); + *bufp = 'A' + i; + *(bufp + 1) = ':'; + *(bufp + 2) = '\0'; + strcat (bufp, path); + if (access_file (bufp, pathbuf, len_pathbuf, pathret)) { + XtStackFree (bufp, buf); + return 1; + } + } + } +#endif + return 0; +} +#endif + +static Boolean TestFile(path) + String path; +{ +#ifndef VMS + int ret = 0; + struct stat status; +#if defined(WIN32) || defined(__EMX__) /* || defined(OS2) */ + char buf[MAX_PATH]; + char* bufp; + int len; + UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS); + + if (AccessFile (path, buf, MAX_PATH, &bufp)) + path = bufp; + + (void) SetErrorMode (olderror); +#endif + ret = (access(path, R_OK) == 0 && /* exists and is readable */ + stat(path, &status) == 0 && /* get the status */ +#ifndef X_NOT_POSIX + S_ISDIR(status.st_mode) == 0); /* not a directory */ +#else + (status.st_mode & S_IFDIR) == 0); /* not a directory */ +#endif /* X_NOT_POSIX else */ +#if defined(WIN32) || defined(__EMX__) /* || defined(OS2) */ + XtStackFree ((XtPointer)bufp, buf); +#endif + return ret; +#else /* VMS */ + return TRUE; /* Who knows what to do here? */ +#endif /* VMS */ +} + +/* return of TRUE = resolved string fit, FALSE = didn't fit. Not + null-terminated and not collapsed if it didn't fit */ + +static Boolean Resolve(source, len, sub, num, buf, collapse) + register char *source; /* The source string */ + register int len; /* The length in bytes of *source */ + Substitution sub; /* Array of string values to substitute */ + Cardinal num; /* Number of substitution entries */ + char *buf; /* Where to put the resolved string; */ + char collapse; /* Character to collapse */ +{ + register int bytesLeft = PATH_MAX; + register char* bp = buf; +#ifndef DONT_COLLAPSE + Boolean atBeginning = TRUE; + Boolean prevIsCollapse = FALSE; + +#define PUT(ch) \ + { \ + if (--bytesLeft == 0) return FALSE; \ + if (prevIsCollapse) \ + if ((*bp = ch) != collapse) { \ + prevIsCollapse = FALSE; \ + bp++; \ + } \ + else bytesLeft++; \ + else if ((*bp++ = ch) == collapse && !atBeginning) \ + prevIsCollapse = TRUE; \ + } +#else /* DONT_COLLAPSE */ + +#define PUT(ch) \ + { \ + if (--bytesLeft == 0) return FALSE; \ + *bp++ = ch; \ + } +#endif /* DONT_COLLAPSE */ +#define escape '%' + + while (len--) { +#ifndef DONT_COLLAPSE + if (*source == collapse) { + PUT(*source); + source++; + continue; + } + else +#endif /* DONT_COLLAPSE */ + if (*source != escape) { + PUT(*source); + } + else { + source++; + if (len-- == 0) { + PUT(escape); + break; + } + + if (*source == ':' || *source == escape) + PUT(*source) + else { + /* Match the character against the match array */ + register int j; + + for (j = 0; j < num && sub[j].match != *source; j++) {} + + /* Substitute the substitution string */ + + if (j >= num) PUT(*source) + else if (sub[j].substitution != NULL) { + char *sp = sub[j].substitution; + while (*sp) { + PUT(*sp); + sp++; + } + } + } + } + source++; +#ifndef DONT_COLLAPSE + atBeginning = FALSE; +#endif /* DONT_COLLAPSE */ + } + PUT('\0'); + + return TRUE; +#undef PUT +#undef escape +} + + +#if NeedFunctionPrototypes +String XtFindFile( + _Xconst char* path, + Substitution substitutions, + Cardinal num_substitutions, + XtFilePredicate predicate + ) +#else +String XtFindFile(path, substitutions, num_substitutions, predicate) + String path; + Substitution substitutions; + Cardinal num_substitutions; + XtFilePredicate predicate; +#endif +{ + char *buf, *buf1, *buf2, *colon; + int len; + Boolean firstTime = TRUE; + + buf = buf1 = __XtMalloc((unsigned)PATH_MAX); + buf2 = __XtMalloc((unsigned)PATH_MAX); + + if (predicate == NULL) predicate = TestFile; + + while (1) { + colon = (String)path; + /* skip leading colons */ + while (*colon) { + if (*colon != ':') break; + colon++; + path++; + } + /* now look for an un-escaped colon */ + for ( ; *colon ; colon++) { + if (*colon == '%' && *(path+1)) { + colon++; /* bump it an extra time to skip %. */ + continue; + } + if (*colon == ':') + break; + } + len = colon - path; + if (Resolve(path, len, substitutions, num_substitutions, + buf, '/')) { + if (firstTime || strcmp(buf1,buf2) != 0) { +#ifdef XNL_DEBUG + printf("Testing file %s\n", buf); +#endif /* XNL_DEBUG */ + + /* Check out the file */ + if ((*predicate) (buf)) { + /* We've found it, return it */ +#ifdef XNL_DEBUG + printf("File found.\n"); +#endif /* XNL_DEBUG */ + if (buf == buf1) XtFree(buf2); + else XtFree(buf1); + return buf; + } + if (buf == buf1) + buf = buf2; + else + buf = buf1; + firstTime = FALSE; + } + } + + /* Nope...any more paths? */ + + if (*colon == '\0') break; + path = colon+1; + } + + /* No file found */ + + XtFree(buf1); + XtFree(buf2); + return NULL; +} + + +/* The implementation of this routine is operating system dependent */ +/* Should match the code in Xlib _XlcMapOSLocaleName */ + +static char *ExtractLocaleName(lang) + String lang; +{ + +#if defined(hpux) || defined(CSRG_BASED) || defined(sun) || defined(SVR4) || defined(sgi) || defined(__osf__) || defined(AIXV3) || defined(ultrix) || defined(WIN32) +#ifdef hpux +/* + * We need to discriminated between HPUX 9 and HPUX 10. The equivalent + * code in Xlib in SetLocale.c does include locale.h via X11/Xlocale.h. + */ +#include <locale.h> +#ifndef _LastCategory +/* HPUX 9 and earlier */ +#define SKIPCOUNT 2 +#define STARTCHAR ':' +#define ENDCHAR ';' +#else +/* HPUX 10 */ +#define ENDCHAR ' ' +#endif +#else +#ifdef ultrix +#define SKIPCOUNT 2 +#define STARTCHAR '\001' +#define ENDCHAR '\001' +#else +#ifdef WIN32 +#define SKIPCOUNT 1 +#define STARTCHAR '=' +#define ENDCHAR ';' +#define WHITEFILL +#else +#if defined(__osf__) || (defined(AIXV3) && !defined(AIXV4)) +#define STARTCHAR ' ' +#define ENDCHAR ' ' +#else +#if !defined(sun) || defined(SVR4) +#define STARTCHAR '/' +#endif +#define ENDCHAR '/' +#endif +#endif +#endif +#endif + + char *start; + char *end; + int len; +#ifdef SKIPCOUNT + int n; +#endif + static char* buf = NULL; + + start = lang; +#ifdef SKIPCOUNT + for (n = SKIPCOUNT; + --n >= 0 && start && (start = strchr (start, STARTCHAR)); + start++) + ; + if (!start) + start = lang; +#endif +#ifdef STARTCHAR + if (start && (start = strchr (start, STARTCHAR))) { + start++; +#endif + if (end = strchr (start, ENDCHAR)) { + len = end - start; + if (buf != NULL) XtFree (buf); + buf = XtMalloc (len + 1); + if (buf == NULL) return NULL; + strncpy(buf, start, len); + *(buf + len) = '\0'; +#ifdef WHITEFILL + for (start = buf; start = strchr(start, ' '); ) + *start++ = '-'; +#endif + return buf; + } +#ifdef STARTCHAR + } +#endif +#ifdef WHITEFILL + if (strchr(lang, ' ')) { + if (buf != NULL) XtFree (buf); + else buf = XtMalloc (strlen (lang) + 1); + if (buf == NULL) return NULL; + strcpy(buf, lang); + for (start = buf; start = strchr(start, ' '); ) + *start++ = '-'; + return buf; + } +#endif +#undef STARTCHAR +#undef ENDCHAR +#undef WHITEFILL +#endif + + return lang; +} + +static void FillInLangSubs(subs, pd) + Substitution subs; + XtPerDisplay pd; +{ + int len; + char *string, *p1, *p2, *p3; + char **rest; + char *ch; + + if (pd->language == NULL || + (pd->language != NULL && pd->language[0] == '\0')) { + subs[0].substitution = subs[1].substitution = + subs[2].substitution = subs[3].substitution = NULL; + return; + } + + string = ExtractLocaleName(pd->language); + + if (string == NULL || + (string != NULL && string[0] == '\0')) { + subs[0].substitution = subs[1].substitution = + subs[2].substitution = subs[3].substitution = NULL; + return; + } + + len = strlen(string) + 1; + subs[0].substitution = string; + p1 = subs[1].substitution = __XtMalloc((Cardinal) 3*len); + p2 = subs[2].substitution = subs[1].substitution + len; + p3 = subs[3].substitution = subs[2].substitution + len; + + /* Everything up to the first "_" goes into p1. From "_" to "." in + p2. The rest in p3. If no delimiters, all goes into p1. We + assume p1, p2, and p3 are large enough. */ + + *p1 = *p2 = *p3 = '\0'; + + ch = strchr(string, '_'); + if (ch != NULL) { + len = ch - string; + (void) strncpy(p1, string, len); + p1[len] = '\0'; + string = ch + 1; + rest = &p2; + } else rest = &p1; + + /* Rest points to where we put the first part */ + + ch = strchr(string, '.'); + if (ch != NULL) { + len = ch - string; + strncpy(*rest, string, len); + (*rest)[len] = '\0'; + (void) strcpy(p3, ch+1); + } else (void) strcpy(*rest, string); +} + +/* + * default path used if environment variable XFILESEARCHPATH + * is not defined. Also substitued for %D. + * The exact value should be documented in the implementation + * notes for any Xt implementation. + */ +#if NeedFunctionPrototypes +static char *implementation_default_path(void) +#else +static char *implementation_default_path() +#endif +{ +#ifdef WIN32 + /* if you know how to pass % thru the compiler let me know */ + static char xfilesearchpath[] = XFILESEARCHPATHDEFAULT; + static Bool fixed; + char *ch; + + if (!fixed) { + for (ch = xfilesearchpath; ch = strchr(ch, ';'); ch++) + *ch = '%'; + fixed = True; + } + return xfilesearchpath; +#else + return XFILESEARCHPATHDEFAULT; +#endif +} + + +static SubstitutionRec defaultSubs[] = { + {'N', NULL}, + {'T', NULL}, + {'S', NULL}, + {'C', NULL}, + {'L', NULL}, + {'l', NULL}, + {'t', NULL}, + {'c', NULL} +}; + + +#if NeedFunctionPrototypes +String XtResolvePathname( + Display *dpy, + _Xconst char* type, + _Xconst char* filename, + _Xconst char* suffix, + _Xconst char* path, + Substitution substitutions, + Cardinal num_substitutions, + XtFilePredicate predicate + ) +#else +String XtResolvePathname(dpy, type, filename, suffix, path, substitutions, + num_substitutions, predicate) + Display *dpy; + String type, filename, suffix, path; + Substitution substitutions; + Cardinal num_substitutions; + XtFilePredicate predicate; +#endif +{ + XtPerDisplay pd; + static char *defaultPath = NULL; + char *impl_default = implementation_default_path(); + int idef_len = strlen(impl_default); + char *massagedPath; + int bytesAllocd, bytesLeft; + char *ch, *result; + Substitution merged_substitutions; + XrmRepresentation db_type; + XrmValue value; + XrmName name_list[3]; + XrmClass class_list[3]; + Boolean pathMallocd = False; + + LOCK_PROCESS; + pd = _XtGetPerDisplay(dpy); + if (path == NULL) { +#ifndef VMS + if (defaultPath == NULL) { + defaultPath = getenv("XFILESEARCHPATH"); + if (defaultPath == NULL) + defaultPath = impl_default; + } + path = defaultPath; +#else + path = ""; /* NULL would kill us later */ +#endif /* VMS */ + } + + if (filename == NULL) { + filename = XrmClassToString(pd->class); + } + + bytesAllocd = bytesLeft = 1000; + massagedPath = ALLOCATE_LOCAL(bytesAllocd); + if (massagedPath == NULL) _XtAllocError(NULL); + + if (path[0] == ':') { + strcpy(massagedPath, "%N%S"); + ch = &massagedPath[4]; + bytesLeft -= 4; + } else ch = massagedPath; + + /* Insert %N%S between adjacent colons + * and default path for %D. + * Default path should not have any adjacent colons of its own. + */ + + while (*path != '\0') { + if (bytesLeft < idef_len) { + int bytesUsed = bytesAllocd - bytesLeft; + char *new; + bytesAllocd +=1000; + new = __XtMalloc((Cardinal) bytesAllocd); + strncpy( new, massagedPath, bytesUsed ); + ch = new + bytesUsed; + if (pathMallocd) + XtFree(massagedPath); + else + DEALLOCATE_LOCAL(massagedPath); + pathMallocd = True; + massagedPath = new; + bytesLeft = bytesAllocd - bytesUsed; + } + if (*path == '%' && *(path+1) == ':') { + *ch++ = '%'; + *ch++ = ':'; + path += 2; + bytesLeft -= 2; + continue; + } + if (*path == ':' && *(path+1) == ':') { + strcpy(ch, ":%N%S:"); + ch += 6; + bytesLeft -= 6; + while (*path == ':') path++; + continue; + } + if (*path == '%' && *(path+1) == 'D') { + strcpy(ch, impl_default); + ch += idef_len; + bytesLeft -= idef_len; + path += 2; + continue; + } + *ch++ = *path++; + bytesLeft--; + } + *ch = '\0'; +#ifdef XNL_DEBUG + printf("Massaged path: %s\n", massagedPath); +#endif /* XNL_DEBUG */ + + if (num_substitutions == 0) + merged_substitutions = defaultSubs; + else { + int i = XtNumber(defaultSubs); + Substitution sub, def; + merged_substitutions = sub = (Substitution) + ALLOCATE_LOCAL((unsigned)(num_substitutions+i)*sizeof(SubstitutionRec)); + if (sub == NULL) _XtAllocError(NULL); + for (def = defaultSubs; i--; sub++, def++) sub->match = def->match; + for (i = num_substitutions; i--; ) *sub++ = *substitutions++; + } + merged_substitutions[0].substitution = (String)filename; + merged_substitutions[1].substitution = (String)type; + merged_substitutions[2].substitution = (String)suffix; + name_list[0] = pd->name; + name_list[1] = XrmPermStringToQuark("customization"); + name_list[2] = NULLQUARK; + class_list[0] = pd->class; + class_list[1] = XrmPermStringToQuark("Customization"); + class_list[2] = NULLQUARK; + if (XrmQGetResource(XrmGetDatabase(dpy), name_list, class_list, + &db_type, &value) && + db_type == _XtQString) + merged_substitutions[3].substitution = (char *)value.addr; + else + merged_substitutions[3].substitution = NULL; + FillInLangSubs(&merged_substitutions[4], pd); + + result = XtFindFile(massagedPath, merged_substitutions, + num_substitutions + XtNumber(defaultSubs), + predicate); + + if (merged_substitutions[5].substitution != NULL) + XtFree( (XtPointer)merged_substitutions[5].substitution ); + + if (merged_substitutions != defaultSubs) + DEALLOCATE_LOCAL(merged_substitutions); + + if (pathMallocd) + XtFree(massagedPath); + else + DEALLOCATE_LOCAL(massagedPath); + + UNLOCK_PROCESS; + return result; +} + + +Boolean XtCallAcceptFocus(widget, time) + Widget widget; + Time *time; +{ + XtAcceptFocusProc ac; + Boolean retval; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + LOCK_PROCESS; + ac = XtClass(widget)->core_class.accept_focus; + UNLOCK_PROCESS; + + if (ac != NULL) + retval = (*ac) (widget, time); + else + retval = FALSE; + UNLOCK_APP(app); + return retval; +} + +#ifdef XT_GEO_TATTLER +/************************************************************************** + GeoTattler: This is used to debug Geometry management in Xt. + + It uses a pseudo resource XtNgeotattler. + + E.G. if those lines are found in the resource database: + + myapp*draw.XmScale.geoTattler: ON + *XmScrollBar.geoTattler:ON + *XmRowColumn.exit_button.geoTattler:ON + + then: + + all the XmScale children of the widget named draw, + all the XmScrollBars, + the widget named exit_button in any XmRowColumn + + will return True to the function IsTattled(), and will generate + outlined trace to stdout. + +*************************************************************************/ + +#define XtNgeoTattler "geoTattler" +#define XtCGeoTattler "GeoTattler" + +typedef struct { Boolean geo_tattler ;} GeoDataRec ; + +static XtResource geo_resources[] = { + { XtNgeoTattler, XtCGeoTattler, XtRBoolean, sizeof(Boolean), + XtOffsetOf(GeoDataRec, geo_tattler), + XtRImmediate, (XtPointer) False } +}; + +/************************************************************************ + This function uses XtGetSubresources to find out if a widget + needs to be geo-spied by the caller. */ +#if NeedFunctionPrototypes +static Boolean IsTattled (Widget widget) +#else +static Boolean IsTattled (widget) Widget widget ; +#endif +{ + GeoDataRec geo_data ; + + XtGetSubresources(widget, (XtPointer)&geo_data, + (String)NULL, (String)NULL, + geo_resources, XtNumber(geo_resources), + NULL, 0); + + return geo_data.geo_tattler; + +} /* IsTattled */ + +static int n_tab = 0 ; /* not MT for now */ + +void +#if NeedFunctionPrototypes +_XtGeoTab (int direction) /* +1 or -1 */ +#else +_XtGeoTab (direction) +int direction ; +#endif +{ + n_tab += direction ; +} + + +void +#if NeedVarargsPrototypes +_XtGeoTrace (Widget widget, ...) +#else +_XtGeoTrace (widget, va_alist) +Widget widget; +va_dcl +#endif +{ + va_list args; + char *fmt; + int i ; + if (IsTattled(widget)) { + Va_start(args, widget); + fmt = va_arg(args, char *); + for (i=0; i<n_tab; i++) printf(" "); + (void) vprintf(fmt, args); + va_end(args); + } +} + +#endif /* XT_GEO_TATTLER */ + diff --git a/src/Keyboard.c b/src/Keyboard.c new file mode 100644 index 0000000..5f1e84e --- /dev/null +++ b/src/Keyboard.c @@ -0,0 +1,854 @@ +/* $Xorg: Keyboard.c,v 1.5 2001/02/09 02:03:55 xorgcvs Exp $ */ + +/******************************************************** + +Copyright 1988 by Hewlett-Packard Company +Copyright 1987, 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the names of +Hewlett-Packard, Digital, or Sun not be used in advertising or +publicity pertaining to distribution of the software without specific, +written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +********************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" + +#include "PassivGraI.h" + +#define _GetWindowedAncestor(w) (XtIsWidget(w) ? w : _XtWindowedAncestor(w)) +extern void _XtFillAncestorList(); +extern void _XtSendFocusEvent(); + +/* InActiveSubtree cache of the current focus source and its ancestors */ +static Widget *pathTrace = NULL; +static int pathTraceDepth = 0; +static int pathTraceMax = 0; + +/* FindKeyDestination cache of focus destination and ancestors up to source */ +static Widget *pseudoTrace = NULL; +static int pseudoTraceDepth = 0; +static int pseudoTraceMax = 0; + +void _XtClearAncestorCache(widget) + Widget widget; +{ + /* the caller must lock the process lock */ + if (pathTraceDepth && pathTrace[0] == widget) + pathTraceDepth = 0; +} + +static XtServerGrabPtr CheckServerGrabs(event, trace, traceDepth) + XEvent *event; + Widget *trace; + Cardinal traceDepth; +{ + XtServerGrabPtr grab; + Cardinal i; + + for (i = traceDepth; i > 0; i--) + { + if ((grab = _XtCheckServerGrabsOnWidget(event, trace[i-1], KEYBOARD))) + return (grab); + } + return (XtServerGrabPtr)0; +} + +static Boolean IsParent(a, b) + Widget a, b; +{ + for (b = XtParent(b); b; b = XtParent(b)) { + if (b == a) return TRUE; + if (XtIsShell(b)) return FALSE; + } + return FALSE; +} + +#define RelRtn(lca, type) {*relTypeRtn = type; return lca;} + +static Widget CommonAncestor(a, b, relTypeRtn) + register Widget a, b; + XtGeneology * relTypeRtn; +{ + if (a == b) + { + RelRtn(a, XtMySelf) + } + else if (IsParent(a, b)) + { + RelRtn(a, XtMyAncestor) + } + else if (IsParent(b, a)) + { + RelRtn(b, XtMyDescendant) + } + else + for (b = XtParent(b); + b && !XtIsShell(b); + b = XtParent(b)) + if (IsParent(b, a)) + { + RelRtn(b, XtMyCousin) + } + RelRtn(NULL, XtUnrelated) +} +#undef RelRtn + + + + + +static Widget _FindFocusWidget(widget, trace, traceDepth, activeCheck, isTarget) + Widget widget; + Widget *trace; + int traceDepth; + Boolean activeCheck; + Boolean *isTarget; +{ + int src; + Widget dst; + XtPerWidgetInput pwi = NULL; + + /* For each ancestor, starting at the top, see if it's forwarded */ + + + /* first check the trace list till done or we go to branch */ + for (src = traceDepth-1, dst = widget; src > 0;) + { + if ((pwi = _XtGetPerWidgetInput(trace[src], FALSE))) + { + if (pwi->focusKid) + { + dst = pwi->focusKid; + for (src--; src > 0 && trace[src] != dst; src--) {} + } + else dst = trace[--src]; + } + else dst = trace[--src]; + } + + if (isTarget) { + if (pwi && pwi->focusKid == widget) + *isTarget = TRUE; + else + *isTarget = FALSE; + } + + if (!activeCheck) + while (XtIsWidget(dst) + && (pwi = _XtGetPerWidgetInput(dst, FALSE)) + && pwi->focusKid) + dst = pwi->focusKid; + + return dst; +} + + +static Widget FindFocusWidget(widget, pdi) + Widget widget; + XtPerDisplayInput pdi; +{ + if (pdi->focusWidget) + return pdi->focusWidget; + else + return _FindFocusWidget(widget, pdi->trace, pdi->traceDepth, FALSE, NULL); +} + +Widget XtGetKeyboardFocusWidget(widget) + Widget widget; +{ + XtPerDisplayInput pdi; + Widget retval; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + retval = FindFocusWidget(widget, pdi); + UNLOCK_APP(app); + return retval; +} + +static Boolean IsOutside(e, w) + XKeyEvent *e; + Widget w; +{ + Position left, right, top, bottom; + + /* + * if the pointer is outside the shell or inside + * the window try to see if it would recieve the + * focus + */ + XtTranslateCoords(w, 0, 0, &left, &top); + /* We need to take borders into consideration */ + left = left - w->core.border_width; + top = top - w->core.border_width; + right = left + w->core.width + w->core.border_width; + bottom = top + w->core.height + w->core.border_width; + + if ( + (e->x_root < left) || (e->y_root < top) || + (e->x_root > right) || (e->y_root > bottom)) + return TRUE; + else + return FALSE; +} + +static Widget FindKeyDestination(widget, event, + prevGrab, prevGrabType, + devGrab, devGrabType, + pdi) + Widget widget; + XKeyEvent *event; + XtServerGrabPtr prevGrab; + XtServerGrabType prevGrabType; + XtServerGrabPtr devGrab; + XtServerGrabType devGrabType; + XtPerDisplayInput pdi; +{ + + Widget dspWidget; + Widget focusWidget; + + LOCK_PROCESS; + dspWidget = + focusWidget = + pdi->focusWidget = + _GetWindowedAncestor(FindFocusWidget(widget, pdi)); + + + /* + * If a grab is active from a previous activation then dispatch + * based on owner_events ala protocol but with focus being + * determined by XtSetKeyboardFocus. + */ + if (IsAnyGrab(prevGrabType)) + { + if (prevGrab->ownerEvents) + dspWidget = focusWidget; + else + dspWidget = prevGrab->widget; + } + else + { + /* + * If the focus widget is the event widget or a descendant + * then we can avoid the rest of this. Else ugh... + */ + if (focusWidget != widget) + { + XtGeneology ewRelFw; /* relationship of event widget to + focusWidget */ + Widget lca; + + lca = CommonAncestor(widget, focusWidget, &ewRelFw); + + /* + * if the event widget is an ancestor of focus due to the pointer + * and/or the grab being in an ancestor and it's a passive grab + * send to grab widget. + * we are also dispatching to widget if ownerEvents and the event + * is outside the client + */ + if ((ewRelFw == XtMyAncestor) && + (devGrabType == XtPassiveServerGrab)) + { + if (IsOutside(event, widget) || + event->type ==KeyPress + ) + dspWidget = devGrab->widget; + } + else + { + /* + * if the grab widget is not an ancestor of the focus + * release the grab in order to avoid locking. There + * is a possible case in that ownerEvents true will fall + * through and if synch is set and the event widget + * could turn it off we'll lock. check for it ? why not + */ + if ((ewRelFw != XtMyAncestor) + && (devGrabType == XtPassiveServerGrab) + && (!IsAnyGrab(prevGrabType)) + ) + { + XtUngrabKeyboard(devGrab->widget, + event->time); + devGrabType = XtNoServerGrab; + } + /* + * if there isn't a grab with then check + * for a logical grab that would have been activated + * if the server was using Xt focus instead of server + * focus + */ + if ( + (event->type != KeyPress) || + (event->keycode == 0) /* Xlib XIM composed input */ + ) + dspWidget = focusWidget; + else + { + XtServerGrabPtr grab; + + if (!pseudoTraceDepth || + !(focusWidget == pseudoTrace[0]) || + !(lca == pseudoTrace[pseudoTraceDepth])) + { + /* + * fill ancestor list from lca + * (non-inclusive)to focusWidget by + * passing in lca as breakWidget + */ + _XtFillAncestorList(&pseudoTrace, + &pseudoTraceMax, + &pseudoTraceDepth, + focusWidget, + lca); + /* ignore lca */ + pseudoTraceDepth--; + } + if ((grab = CheckServerGrabs((XEvent*)event, + pseudoTrace, + pseudoTraceDepth))) + { + XtDevice device = &pdi->keyboard; + + device->grabType = XtPseudoPassiveServerGrab; + pdi->activatingKey = event->keycode; + device->grab = *grab; + + if (grab + ) + dspWidget = grab->widget; + else + dspWidget = focusWidget; + } + } + } + } + } + UNLOCK_PROCESS; + return dspWidget; +} + +Widget _XtProcessKeyboardEvent(event, widget, pdi) + XKeyEvent *event; + Widget widget; + XtPerDisplayInput pdi; +{ + XtDevice device = &pdi->keyboard; + XtServerGrabPtr newGrab, devGrab = &device->grab; + XtServerGrabRec prevGrabRec; + XtServerGrabType prevGrabType = device->grabType; + Widget dspWidget = NULL; + Boolean deactivateGrab = FALSE; + + prevGrabRec = *devGrab; + + switch (event->type) + { + case KeyPress: + { + if (event->keycode != 0 && /* Xlib XIM composed input */ + !IsServerGrab(device->grabType) && + (newGrab = CheckServerGrabs((XEvent*)event, + pdi->trace, + pdi->traceDepth))) + { + /* + * honor pseudo-grab from prior event by X + * unlocking keyboard. Not Xt Unlock ! + */ + if (IsPseudoGrab(prevGrabType)) + XUngrabKeyboard(XtDisplay(newGrab->widget), + event->time); + else + { + /* Activate the grab */ + device->grab = *newGrab; + pdi->activatingKey = event->keycode; + device->grabType = XtPassiveServerGrab; + } + } + } + break; + + case KeyRelease: + { + if (IsEitherPassiveGrab(device->grabType) && + (event->keycode == pdi->activatingKey)) + deactivateGrab = TRUE; + } + break; + } + dspWidget = FindKeyDestination(widget, event, + &prevGrabRec, prevGrabType, + devGrab, device->grabType, + pdi); + if (deactivateGrab) + { + /* Deactivate the grab */ + device->grabType = XtNoServerGrab; + pdi->activatingKey = 0; + } + return dspWidget; +} + +static Widget GetShell(widget) + Widget widget; +{ + Widget shell; + + for (shell = widget; + shell && !XtIsShell(shell); + shell = XtParent(shell)){} + return shell; +} + + +/* + * Check that widget really has Xt focus due to it having recieved an + * event + */ +typedef enum {NotActive = 0, IsActive, IsTarget} ActiveType; +static ActiveType InActiveSubtree(widget) + Widget widget; +{ + Boolean isTarget; + ActiveType retval; + + LOCK_PROCESS; + if (!pathTraceDepth || widget != pathTrace[0]) { + _XtFillAncestorList(&pathTrace, + &pathTraceMax, + &pathTraceDepth, + widget, + NULL); + } + if (widget == _FindFocusWidget(widget, + pathTrace, + pathTraceDepth, + TRUE, + &isTarget)) + retval = (isTarget ? IsTarget : IsActive); + else + retval = NotActive; + UNLOCK_PROCESS; + return retval; +} + + + + +/* ARGSUSED */ +void _XtHandleFocus(widget, client_data, event, cont) + Widget widget; + XtPointer client_data; /* child who wants focus */ + XEvent *event; + Boolean *cont; /* unused */ +{ + XtPerDisplayInput pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + XtPerWidgetInput pwi = (XtPerWidgetInput)client_data; + XtGeneology oldFocalPoint = pwi->focalPoint; + XtGeneology newFocalPoint = pwi->focalPoint; + + switch( event->type ) { + + case KeyPress: + case KeyRelease: + /* + * We're getting the keyevents used to guarantee propagating + * child interest ala ForwardEvent in R3 + */ + return; + + case EnterNotify: + case LeaveNotify: + + /* + * If operating in a focus driven model, then enter and + * leave events do not affect the keyboard focus. + */ + if ((event->xcrossing.detail != NotifyInferior) + && (event->xcrossing.focus)) + { + switch (oldFocalPoint) + { + case XtMyAncestor: + if (event->type == LeaveNotify) + newFocalPoint = XtUnrelated; + break; + case XtUnrelated: + if (event->type == EnterNotify) + newFocalPoint = XtMyAncestor; + break; + case XtMySelf: + break; + case XtMyDescendant: + break; + + } + } + break; + case FocusIn: + switch (event->xfocus.detail) + { + case NotifyNonlinear: + case NotifyAncestor: + case NotifyInferior: + newFocalPoint = XtMySelf; + break; + case NotifyNonlinearVirtual: + case NotifyVirtual: + newFocalPoint = XtMyDescendant; + break; + case NotifyPointer: + newFocalPoint = XtMyAncestor; + break; + } + break; + case FocusOut: + switch (event->xfocus.detail) + { + case NotifyPointer: + case NotifyNonlinear: + case NotifyAncestor: + case NotifyNonlinearVirtual: + case NotifyVirtual: + newFocalPoint = XtUnrelated; + break; + case NotifyInferior: + newFocalPoint = XtMyDescendant; + return; + break; + } + break; + } + + if (newFocalPoint != oldFocalPoint) + { + Boolean add; + Widget descendant = pwi->focusKid; + + pwi->focalPoint = newFocalPoint; + + if ((oldFocalPoint == XtUnrelated) && + InActiveSubtree(widget) != NotActive) + { + pdi->focusWidget = NULL; /* invalidate the cache */ + pwi->haveFocus = TRUE; + add = TRUE; + } + else if (newFocalPoint == XtUnrelated) + { + pdi->focusWidget = NULL; /* invalidate the cache */ + pwi->haveFocus = FALSE; + add = FALSE; + } + else + return; + + if (descendant) + { + if (add) + { + _XtSendFocusEvent(descendant, FocusIn); + } + else + { + _XtSendFocusEvent(descendant, FocusOut); + } + } + } +} + + +static void AddFocusHandler(widget, descendant, pwi, psi, pdi, oldEventMask) + Widget widget, descendant; + XtPerWidgetInput pwi; + XtPerWidgetInput psi; + XtPerDisplayInput pdi; + EventMask oldEventMask; +{ + EventMask eventMask, targetEventMask; + Widget target; + + /* + * widget must now select for key events if the descendant is + * interested in them. + * + * shell borders are not occluded by the child, they're occluded + * by reparenting window managers. !!! + */ + target = descendant ? _GetWindowedAncestor(descendant) : NULL; + targetEventMask = XtBuildEventMask(target); + eventMask = targetEventMask & (KeyPressMask | KeyReleaseMask); + eventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask; + + if (oldEventMask) { + oldEventMask &= KeyPressMask | KeyReleaseMask; + oldEventMask |= FocusChangeMask | EnterWindowMask | LeaveWindowMask; + + if (oldEventMask != eventMask) + XtRemoveEventHandler(widget, (oldEventMask & ~eventMask), + False, _XtHandleFocus, (XtPointer)pwi); + } + + if (oldEventMask != eventMask) + XtAddEventHandler(widget, eventMask, False, + _XtHandleFocus, (XtPointer)pwi); + + /* What follows is too much grief to go through if the + * target doesn't actually care about focus change events, + * so just invalidate the focus cache & refill it when + * the next input event actually arrives. + */ + + if (!(targetEventMask & FocusChangeMask)) { + pdi->focusWidget = NULL; + return; + } + + if (XtIsRealized(widget) && !pwi->haveFocus) { + if (psi->haveFocus) { + Window root, child; + int root_x, root_y, win_x, win_y; + int left, right, top, bottom; + unsigned int modMask; + ActiveType act; + + /* + * If the shell has the focus but the source widget + * doesn't, it may only be because the source widget + * wasn't previously tracking focus or crossing events. + * If the target wants focus events, we have to + * now determine whether the source has the focus. + */ + + if ((act = InActiveSubtree(widget)) == IsTarget) + pwi->haveFocus = TRUE; + else if (act == IsActive) { + /* + * An ancestor contains the focus, so if source + * contains the pointer, then source has the focus. + */ + + if (XQueryPointer(XtDisplay(widget), XtWindow(widget), + &root, &child, + &root_x, &root_y, &win_x, &win_y, &modMask)) + { + /* We need to take borders into consideration */ + left = top = -((int) widget->core.border_width); + right = (int) (widget->core.width + (widget->core.border_width << 1)); + bottom = (int) (widget->core.height + (widget->core.border_width << 1)); + + if (win_x >= left && win_x < right && + win_y >= top && win_y < bottom) + pwi->haveFocus = TRUE; + } + } + } + } + if (pwi->haveFocus) { + pdi->focusWidget = NULL; /* invalidate the cache */ + _XtSendFocusEvent(target, FocusIn); + } +} + + +/* ARGSUSED */ +static void QueryEventMask(widget, client_data, event, cont) + Widget widget; /* child who gets focus */ + XtPointer client_data; /* ancestor giving it */ + XEvent *event; + Boolean *cont; /* unused */ +{ + /* widget was once the target of an XtSetKeyboardFocus but + * was unrealized at the time. Make sure ancestor still wants + * focus set here then install the handler now that we know the + * complete event mask. + */ + Widget ancestor = (Widget)client_data; + XtPerWidgetInput pwi = _XtGetPerWidgetInput(ancestor, FALSE); + Widget target = pwi->queryEventDescendant; + + /* use of 'target' is non-standard hackery; allows focus to non-widget */ + if (pwi && (pwi->focusKid == target)) { + AddFocusHandler(ancestor, target, pwi, + _XtGetPerWidgetInput(GetShell(ancestor), TRUE), + _XtGetPerDisplayInput(XtDisplay(ancestor)), + (EventMask)0); + } + XtRemoveEventHandler(widget, XtAllEvents, True, + QueryEventMask, client_data); + pwi->map_handler_added = FALSE; +} + + +/* ARGSUSED */ +static void FocusDestroyCallback(widget, closure, call_data) + Widget widget; + XtPointer closure; /* Widget */ + XtPointer call_data; +{ + XtSetKeyboardFocus((Widget)closure, None); +} + +void XtSetKeyboardFocus(widget, descendant) + Widget widget; + Widget descendant; +{ + XtPerDisplayInput pdi; + XtPerWidgetInput pwi; + Widget oldDesc, oldTarget, target, hookobj; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + LOCK_PROCESS; + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + pwi = _XtGetPerWidgetInput(widget, TRUE); + oldDesc = pwi->focusKid; + + if (descendant == widget) descendant = (Widget)None; + + target = descendant ? _GetWindowedAncestor(descendant) : NULL; + oldTarget = oldDesc ? _GetWindowedAncestor(oldDesc) : NULL; + + if (descendant != oldDesc) { + + /* update the forward path */ + pwi->focusKid = descendant; + + + /* all the rest handles focus ins and focus outs and misc gunk */ + + if (oldDesc) { + /* invalidate FindKeyDestination's ancestor list */ + if (pseudoTraceDepth && oldTarget == pseudoTrace[0]) + pseudoTraceDepth = 0; + + XtRemoveCallback(oldDesc, XtNdestroyCallback, + FocusDestroyCallback, (XtPointer)widget); + + if (!oldTarget->core.being_destroyed) { + if (pwi->map_handler_added) { + XtRemoveEventHandler(oldTarget, XtAllEvents, True, + QueryEventMask, (XtPointer)widget); + pwi->map_handler_added = FALSE; + } + if (pwi->haveFocus) { + _XtSendFocusEvent( oldTarget, FocusOut); + } + } + else if (pwi->map_handler_added) { + pwi->map_handler_added = FALSE; + } + + if (pwi->haveFocus) + pdi->focusWidget = NULL; /* invalidate cache */ + + /* + * If there was a forward path then remove the handler if + * the path is being set to null and it isn't a shell. + * shells always have a handler for tracking focus for the + * hierarchy. + * + * Keep the pwi record on the assumption that the client + * will continue to dynamically assign focus for this widget. + */ + if (!XtIsShell(widget) && !descendant) { + XtRemoveEventHandler(widget, XtAllEvents, True, + _XtHandleFocus, (XtPointer)pwi); + pwi->haveFocus = FALSE; + } + } + + if (descendant) { + Widget shell = GetShell(widget); + XtPerWidgetInput psi = _XtGetPerWidgetInput(shell, TRUE); + XtAddCallback (descendant, XtNdestroyCallback, + FocusDestroyCallback, (XtPointer) widget); + + AddFocusHandler(widget, descendant, pwi, psi, pdi, + oldTarget ? XtBuildEventMask(oldTarget) : 0); + + if (widget != shell) + XtAddEventHandler( + shell, + FocusChangeMask | EnterWindowMask | LeaveWindowMask, + False, + _XtHandleFocus, + (XtPointer)psi + ); + + if (! XtIsRealized(target)) { + XtAddEventHandler(target, (EventMask)StructureNotifyMask, + False, QueryEventMask, (XtPointer)widget); + pwi->map_handler_added = TRUE; + pwi->queryEventDescendant = descendant; + } + } + } + hookobj = XtHooksOfDisplay(XtDisplay(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHsetKeyboardFocus; + call_data.widget = widget; + call_data.event_data = (XtPointer) descendant; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_PROCESS; + UNLOCK_APP(app); +} diff --git a/src/Manage.c b/src/Manage.c new file mode 100644 index 0000000..98ad68e --- /dev/null +++ b/src/Manage.c @@ -0,0 +1,498 @@ +/* $Xorg: Manage.c,v 1.4 2001/02/09 02:03:55 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" + +static String XtNinvalidChild = "invalidChild"; +static String XtNxtUnmanageChildren = "xtUnmanageChildren"; +static String XtNxtManageChildren = "xtManageChildren"; +static String XtNxtChangeManagedSet = "xtChangeManagedSet"; + +static void UnmanageChildren(children, num_children, parent, num_unique_children, call_change_managed, caller_func) + WidgetList children; + Cardinal num_children; + Widget parent; + Cardinal* num_unique_children; + Boolean call_change_managed; + String caller_func; +{ + Widget child; + Cardinal i; + XtWidgetProc change_managed; + Bool parent_realized; + + *num_unique_children = 0; + + if (XtIsComposite((Widget) parent)) { + LOCK_PROCESS; + change_managed = ((CompositeWidgetClass) parent->core.widget_class) + ->composite_class.change_managed; + UNLOCK_PROCESS; + parent_realized = XtIsRealized((Widget)parent); + } else { + XtAppErrorMsg(XtWidgetToApplicationContext((Widget)parent), + "invalidParent",caller_func, XtCXtToolkitError, + "Attempt to unmanage a child when parent is not Composite", + (String *) NULL, (Cardinal *) NULL); + } + + for (i = 0; i < num_children; i++) { + child = children[i]; + if (child == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext(parent), + XtNinvalidChild,caller_func,XtCXtToolkitError, + "Null child passed to XtUnmanageChildren", + (String *)NULL, (Cardinal *)NULL); + return; + } + if (child->core.parent != parent) { + XtAppWarningMsg(XtWidgetToApplicationContext(parent), + "ambiguousParent",caller_func,XtCXtToolkitError, + "Not all children have same parent in UnmanageChildren", + (String *)NULL, (Cardinal *)NULL); + } else + if (child->core.managed) { + (*num_unique_children)++; + CALLGEOTAT(_XtGeoTrace(child,"Child \"%s\" is marked unmanaged\n", + XtName(child))); + child->core.managed = FALSE; + if (XtIsWidget(child) + && XtIsRealized(child) + && child->core.mapped_when_managed) + XtUnmapWidget(child); + else + { /* RectObj child */ + Widget pw = child->core.parent; + RectObj r = (RectObj) child; + while ((pw!=NULL) && (!XtIsWidget(pw))) pw = pw->core.parent; + if ((pw!=NULL) && XtIsRealized (pw)) + XClearArea (XtDisplay (pw), XtWindow (pw), + r->rectangle.x, r->rectangle.y, + r->rectangle.width + (r->rectangle.border_width << 1), + r->rectangle.height + (r->rectangle.border_width << 1), + TRUE); + } + + } + } + if (call_change_managed && *num_unique_children != 0 && + change_managed != NULL && parent_realized) { + CALLGEOTAT(_XtGeoTrace((Widget)parent, + "Call parent: \"%s\"[%d,%d]'s changemanaged proc\n", + XtName((Widget)parent), + parent->core.width,parent->core.height)); + (*change_managed) (parent); + } +} /* UnmanageChildren */ + +void XtUnmanageChildren (children, num_children) + WidgetList children; + Cardinal num_children; +{ + Widget parent, hookobj; + Cardinal ii; + XtAppContext app; + + if (num_children == 0) return; + if (children[0] == NULL) { + XtWarningMsg(XtNinvalidChild,XtNxtUnmanageChildren,XtCXtToolkitError, + "Null child found in argument list to unmanage", + (String *)NULL, (Cardinal *)NULL); + return; + } + app = XtWidgetToApplicationContext(children[0]); + LOCK_APP(app); + parent = children[0]->core.parent; + if (parent->core.being_destroyed) { + UNLOCK_APP(app); + return; + } + UnmanageChildren(children, num_children, parent, &ii, + (Boolean)True, XtNxtUnmanageChildren); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(children[0])); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHunmanageChildren; + call_data.widget = parent; + call_data.event_data = (XtPointer) children; + call_data.num_event_data = num_children; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} /* XtUnmanageChildren */ + +void XtUnmanageChild(child) + Widget child; +{ + XtUnmanageChildren(&child, (Cardinal)1); +} /* XtUnmanageChild */ + + +static void ManageChildren(children, num_children, parent, call_change_managed, caller_func) + WidgetList children; + Cardinal num_children; + Widget parent; + Boolean call_change_managed; + String caller_func; +{ +#define MAXCHILDREN 100 + Widget child; + Cardinal num_unique_children, i; + XtWidgetProc change_managed; + WidgetList unique_children; + Widget cache[MAXCHILDREN]; + Bool parent_realized; + + if (XtIsComposite((Widget) parent)) { + LOCK_PROCESS; + change_managed = ((CompositeWidgetClass) parent->core.widget_class) + ->composite_class.change_managed; + UNLOCK_PROCESS; + parent_realized = XtIsRealized((Widget)parent); + } else { + XtAppErrorMsg(XtWidgetToApplicationContext((Widget)parent), + "invalidParent",caller_func, XtCXtToolkitError, + "Attempt to manage a child when parent is not Composite", + (String *) NULL, (Cardinal *) NULL); + } + + /* Construct new list of children that really need to be operated upon. */ + if (num_children <= MAXCHILDREN) { + unique_children = cache; + } else { + unique_children = (WidgetList) __XtMalloc(num_children * sizeof(Widget)); + } + num_unique_children = 0; + for (i = 0; i < num_children; i++) { + child = children[i]; + if (child == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext((Widget)parent), + XtNinvalidChild,caller_func,XtCXtToolkitError, + "null child passed to ManageChildren", + (String *)NULL, (Cardinal *)NULL); + if (unique_children != cache) XtFree((char *) unique_children); + return; + } +#ifdef DEBUG + if (!XtIsRectObj(child)) { + String params[2]; + Cardinal num_params = 2; + params[0] = XtName(child); + params[1] = child->core.widget_class->core_class.class_name; + XtAppWarningMsg(XtWidgetToApplicationContext((Widget)parent), + "notRectObj",caller_func,XtCXtToolkitError, + "child \"%s\", class %s is not a RectObj", + params, &num_params); + continue; + } +#endif /*DEBUG*/ + if (child->core.parent != parent) { + XtAppWarningMsg(XtWidgetToApplicationContext((Widget)parent), + "ambiguousParent",caller_func,XtCXtToolkitError, + "Not all children have same parent in XtManageChildren", + (String *)NULL, (Cardinal *)NULL); + } else if (! child->core.managed && !child->core.being_destroyed) { + unique_children[num_unique_children++] = child; + CALLGEOTAT(_XtGeoTrace(child, + "Child \"%s\"[%d,%d] is marked managed\n", + XtName(child), + child->core.width,child->core.height)); + child->core.managed = TRUE; + } + } + + if ((call_change_managed || num_unique_children != 0) && parent_realized) { + /* Compute geometry of new managed set of children. */ + if (change_managed != NULL) { + CALLGEOTAT(_XtGeoTrace((Widget)parent, + "Call parent: \"%s\"[%d,%d]'s changemanaged\n", + XtName((Widget)parent), + parent->core.width,parent->core.height)); + (*change_managed) ((Widget)parent); + } + + /* Realize each child if necessary, then map if necessary */ + for (i = 0; i < num_unique_children; i++) { + child = unique_children[i]; + if (XtIsWidget(child)) { + if (! XtIsRealized(child)) XtRealizeWidget(child); + if (child->core.mapped_when_managed) XtMapWidget(child); + } else { /* RectObj child */ + Widget pw = child->core.parent; + RectObj r = (RectObj) child; + while ((pw!=NULL) && (!XtIsWidget(pw))) + pw = pw->core.parent; + if (pw != NULL) + XClearArea (XtDisplay (pw), XtWindow (pw), + r->rectangle.x, r->rectangle.y, + r->rectangle.width + (r->rectangle.border_width << 1), + r->rectangle.height + (r->rectangle.border_width << 1), + TRUE); + } + } + } + + if (unique_children != cache) XtFree((char *) unique_children); +} /* ManageChildren */ + +void XtManageChildren(children, num_children) + WidgetList children; + Cardinal num_children; +{ + Widget parent, hookobj; + XtAppContext app; + + if (num_children == 0) return; + if (children[0] == NULL) { + XtWarningMsg(XtNinvalidChild, XtNxtManageChildren, XtCXtToolkitError, + "null child passed to XtManageChildren", + (String*)NULL, (Cardinal*)NULL); + return; + } + app = XtWidgetToApplicationContext(children[0]); + LOCK_APP(app); + parent = children[0]->core.parent; + if (parent->core.being_destroyed) { + UNLOCK_APP(app); + return; + } + ManageChildren(children, num_children, parent, (Boolean)False, + XtNxtManageChildren); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(children[0])); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHmanageChildren; + call_data.widget = parent; + call_data.event_data = (XtPointer) children; + call_data.num_event_data = num_children; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} /* XtManageChildren */ + +void XtManageChild(child) + Widget child; +{ + XtManageChildren(&child, (Cardinal) 1); +} /* XtManageChild */ + + +#if NeedFunctionPrototypes +void XtSetMappedWhenManaged( + Widget widget, + _XtBoolean mapped_when_managed + ) +#else +void XtSetMappedWhenManaged(widget, mapped_when_managed) + Widget widget; + Boolean mapped_when_managed; +#endif +{ + Widget hookobj; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + if (widget->core.mapped_when_managed == mapped_when_managed) { + UNLOCK_APP(app); + return; + } + widget->core.mapped_when_managed = mapped_when_managed; + + hookobj = XtHooksOfDisplay(XtDisplay(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHsetMappedWhenManaged; + call_data.widget = widget; + call_data.event_data = (XtPointer) mapped_when_managed; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + + if (! XtIsManaged(widget)) { + UNLOCK_APP(app); + return; + } + + if (mapped_when_managed) { + /* Didn't used to be mapped when managed. */ + if (XtIsRealized(widget)) XtMapWidget(widget); + } else { + /* Used to be mapped when managed. */ + if (XtIsRealized(widget)) XtUnmapWidget(widget); + } + UNLOCK_APP(app); +} /* XtSetMappedWhenManaged */ + + +#if NeedFunctionPrototypes +void XtChangeManagedSet( + WidgetList unmanage_children, + Cardinal num_unmanage, + XtDoChangeProc do_change_proc, + XtPointer client_data, + WidgetList manage_children, + Cardinal num_manage +) +#else +void XtChangeManagedSet(unmanage_children, num_unmanage, do_change_proc, + client_data, manage_children, num_manage) + WidgetList unmanage_children; + Cardinal num_unmanage; + XtDoChangeProc do_change_proc; + XtPointer client_data; + WidgetList manage_children; + Cardinal num_manage; +#endif +{ + WidgetList childp; + Widget parent; + int i; + Cardinal some_unmanaged; + Boolean call_out; + CompositeClassExtension ext; + XtAppContext app; + Widget hookobj; + XtChangeHookDataRec call_data; + + if (num_unmanage == 0 && num_manage == 0) + return; + + /* specification doesn't state that library will check for NULL in list */ + + childp = num_unmanage ? unmanage_children : manage_children; + app = XtWidgetToApplicationContext(*childp); + LOCK_APP(app); + + parent = XtParent(*childp); + childp = unmanage_children; + for (i = num_unmanage; --i >= 0 && XtParent(*childp) == parent; childp++); + call_out = (i >= 0); + childp = manage_children; + for (i = num_manage; --i >= 0 && XtParent(*childp) == parent; childp++); + if (call_out || i >= 0) { + XtAppWarningMsg(app, "ambiguousParent", XtNxtChangeManagedSet, + XtCXtToolkitError, "Not all children have same parent", + (String *)NULL, (Cardinal *)NULL); + } + if (! XtIsComposite(parent)) { + UNLOCK_APP(app); + XtAppErrorMsg(app, "invalidParent", XtNxtChangeManagedSet, + XtCXtToolkitError, + "Attempt to manage a child when parent is not Composite", + (String *) NULL, (Cardinal *) NULL); + } + if (parent->core.being_destroyed) { + UNLOCK_APP(app); + return; + } + + call_out = False; + if (do_change_proc) { + ext = (CompositeClassExtension) + XtGetClassExtension(parent->core.widget_class, + XtOffsetOf(CompositeClassRec, + composite_class.extension), + NULLQUARK, XtCompositeExtensionVersion, + sizeof(CompositeClassExtensionRec)); + if (!ext || !ext->allows_change_managed_set) + call_out = True; + } + + UnmanageChildren(unmanage_children, num_unmanage, parent, + &some_unmanaged, call_out, XtNxtChangeManagedSet); + + hookobj = XtHooksOfDisplay(XtDisplay(parent)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + call_data.type = XtHunmanageSet; + call_data.widget = parent; + call_data.event_data = (XtPointer) unmanage_children; + call_data.num_event_data = num_unmanage; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer) &call_data); + } + + if (do_change_proc) + (*do_change_proc)(parent, unmanage_children, &num_unmanage, + manage_children, &num_manage, client_data); + + call_out = (some_unmanaged && !call_out); + ManageChildren(manage_children, num_manage, parent, call_out, + XtNxtChangeManagedSet); + + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + call_data.type = XtHmanageSet; + call_data.event_data = (XtPointer) manage_children; + call_data.num_event_data = num_manage; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer) &call_data); + } + UNLOCK_APP(app); +} /* XtChangeManagedSet */ diff --git a/src/NextEvent.c b/src/NextEvent.c new file mode 100644 index 0000000..0e6c45f --- /dev/null +++ b/src/NextEvent.c @@ -0,0 +1,1643 @@ +/* $Xorg: NextEvent.c,v 1.11 2001/03/19 14:27:27 coskrey Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include <stdio.h> +#include <errno.h> +#ifdef X_NOT_STDC_ENV +extern int errno; +#endif + +static TimerEventRec* freeTimerRecs; +static WorkProcRec* freeWorkRecs; +static SignalEventRec* freeSignalRecs; + +/* Some systems running NTP daemons are known to return strange usec + * values from gettimeofday. + */ + +#ifndef NEEDS_NTPD_FIXUP +# if defined(sun) || defined(MOTOROLA) || defined(sco324) || (defined(__osf__) && defined(__alpha)) +# define NEEDS_NTPD_FIXUP 1 +# else +# define NEEDS_NTPD_FIXUP 0 +# endif +#endif + +#if NEEDS_NTPD_FIXUP +#define FIXUP_TIMEVAL(t) { \ + while ((t).tv_usec >= 1000000) { \ + (t).tv_usec -= 1000000; \ + (t).tv_sec++; \ + } \ + while ((t).tv_usec < 0) { \ + if ((t).tv_sec > 0) { \ + (t).tv_usec += 1000000; \ + (t).tv_sec--; \ + } else { \ + (t).tv_usec = 0; \ + break; \ + } \ + }} +#else +#define FIXUP_TIMEVAL(t) +#endif /*NEEDS_NTPD_FIXUP*/ + +/* + * Private routines + */ +#define ADD_TIME(dest, src1, src2) { \ + if(((dest).tv_usec = (src1).tv_usec + (src2).tv_usec) >= 1000000) {\ + (dest).tv_usec -= 1000000;\ + (dest).tv_sec = (src1).tv_sec + (src2).tv_sec + 1 ; \ + } else { (dest).tv_sec = (src1).tv_sec + (src2).tv_sec ; \ + if(((dest).tv_sec >= 1) && (((dest).tv_usec <0))) { \ + (dest).tv_sec --;(dest).tv_usec += 1000000; } } } + + +#define TIMEDELTA(dest, src1, src2) { \ + if(((dest).tv_usec = (src1).tv_usec - (src2).tv_usec) < 0) {\ + (dest).tv_usec += 1000000;\ + (dest).tv_sec = (src1).tv_sec - (src2).tv_sec - 1;\ + } else (dest).tv_sec = (src1).tv_sec - (src2).tv_sec; } + +#define IS_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \ + || (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec > (t1).tv_usec))) + +#define IS_AT_OR_AFTER(t1, t2) (((t2).tv_sec > (t1).tv_sec) \ + || (((t2).tv_sec == (t1).tv_sec)&& ((t2).tv_usec >= (t1).tv_usec))) + +#ifdef USE_POLL +#ifndef XT_DEFAULT_FDLIST_SIZE +#define XT_DEFAULT_FDLIST_SIZE 32 +#endif +#endif + +static void AdjustHowLong (howlong, start_time) + unsigned long *howlong; + struct timeval *start_time; +{ + struct timeval new_time, time_spent, lstart_time; + + lstart_time = *start_time; + X_GETTIMEOFDAY (&new_time); + FIXUP_TIMEVAL(new_time); + TIMEDELTA(time_spent, new_time, lstart_time); + if(*howlong <= (time_spent.tv_sec*1000+time_spent.tv_usec/1000)) + *howlong = (unsigned long)0; /* Timed out */ + else + *howlong -= (time_spent.tv_sec*1000+time_spent.tv_usec/1000); +} + +typedef struct { + struct timeval cur_time; + struct timeval start_time; + struct timeval wait_time; + struct timeval new_time; + struct timeval time_spent; + struct timeval max_wait_time; +#ifndef USE_POLL + struct timeval *wait_time_ptr; +#else + int poll_wait; +#endif +} wait_times_t, *wait_times_ptr_t; + +static struct timeval zero_time = { 0 , 0}; +#ifndef USE_POLL +static fd_set zero_fd = { 0 }; +#else +#define X_BLOCK -1 +#define X_DONT_BLOCK 0 +#endif + +static void InitTimes (block, howlong, wt) + Boolean block; + unsigned long* howlong; + wait_times_ptr_t wt; +{ + if (block) { + X_GETTIMEOFDAY (&wt->cur_time); + FIXUP_TIMEVAL(wt->cur_time); + wt->start_time = wt->cur_time; + if(howlong == NULL) { /* special case for ever */ +#ifndef USE_POLL + wt->wait_time_ptr = NULL; +#else + wt->poll_wait = X_BLOCK; +#endif + } else { /* block until at most */ + wt->max_wait_time.tv_sec = *howlong/1000; + wt->max_wait_time.tv_usec = (*howlong %1000)*1000; +#ifndef USE_POLL + wt->wait_time_ptr = &wt->max_wait_time; +#else + wt->poll_wait = *howlong; +#endif + } + } else { /* don't block */ + wt->max_wait_time = zero_time; +#ifndef USE_POLL + wt->wait_time_ptr = &wt->max_wait_time; +#else + wt->poll_wait = X_DONT_BLOCK; +#endif + } +} + +typedef struct { +#ifndef USE_POLL + fd_set rmask, wmask, emask; + int nfds; +#else + struct pollfd* fdlist; + struct pollfd* stack; + int fdlistlen, num_dpys; +#endif +} wait_fds_t, *wait_fds_ptr_t; + +static void InitFds (app, ignoreEvents, ignoreInputs, wf) + XtAppContext app; + Boolean ignoreEvents; + Boolean ignoreInputs; + wait_fds_ptr_t wf; +{ + int ii; + app->rebuild_fdlist = FALSE; +#ifndef USE_POLL + wf->nfds = app->fds.nfds; + if( !ignoreInputs ) { + wf->rmask = app->fds.rmask; + wf->wmask = app->fds.wmask; + wf->emask = app->fds.emask; + } else + wf->rmask = wf->wmask = wf->emask = zero_fd; + + if (!ignoreEvents) + for (ii = 0; ii < app->count; ii++) { + FD_SET (ConnectionNumber(app->list[ii]), &wf->rmask); + } +#else +#ifndef POLLRDNORM +#define POLLRDNORM 0 +#endif + +#ifndef POLLRDBAND +#define POLLRDBAND 0 +#endif + +#ifndef POLLWRNORM +#define POLLWRNORM 0 +#endif + +#ifndef POLLWRBAND +#define POLLWRBAND 0 +#endif + +#define XPOLL_READ (POLLIN|POLLRDNORM|POLLPRI|POLLRDBAND) +#define XPOLL_WRITE (POLLOUT|POLLWRNORM|POLLWRBAND) +#define XPOLL_EXCEPT 0 + + if (!ignoreEvents) + wf->fdlistlen = wf->num_dpys = app->count; + else + wf->fdlistlen = wf->num_dpys = 0; + + if (!ignoreInputs && app->input_list != NULL) { + int ii; + for (ii = 0; ii < (int) app->input_max; ii++) + if (app->input_list[ii] != NULL) + wf->fdlistlen++; + } + + if (!wf->fdlist || wf->fdlist == wf->stack) { + wf->fdlist = (struct pollfd*) + XtStackAlloc (sizeof (struct pollfd) * wf->fdlistlen, wf->stack); + } else { + wf->fdlist = (struct pollfd*) + XtRealloc ((char*) wf->fdlist, + sizeof (struct pollfd) * wf->fdlistlen); + } + + if (wf->fdlistlen) { + struct pollfd* fdlp = wf->fdlist; + InputEvent* iep; + + if (!ignoreEvents) + for (ii = 0 ; ii < wf->num_dpys; ii++, fdlp++) { + fdlp->fd = ConnectionNumber (app->list[ii]); + fdlp->events = POLLIN; + } + if (!ignoreInputs && app->input_list != NULL) + for (ii = 0; ii < app->input_max; ii++) + if (app->input_list[ii] != NULL) { + iep = app->input_list[ii]; + fdlp->fd = ii; + fdlp->events = 0; + for ( ; iep; iep = iep->ie_next) { + if (iep->ie_condition & XtInputReadMask) + fdlp->events |= XPOLL_READ; + if (iep->ie_condition & XtInputWriteMask) + fdlp->events |= XPOLL_WRITE; + if (iep->ie_condition & XtInputExceptMask) + fdlp->events |= XPOLL_EXCEPT; + } + fdlp++; + } + } +#endif +} + +static void AdjustTimes (app, block, howlong, ignoreTimers, wt) + XtAppContext app; + Boolean block; + unsigned long* howlong; + Boolean ignoreTimers; + wait_times_ptr_t wt; +{ + if (app->timerQueue != NULL && !ignoreTimers && block) { + if (IS_AFTER (wt->cur_time, app->timerQueue->te_timer_value)) { + TIMEDELTA (wt->wait_time, app->timerQueue->te_timer_value, wt->cur_time); + if (howlong == NULL || IS_AFTER (wt->wait_time, wt->max_wait_time)) +#ifndef USE_POLL + wt->wait_time_ptr = &wt->wait_time; + else + wt->wait_time_ptr = &wt->max_wait_time; + } else + wt->wait_time_ptr = &zero_time; + } +#else + wt->poll_wait = wt->wait_time.tv_sec * 1000 + wt->wait_time.tv_usec / 1000; + else + wt->poll_wait = wt->max_wait_time.tv_sec * 1000 + wt->max_wait_time.tv_usec / 1000; + } else + wt->poll_wait = X_DONT_BLOCK; + } +#endif +} + +static int IoWait (wt, wf) + wait_times_ptr_t wt; + wait_fds_ptr_t wf; +{ +#ifndef USE_POLL + return Select (wf->nfds, &wf->rmask, &wf->wmask, &wf->emask, + wt->wait_time_ptr); +#else + return poll (wf->fdlist, wf->fdlistlen, wt->poll_wait); +#endif +} + +static void FindInputs (app, wf, nfds, ignoreEvents, ignoreInputs, dpy_no, found_input) + XtAppContext app; + wait_fds_ptr_t wf; + int nfds; + Boolean ignoreEvents; + Boolean ignoreInputs; + int* dpy_no; + int* found_input; +{ + XtInputMask condition; + InputEvent *ep; + int ii; +#ifndef USE_POLL /* { check ready file descriptors block */ +#ifdef XTHREADS + fd_set rmask; +#endif + int dd; + *dpy_no = -1; + *found_input = False; + +#ifdef XTHREADS + rmask = app->fds.rmask; + for (dd = app->count; dd-- > 0; ) + FD_SET (ConnectionNumber (app->list[dd]), &rmask); +#endif + + for (ii = 0; ii < wf->nfds && nfds > 0; ii++) { + condition = 0; + if (FD_ISSET (ii, &wf->rmask) +#ifdef XTHREADS + && FD_ISSET (ii, &rmask) +#endif + ) { + nfds--; + if (!ignoreEvents) { + for (dd = 0; dd < app->count; dd++) { + if (ii == ConnectionNumber (app->list[dd])) { + if (*dpy_no == -1) { + if (XEventsQueued (app->list[dd], QueuedAfterReading )) + *dpy_no = dd; + /* + * An error event could have arrived + * without any real events, or events + * could have been swallowed by Xlib, + * or the connection may be broken. + * We can't tell the difference, so + * assume Xlib will eventually discover + * a broken connection. + */ + } + goto ENDILOOP; + } + } + } + condition = XtInputReadMask; + } + if (FD_ISSET (ii, &wf->wmask) +#ifdef XTHREADS + && FD_ISSET (ii, &app->fds.wmask) +#endif + ) { + condition |= XtInputWriteMask; + nfds--; + } + if (FD_ISSET (ii, &wf->emask) +#ifdef XTHREADS + && FD_ISSET (ii, &app->fds.emask) +#endif + ) { + condition |= XtInputExceptMask; + nfds--; + } + if (condition) { + for (ep = app->input_list[ii]; ep; ep = ep->ie_next) + if (condition & ep->ie_condition) { + ep->ie_oq = app->outstandingQueue; + app->outstandingQueue = ep; + } + *found_input = True; + } +ENDILOOP: ; + } /* endfor */ +#else /* }{ */ + struct pollfd* fdlp; + + *dpy_no = -1; + *found_input = False; + + if (!ignoreEvents) { + fdlp = wf->fdlist; + for (ii = 0; ii < wf->num_dpys; ii++, fdlp++) { + if (*dpy_no == -1 && fdlp->revents & (POLLIN|POLLHUP|POLLERR) && +#ifdef XTHREADS + !(fdlp->revents & POLLNVAL) && +#endif + XEventsQueued (app->list[ii], QueuedAfterReading)) { + *dpy_no = ii; + break; + } + } + } + + if (!ignoreInputs) { + fdlp = &wf->fdlist[wf->num_dpys]; + for (ii = wf->num_dpys; ii < wf->fdlistlen; ii++, fdlp++) { + condition = 0; + if (fdlp->revents) { + if (fdlp->revents & (XPOLL_READ|POLLHUP|POLLERR) +#ifdef XTHREADS + && !(fdlp->revents & POLLNVAL) +#endif + ) + condition = XtInputReadMask; + if (fdlp->revents & XPOLL_WRITE) + condition |= XtInputWriteMask; + if (fdlp->revents & XPOLL_EXCEPT) + condition |= XtInputExceptMask; + } + if (condition) { + *found_input = True; + for (ep = app->input_list[fdlp->fd]; ep; ep = ep->ie_next) + if (condition & ep->ie_condition) { + ep->ie_oq = app->outstandingQueue; + app->outstandingQueue = ep; + } + } + } + } +#endif /* } */ +} + +/* + * Routine to block in the toolkit. This should be the only call to select. + * + * This routine returns when there is something to be done. + * + * Before calling this with ignoreInputs==False, app->outstandingQueue should + * be checked; this routine will not verify that an alternate input source + * has not already been enqueued. + * + * + * _XtWaitForSomething( appContext, + * ignoreEvent, ignoreTimers, ignoreInputs, ignoreSignals, + * block, drop_lock, howlong) + * XtAppContext app; (Displays to check wait on) + * + * Boolean ignoreEvents; (Don't return if XEvents are available + * Also implies forget XEvents exist) + * + * Boolean ignoreTimers; (Ditto for timers) + * + * Boolean ignoreInputs; (Ditto for input callbacks ) + * + * Boolean ignoreSignals; (Ditto for signals) + * + * Boolean block; (Okay to block) + * + * Boolean drop_lock (drop lock before going into select/poll) + * + * TimeVal howlong; (howlong to wait for if blocking and not + * doing Timers... Null means forever. + * Maybe should mean shortest of both) + * Returns display for which input is available, if any + * and if ignoreEvents==False, else returns -1 + * + * if ignoring everything && block=True && howlong=NULL, you'll have + * lots of time for coffee; better not try it! In fact, it probably + * makes little sense to do this regardless of the value of howlong + * (bottom line is, we don't bother checking here). + * + * If drop_lock is FALSE, the app->lock->mutex is not unlocked before + * entering select/poll. It is illegal for drop_lock to be FALSE if + * ignoreTimers, ignoreInputs, or ignoreSignals is FALSE. + */ +#if NeedFunctionPrototypes +int _XtWaitForSomething( + XtAppContext app, + _XtBoolean ignoreEvents, + _XtBoolean ignoreTimers, + _XtBoolean ignoreInputs, + _XtBoolean ignoreSignals, + _XtBoolean block, +#ifdef XTHREADS + _XtBoolean drop_lock, +#endif + unsigned long *howlong) +#else +int _XtWaitForSomething(app, + ignoreEvents, ignoreTimers, ignoreInputs, ignoreSignals, + block, +#ifdef XTHREADS + drop_lock, +#endif + howlong) + XtAppContext app; + Boolean ignoreEvents; + Boolean ignoreTimers; + Boolean ignoreInputs; + Boolean ignoreSignals; + Boolean block; +#ifdef XTHREADS + Boolean drop_lock; +#endif + unsigned long *howlong; +#endif +{ + wait_times_t wt; + wait_fds_t wf; + int nfds, dpy_no, found_input, dd; +#ifdef XTHREADS + Boolean push_thread = TRUE; + Boolean pushed_thread = FALSE; + int level = 0; +#endif +#ifdef USE_POLL + struct pollfd fdlist[XT_DEFAULT_FDLIST_SIZE]; +#endif + +#ifdef XTHREADS + /* assert ((ignoreTimers && ignoreInputs && ignoreSignals) || drop_lock); */ + /* If not multi-threaded, never drop lock */ + if (app->lock == (ThreadAppProc) NULL) + drop_lock = FALSE; +#endif + + InitTimes (block, howlong, &wt); + +#ifdef USE_POLL + wf.fdlist = NULL; + wf.stack = fdlist; +#endif + + app->rebuild_fdlist = TRUE; + + while (1) { +WaitLoop: + AdjustTimes (app, block, howlong, ignoreTimers, &wt); + + if (block && app->block_hook_list) { + BlockHook hook; + for (hook = app->block_hook_list; + hook != NULL; + hook = hook->next) + (*hook->proc) (hook->closure); + + if (!ignoreEvents) + /* see if the hook(s) generated any protocol */ + for (dd = 0; dd < app->count; dd++) + if (XEventsQueued(app->list[dd], QueuedAlready)) { +#ifdef USE_POLL + XtStackFree ((XtPointer) wf.fdlist, fdlist); +#endif + return dd; + } + } + + if (app->rebuild_fdlist) + InitFds (app, ignoreEvents, ignoreInputs, &wf); + +#ifdef XTHREADS /* { */ + if (drop_lock) { + YIELD_APP_LOCK(app, &push_thread, &pushed_thread, &level); + nfds = IoWait (&wt, &wf); + RESTORE_APP_LOCK(app, level, &pushed_thread); + } else +#endif /* } */ + nfds = IoWait (&wt, &wf); + if (nfds == -1) { + /* + * interrupt occured recalculate time value and wait again. + */ + if (errno == EINTR || errno == EAGAIN) { + if (errno == EAGAIN) { + errno = 0; /* errno is not self reseting */ + continue; + } + errno = 0; /* errno is not self reseting */ + + /* was it interrupted by a signal that we care about? */ + if (!ignoreSignals && app->signalQueue != NULL) { + SignalEventRec *se_ptr = app->signalQueue; + while (se_ptr != NULL) { + if (se_ptr->se_notice) { + if (block && howlong != NULL) + AdjustHowLong (howlong, &wt.start_time); +#ifdef USE_POLL + XtStackFree ((XtPointer) wf.fdlist, fdlist); +#endif + return -1; + } + se_ptr = se_ptr->se_next; + } + } + + if (!ignoreEvents) + /* get Xlib to detect a bad connection */ + for (dd = 0; dd < app->count; dd++) + if (XEventsQueued(app->list[dd], QueuedAfterReading)) { +#ifdef USE_POLL + XtStackFree ((XtPointer) wf.fdlist, fdlist); +#endif + return dd; + } + + if (block) { +#ifndef USE_POLL + if (wt.wait_time_ptr == NULL) +#else + if (wt.poll_wait == X_BLOCK) +#endif + continue; + X_GETTIMEOFDAY (&wt.new_time); + FIXUP_TIMEVAL (wt.new_time); + TIMEDELTA (wt.time_spent, wt.new_time, wt.cur_time); + wt.cur_time = wt.new_time; +#ifndef USE_POLL + if (IS_AFTER (wt.time_spent, *wt.wait_time_ptr)) { + TIMEDELTA (wt.wait_time, *wt.wait_time_ptr, wt.time_spent); + wt.wait_time_ptr = &wt.wait_time; + continue; + } else +#else + if ((wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000) < wt.poll_wait) { + wt.poll_wait -= (wt.time_spent.tv_sec * 1000 + wt.time_spent.tv_usec / 1000); + continue; + } else +#endif + nfds = 0; + } + } else { + char Errno[12]; + String param = Errno; + Cardinal param_count = 1; + + sprintf( Errno, "%d", errno); + XtAppWarningMsg(app, "communicationError","select", + XtCXtToolkitError,"Select failed; error code %s", + ¶m, ¶m_count); + continue; + } + } /* timed out or input available */ + break; + } + + if (nfds == 0) { + /* Timed out */ + if (howlong) + *howlong = (unsigned long)0; +#ifdef USE_POLL + XtStackFree ((XtPointer) wf.fdlist, fdlist); +#endif + return -1; + } + + if (block && howlong != NULL) + AdjustHowLong (howlong, &wt.start_time); + + if (ignoreInputs && ignoreEvents) { +#ifdef USE_POLL + XtStackFree ((XtPointer) wf.fdlist, fdlist); +#endif + return -1; + } else + FindInputs (app, &wf, nfds, + ignoreEvents, ignoreInputs, + &dpy_no, &found_input); + + if (dpy_no >= 0 || found_input) { +#ifdef USE_POLL + XtStackFree ((XtPointer) wf.fdlist, fdlist); +#endif + return dpy_no; + } + goto WaitLoop; +} + +#define IeCallProc(ptr) \ + (*ptr->ie_proc) (ptr->ie_closure, &ptr->ie_source, (XtInputId*)&ptr); + +#define TeCallProc(ptr) \ + (*ptr->te_proc) (ptr->te_closure, (XtIntervalId*)&ptr); + +#define SeCallProc(ptr) \ + (*ptr->se_proc) (ptr->se_closure, (XtSignalId*)&ptr); + +/* + * Public Routines + */ + +XtIntervalId XtAddTimeOut(interval, proc, closure) + unsigned long interval; + XtTimerCallbackProc proc; + XtPointer closure; +{ + return XtAppAddTimeOut(_XtDefaultAppContext(), + interval, proc, closure); +} + +static void QueueTimerEvent(app, ptr) + XtAppContext app; + TimerEventRec *ptr; +{ + TimerEventRec *t,**tt; + tt = &app->timerQueue; + t = *tt; + while (t != NULL && + IS_AFTER(t->te_timer_value, ptr->te_timer_value)) { + tt = &t->te_next; + t = *tt; + } + ptr->te_next = t; + *tt = ptr; +} + +XtIntervalId XtAppAddTimeOut(app, interval, proc, closure) + XtAppContext app; + unsigned long interval; + XtTimerCallbackProc proc; + XtPointer closure; +{ + TimerEventRec *tptr; + struct timeval current_time; + + LOCK_APP(app); + LOCK_PROCESS; + if (freeTimerRecs) { + tptr = freeTimerRecs; + freeTimerRecs = tptr->te_next; + } + else tptr = XtNew(TimerEventRec); + UNLOCK_PROCESS; + + tptr->te_next = NULL; + tptr->te_closure = closure; + tptr->te_proc = proc; + tptr->app = app; + tptr->te_timer_value.tv_sec = interval/1000; + tptr->te_timer_value.tv_usec = (interval%1000)*1000; + X_GETTIMEOFDAY (¤t_time); + FIXUP_TIMEVAL(current_time); + ADD_TIME(tptr->te_timer_value,tptr->te_timer_value,current_time); + QueueTimerEvent(app, tptr); + UNLOCK_APP(app); + return( (XtIntervalId) tptr); +} + +void XtRemoveTimeOut(id) + XtIntervalId id; +{ + TimerEventRec *t, *last, *tid = (TimerEventRec *) id; + XtAppContext app = tid->app; + + /* find it */ + LOCK_APP(app); + for(t = app->timerQueue, last = NULL; + t != NULL && t != tid; + t = t->te_next) last = t; + + if (t == NULL) { + UNLOCK_APP(app); + return; /* couldn't find it */ + } + if(last == NULL) { /* first one on the list */ + app->timerQueue = t->te_next; + } else last->te_next = t->te_next; + + LOCK_PROCESS; + t->te_next = freeTimerRecs; + freeTimerRecs = t; + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +XtWorkProcId XtAddWorkProc(proc, closure) + XtWorkProc proc; + XtPointer closure; +{ + return XtAppAddWorkProc(_XtDefaultAppContext(), proc, closure); +} + +XtWorkProcId XtAppAddWorkProc(app, proc, closure) + XtAppContext app; + XtWorkProc proc; + XtPointer closure; +{ + WorkProcRec *wptr; + + LOCK_APP(app); + LOCK_PROCESS; + if (freeWorkRecs) { + wptr = freeWorkRecs; + freeWorkRecs = wptr->next; + } else wptr = XtNew(WorkProcRec); + UNLOCK_PROCESS; + wptr->next = app->workQueue; + wptr->closure = closure; + wptr->proc = proc; + wptr->app = app; + app->workQueue = wptr; + UNLOCK_APP(app); + return (XtWorkProcId) wptr; +} + +void XtRemoveWorkProc(id) + XtWorkProcId id; +{ + WorkProcRec *wid= (WorkProcRec *) id, *w, *last; + XtAppContext app = wid->app; + + LOCK_APP(app); + /* find it */ + for(w = app->workQueue, last = NULL; + w != NULL && w != wid; w = w->next) last = w; + + if (w == NULL) { + UNLOCK_APP(app); + return; /* couldn't find it */ + } + + if(last == NULL) app->workQueue = w->next; + else last->next = w->next; + LOCK_PROCESS; + w->next = freeWorkRecs; + freeWorkRecs = w; + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +XtSignalId XtAddSignal(proc, closure) + XtSignalCallbackProc proc; + XtPointer closure; +{ + return XtAppAddSignal(_XtDefaultAppContext(), proc, closure); +} + +XtSignalId XtAppAddSignal(app, proc, closure) + XtAppContext app; + XtSignalCallbackProc proc; + XtPointer closure; +{ + SignalEventRec *sptr; + + LOCK_APP(app); + LOCK_PROCESS; + if (freeSignalRecs) { + sptr = freeSignalRecs; + freeSignalRecs = sptr->se_next; + } else + sptr = XtNew(SignalEventRec); + UNLOCK_PROCESS; + sptr->se_next = app->signalQueue; + sptr->se_closure = closure; + sptr->se_proc = proc; + sptr->app = app; + sptr->se_notice = FALSE; + app->signalQueue = sptr; + UNLOCK_APP(app); + return (XtSignalId) sptr; +} + +void XtRemoveSignal(id) + XtSignalId id; +{ + SignalEventRec *sid = (SignalEventRec*) id, *s, *last = NULL; + XtAppContext app = sid->app; + + LOCK_APP(app); + for (s = app->signalQueue; s != NULL && s != sid; s = s->se_next) + last = s; + if (s == NULL) { + UNLOCK_APP(app); + return; + } + if (last == NULL) + app->signalQueue = s->se_next; + else + last->se_next = s->se_next; + LOCK_PROCESS; + s->se_next = freeSignalRecs; + freeSignalRecs = s; + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +void XtNoticeSignal(id) + XtSignalId id; +{ + /* + * It would be overkill to lock the app to set this flag. + * In the worst case, 2..n threads would be modifying this + * flag. The last one wins. Since signals occur asynchronously + * anyway, this can occur with or without threads. + * + * The other issue is that thread t1 sets the flag in a + * signalrec that has been deleted in thread t2. We rely + * on a detail of the implementation, i.e. free'd signalrecs + * aren't really free'd, they're just moved to a list of + * free recs, so deref'ing one won't hurt anything. + * + * Lastly, and perhaps most importantly, since POSIX threads + * says that the handling of asynchronous signals in a synchronous + * threads environment is undefined. Therefor it would be an + * error for both signals and threads to be in use in the same + * program. + */ + SignalEventRec *sid = (SignalEventRec*) id; + sid->se_notice = TRUE; +} + +XtInputId XtAddInput( source, Condition, proc, closure) + int source; + XtPointer Condition; + XtInputCallbackProc proc; + XtPointer closure; +{ + return XtAppAddInput(_XtDefaultAppContext(), + source, Condition, proc, closure); +} + +XtInputId XtAppAddInput(app, source, Condition, proc, closure) + XtAppContext app; + int source; + XtPointer Condition; + XtInputCallbackProc proc; + XtPointer closure; +{ + InputEvent* sptr; + XtInputMask condition = (XtInputMask) Condition; + + LOCK_APP(app); + if (!condition || + condition & ~(XtInputReadMask|XtInputWriteMask|XtInputExceptMask)) + XtAppErrorMsg(app,"invalidParameter","xtAddInput",XtCXtToolkitError, + "invalid condition passed to XtAppAddInput", + (String *)NULL, (Cardinal *)NULL); + + if (app->input_max <= source) { + Cardinal n = source + 1; + int ii; + app->input_list = (InputEvent**)XtRealloc((char*) app->input_list, + n * sizeof(InputEvent*)); + for (ii = app->input_max; ii < (int) n; ii++) + app->input_list[ii] = (InputEvent*) NULL; + app->input_max = n; + } + sptr = XtNew(InputEvent); + sptr->ie_proc = proc; + sptr->ie_closure = closure; + sptr->app = app; + sptr->ie_oq = NULL; + sptr->ie_source = source; + sptr->ie_condition = condition; + sptr->ie_next = app->input_list[source]; + app->input_list[source] = sptr; + +#ifndef USE_POLL + if (condition & XtInputReadMask) FD_SET(source, &app->fds.rmask); + if (condition & XtInputWriteMask) FD_SET(source, &app->fds.wmask); + if (condition & XtInputExceptMask) FD_SET(source, &app->fds.emask); + + if (app->fds.nfds < (source+1)) app->fds.nfds = source+1; +#else + if (sptr->ie_next == NULL) + app->fds.nfds++; +#endif + app->input_count++; + app->rebuild_fdlist = TRUE; + UNLOCK_APP(app); + return((XtInputId)sptr); +} + +void XtRemoveInput( id ) + register XtInputId id; +{ + register InputEvent *sptr, *lptr; + XtAppContext app = ((InputEvent *)id)->app; + register int source = ((InputEvent *)id)->ie_source; + Boolean found = False; + + LOCK_APP(app); + sptr = app->outstandingQueue; + lptr = NULL; + for (; sptr != NULL; sptr = sptr->ie_oq) { + if (sptr == (InputEvent *)id) { + if (lptr == NULL) app->outstandingQueue = sptr->ie_oq; + else lptr->ie_oq = sptr->ie_oq; + } + lptr = sptr; + } + + if(app->input_list && (sptr = app->input_list[source]) != NULL) { + for( lptr = NULL ; sptr; sptr = sptr->ie_next ){ + if(sptr == (InputEvent *) id) { +#ifndef USE_POLL + XtInputMask condition = 0; +#endif + if(lptr == NULL) { + app->input_list[source] = sptr->ie_next; + } else { + lptr->ie_next = sptr->ie_next; + } +#ifndef USE_POLL + for (lptr = app->input_list[source]; + lptr; lptr = lptr->ie_next) + condition |= lptr->ie_condition; + if ((sptr->ie_condition & XtInputReadMask) && + !(condition & XtInputReadMask)) + FD_CLR(source, &app->fds.rmask); + if ((sptr->ie_condition & XtInputWriteMask) && + !(condition & XtInputWriteMask)) + FD_CLR(source, &app->fds.wmask); + if ((sptr->ie_condition & XtInputExceptMask) && + !(condition & XtInputExceptMask)) + FD_CLR(source, &app->fds.emask); +#endif + XtFree((char *) sptr); + found = True; + break; + } + lptr = sptr; + } + } + + if (found) { + app->input_count--; + if (app->input_list[source] == NULL) + +#ifdef USE_POLL + + app->fds.nfds--; + +#else + + { + int display; + int source; + + /* + * Search through list[] for largest connection number + */ + + app->fds.nfds = 0; + + for (display = 0; display < app->count; display++) { + if ((ConnectionNumber(app->list[display]) + 1) > app->fds.nfds) { + app->fds.nfds = ConnectionNumber(app->list[display]) + 1; + } + } + + /* + * Search through input_list[] for largest input source, i.e. + * file descriptor + */ + + for (source = (app->input_max - 1); ((source >= 0) && ((source +1) > app->fds.nfds)); source--) { + if (app->input_list[source] != (InputEvent *) NULL) { + app->fds.nfds = (source + 1); + break; + } + } + } + +#endif + + app->rebuild_fdlist = TRUE; + } else + XtAppWarningMsg(app, "invalidProcedure","inputHandler", + XtCXtToolkitError, + "XtRemoveInput: Input handler not found", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_APP(app); +} + +void _XtRemoveAllInputs(app) + XtAppContext app; +{ + int i; + for (i = 0; i < app->input_max; i++) { + InputEvent* ep = app->input_list[i]; + while (ep) { + InputEvent *next = ep->ie_next; + XtFree( (char*)ep ); + ep = next; + } + } + XtFree((char *) app->input_list); +} + +/* Do alternate input and timer callbacks if there are any */ + +static void DoOtherSources(app) + XtAppContext app; +{ + TimerEventRec *te_ptr; + InputEvent *ie_ptr; + struct timeval cur_time; + +#define DrainQueue() \ + for (ie_ptr = app->outstandingQueue; ie_ptr != NULL;) { \ + app->outstandingQueue = ie_ptr->ie_oq; \ + ie_ptr ->ie_oq = NULL; \ + IeCallProc(ie_ptr); \ + ie_ptr = app->outstandingQueue; \ + } +/*enddef*/ + DrainQueue(); + if (app->input_count > 0) { + /* Call _XtWaitForSomething to get input queued up */ + (void) _XtWaitForSomething (app, + TRUE, TRUE, FALSE, TRUE, + FALSE, +#ifdef XTHREADS + TRUE, +#endif + (unsigned long *)NULL); + DrainQueue(); + } + if (app->timerQueue != NULL) { /* check timeout queue */ + X_GETTIMEOFDAY (&cur_time); + FIXUP_TIMEVAL(cur_time); + while(IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time)) { + te_ptr = app->timerQueue; + app->timerQueue = te_ptr->te_next; + te_ptr->te_next = NULL; + if (te_ptr->te_proc != NULL) + TeCallProc(te_ptr); + LOCK_PROCESS; + te_ptr->te_next = freeTimerRecs; + freeTimerRecs = te_ptr; + UNLOCK_PROCESS; + if (app->timerQueue == NULL) break; + } + } + if (app->signalQueue != NULL) { + SignalEventRec *se_ptr = app->signalQueue; + while (se_ptr != NULL) { + if (se_ptr->se_notice) { + se_ptr->se_notice = FALSE; + if (se_ptr->se_proc != NULL) + SeCallProc(se_ptr); + } + se_ptr = se_ptr->se_next; + } + } +#undef DrainQueue +} + +/* If there are any work procs, call them. Return whether we did so */ + +static Boolean CallWorkProc(app) + XtAppContext app; +{ + register WorkProcRec *w = app->workQueue; + Boolean delete; + + if (w == NULL) return FALSE; + + app->workQueue = w->next; + + delete = (*(w->proc)) (w->closure); + + if (delete) { + LOCK_PROCESS; + w->next = freeWorkRecs; + freeWorkRecs = w; + UNLOCK_PROCESS; + } + else { + w->next = app->workQueue; + app->workQueue = w; + } + return TRUE; +} + +/* + * XtNextEvent() + * return next event; + */ + +void XtNextEvent(event) + XEvent *event; +{ + XtAppNextEvent(_XtDefaultAppContext(), event); +} + +#if NeedFunctionPrototypes +void _XtRefreshMapping( + XEvent* event, + _XtBoolean dispatch) +#else +void _XtRefreshMapping(event, dispatch) + XEvent *event; + Boolean dispatch; +#endif +{ + XtPerDisplay pd; + + LOCK_PROCESS; + pd = _XtGetPerDisplay(event->xmapping.display); + if (event->xmapping.request != MappingPointer && + pd && pd->keysyms && (event->xmapping.serial >= pd->keysyms_serial)) + _XtBuildKeysymTables( event->xmapping.display, pd ); + XRefreshKeyboardMapping(&event->xmapping); + if (dispatch && pd && pd->mapping_callbacks) + XtCallCallbackList((Widget) NULL, + (XtCallbackList)pd->mapping_callbacks, + (XtPointer)event ); + UNLOCK_PROCESS; +} + +void XtAppNextEvent(app, event) + XtAppContext app; + XEvent *event; +{ + int i, d; + + LOCK_APP(app); + for (;;) { + if (app->count == 0) + DoOtherSources(app); + else { + for (i = 1; i <= app->count; i++) { + d = (i + app->last) % app->count; + if (d == 0) DoOtherSources(app); + if (XEventsQueued(app->list[d], QueuedAfterReading)) + goto GotEvent; + } + for (i = 1; i <= app->count; i++) { + d = (i + app->last) % app->count; + if (XEventsQueued(app->list[d], QueuedAfterFlush)) + goto GotEvent; + } + } + + /* We're ready to wait...if there is a work proc, call it */ + if (CallWorkProc(app)) continue; + + d = _XtWaitForSomething (app, + FALSE, FALSE, FALSE, FALSE, + TRUE, +#ifdef XTHREADS + TRUE, +#endif + (unsigned long *) NULL); + + if (d != -1) { + GotEvent: + XNextEvent (app->list[d], event); +#ifdef XTHREADS + /* assert(app->list[d] == event->xany.display); */ +#endif + app->last = d; + if (event->xany.type == MappingNotify) + _XtRefreshMapping(event, False); + UNLOCK_APP(app); + return; + } + + } /* for */ +} + +void XtProcessEvent(mask) + XtInputMask mask; +{ + XtAppProcessEvent(_XtDefaultAppContext(), mask); +} + +void XtAppProcessEvent(app, mask) + XtAppContext app; + XtInputMask mask; +{ + int i, d; + XEvent event; + struct timeval cur_time; + + LOCK_APP(app); + if (mask == 0) { + UNLOCK_APP(app); + return; + } + + for (;;) { + + if (mask & XtIMSignal && app->signalQueue != NULL) { + SignalEventRec *se_ptr = app->signalQueue; + while (se_ptr != NULL) { + if (se_ptr->se_notice) { + se_ptr->se_notice = FALSE; + SeCallProc(se_ptr); + UNLOCK_APP(app); + return; + } + se_ptr = se_ptr->se_next; + } + } + + if (mask & XtIMTimer && app->timerQueue != NULL) { + X_GETTIMEOFDAY (&cur_time); + FIXUP_TIMEVAL(cur_time); + if (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)){ + TimerEventRec *te_ptr = app->timerQueue; + app->timerQueue = app->timerQueue->te_next; + te_ptr->te_next = NULL; + if (te_ptr->te_proc != NULL) + TeCallProc(te_ptr); + LOCK_PROCESS; + te_ptr->te_next = freeTimerRecs; + freeTimerRecs = te_ptr; + UNLOCK_PROCESS; + UNLOCK_APP(app); + return; + } + } + + if (mask & XtIMAlternateInput) { + if (app->input_count > 0 && app->outstandingQueue == NULL) { + /* Call _XtWaitForSomething to get input queued up */ + (void) _XtWaitForSomething (app, + TRUE, TRUE, FALSE, TRUE, + FALSE, +#ifdef XTHREADS + TRUE, +#endif + (unsigned long *)NULL); + } + if (app->outstandingQueue != NULL) { + InputEvent *ie_ptr = app->outstandingQueue; + app->outstandingQueue = ie_ptr->ie_oq; + ie_ptr->ie_oq = NULL; + IeCallProc(ie_ptr); + UNLOCK_APP(app); + return; + } + } + + if (mask & XtIMXEvent) { + for (i = 1; i <= app->count; i++) { + d = (i + app->last) % app->count; + if (XEventsQueued(app->list[d], QueuedAfterReading)) + goto GotEvent; + } + for (i = 1; i <= app->count; i++) { + d = (i + app->last) % app->count; + if (XEventsQueued(app->list[d], QueuedAfterFlush)) + goto GotEvent; + } + } + + /* Nothing to do...wait for something */ + + if (CallWorkProc(app)) continue; + + d = _XtWaitForSomething (app, + (mask & XtIMXEvent ? FALSE : TRUE), + (mask & XtIMTimer ? FALSE : TRUE), + (mask & XtIMAlternateInput ? FALSE : TRUE), + (mask & XtIMSignal ? FALSE : TRUE), + TRUE, +#ifdef XTHREADS + TRUE, +#endif + (unsigned long *) NULL); + + if (mask & XtIMXEvent && d != -1) { + GotEvent: + XNextEvent(app->list[d], &event); +#ifdef XTHREADS + /* assert(app->list[d] == event.xany.display); */ +#endif + app->last = d; + if (event.xany.type == MappingNotify) { + _XtRefreshMapping(&event, False); + } + XtDispatchEvent(&event); + UNLOCK_APP(app); + return; + } + + } +} + +Boolean XtPending() +{ + return (XtAppPending(_XtDefaultAppContext()) != 0); +} + +XtInputMask XtAppPending(app) + XtAppContext app; +{ + struct timeval cur_time; + int d; + XtInputMask ret = 0; + +/* + * Check for pending X events + */ + LOCK_APP(app); + for (d = 0; d < app->count; d++) { + if (XEventsQueued(app->list[d], QueuedAfterReading)) { + ret = XtIMXEvent; + break; + } + } + if (ret == 0) { + for (d = 0; d < app->count; d++) { + if (XEventsQueued(app->list[d], QueuedAfterFlush)) { + ret = XtIMXEvent; + break; + } + } + } + + if (app->signalQueue != NULL) { + SignalEventRec *se_ptr = app->signalQueue; + while (se_ptr != NULL) { + if (se_ptr->se_notice) { + ret |= XtIMSignal; + break; + } + se_ptr = se_ptr->se_next; + } + } + +/* + * Check for pending alternate input + */ + if (app->timerQueue != NULL) { /* check timeout queue */ + X_GETTIMEOFDAY (&cur_time); + FIXUP_TIMEVAL(cur_time); + if ((IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) && + (app->timerQueue->te_proc != 0)) { + ret |= XtIMTimer; + } + } + + if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput; + else { + /* This won't cause a wait, but will enqueue any input */ + + if(_XtWaitForSomething (app, + FALSE, TRUE, FALSE, TRUE, + FALSE, +#ifdef XTHREADS + TRUE, +#endif + (unsigned long *) NULL) != -1) + ret |= XtIMXEvent; + if (app->outstandingQueue != NULL) ret |= XtIMAlternateInput; + } + UNLOCK_APP(app); + return ret; +} + +/* Peek at alternate input and timer callbacks if there are any */ + +static Boolean PeekOtherSources(app) + XtAppContext app; +{ + struct timeval cur_time; + + if (app->outstandingQueue != NULL) return TRUE; + + if (app->signalQueue != NULL) { + SignalEventRec *se_ptr = app->signalQueue; + while (se_ptr != NULL) { + if (se_ptr->se_notice) + return TRUE; + se_ptr = se_ptr->se_next; + } + } + + if (app->input_count > 0) { + /* Call _XtWaitForSomething to get input queued up */ + (void) _XtWaitForSomething (app, + TRUE, TRUE, FALSE, TRUE, + FALSE, +#ifdef XTHREADS + TRUE, +#endif + (unsigned long *)NULL); + if (app->outstandingQueue != NULL) return TRUE; + } + + if (app->timerQueue != NULL) { /* check timeout queue */ + X_GETTIMEOFDAY (&cur_time); + FIXUP_TIMEVAL(cur_time); + if (IS_AT_OR_AFTER (app->timerQueue->te_timer_value, cur_time)) + return TRUE; + } + + return FALSE; +} + +Boolean XtPeekEvent(event) + XEvent *event; +{ + return XtAppPeekEvent(_XtDefaultAppContext(), event); +} + +Boolean XtAppPeekEvent(app, event) + XtAppContext app; + XEvent *event; +{ + int i, d; + Boolean foundCall = FALSE; + + LOCK_APP(app); + for (i = 1; i <= app->count; i++) { + d = (i + app->last) % app->count; + if (d == 0) foundCall = PeekOtherSources(app); + if (XEventsQueued(app->list[d], QueuedAfterReading)) + goto GotEvent; + } + for (i = 1; i <= app->count; i++) { + d = (i + app->last) % app->count; + if (XEventsQueued(app->list[d], QueuedAfterFlush)) + goto GotEvent; + } + + if (foundCall) { + event->xany.type = 0; + event->xany.display = NULL; + event->xany.window = 0; + UNLOCK_APP(app); + return FALSE; + } + + while (1) { + d = _XtWaitForSomething (app, + FALSE, FALSE, FALSE, FALSE, + TRUE, +#ifdef XTHREADS + TRUE, +#endif + (unsigned long *) NULL); + + if (d != -1) { /* event */ + GotEvent: + XPeekEvent(app->list[d], event); + app->last = (d == 0 ? app->count : d) - 1; + UNLOCK_APP(app); + return TRUE; + } + else { /* input or timer or signal */ + /* + * Check to see why a -1 was returned, if a timer expired, + * call it and block some more + */ + if (app->timerQueue != NULL) { /* timer */ + struct timeval cur_time; + Bool did_timer = False; + + X_GETTIMEOFDAY (&cur_time); + FIXUP_TIMEVAL(cur_time); + while (IS_AT_OR_AFTER(app->timerQueue->te_timer_value, cur_time)) { + TimerEventRec *te_ptr = app->timerQueue; + app->timerQueue = app->timerQueue->te_next; + te_ptr->te_next = NULL; + if (te_ptr->te_proc != NULL) + TeCallProc(te_ptr); + LOCK_PROCESS; + did_timer = True; + te_ptr->te_next = freeTimerRecs; + freeTimerRecs = te_ptr; + UNLOCK_PROCESS; + if (app->timerQueue == NULL) break; + } + if (did_timer) + { + for (d = 0; d < app->count; d++) + /* the timer's procedure may have caused an event */ + if (XEventsQueued(app->list[d], QueuedAfterFlush)) { + goto GotEvent; + } + continue; /* keep blocking */ + } + } + if (app->signalQueue != NULL) { /* signal */ + /* spec is vague here; we'll assume signals also return FALSE */ + event->xany.type = 0; + event->xany.display = NULL; + event->xany.window = 0; + UNLOCK_APP(app); + return FALSE; + } + else { /* input */ + event->xany.type = 0; + event->xany.display = NULL; + event->xany.window = 0; + UNLOCK_APP(app); + return FALSE; + } + } + } /* end while */ +} diff --git a/src/Object.c b/src/Object.c new file mode 100644 index 0000000..29d9066 --- /dev/null +++ b/src/Object.c @@ -0,0 +1,292 @@ +/* $Xorg: Object.c,v 1.4 2001/02/09 02:03:56 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#define OBJECT +#include "IntrinsicI.h" +#include "StringDefs.h" + +static XtResource resources[] = { + {XtNdestroyCallback, XtCCallback, XtRCallback,sizeof(XtPointer), + XtOffsetOf(ObjectRec,object.destroy_callbacks), + XtRCallback, (XtPointer)NULL} + }; + +static void ObjectClassPartInitialize(); +static Boolean ObjectSetValues(); +static void ObjectDestroy(); + +externaldef(objectclassrec) ObjectClassRec objectClassRec = { + { + /* superclass */ NULL, + /* class_name */ "Object", + /* widget_size */ sizeof(ObjectRec), + /* class_initialize */ NULL, + /* class_part_initialize*/ ObjectClassPartInitialize, + /* class_inited */ FALSE, + /* initialize */ NULL, + /* initialize_hook */ NULL, + /* pad */ NULL, + /* pad */ NULL, + /* pad */ 0, + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* pad */ FALSE, + /* pad */ FALSE, + /* pad */ FALSE, + /* pad */ FALSE, + /* destroy */ ObjectDestroy, + /* pad */ NULL, + /* pad */ NULL, + /* set_values */ ObjectSetValues, + /* set_values_hook */ NULL, + /* pad */ NULL, + /* get_values_hook */ NULL, + /* pad */ NULL, + /* version */ XtVersion, + /* callback_offsets */ NULL, + /* pad */ NULL, + /* pad */ NULL, + /* pad */ NULL, + /* extension */ NULL +} +}; + +externaldef(objectClass) WidgetClass objectClass + = (WidgetClass)&objectClassRec; + +/* + * Start of object routines. + */ + + +static void ConstructCallbackOffsets(widgetClass) + WidgetClass widgetClass; +{ + static XrmQuark QCallback = NULLQUARK; + register int i; + register int tableSize; + register CallbackTable newTable; + register CallbackTable superTable; + register XrmResourceList resourceList; + ObjectClass objectClass = (ObjectClass)widgetClass; + + /* + This function builds an array of pointers to the resource + structures which describe the callbacks for this widget class. + This array is special in that the 0th entry is the number of + callback pointers. + */ + + if (QCallback == NULLQUARK) + QCallback = XrmPermStringToQuark(XtRCallback); + + if (objectClass->object_class.superclass != NULL) { + superTable = (CallbackTable) + ((ObjectClass) objectClass->object_class.superclass)-> + object_class.callback_private; + tableSize = (int) superTable[0]; + } else { + superTable = (CallbackTable) NULL; + tableSize = 0; + } + + /* Count the number of callbacks */ + resourceList = (XrmResourceList) objectClass->object_class.resources; + for (i = objectClass->object_class.num_resources; --i >= 0; resourceList++) + if (resourceList->xrm_type == QCallback) + tableSize++; + + /* + * Allocate and load the table. Make sure that the new callback + * offsets occur in the table ahead of the superclass callback + * offsets so that resource overrides work. + */ + newTable = (CallbackTable) + __XtMalloc(sizeof(XrmResource *) * (tableSize + 1)); + + newTable[0] = (XrmResource *) tableSize; + + if (superTable) + tableSize -= (int) superTable[0]; + resourceList = (XrmResourceList) objectClass->object_class.resources; + for (i=1; tableSize > 0; resourceList++) + if (resourceList->xrm_type == QCallback) { + newTable[i++] = resourceList; + tableSize--; + } + + if (superTable) + for (tableSize = (int) *superTable++; --tableSize >= 0; superTable++) + newTable[i++] = *superTable; + + objectClass->object_class.callback_private = (XtPointer) newTable; +} + +static void InheritObjectExtensionMethods(widget_class) + WidgetClass widget_class; +{ + ObjectClass oc = (ObjectClass) widget_class; + ObjectClassExtension ext, super_ext = NULL; + + ext = (ObjectClassExtension) + XtGetClassExtension(widget_class, + XtOffsetOf(ObjectClassRec, object_class.extension), + NULLQUARK, XtObjectExtensionVersion, + sizeof(ObjectClassExtensionRec)); + + if (oc->object_class.superclass) + super_ext = (ObjectClassExtension) + XtGetClassExtension(oc->object_class.superclass, + XtOffsetOf(ObjectClassRec, object_class.extension), + NULLQUARK, XtObjectExtensionVersion, + sizeof(ObjectClassExtensionRec)); + LOCK_PROCESS; + if (ext) { + if (ext->allocate == XtInheritAllocate) + ext->allocate = (super_ext ? super_ext->allocate : NULL); + if (ext->deallocate == XtInheritDeallocate) + ext->deallocate = (super_ext ? super_ext->deallocate : NULL); + } else if (super_ext) { + /* Be careful to inherit only what is appropriate */ + ext = (ObjectClassExtension) + __XtCalloc(1, sizeof(ObjectClassExtensionRec)); + ext->next_extension = oc->object_class.extension; + ext->record_type = NULLQUARK; + ext->version = XtObjectExtensionVersion; + ext->record_size = sizeof(ObjectClassExtensionRec); + ext->allocate = super_ext->allocate; + ext->deallocate = super_ext->deallocate; + oc->object_class.extension = (XtPointer) ext; + } + UNLOCK_PROCESS; +} + +static void ObjectClassPartInitialize(wc) + register WidgetClass wc; +{ + ObjectClass oc = (ObjectClass)wc; + + oc->object_class.xrm_class = + XrmPermStringToQuark(oc->object_class.class_name); + + if (oc->object_class.resources) + _XtCompileResourceList(oc->object_class.resources, + oc->object_class.num_resources); + + ConstructCallbackOffsets(wc); + _XtResourceDependencies(wc); + InheritObjectExtensionMethods(wc); +} + + +/*ARGSUSED*/ +static Boolean ObjectSetValues(old, request, widget, args, num_args) + Widget old, request, widget; + ArgList args; + Cardinal *num_args; +{ + register CallbackTable offsets; + register int i; + register InternalCallbackList *ol, *nl; + + LOCK_PROCESS; + /* Compile any callback lists into internal form */ + offsets = (CallbackTable) XtClass(widget)->core_class.callback_private; + + for (i= (int) *(offsets++); --i >= 0; offsets++) { + ol = (InternalCallbackList *) + ((char *) old - (*offsets)->xrm_offset - 1); + nl = (InternalCallbackList *) + ((char *) widget - (*offsets)->xrm_offset - 1); + if (*ol != *nl) { + if (*ol != NULL) + XtFree((char *) *ol); + if (*nl != NULL) + *nl = _XtCompileCallbackList((XtCallbackList) *nl); + } + } + UNLOCK_PROCESS; + return False; +} + + +static void ObjectDestroy (widget) + register Widget widget; +{ + register CallbackTable offsets; + register int i; + register InternalCallbackList cl; + + /* Remove all callbacks associated with widget */ + LOCK_PROCESS; + offsets = (CallbackTable) + widget->core.widget_class->core_class.callback_private; + + for (i = (int) *(offsets++); --i >= 0; offsets++) { + cl = *(InternalCallbackList *) + ((char *) widget - (*offsets)->xrm_offset - 1); + if (cl) XtFree((char *) cl); + } + UNLOCK_PROCESS; +} /* ObjectDestroy */ + + diff --git a/src/PassivGrab.c b/src/PassivGrab.c new file mode 100644 index 0000000..4242ea6 --- /dev/null +++ b/src/PassivGrab.c @@ -0,0 +1,1119 @@ +/* $Xorg: PassivGrab.c,v 1.5 2001/02/09 02:03:56 xorgcvs Exp $ */ + +/******************************************************** + +Copyright 1988 by Hewlett-Packard Company +Copyright 1987, 1988, 1989,1990 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the names of +Hewlett-Packard, Digital, or Sun not be used in advertising or +publicity pertaining to distribution of the software without specific, +written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +********************************************************/ + +/* + +Copyright 1987, 1988, 1989, 1990, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "StringDefs.h" +#include "PassivGraI.h" + +/* typedef unsigned long Mask; */ +#define BITMASK(i) (((Mask)1) << ((i) & 31)) +#define MASKIDX(i) ((i) >> 5) +#define MASKWORD(buf, i) buf[MASKIDX(i)] +#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) +#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) +#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) +#define MasksPerDetailMask 8 + +#define pDisplay(grabPtr) (((grabPtr)->widget)->core.screen->display) +#define pWindow(grabPtr) (((grabPtr)->widget)->core.window) + + +/***************************************************************************/ +/*********************** Internal Support Routines *************************/ +/***************************************************************************/ + +/* + * Turn off (clear) the bit in the specified detail mask which is associated + * with the detail. + */ + +static void DeleteDetailFromMask(ppDetailMask, detail) + Mask **ppDetailMask; + unsigned short detail; +{ + Mask *pDetailMask = *ppDetailMask; + + if (!pDetailMask) { + int i; + pDetailMask = (Mask *)__XtMalloc(sizeof(Mask) * MasksPerDetailMask); + for (i = MasksPerDetailMask; --i >= 0; ) + pDetailMask[i] = ~0; + *ppDetailMask = pDetailMask; + } + BITCLEAR((pDetailMask), detail); +} + + +/* + * Make an exact copy of the specified detail mask. + */ + +static Mask *CopyDetailMask(pOriginalDetailMask) + Mask *pOriginalDetailMask; +{ + Mask *pTempMask; + int i; + + if (!pOriginalDetailMask) + return NULL; + + pTempMask = (Mask *)__XtMalloc(sizeof(Mask) * MasksPerDetailMask); + + for ( i = 0; i < MasksPerDetailMask; i++) + pTempMask[i]= pOriginalDetailMask[i]; + + return pTempMask; +} + + +/* + * Allocate a new grab entry, and fill in all of the fields using the + * specified parameters. + */ + +static XtServerGrabPtr CreateGrab(widget, ownerEvents, modifiers, + keybut, pointer_mode, keyboard_mode, + event_mask, confine_to, cursor, need_ext) + Widget widget; + Boolean ownerEvents; + Modifiers modifiers; + KeyCode keybut; + int pointer_mode, keyboard_mode; + Mask event_mask; + Window confine_to; + Cursor cursor; + Boolean need_ext; +{ + XtServerGrabPtr grab; + + if (confine_to || cursor) + need_ext = True; + grab = (XtServerGrabPtr)__XtMalloc(sizeof(XtServerGrabRec) + + (need_ext ? sizeof(XtServerGrabExtRec) + : 0)); + grab->next = NULL; + grab->widget = widget; + grab->ownerEvents = ownerEvents; + grab->pointerMode = pointer_mode; + grab->keyboardMode = keyboard_mode; + grab->eventMask = event_mask; + grab->hasExt = need_ext; + grab->confineToIsWidgetWin = (XtWindow (widget) == confine_to); + grab->modifiers = modifiers; + grab->keybut = keybut; + if (need_ext) { + XtServerGrabExtPtr ext = GRABEXT(grab); + ext->pModifiersMask = NULL; + ext->pKeyButMask = NULL; + ext->confineTo = confine_to; + ext->cursor = cursor; + } + return grab; +} + + +/* + * Free up the space occupied by a grab entry. + */ + +static void FreeGrab(pGrab) + XtServerGrabPtr pGrab; +{ + if (pGrab->hasExt) { + XtServerGrabExtPtr ext = GRABEXT(pGrab); + if (ext->pModifiersMask) + XtFree((char *)ext->pModifiersMask); + if (ext->pKeyButMask) + XtFree((char *)ext->pKeyButMask); + } + XtFree((char *)pGrab); +} + +typedef struct _DetailRec { + unsigned short exact; + Mask *pMask; +} DetailRec, *DetailPtr; + +/* + * If the first detail is set to 'exception' and the second detail + * is contained in the mask of the first, then TRUE is returned. + */ + +static Bool IsInGrabMask(firstDetail, secondDetail, exception) + register DetailPtr firstDetail, secondDetail; + unsigned short exception; +{ + if (firstDetail->exact == exception) { + if (!firstDetail->pMask) + return TRUE; + + /* (at present) never called with two non-null pMasks */ + if (secondDetail->exact == exception) + return FALSE; + + if (GETBIT(firstDetail->pMask, secondDetail->exact)) + return TRUE; + } + + return FALSE; +} + + +/* + * If neither of the details is set to 'exception', and they match + * exactly, then TRUE is returned. + */ + +static Bool IdenticalExactDetails(firstExact, secondExact, exception) + unsigned short firstExact, secondExact, exception; +{ + if ((firstExact == exception) || (secondExact == exception)) + return FALSE; + + if (firstExact == secondExact) + return TRUE; + + return FALSE; +} + + +/* + * If the first detail is set to 'exception', and its mask has the bit + * enabled which corresponds to the second detail, OR if neither of the + * details is set to 'exception' and the details match exactly, then + * TRUE is returned. + */ + +static Bool DetailSupersedesSecond(firstDetail, secondDetail, exception) + register DetailPtr firstDetail, secondDetail; + unsigned short exception; +{ + if (IsInGrabMask(firstDetail, secondDetail, exception)) + return TRUE; + + if (IdenticalExactDetails(firstDetail->exact, secondDetail->exact, + exception)) + return TRUE; + + return FALSE; +} + + +/* + * If the two grab events match exactly, or if the first grab entry + * 'encompasses' the second grab entry, then TRUE is returned. + */ + +static Bool GrabSupersedesSecond(pFirstGrab, pSecondGrab) + register XtServerGrabPtr pFirstGrab, pSecondGrab; +{ + DetailRec first, second; + + first.exact = pFirstGrab->modifiers; + if (pFirstGrab->hasExt) + first.pMask = GRABEXT(pFirstGrab)->pModifiersMask; + else + first.pMask = NULL; + second.exact = pSecondGrab->modifiers; + if (pSecondGrab->hasExt) + second.pMask = GRABEXT(pSecondGrab)->pModifiersMask; + else + second.pMask = NULL; + if (!DetailSupersedesSecond(&first, &second, (unsigned short)AnyModifier)) + return FALSE; + + first.exact = pFirstGrab->keybut; + if (pFirstGrab->hasExt) + first.pMask = GRABEXT(pFirstGrab)->pKeyButMask; + else + first.pMask = NULL; + second.exact = pSecondGrab->keybut; + if (pSecondGrab->hasExt) + second.pMask = GRABEXT(pSecondGrab)->pKeyButMask; + else + second.pMask = NULL; + if (DetailSupersedesSecond(&first, &second, (unsigned short)AnyKey)) + return TRUE; + + return FALSE; +} + + +/* + * Two grabs are considered to be matching if either of the following are true: + * + * 1) The two grab entries match exactly, or the first grab entry + * encompasses the second grab entry. + * 2) The second grab entry encompasses the first grab entry. + * 3) The keycodes match exactly, and one entry's modifiers encompasses + * the others. + * 4) The keycode for one entry encompasses the other, and the detail + * for the other entry encompasses the first. + */ + +static Bool GrabMatchesSecond(pFirstGrab, pSecondGrab) + register XtServerGrabPtr pFirstGrab, pSecondGrab; +{ + DetailRec firstD, firstM, secondD, secondM; + + if (pDisplay(pFirstGrab) != pDisplay(pSecondGrab)) + return FALSE; + + if (GrabSupersedesSecond(pFirstGrab, pSecondGrab)) + return TRUE; + + if (GrabSupersedesSecond(pSecondGrab, pFirstGrab)) + return TRUE; + + firstD.exact = pFirstGrab->keybut; + firstM.exact = pFirstGrab->modifiers; + if (pFirstGrab->hasExt) { + firstD.pMask = GRABEXT(pFirstGrab)->pKeyButMask; + firstM.pMask = GRABEXT(pFirstGrab)->pModifiersMask; + } else { + firstD.pMask = NULL; + firstM.pMask = NULL; + } + secondD.exact = pSecondGrab->keybut; + secondM.exact = pSecondGrab->modifiers; + if (pSecondGrab->hasExt) { + secondD.pMask = GRABEXT(pSecondGrab)->pKeyButMask; + secondM.pMask = GRABEXT(pSecondGrab)->pModifiersMask; + } else { + secondD.pMask = NULL; + secondM.pMask = NULL; + } + + if (DetailSupersedesSecond(&secondD, &firstD, (unsigned short)AnyKey) && + DetailSupersedesSecond(&firstM, &secondM, (unsigned short)AnyModifier)) + return TRUE; + + if (DetailSupersedesSecond(&firstD, &secondD, (unsigned short)AnyKey) && + DetailSupersedesSecond(&secondM, &firstM, (unsigned short)AnyModifier)) + return TRUE; + + return FALSE; +} + + +/* + * Delete a grab combination from the passive grab list. Each entry will + * be checked to see if it is affected by the grab being deleted. This + * may result in multiple entries being modified/deleted. + */ + +static void DeleteServerGrabFromList(passiveListPtr, pMinuendGrab) + XtServerGrabPtr *passiveListPtr; + XtServerGrabPtr pMinuendGrab; +{ + register XtServerGrabPtr *next; + register XtServerGrabPtr grab; + register XtServerGrabExtPtr ext; + + for (next = passiveListPtr; (grab = *next); ) + { + if (GrabMatchesSecond(grab, pMinuendGrab) && + (pDisplay(grab) == pDisplay(pMinuendGrab))) + { + if (GrabSupersedesSecond(pMinuendGrab, grab)) + { + /* + * The entry being deleted encompasses the list entry, + * so delete the list entry. + */ + *next = grab->next; + FreeGrab(grab); + continue; + } + + if (!grab->hasExt) { + grab = (XtServerGrabPtr) + XtRealloc((char *)grab, (sizeof(XtServerGrabRec) + + sizeof(XtServerGrabExtRec))); + *next = grab; + grab->hasExt = True; + ext = GRABEXT(grab); + ext->pKeyButMask = NULL; + ext->pModifiersMask = NULL; + ext->confineTo = None; + ext->cursor = None; + } else + ext = GRABEXT(grab); + if ((grab->keybut == AnyKey) && (grab->modifiers != AnyModifier)) + { + /* + * If the list entry has the key detail of AnyKey, and + * a modifier detail not set to AnyModifier, then we + * simply need to turn off the key detail bit in the + * list entry's key detail mask. + */ + DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut); + } else if ((grab->modifiers == AnyModifier) && + (grab->keybut != AnyKey)) { + /* + * The list entry has a specific key detail, but its + * modifier detail is set to AnyModifier; so, we only + * need to turn off the specified modifier combination + * in the list entry's modifier mask. + */ + DeleteDetailFromMask(&ext->pModifiersMask, + pMinuendGrab->modifiers); + } else if ((pMinuendGrab->keybut != AnyKey) && + (pMinuendGrab->modifiers != AnyModifier)) { + /* + * The list entry has a key detail of AnyKey and a + * modifier detail of AnyModifier; the entry being + * deleted has a specific key and a specific modifier + * combination. Therefore, we need to mask off the + * keycode from the list entry, and also create a + * new entry for this keycode, which has a modifier + * mask set to AnyModifier & ~(deleted modifiers). + */ + XtServerGrabPtr pNewGrab; + + DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut); + pNewGrab = CreateGrab(grab->widget, + (Boolean)grab->ownerEvents, + (Modifiers)AnyModifier, + pMinuendGrab->keybut, + (int)grab->pointerMode, + (int)grab->keyboardMode, + (Mask)0, (Window)0, (Cursor)0, True); + GRABEXT(pNewGrab)->pModifiersMask = + CopyDetailMask(ext->pModifiersMask); + + DeleteDetailFromMask(&GRABEXT(pNewGrab)->pModifiersMask, + pMinuendGrab->modifiers); + + pNewGrab->next = *passiveListPtr; + *passiveListPtr = pNewGrab; + } else if (pMinuendGrab->keybut == AnyKey) { + /* + * The list entry has keycode AnyKey and modifier + * AnyModifier; the entry being deleted has + * keycode AnyKey and specific modifiers. So we + * simply need to mask off the specified modifier + * combination. + */ + DeleteDetailFromMask(&ext->pModifiersMask, + pMinuendGrab->modifiers); + } else { + /* + * The list entry has keycode AnyKey and modifier + * AnyModifier; the entry being deleted has a + * specific keycode and modifier AnyModifier. So + * we simply need to mask off the specified + * keycode. + */ + DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut); + } + } + next = &(*next)->next; + } +} + +static void DestroyPassiveList(passiveListPtr) + XtServerGrabPtr *passiveListPtr; +{ + XtServerGrabPtr next, grab; + + for (next = *passiveListPtr; next; ) { + grab = next; + next = grab->next; + + /* not necessary to explicitly ungrab key or button; + * window is being destroyed so server will take care of it. + */ + + FreeGrab(grab); + } +} + + +/* + * This function is called at widget destroy time to clean up + */ +/*ARGSUSED*/ +void _XtDestroyServerGrabs(w, closure, call_data) + Widget w; + XtPointer closure; + XtPointer call_data; /* unused */ +{ + XtPerWidgetInput pwi = (XtPerWidgetInput)closure; + XtPerDisplayInput pdi; + + LOCK_PROCESS; + pdi = _XtGetPerDisplayInput(XtDisplay(w)); + _XtClearAncestorCache(w); + UNLOCK_PROCESS; + + /* Remove the active grab, if necessary */ + if ((pdi->keyboard.grabType != XtNoServerGrab) && + (pdi->keyboard.grab.widget == w)) { + pdi->keyboard.grabType = XtNoServerGrab; + pdi->activatingKey = (KeyCode)0; + } + if ((pdi->pointer.grabType != XtNoServerGrab) && + (pdi->pointer.grab.widget == w)) + pdi->pointer.grabType = XtNoServerGrab; + + DestroyPassiveList(&pwi->keyList); + DestroyPassiveList(&pwi->ptrList); + + _XtFreePerWidgetInput(w, pwi); +} + +/* + * If the incoming event is on the passive grab list, then activate + * the grab. The grab will remain in effect until the key is released. + */ + +#if NeedFunctionPrototypes +XtServerGrabPtr _XtCheckServerGrabsOnWidget ( + XEvent *event, + Widget widget, + _XtBoolean isKeyboard + ) +#else +XtServerGrabPtr _XtCheckServerGrabsOnWidget (event, widget, isKeyboard) + XEvent *event; + Widget widget; + Boolean isKeyboard; +#endif +{ + register XtServerGrabPtr grab; + XtServerGrabRec tempGrab; + XtServerGrabPtr *passiveListPtr; + XtPerWidgetInput pwi; + + LOCK_PROCESS; + pwi = _XtGetPerWidgetInput(widget, FALSE); + UNLOCK_PROCESS; + if (!pwi) + return (XtServerGrabPtr)NULL; + if (isKeyboard) + passiveListPtr = &pwi->keyList; + else + passiveListPtr = &pwi->ptrList; + + /* + * if either there is no entry in the context manager or the entry + * is empty, or the keyboard is grabed, then no work to be done + */ + if (!*passiveListPtr) + return (XtServerGrabPtr)NULL; + + /* Take only the lower thirteen bits as modifier state. The X Keyboard + * Extension may be representing keyboard group state in two upper bits. + */ + tempGrab.widget = widget; + tempGrab.keybut = event->xkey.keycode; /* also xbutton.button */ + tempGrab.modifiers = event->xkey.state & 0x1FFF; /*also xbutton.state*/ + tempGrab.hasExt = False; + + for (grab = *passiveListPtr; grab; grab = grab->next) { + if (GrabMatchesSecond(&tempGrab, grab)) + return (grab); + } + return (XtServerGrabPtr)NULL; +} + +/* + * This handler is needed to guarantee that we see releases on passive + * button grabs for widgets that haven't selected for button release. + */ + +/*ARGSUSED*/ +static void ActiveHandler (widget, pdi, event, cont) + Widget widget; + XtPointer pdi; + XEvent *event; + Boolean *cont; +{ + /* nothing */ +} + + +/* + * MakeGrab + */ +static void MakeGrab(grab, passiveListPtr, isKeyboard, pdi, pwi) + XtServerGrabPtr grab; + XtServerGrabPtr *passiveListPtr; + Boolean isKeyboard; + XtPerDisplayInput pdi; + XtPerWidgetInput pwi; +{ + if (!isKeyboard && !pwi->active_handler_added) { + XtAddEventHandler(grab->widget, ButtonReleaseMask, FALSE, + ActiveHandler, (XtPointer)pdi); + pwi->active_handler_added = TRUE; + } + + if (isKeyboard) { + XGrabKey(pDisplay(grab), + grab->keybut, grab->modifiers, + pWindow(grab), grab->ownerEvents, + grab->pointerMode, grab->keyboardMode); + } else { + Window confineTo = None; + Cursor cursor = None; + + if (grab->hasExt) { + if (grab->confineToIsWidgetWin) + confineTo = XtWindow (grab->widget); + else + confineTo = GRABEXT(grab)->confineTo; + cursor = GRABEXT(grab)->cursor; + } + XGrabButton(pDisplay(grab), + grab->keybut, grab->modifiers, + pWindow(grab), grab->ownerEvents, grab->eventMask, + grab->pointerMode, grab->keyboardMode, + confineTo, cursor); + } + + /* Add the new grab entry to the passive key grab list */ + grab->next = *passiveListPtr; + *passiveListPtr = grab; +} + +static void MakeGrabs(passiveListPtr, isKeyboard, pdi) + XtServerGrabPtr *passiveListPtr; + Boolean isKeyboard; + XtPerDisplayInput pdi; +{ + XtServerGrabPtr next = *passiveListPtr; + XtServerGrabPtr grab; + XtPerWidgetInput pwi; + /* + * make MakeGrab build a new list that has had the merge + * processing done on it. Start with an empty list + * (passiveListPtr). + */ + LOCK_PROCESS; + *passiveListPtr = NULL; + while (next) + { + grab = next; + next = grab->next; + pwi = _XtGetPerWidgetInput(grab->widget, FALSE); + MakeGrab(grab, passiveListPtr, isKeyboard, pdi, pwi); + } + UNLOCK_PROCESS; +} + +/* + * This function is the event handler attached to the associated widget + * when grabs need to be added, but the widget is not yet realized. When + * it is first mapped, this handler will be invoked, and it will add all + * needed grabs. + */ + +/*ARGSUSED*/ +static void RealizeHandler (widget, closure, event, cont) + Widget widget; + XtPointer closure; + XEvent *event; /* unused */ + Boolean *cont; /* unused */ +{ + XtPerWidgetInput pwi = (XtPerWidgetInput)closure; + XtPerDisplayInput pdi; + + LOCK_PROCESS; + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + UNLOCK_PROCESS; + MakeGrabs(&pwi->keyList, KEYBOARD, pdi); + MakeGrabs(&pwi->ptrList, POINTER, pdi); + + XtRemoveEventHandler(widget, XtAllEvents, True, + RealizeHandler, (XtPointer)pwi); + pwi->realize_handler_added = FALSE; +} + +/***************************************************************************/ +/**************************** Global Routines ******************************/ +/***************************************************************************/ + + +/* + * Routine used by an application to set up a passive grab for a key/modifier + * combination. + */ + +static +void GrabKeyOrButton (widget, keyOrButton, modifiers, owner_events, + pointer_mode, keyboard_mode, event_mask, + confine_to, cursor, isKeyboard) + Widget widget; + KeyCode keyOrButton; + Modifiers modifiers; + Boolean owner_events; + int pointer_mode; + int keyboard_mode; + Mask event_mask; + Window confine_to; + Cursor cursor; + Boolean isKeyboard; +{ + XtServerGrabPtr *passiveListPtr; + XtServerGrabPtr newGrab; + XtPerWidgetInput pwi; + XtPerDisplayInput pdi; + + + XtCheckSubclass(widget, coreWidgetClass, "in XtGrabKey or XtGrabButton"); + LOCK_PROCESS; + pwi = _XtGetPerWidgetInput(widget, TRUE); + if (isKeyboard) + passiveListPtr = &pwi->keyList; + else + passiveListPtr = &pwi->ptrList; + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + UNLOCK_PROCESS; + newGrab = CreateGrab(widget, owner_events, modifiers, + keyOrButton, pointer_mode, keyboard_mode, + event_mask, confine_to, cursor, False); + /* + * if the widget is realized then process the entry into the grab + * list. else if the list is empty (i.e. first time) then add the + * event handler. then add the raw entry to the list for processing + * in the handler at realize time. + */ + if (XtIsRealized(widget)) + MakeGrab(newGrab, passiveListPtr, isKeyboard, pdi, pwi); + else { + if (!pwi->realize_handler_added) + { + XtAddEventHandler(widget, StructureNotifyMask, FALSE, + RealizeHandler, + (XtPointer)pwi); + pwi->realize_handler_added = TRUE; + } + + while (*passiveListPtr) + passiveListPtr = &(*passiveListPtr)->next; + *passiveListPtr = newGrab; + } +} + + +static +void UngrabKeyOrButton (widget, keyOrButton, modifiers, isKeyboard) + Widget widget; + int keyOrButton; + Modifiers modifiers; + Boolean isKeyboard; +{ + XtServerGrabRec tempGrab; + XtPerWidgetInput pwi; + + XtCheckSubclass(widget, coreWidgetClass, + "in XtUngrabKey or XtUngrabButton"); + + /* Build a temporary grab list entry */ + tempGrab.widget = widget; + tempGrab.modifiers = modifiers; + tempGrab.keybut = keyOrButton; + tempGrab.hasExt = False; + + LOCK_PROCESS; + pwi = _XtGetPerWidgetInput(widget, FALSE); + UNLOCK_PROCESS; + /* + * if there is no entry in the context manager then somethings wrong + */ + if (!pwi) + { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidGrab", "ungrabKeyOrButton", XtCXtToolkitError, + "Attempt to remove nonexistent passive grab", + (String *)NULL, (Cardinal *)NULL); + return; + } + + if (XtIsRealized(widget)) + { + if (isKeyboard) + XUngrabKey(widget->core.screen->display, + keyOrButton, (unsigned int)modifiers, + widget->core.window); + else + XUngrabButton(widget->core.screen->display, + keyOrButton, (unsigned int)modifiers, + widget->core.window); + } + + + /* Delete all entries which are encompassed by the specified grab. */ + DeleteServerGrabFromList(isKeyboard ? &pwi->keyList : &pwi->ptrList, + &tempGrab); +} + +#if NeedFunctionPrototypes +void XtGrabKey ( + Widget widget, + _XtKeyCode keycode, + Modifiers modifiers, + _XtBoolean owner_events, + int pointer_mode, + int keyboard_mode + ) +#else +void XtGrabKey (widget, keycode, modifiers, owner_events, + pointer_mode, keyboard_mode) + Widget widget; + KeyCode keycode; + Modifiers modifiers; + Boolean owner_events; + int pointer_mode; + int keyboard_mode; +#endif +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + GrabKeyOrButton(widget, (KeyCode)keycode, modifiers, owner_events, + pointer_mode, keyboard_mode, + (Mask)0, (Window)None, (Cursor)None, KEYBOARD); + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtGrabButton( + Widget widget, + int button, + Modifiers modifiers, + _XtBoolean owner_events, + unsigned int event_mask, + int pointer_mode, + int keyboard_mode, + Window confine_to, + Cursor cursor + ) +#else +void XtGrabButton(widget, button, modifiers, owner_events, + event_mask, pointer_mode, keyboard_mode, + confine_to, cursor) + Widget widget; + int button; + Modifiers modifiers; + Boolean owner_events; + unsigned int event_mask; + int pointer_mode; + int keyboard_mode; + Window confine_to; + Cursor cursor; +#endif +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + GrabKeyOrButton(widget, (KeyCode)button, modifiers, owner_events, + pointer_mode, keyboard_mode, + (Mask)event_mask, confine_to, cursor, POINTER); + UNLOCK_APP(app); +} + + +/* + * Routine used by an application to clear a passive grab for a key/modifier + * combination. + */ + +#if NeedFunctionPrototypes +void XtUngrabKey ( + Widget widget, + _XtKeyCode keycode, + Modifiers modifiers + ) +#else +void XtUngrabKey (widget, keycode, modifiers) + Widget widget; + KeyCode keycode; + Modifiers modifiers; +#endif +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + UngrabKeyOrButton(widget, (int)keycode, modifiers, KEYBOARD); + UNLOCK_APP(app); +} + +void XtUngrabButton (widget, button, modifiers) + Widget widget; + unsigned int button; + Modifiers modifiers; +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + UngrabKeyOrButton(widget, (KeyCode)button, modifiers, POINTER); + UNLOCK_APP(app); +} + +/* + * Active grab of Device. clear any client side grabs so we dont lock + */ +static int GrabDevice (widget, owner_events, + pointer_mode, keyboard_mode, + event_mask, confine_to, cursor, time, isKeyboard) + Widget widget; + Boolean owner_events; + int pointer_mode; + int keyboard_mode; + Mask event_mask; + Window confine_to; + Cursor cursor; + Time time; + Boolean isKeyboard; +{ + XtPerDisplayInput pdi; + int returnVal; + + XtCheckSubclass(widget, coreWidgetClass, + "in XtGrabKeyboard or XtGrabPointer"); + if (!XtIsRealized(widget)) + return GrabNotViewable; + LOCK_PROCESS; + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + UNLOCK_PROCESS; + if (!isKeyboard) + returnVal = XGrabPointer(XtDisplay(widget), XtWindow(widget), + owner_events, event_mask, + pointer_mode, keyboard_mode, + confine_to, cursor, time); + else + returnVal = XGrabKeyboard(XtDisplay(widget), XtWindow(widget), + owner_events, pointer_mode, + keyboard_mode, time); + + if (returnVal == GrabSuccess) { + XtDevice device; + + device = isKeyboard ? &pdi->keyboard : &pdi->pointer; + /* fill in the server grab rec */ + device->grab.widget = widget; + device->grab.modifiers = 0; + device->grab.keybut = 0; + device->grab.ownerEvents = owner_events; + device->grab.pointerMode = pointer_mode; + device->grab.keyboardMode = keyboard_mode; + device->grab.hasExt = False; + device->grabType = XtActiveServerGrab; + pdi->activatingKey = (KeyCode)0; + } + return returnVal; +} + +static void UngrabDevice(widget, time, isKeyboard) + Widget widget; + Time time; + Boolean isKeyboard; +{ + XtPerDisplayInput pdi; + XtDevice device; + + LOCK_PROCESS; + pdi = _XtGetPerDisplayInput(XtDisplay(widget)); + UNLOCK_PROCESS; + device = isKeyboard ? &pdi->keyboard : &pdi->pointer; + XtCheckSubclass(widget, coreWidgetClass, + "in XtUngrabKeyboard or XtUngrabPointer"); + + if (device->grabType != XtNoServerGrab) { + + if (device->grabType != XtPseudoPassiveServerGrab + && XtIsRealized(widget)) { + if (isKeyboard) + XUngrabKeyboard(XtDisplay(widget), time); + else + XUngrabPointer(XtDisplay(widget), time); + } + device->grabType = XtNoServerGrab; + pdi->activatingKey = (KeyCode)0; + } +} + + +/* + * Active grab of keyboard. clear any client side grabs so we dont lock + */ +#if NeedFunctionPrototypes +int XtGrabKeyboard ( + Widget widget, + _XtBoolean owner_events, + int pointer_mode, + int keyboard_mode, + Time time + ) +#else +int XtGrabKeyboard (widget, owner_events, + pointer_mode, keyboard_mode, time) + Widget widget; + Boolean owner_events; + int pointer_mode; + int keyboard_mode; + Time time; +#endif +{ + int retval; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + retval = GrabDevice (widget, owner_events, + pointer_mode, keyboard_mode, + (Mask)0, (Window)None, (Cursor)None, time, KEYBOARD); + UNLOCK_APP(app); + return retval; +} + + +/* + * Ungrab the keyboard + */ + +void XtUngrabKeyboard(widget, time) + Widget widget; + Time time; +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + UngrabDevice(widget, time, KEYBOARD); + UNLOCK_APP(app); +} + + + + +/* + * grab the pointer + */ +#if NeedFunctionPrototypes +int XtGrabPointer ( + Widget widget, + _XtBoolean owner_events, + unsigned int event_mask, + int pointer_mode, + int keyboard_mode, + Window confine_to, + Cursor cursor, + Time time + ) +#else +int XtGrabPointer (widget, owner_events, event_mask, + pointer_mode, keyboard_mode, + confine_to, cursor, time) + Widget widget; + Boolean owner_events; + unsigned int event_mask; + int pointer_mode; + int keyboard_mode; + Window confine_to; + Cursor cursor; + Time time; +#endif +{ + int retval; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + retval = GrabDevice (widget, owner_events, + pointer_mode, keyboard_mode, + (Mask)event_mask, confine_to, + cursor, time, POINTER); + UNLOCK_APP(app); + return retval; +} + + +/* + * Ungrab the pointer + */ + +void XtUngrabPointer(widget, time) + Widget widget; + Time time; +{ + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + UngrabDevice(widget, time, POINTER); + UNLOCK_APP(app); +} + + +void _XtRegisterPassiveGrabs (widget) + Widget widget; +{ + XtPerWidgetInput pwi = _XtGetPerWidgetInput (widget, FALSE); + + if (pwi != NULL && !pwi->realize_handler_added) { + XtAddEventHandler(widget, StructureNotifyMask, FALSE, + RealizeHandler, + (XtPointer)pwi); + pwi->realize_handler_added = TRUE; + } +} + diff --git a/src/Pointer.c b/src/Pointer.c new file mode 100644 index 0000000..1c981d2 --- /dev/null +++ b/src/Pointer.c @@ -0,0 +1,112 @@ +/* $Xorg: Pointer.c,v 1.4 2001/02/09 02:03:56 xorgcvs Exp $ */ + +/******************************************************** + +Copyright 1988 by Hewlett-Packard Company +Copyright 1987, 1988, 1989 by Digital Equipment Corporation, Maynard + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the names of +Hewlett-Packard or Digital not be used in advertising or +publicity pertaining to distribution of the software without specific, +written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + +/* + +Copyright 1987, 1988, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "PassivGraI.h" + + +#define AllButtonsMask (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask) + +Widget _XtProcessPointerEvent(event, widget, pdi) + XButtonEvent *event; + Widget widget; + XtPerDisplayInput pdi; +{ + XtDevice device = &pdi->pointer; + XtServerGrabPtr newGrab = NULL, devGrab = &device->grab; + Widget dspWidget = NULL; + Boolean deactivateGrab = FALSE; + + switch (event->type) + { + case ButtonPress: + { + if (!IsServerGrab(device->grabType)) + { + Cardinal i; + + for (i = pdi->traceDepth; + i > 0 && !newGrab; + i--) + newGrab = _XtCheckServerGrabsOnWidget((XEvent*)event, + pdi->trace[i-1], + POINTER); + } + if (newGrab) + { + /* Activate the grab */ + device->grab = *newGrab; + device->grabType = XtPassiveServerGrab; + } + } + break; + + case ButtonRelease: + { + if ((device->grabType == XtPassiveServerGrab) && + !(event->state & ~(Button1Mask << (event->button - 1)) & + AllButtonsMask)) + deactivateGrab = TRUE; + } + break; + } + + if (IsServerGrab(device->grabType) && !(devGrab)->ownerEvents) + dspWidget = (devGrab)->widget; + else + dspWidget = widget; + + if (deactivateGrab) + device->grabType = XtNoServerGrab; + + return dspWidget; +} diff --git a/src/Popup.c b/src/Popup.c new file mode 100644 index 0000000..1549a68 --- /dev/null +++ b/src/Popup.c @@ -0,0 +1,211 @@ +/* $Xorg: Popup.c,v 1.4 2001/02/09 02:03:56 xorgcvs Exp $ */ + +/*********************************************************** + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#include "IntrinsicI.h" +#include "ShellP.h" + +#if NeedFunctionPrototypes +void _XtPopup( + Widget widget, + XtGrabKind grab_kind, + _XtBoolean spring_loaded + ) +#else +void _XtPopup(widget, grab_kind, spring_loaded) + Widget widget; + XtGrabKind grab_kind; + Boolean spring_loaded; +#endif +{ + register ShellWidget shell_widget = (ShellWidget) widget; + + if (! XtIsShell(widget)) { + XtAppErrorMsg(XtWidgetToApplicationContext(widget), + "invalidClass","xtPopup",XtCXtToolkitError, + "XtPopup requires a subclass of shellWidgetClass", + (String *)NULL, (Cardinal *)NULL); + } + + if (! shell_widget->shell.popped_up) { + XtGrabKind call_data = grab_kind; + XtCallCallbacks(widget, XtNpopupCallback, (XtPointer)&call_data); + shell_widget->shell.popped_up = TRUE; + shell_widget->shell.grab_kind = grab_kind; + shell_widget->shell.spring_loaded = spring_loaded; + if (shell_widget->shell.create_popup_child_proc != NULL) { + (*(shell_widget->shell.create_popup_child_proc))(widget); + } + if (grab_kind == XtGrabExclusive) { + XtAddGrab(widget, TRUE, spring_loaded); + } else if (grab_kind == XtGrabNonexclusive) { + XtAddGrab(widget, FALSE, spring_loaded); + } + XtRealizeWidget(widget); + XMapRaised(XtDisplay(widget), XtWindow(widget)); + } else + XRaiseWindow(XtDisplay(widget), XtWindow(widget)); + +} /* _XtPopup */ + +#if NeedFunctionPrototypes +void XtPopup (Widget widget, XtGrabKind grab_kind) +#else +void XtPopup (widget, grab_kind) + Widget widget; + XtGrabKind grab_kind; +#endif +{ + Widget hookobj; + + switch (grab_kind) { + + case XtGrabNone: + case XtGrabExclusive: + case XtGrabNonexclusive: + break; + + default: + XtAppWarningMsg( + XtWidgetToApplicationContext(widget), + "invalidGrabKind","xtPopup",XtCXtToolkitError, + "grab kind argument has invalid value; XtGrabNone assumed", + (String *)NULL, (Cardinal *)NULL); + grab_kind = XtGrabNone; + } + + _XtPopup(widget, grab_kind, FALSE); + + hookobj = XtHooksOfDisplay(XtDisplay(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHpopup; + call_data.widget = widget; + call_data.event_data = (XtPointer)grab_kind; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } +} /* XtPopup */ + +void XtPopupSpringLoaded (widget) + Widget widget; +{ + Widget hookobj; + + _XtPopup(widget, XtGrabExclusive, True); + + hookobj = XtHooksOfDisplay(XtDisplay(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHpopupSpringLoaded; + call_data.widget = widget; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } +} + +void XtPopdown(widget) + Widget widget; +{ + /* Unmap a shell widget if it is mapped, and remove from grab list */ + Widget hookobj; + ShellWidget shell_widget = (ShellWidget) widget; + XtGrabKind grab_kind; + + if (! XtIsShell(widget)) { + XtAppErrorMsg(XtWidgetToApplicationContext(widget), + "invalidClass","xtPopdown",XtCXtToolkitError, + "XtPopdown requires a subclass of shellWidgetClass", + (String *)NULL, (Cardinal *)NULL); + } + +#ifndef X_NO_XT_POPDOWN_CONFORMANCE + if (!shell_widget->shell.popped_up) + return; +#endif + + grab_kind = shell_widget->shell.grab_kind; + XWithdrawWindow(XtDisplay(widget), XtWindow(widget), + XScreenNumberOfScreen(XtScreen(widget))); + if (grab_kind != XtGrabNone) + XtRemoveGrab(widget); + shell_widget->shell.popped_up = FALSE; + XtCallCallbacks(widget, XtNpopdownCallback, (XtPointer)&grab_kind); + + hookobj = XtHooksOfDisplay(XtDisplay(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHpopdown; + call_data.widget = widget; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } +} /* XtPopdown */ + +/* ARGSUSED */ +void XtCallbackPopdown(widget, closure, call_data) + Widget widget; + XtPointer closure; + XtPointer call_data; +{ + register XtPopdownID id = (XtPopdownID) closure; + + XtPopdown(id->shell_widget); + if (id->enable_widget != NULL) { + XtSetSensitive(id->enable_widget, TRUE); + } +} /* XtCallbackPopdown */ + + + diff --git a/src/PopupCB.c b/src/PopupCB.c new file mode 100644 index 0000000..25ea17d --- /dev/null +++ b/src/PopupCB.c @@ -0,0 +1,81 @@ +/* $Xorg: PopupCB.c,v 1.4 2001/02/09 02:03:56 xorgcvs Exp $ */ + +/*********************************************************** + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#include "IntrinsicI.h" + +/* ARGSUSED */ +void XtCallbackNone(widget, closure, call_data) + Widget widget; + XtPointer closure; + XtPointer call_data; +{ + XtSetSensitive(widget, FALSE); + _XtPopup((Widget) closure, XtGrabNone, FALSE); +} /* XtCallbackNone */ + +/* ARGSUSED */ +void XtCallbackNonexclusive(widget, closure, call_data) + Widget widget; + XtPointer closure; + XtPointer call_data; +{ + + XtSetSensitive(widget, FALSE); + _XtPopup((Widget) closure, XtGrabNonexclusive, FALSE); +} /* XtCallbackNonexclusive */ + +/* ARGSUSED */ +void XtCallbackExclusive(widget, closure, call_data) + Widget widget; + XtPointer closure; + XtPointer call_data; +{ + XtSetSensitive(widget, FALSE); + _XtPopup((Widget) closure, XtGrabExclusive, FALSE); +} /* XtCallbackExclusive */ diff --git a/src/RectObj.c b/src/RectObj.c new file mode 100644 index 0000000..6d4708f --- /dev/null +++ b/src/RectObj.c @@ -0,0 +1,188 @@ +/* $Xorg: RectObj.c,v 1.4 2001/02/09 02:03:56 xorgcvs Exp $ */ + +/*********************************************************** + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +#define RECTOBJ +#include "IntrinsicI.h" +#include "StringDefs.h" +/****************************************************************** + * + * Rectangle Object Resources + * + ******************************************************************/ + +static void XtCopyAncestorSensitive(); + +static XtResource resources[] = { + + {XtNancestorSensitive, XtCSensitive, XtRBoolean, sizeof(Boolean), + XtOffsetOf(RectObjRec,rectangle.ancestor_sensitive),XtRCallProc, + (XtPointer)XtCopyAncestorSensitive}, + {XtNx, XtCPosition, XtRPosition, sizeof(Position), + XtOffsetOf(RectObjRec,rectangle.x), XtRImmediate, (XtPointer)0}, + {XtNy, XtCPosition, XtRPosition, sizeof(Position), + XtOffsetOf(RectObjRec,rectangle.y), XtRImmediate, (XtPointer)0}, + {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension), + XtOffsetOf(RectObjRec,rectangle.width), XtRImmediate, (XtPointer)0}, + {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension), + XtOffsetOf(RectObjRec,rectangle.height), XtRImmediate, (XtPointer)0}, + {XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension), + XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, + (XtPointer)1}, + {XtNsensitive, XtCSensitive, XtRBoolean, sizeof(Boolean), + XtOffsetOf(RectObjRec,rectangle.sensitive), XtRImmediate, + (XtPointer)True} + }; + +static void RectClassPartInitialize(); +static void RectSetValuesAlmost(); + +externaldef(rectobjclassrec) RectObjClassRec rectObjClassRec = { + { + /* superclass */ (WidgetClass)&objectClassRec, + /* class_name */ "Rect", + /* widget_size */ sizeof(RectObjRec), + /* class_initialize */ NULL, + /* class_part_initialize*/ RectClassPartInitialize, + /* class_inited */ FALSE, + /* initialize */ NULL, + /* initialize_hook */ NULL, + /* realize */ NULL, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ NULL, + /* expose */ NULL, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ RectSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + } +}; + +externaldef(rectObjClass) +WidgetClass rectObjClass = (WidgetClass)&rectObjClassRec; + +/*ARGSUSED*/ +static void XtCopyAncestorSensitive(widget, offset, value) + Widget widget; + int offset; + XrmValue *value; +{ + static Boolean sensitive; + Widget parent = widget->core.parent; + + sensitive = (parent->core.ancestor_sensitive & parent->core.sensitive); + value->addr = (XPointer)(&sensitive); +} + + +/* + * Start of rectangle object methods + */ + + +static void RectClassPartInitialize(wc) + register WidgetClass wc; +{ + register RectObjClass roc = (RectObjClass)wc; + register RectObjClass super = ((RectObjClass)roc->rect_class.superclass); + + /* We don't need to check for null super since we'll get to object + eventually, and it had better define them! */ + + + if (roc->rect_class.resize == XtInheritResize) { + roc->rect_class.resize = super->rect_class.resize; + } + + if (roc->rect_class.expose == XtInheritExpose) { + roc->rect_class.expose = super->rect_class.expose; + } + + if (roc->rect_class.set_values_almost == XtInheritSetValuesAlmost) { + roc->rect_class.set_values_almost = super->rect_class.set_values_almost; + } + + + if (roc->rect_class.query_geometry == XtInheritQueryGeometry) { + roc->rect_class.query_geometry = super->rect_class.query_geometry; + } +} + +/* + * Why there isn't an Initialize Method: + * + * Initialization of the RectObj non-Resource field is done by the + * intrinsics in _XtCreateWidget in order that the field is initialized + * for use by converters during instance resource resolution. + */ + +/*ARGSUSED*/ +static void RectSetValuesAlmost(old, new, request, reply) + Widget old; + Widget new; + XtWidgetGeometry *request; + XtWidgetGeometry *reply; +{ + *request = *reply; +} diff --git a/src/ResConfig.c b/src/ResConfig.c new file mode 100644 index 0000000..68ccbb7 --- /dev/null +++ b/src/ResConfig.c @@ -0,0 +1,1020 @@ +/* $Xorg: ResConfig.c,v 1.5 2001/02/09 02:03:56 xorgcvs Exp $ */ +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ +/***************************************************************** + +(C) COPYRIGHT International Business Machines Corp. 1992,1997 + All Rights Reserved + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE IBM CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, +BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the IBM Corporation shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in this Software without prior written authorization from the IBM +Corporation. + +******************************************************************/ + +#include "Intrinsic.h" +#include "IntrinsicI.h" +#include "Core.h" +#include "CoreP.h" +#include "ShellP.h" +#include "StringDefs.h" +#include "ResConfigP.h" +#include <X11/Xatom.h> + +#ifdef DEBUG +#include <stdio.h> +#endif + +#define MAX_BUFFER 512 + +static void _search_child(); +static void _set_and_search(); +static int _locate_children(); + +#if defined(sun) && !defined(SVR4) +# define Strtoul(a,b,c) (unsigned long)strtol(a,b,c) +#else +# define Strtoul(a,b,c) strtoul(a,b,c) +#endif + + +/* + * NAME: _set_resource_values + * + * FUNCTION: + * This function sets the value on the widget. It must first determine + * if the last part is a valid resource for that widget. (eg. + * labelString is a valid resource for label but not for bulletin board) + * It must also add the resource to the application's resource database + * and then query it out using specific resource strings that it builds + * from the widget information. This ensures that a customizing tool + * on-the-fly paradigm is followed: an application that is + * instantaneously updated should look the same as one that is restarted + * and uses the .Xdefaults file. + * + * PARAMETERS: + * w the widget to match + * resource the resource string to be matched + * value the value to be set + * last_part the last resource part (e.g. *background) + * + * RETURN VALUES: void + * + * ERRORS: none + */ +static void +_set_resource_values (w, resource, value, last_part) + Widget w; + char *resource; + char *value; + char *last_part; +{ + XrmDatabase db = NULL; + char *resource_name = NULL; + char *resource_class = NULL; + char *return_type; + XrmValue return_value; + char *resource_value; + Widget cur = w; + char *temp; + XtResourceList resources_return = NULL; + Cardinal num_resources_return = 0; + int res_index; + Boolean found_resource = False; + Display *dpy; + XrmDatabase tmp_db; + + if (!XtIsWidget (w)) + dpy = XtDisplay (w->core.parent); + else + dpy = XtDisplay (w); + tmp_db = XtDatabase(dpy); + + /* + * get a list of all the valid resources for this widget + */ + XtGetResourceList (w->core.widget_class, + &resources_return, &num_resources_return); + + /* + * try to match the last_part of the resource string with + * a resource in this resource list + */ + for (res_index=0; res_index<num_resources_return; res_index++) { + if ((strcmp (last_part, + resources_return[res_index].resource_name) == 0) || + (strcmp (last_part, + resources_return[res_index].resource_class) == 0)) { + found_resource = True; + break; + } + } + + /* + * if resource is not a valid resource for this widget + * or the resource name or class are NULL + * then exit this function + */ + if (!found_resource + || !resources_return[res_index].resource_name + || !resources_return[res_index].resource_class) { + XtFree ((char *) resources_return); + return; + } + + /* + * build the full resource name and class specifications so + * that you can query the resource database + * eg: .app.button1.foreground + * .App.XmPushButton.Foreground + */ + while (cur != NULL) { + /* + * create resource name string + */ + if (resource_name) { + temp = XtMalloc (sizeof(char) * + (2 + strlen(cur->core.name) + + strlen(resource_name))); + sprintf (temp, ".%s%s", cur->core.name, resource_name); + XtFree (resource_name); + } else if (!XtIsWidget (cur) || !cur->core.name) { + cur = XtParent(cur); + continue; + } else { + temp = XtMalloc (sizeof(char) * + (2 + strlen(cur->core.name))); + sprintf (temp, ".%s", cur->core.name); + } + resource_name = temp; + + /* + * create resource class string + */ + if ((XtIsTopLevelShell (cur)) && (XtParent (cur) == NULL)) { + ApplicationShellWidget top = + (ApplicationShellWidget) (cur); + + if (resource_class) { + temp = XtMalloc (sizeof(char) * + (2 + strlen(top->application.class) + + strlen(resource_class))); + sprintf (temp, ".%s%s", + top->application.class, resource_class); + } else { + temp = XtMalloc (sizeof(char) * + (2 + strlen(top->application.class))); + sprintf (temp, ".%s", + top->application.class); + } + } else { + if (resource_class) { + temp = XtMalloc (sizeof(char) * + (2 + strlen( + cur->core.widget_class->core_class.class_name) + + strlen(resource_class))); + sprintf (temp, ".%s%s", + cur->core.widget_class->core_class.class_name, + resource_class); + } else { + temp = XtMalloc (sizeof(char) * + (2 + strlen( + cur->core.widget_class->core_class.class_name))); + sprintf (temp, ".%s", + cur->core.widget_class->core_class.class_name); + } + } + if (resource_class != NULL) + XtFree (resource_class); + resource_class = temp; + + cur = XtParent(cur); + } + + /* + * add the resource name to the end of the resource name string + */ + temp = XtMalloc (2 + strlen(resource_name) + + strlen(resources_return[res_index].resource_name)); + sprintf (temp, "%s.%s", resource_name, + resources_return[res_index].resource_name); + if (resource_name != NULL) + XtFree (resource_name); + resource_name = temp; + + /* + * add the resource class to the end of the resource class string + */ + temp = XtMalloc (2 + strlen(resource_class) + + strlen(resources_return[res_index].resource_class)); + sprintf (temp, "%s.%s", resource_class, + resources_return[res_index].resource_class); + if (resource_class != NULL) + XtFree (resource_class); + resource_class = temp; + +#ifdef DEBUG + fprintf (stderr, "resource_name = %s\n", resource_name); + fprintf (stderr, "resource_class = %s\n", resource_class); +#endif + + /* + * put the resource and its value in a resource database and + * then query it back out again using the specific name and + * class resource strings that were built above. This is + * necessary to maintain a precedence similar to the .Xdefaults + * file + */ + XrmPutStringResource (&db, resource, value); + XrmMergeDatabases (db, &tmp_db); + XrmGetResource (tmp_db, resource_name, resource_class, + &return_type, &return_value); + if (return_type) + resource_value = XtNewString (return_value.addr); + else + resource_value = XtNewString (value); + +#ifdef DEBUG + fprintf (stderr, + "Apply:\n\twidget = %s\n\tlast_part = %s\n\tvalue = %s\n", + (w->core.name == NULL) ? "NULL" : w->core.name, + resources_return[res_index].resource_name, + resource_value); +#endif + /* + * use XtVaSetValues with XtVaTypedArg to convert the value of + * type String the the same type as the resource (last_part). + * Then set the value. + */ + XtVaSetValues (w, + XtVaTypedArg, resources_return[res_index].resource_name, + XtRString, resource_value, + strlen (resource_value) + 1, + NULL); + + XtFree ((char *) resources_return); + XtFree (resource_name); + XtFree (resource_class); + XtFree (resource_value); +} + +/* + * NAME: _apply_values_to_children + * + * FUNCTION: + * Once the resource string matches the value must be applied to + * all children if applicable. (eg. App*Form.background must apply + * background to all children of the Form widget) + * + * PARAMETERS: + * w the widget to match + * remainder the part of the resource string left over + * resource the resource string to be matched + * value the value to be set + * last_token the last * or . before the final resoruce part + * last_part the last resource part (e.g. *background) + * + * RETURN VALUES: void + * + * ERRORS: none + */ +static void +_apply_values_to_children (w, remainder, resource, value, last_token, last_part) + Widget w; + char *remainder; + char *resource; + char *value; + char last_token; + char *last_part; +{ + int i; + int num_children; + Widget *children; + + /* + * Recursively search through the children + */ + num_children = _locate_children (w, &children); + + for (i=0; i<num_children; i++) { + +#ifdef DEBUG + if (XtIsWidget (children[i]) && XtIsWidget (w)) + fprintf (stderr, "searching child %s of parent %s\n", + children[i]->core.name, w->core.name); + else + fprintf (stderr,"searching child (NULL) of parent %s\n", + w->core.name); + if (!XtIsWidget (children[i])) + fprintf (stderr, "children[%d] is NOT a widget\n", i); + if (!XtIsWidget (w)) + fprintf (stderr, "w is NOT a widget\n"); +#endif + + _set_resource_values (children[i], resource, value, last_part); + _apply_values_to_children (children[i], remainder, + resource, value, last_token, last_part); + } + + XtFree ((char *)children); +} + +/* + * NAME: _search_child + * + * FUNCTION: + * descends through each child of the tree + * + * PARAMETERS: + * w the widget whose children are to be searched + * indx index into the resource string + * remainder the remaining part of the resource string + * resource the resource string to be matched + * value the value to be applied + * last_token the last * or . before the final resoruce part + * last_part the last resource part (e.g. *background) + * + * RETURN VALUES: none + * + * ERRORS: none + */ +static void +_search_child (w, indx, remainder, resource, value, last_token, last_part) + Widget w; + char *indx; + char *remainder; + char *resource; + char *value; + char last_token; + char *last_part; +{ + int i; + int num_children; + Widget *children; + + /* + * Recursively search through the children + */ + num_children = _locate_children (w, &children); + for (i=0; i<num_children; i++) { + _set_and_search (children[i], indx, remainder, resource, + value, last_token, last_part); + } + + XtFree ((char *)children); +} + +/* + * NAME: _get_part + * + * FUNCTION: + * This routine will return the token and following part of the resource + * when given the current index it will update the index accordingly + * + * PARAMETERS: + * remainder the part of the resource string left over + * indx the index into the resource string + * part the parsed off part of the resource string + * + * RETURN VALUES: + * char the token (* or . or ?) preceding the resource part + * indx the index into the resource string + * part the parsed off part of the resource string + * + * ERRORS: none + */ +/* ARGSUSED */ +static char +_get_part (remainder, indx, part) + char *remainder; + char **indx; + char **part; +{ + char buffer[MAX_BUFFER]; + char *buf_ptr; + char token = **indx; + int i = 0; + + /* + * copy the remainder part into the buffer + */ + buf_ptr = buffer; + (*indx)++; /* get rid of the token */ + while (**indx && (**indx != '.') && (**indx != '*')) { + *buf_ptr++ = *(*indx)++; + if (++i >= MAX_BUFFER - 1) + break; + } + *buf_ptr = '\0'; + + *part = XtNewString (buffer); /* return a new string to part */ + + if (strcmp (*indx, "") == 0) + *indx = NULL; + + return (token); /* return the token */ +} + +/* + * NAME: _match_resource_to_widget + * + * FUNCTION: + * This function matches the resource part to the widget name or class + * + * PARAMETERS: + * w the widget to match + * part the parsed off part of the resource string + * + * RETURN VALUES: + * Boolean true if a match occurs + * + * ERRORS: none + */ +static Boolean +_match_resource_to_widget (w, part) + Widget w; + char *part; +{ + /* + * Match any widget at this level if the ? is used + */ + if (strcmp (part, "?") == 0) + return (True); + + /* + * if the object is really a widget then its name can be matched + * otherwise only use its class. Note that if you try to reference + * a widget name when the object is not a widget, you may get a + * core dump from an invalid pointer reference. + */ + if (XtIsWidget (w)) { + if ((strcmp (w->core.name, part) == 0) || + (strcmp (w->core.widget_class->core_class.class_name, + part) == 0)) + return (True); + else + return (False); + } else { + if ((strcmp (w->core.widget_class->core_class.class_name, + part) == 0)) + return (True); + else + return (False); + } +} + +/* + * NAME: _set_and_search + * + * FUNCTION: + * The algorithm to search the widget tree and apply a resource string + * + * PARAMETERS: + * w the widget to match + * indx the index into the resource string + * remainder the part of the resource string left over + * resource the resource string to be matched + * value the value to be set + * last_token the last * or . before the final resoruce part + * last_part the last resource part (e.g. *background) + * + * RETURN VALUES: none + * + * ERRORS: none + * + * ALGORITHM: + * loop (look at all children) + * if (resource segment and current widget match) + * if '.' + * if at end of resource string + * set values ( .=over all children + * *=this widget only) + * else + * descend the widget tree + * and parse off resource segment + * exit the loop + * if '*' + * if at end of resource string + * set values ( .=over all children + * *=this widget only) + * descend and parse + * else + * if '.' + * continue looping + * if '*' + * descend but don't parse + * continue looping + * end loop + * + * NOTE: the _set_resource_values routine will not allow a value to be + * set on a resource against the rules of the resource database manager + */ +static void +_set_and_search (w, indx, remainder, resource, value, last_token, last_part) + Widget w; + char *indx; + char *remainder; + char *resource; + char *value; + char last_token; + char *last_part; +{ + char *part; + char *local_index = indx; + char token; + + /* + * parse off one part, return token and the new index + */ + token = _get_part (remainder, &local_index, &part); + + if (_match_resource_to_widget (w, part)) { + if (token == '.') { + if (local_index == NULL) { + if (last_token == '.') { + _set_resource_values (w, resource, + value, last_part); + } else if (last_token == '*') { + _set_resource_values (w, resource, + value, last_part); + _apply_values_to_children (w, + remainder, resource, value, + last_token, last_part); + } + } else + _search_child (w, local_index, remainder, + resource, value, last_token, last_part); + return; + } + if (token == '*') { + if (local_index == NULL) { + if (last_token == '.') { + _set_resource_values (w, resource, + value, last_part); + } else if (last_token == '*') { + _set_resource_values (w, resource, + value, last_part); + _apply_values_to_children ( w, + remainder, resource, value, + last_token, last_part); + } + } else + _search_child (w, local_index, remainder, + resource, value, last_token, last_part); + } + } else {/* if the widget name and class don't match the part */ + /* if (token == '.') just continue looping */ + + if (token == '*') { + _search_child (w, indx, remainder, resource, value, + last_token, last_part); + } + } + + XtFree (part); +} + +/* + * NAME: _get_last_part + * + * FUNCTION: + * This routine will parse off the last segment of a resource string + * and its token and return them. the remainder of resource is also + * returned. strcoll is used to guarantee no problems with + * international strings. + * + * PARAMETERS: + * remainder the part of the resource string left over + * part the parsed off part of the resource string + * + * RETURN VALUES: + * char the token (* or . or ?) preceding the resource part + * remainder the part of the resource string left over + * part the parsed off part of the resource string + * + * ERRORS: none + */ +static char +_get_last_part (remainder, part) + char *remainder; + char **part; +{ + char *loose, *tight; + + loose = strrchr (remainder, '*'); + tight = strrchr (remainder, '.'); + + if ((loose == NULL) && (tight == NULL)) { + *part = XtNewString (remainder); + return ('.'); + } + if ((loose == NULL) || (tight && (strcoll (loose, tight) < 0))) { + *tight++ = '\0'; /* shorten the remainder string */ + *part = XtNewString (tight); + return ('.'); + } + if ((tight == NULL) || (loose && (strcoll (tight, loose) < 0))) { + *loose++ = '\0'; + *part = XtNewString (loose); + return ('*'); + } + + return ('0'); /* error - return 0 */ +} + +/* + * NAME: _search_widget_tree + * + * FUNCTION: + * This function tries to match a resource string to the widgets + * it applies to. The functions it invokes to do this then set + * the value for that resource to each widget. + * + * The resource string has to be parsed into the following format: + * resource = App*Form*button1.background + * remainder = *Form*button1 + * last_part = background last_token = . + * As the widget tree is recursively descended, these variables are + * passed. The remainder is parsed at each level in the widget + * tree as the _set_and_search function attempts to match + * the resource part (eg. part = Form token = *) to a widget. When + * the entire resource string has been matched, the _set_resource_values + * functions is called to apply the value to the widget or widgets. + * + * PARAMETERS: + * w a widget from whose toplevel shell ancestor + * the search will start + * resource the resource string to match + * value the value to apply + * + * RETURN VALUES: none + * + * ERRORS: none + */ +static void +_search_widget_tree (w, resource, value) + Widget w; + char *resource; + char *value; +{ + Widget parent = w; + char *last_part; + char *remainder; + char last_token; + char *indx, *copy; + char *loose, *tight; + int loose_len, tight_len; + + /* + * Find the root of the tree given any widget + */ + while (XtParent(parent) != NULL) { + parent = XtParent(parent); + } +#ifdef DEBUG + if (XtIsWidget (w) && XtIsWidget (parent)) + fprintf (stderr, "widget = %s parent = %s\n", + w->core.name, parent->core.name); + else + fprintf (stderr, "widget = NULL parent = NULL\n"); +#endif + + /* + * parse off the Class name that was prepended to this string in + * a customizing tool + */ + loose = strchr (resource, '*'); + tight = strchr (resource, '.'); + if ((loose == NULL) && (tight == NULL)) + return; + + loose_len = (loose) ? strlen (loose) : 0; + tight_len = (tight) ? strlen (tight) : 0; + + if ((loose == NULL) || (tight_len > loose_len)) + remainder = XtNewString (tight); + else if ((tight == NULL) || (loose_len > tight_len)) + remainder = XtNewString (loose); + + /* + * Parse last segment off of resource string, (eg. background, font, + * etc.) + */ + last_token = _get_last_part (remainder, &last_part); + /* + * this case covers resources of only one level (eg. *background) + */ + if (strcmp (remainder, "") == 0) { + _set_resource_values (w, resource, value, last_part); + if (last_token == '*') + _apply_values_to_children (parent, remainder, resource, + value, last_token, last_part); + /* + * all other resource strings are recursively applied to the widget tree. + * Prepend a '.' to the remainder string if there is no leading token. + */ + } else { + if (remainder[0] != '*' && remainder[0] != '.') { + copy = XtMalloc (strlen(remainder) + 2); + sprintf (copy, ".%s", remainder); + XtFree (remainder); + remainder = copy; + } + indx = remainder; + _set_and_search (parent, indx, remainder, resource, value, + last_token, last_part); + } + + XtFree (remainder); + XtFree (last_part); +} + +/* + * NAME: _locate_children + * + * FUNCTION: + * returns a list of all of a widget's children + * + * PARAMETERS: + * w the parent to search for its children + * children the list of children that is created + * normal flag for normal children + * popup flag for popup children + * + * RETURN VALUES: + * int the number of children + * children the list of children found + * + * ERRORS: none + */ +static int +_locate_children (parent, children) + Widget parent; + Widget **children; +{ + CompositeWidget comp = (CompositeWidget) parent; + int i; + int num_children = 0; + int current = 0; + + /* + * count the number of children + */ + if (XtIsWidget (parent)) + num_children += parent->core.num_popups; + if (XtIsComposite (parent)) + num_children += comp->composite.num_children; + if (num_children == 0) { + *children = NULL; + return (0); + } + + *children = (Widget *) + XtMalloc ((Cardinal) sizeof(Widget) * num_children); + + if (XtIsComposite (parent)) { + for (i=0; i<comp->composite.num_children; i++) { + (*children)[current] = comp->composite.children[i]; + current++; + } + } + + if (XtIsWidget (parent)) { + for (i=0; i<parent->core.num_popups; i++) { + (*children)[current] = comp->core.popup_list[i]; + current++; + } + } + + return (num_children); +} + +#ifdef DEBUG +/* + * NAME: dump_widget_tree + * + * FUNCTION: + * recursively printout entire widget tree + * + * PARAMETERS: + * w the widget to match + * indent the amount to indent each line + * + * RETURN VALUES: void + * + * ERRORS: none + */ +static void +dump_widget_tree (w, indent) + Widget w; + int indent; +{ + int i,j; + int num_children; + Widget *children; + + /* + * Recursively search through the children + */ + num_children = _locate_children (w, &children); + indent += 2; + for (i=0; i<num_children; i++) { + if (children[i] != NULL) { + for (j=0; j<indent; j++) + fprintf (stderr, " "); + if (XtIsWidget (children[i])) { + fprintf (stderr, "(%s)\t",children[i]->core.name); + fprintf (stderr, "(%s)\n", + children[i]->core.widget_class->core_class.class_name); + } else { + fprintf (stderr, "(NULL)\t"); + fprintf (stderr, "(%s)\n", + children[i]->core.widget_class->core_class.class_name); + } + } + dump_widget_tree (children[i], indent); + } + + XtFree ((char *)children); +} +#endif + +/* + * NAME: _XtResourceConfiguationEH + * + * FUNCTION: + * This function is the event handler for the on-the-fly communication + * with a resource customization tool. This event handler must be + * registered for the toplevel shell of each app. This is best done + * in the _XtCreatePopupShell and _XtAppCreateShell functions in Xt's + * Create.c source file. + * + * The property used to communicate with a customizing tool is + * placed on the toplevel shell window of the application. The + * customizing tool places a property on this window which causes + * this event handler to be invoked via the PropertyNotify event. + * This event handler reads the property and then deletes it from + * the server. The contents of the property are a resource string + * and value. The event handler then calls functions to walk the + * applications widget tree, determining which widgets are affected + * by the resource string, and then applying the value with XtSetValues. + * + * PARAMETERS: + * w the widget that invoked this event handler + * client_data not used + * event the event structure + * + * RETURN VALUES: none + * + * ERRORS: none + */ +/* ARGSUSED */ +void +_XtResourceConfigurationEH (w, client_data, event) + Widget w; + XtPointer client_data; + XEvent *event; +{ + Atom actual_type; + int actual_format; + unsigned long nitems; + unsigned long leftover; + unsigned char *data = NULL; + unsigned long resource_len; + char *data_ptr; + char *resource; + char *value; +#ifdef DEBUG + int indent = 0; +#endif + XtPerDisplay pd; + +#ifdef DEBUG + fprintf (stderr, "in _XtResourceConfiguationEH atom = %d\n",event->xproperty.atom); + fprintf (stderr, " window = %x\n", XtWindow (w)); + if (XtIsWidget (w)) + fprintf (stderr, " widget = %x name = %s\n", w, w->core.name); +#endif + + pd = _XtGetPerDisplay (XtDisplay (w)); + + /* + * The window on which a customizing tool places the property + * is determined at this point. It should be the applications + * toplevel shell window. + * + * A customizing tool sends a "ping" to the application on + * the RCM_INIT property. The application answers the ping + * by deleting the property. + */ + if (event->xproperty.atom == pd->rcm_init) { + XDeleteProperty (XtDisplay(w), XtWindow (w), pd->rcm_init); + +#ifdef DEBUG + if (XtIsWidget (w)) + fprintf (stderr, "%s\n", w->core.name); + else + fprintf (stderr, "NULL name\n"); + dump_widget_tree(w, indent); + + fprintf (stderr, "answer ping\n"); +#endif + } + + /* + * This event handler ignores any property notify events that + * are not RCM_INIT or RCM_DATA + */ + if (event->xproperty.atom != pd->rcm_data) + return; + + /* + * Retrieve the data from the property + */ +#ifdef DEBUG + fprintf (stderr, "receiving RCM_DATA property\n"); +#endif + if (XGetWindowProperty (XtDisplay(w), + XtWindow (w), + pd->rcm_data, 0L, 8192L, + TRUE, XA_STRING, + &actual_type, &actual_format, &nitems, &leftover, + &data ) == Success && actual_type == XA_STRING + && actual_format == 8) { + /* + * data format is: + * + * resource_length, resource, value + * + * convert the resource_length to a long, skip over it, put a + * zero byte at the end of the resource, and pick off the + * resource and value fields. + */ + if (data) { + resource_len = Strtoul (data, &data_ptr, 10); + data_ptr++; + + data_ptr[resource_len] = '\0'; + + resource = XtNewString (data_ptr); + value = XtNewString (&data_ptr[resource_len + 1]); +#ifdef DEBUG + fprintf (stderr, "resource_len=%d\n",resource_len); + fprintf (stderr, "resource = %s\t value = %s\n", + resource, value); +#endif + /* + * descend the application widget tree and + * apply the value to the appropriate widgets + */ + _search_widget_tree (w, resource, value); + + XtFree (resource); + XtFree (value); + } + } + + if (data) + XFree ((char *)data); +} diff --git a/src/Resources.c b/src/Resources.c new file mode 100644 index 0000000..20a56c0 --- /dev/null +++ b/src/Resources.c @@ -0,0 +1,1294 @@ +/* $Xorg: Resources.c,v 1.4 2001/02/09 02:03:56 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/*LINTLIBRARY*/ +#include "IntrinsicI.h" +#include "VarargsI.h" +#include "Shell.h" +#include "ShellP.h" +#include "StringDefs.h" +#include <stdio.h> + +static XrmClass QBoolean, QString, QCallProc, QImmediate; +static XrmName QinitialResourcesPersistent, QInitialResourcesPersistent; +static XrmClass QTranslations, QTranslationTable; +static XrmName Qtranslations, QbaseTranslations; +static XrmName Qscreen; +static XrmClass QScreen; + +#ifdef CRAY +void Cjump(); +char *Cjumpp = (char *) Cjump; +void Cjump() {} +#endif + +void _XtCopyFromParent(widget, offset, value) + Widget widget; + int offset; + XrmValue *value; +{ + if (widget->core.parent == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidParent","xtCopyFromParent",XtCXtToolkitError, + "CopyFromParent must have non-NULL parent", + (String *)NULL, (Cardinal *)NULL); + value->addr = NULL; + return; + } + value->addr = (XPointer)(((char *)widget->core.parent) + offset); +} /* _XtCopyFromParent */ + + +/* If the alignment characteristics of your machine are right, these may be + faster */ + +#ifdef UNALIGNED + +void _XtCopyFromArg(src, dst, size) + XtArgVal src; + char* dst; + register unsigned int size; +{ + if (size == sizeof(long)) *(long *)dst = (long)src; + else if (size == sizeof(short)) *(short *)dst = (short)src; + else if (size == sizeof(char)) *(char *)dst = (char)src; + else if (size == sizeof(XtPointer)) *(XtPointer *)dst = (XtPointer)src; + else if (size == sizeof(char*)) *(char **)dst = (char*)src; + else if (size == sizeof(XtArgVal)) *(XtArgVal *)dst = src; + else if (size > sizeof(XtArgVal)) + (void) memmove((char *) dst, (char *) src, (int) size); + else + (void) memmove((char *) dst, (char *) &src, (int) size); +} /* _XtCopyFromArg */ + +void _XtCopyToArg(src, dst, size) + char* src; + XtArgVal *dst; + register unsigned int size; +{ + if (! (*dst)) { +#ifdef GETVALUES_BUG + /* old GetValues semantics (storing directly into arglists) are bad, + * but preserve for compatibility as long as arglist contains NULL. + */ + if (size == sizeof(long)) *dst = (XtArgVal)*(long*)src; + else if (size == sizeof(short)) *dst = (XtArgVal)*(short*)src; + else if (size == sizeof(char)) *dst = (XtArgVal)*(char*)src; + else if (size == sizeof(XtPointer)) *dst = (XtArgVal)*(XtPointer*)src; + else if (size == sizeof(char*)) *dst = (XtArgVal)*(char**)src; + else if (size == sizeof(XtArgVal)) *dst = *(XtArgVal*)src; + else (void) memmove((char*)dst, (char*)src, (int)size); +#else + XtErrorMsg("invalidGetValues", "xtGetValues", XtCXtToolkitError, + "NULL ArgVal in XtGetValues", (String*) NULL, (Cardinal*) NULL); +#endif + } + else { + /* proper GetValues semantics: argval is pointer to destination */ + if (size == sizeof(long)) *((long*)*dst) = *(long*)src; + else if (size == sizeof(short)) *((short*)*dst) = *(short*)src; + else if (size == sizeof(char)) *((char*)*dst) = *(char*)src; + else if (size == sizeof(XtPointer)) *((XtPointer*)*dst) = *(XtPointer*)src; + else if (size == sizeof(char*)) *((char**)*dst) = *(char**)src; + else if (size == sizeof(XtArgVal)) *((XtArgVal*)*dst)= *(XtArgVal*)src; + else (void) memmove((char*)*dst, (char*)src, (int)size); + } +} /* _XtCopyToArg */ + +static void CopyToArg(src, dst, size) + char* src; + XtArgVal *dst; + register unsigned int size; +{ + if (! (*dst)) { + /* old GetValues semantics (storing directly into arglists) are bad, + * but preserve for compatibility as long as arglist contains NULL. + */ + if (size == sizeof(long)) *dst = (XtArgVal)*(long*)src; + else if (size == sizeof(short)) *dst = (XtArgVal)*(short*)src; + else if (size == sizeof(char)) *dst = (XtArgVal)*(char*)src; + else if (size == sizeof(XtPointer)) *dst = (XtArgVal)*(XtPointer*)src; + else if (size == sizeof(char*)) *dst = (XtArgVal)*(char**)src; + else if (size == sizeof(XtArgVal)) *dst = *(XtArgVal*)src; + else (void) memmove((char*)dst, (char*)src, (int)size); + } + else { + /* proper GetValues semantics: argval is pointer to destination */ + if (size == sizeof(long)) *((long*)*dst) = *(long*)src; + else if (size == sizeof(short)) *((short*)*dst) = *(short*)src; + else if (size == sizeof(char)) *((char*)*dst) = *(char*)src; + else if (size == sizeof(XtPointer)) *((XtPointer*)*dst) = *(XtPointer*)src; + else if (size == sizeof(char*)) *((char**)*dst) = *(char**)src; + else if (size == sizeof(XtArgVal)) *((XtArgVal*)*dst)= *(XtArgVal*)src; + else (void) memmove((char*)*dst, (char*)src, (int)size); + } +} /* CopyToArg */ + +#else +void _XtCopyFromArg(src, dst, size) + XtArgVal src; + char* dst; + register unsigned int size; +{ + if (size > sizeof(XtArgVal)) + (void) memmove((char *) dst, (char *) src, (int) size); + else { + union { + long longval; +#ifdef LONG64 + int intval; +#endif + short shortval; + char charval; + char* charptr; + XtPointer ptr; + } u; + char *p = (char*)&u; + if (size == sizeof(long)) u.longval = (long)src; +#ifdef LONG64 + else if (size == sizeof(int)) u.intval = (int)src; +#endif + else if (size == sizeof(short)) u.shortval = (short)src; + else if (size == sizeof(char)) u.charval = (char)src; + else if (size == sizeof(XtPointer)) u.ptr = (XtPointer)src; + else if (size == sizeof(char*)) u.charptr = (char*)src; + else p = (char*)&src; + + (void) memmove(dst, p, (int) size); + } +} /* _XtCopyFromArg */ + +void _XtCopyToArg(src, dst, size) + char* src; + XtArgVal *dst; + register unsigned int size; +{ + if (!*dst) { +#ifdef GETVALUES_BUG + /* old GetValues semantics (storing directly into arglists) are bad, + * but preserve for compatibility as long as arglist contains NULL. + */ + union { + long longval; +#ifdef LONG64 + int intval; +#endif + short shortval; + char charval; + char* charptr; + XtPointer ptr; + } u; + if (size <= sizeof(XtArgVal)) { + (void) memmove((char*)&u, (char*)src, (int)size ); + if (size == sizeof(long)) *dst = (XtArgVal)u.longval; +#ifdef LONG64 + else if (size == sizeof(int)) *dst = (XtArgVal)u.intval; +#endif + else if (size == sizeof(short)) *dst = (XtArgVal)u.shortval; + else if (size == sizeof(char)) *dst = (XtArgVal)u.charval; + else if (size == sizeof(char*)) *dst = (XtArgVal)u.charptr; + else if (size == sizeof(XtPointer)) *dst = (XtArgVal)u.ptr; + else (void) memmove((char*)dst, (char*)src, (int)size ); + } + else + (void) memmove((char*)dst, (char*)src, (int)size ); +#else + XtErrorMsg("invalidGetValues", "xtGetValues", XtCXtToolkitError, + "NULL ArgVal in XtGetValues", (String*) NULL, (Cardinal*) NULL); +#endif + } + else { + /* proper GetValues semantics: argval is pointer to destination */ + (void) memmove((char*)*dst, (char*)src, (int)size ); + } +} /* _XtCopyToArg */ + +static void CopyToArg(src, dst, size) + char* src; + XtArgVal *dst; + register unsigned int size; +{ + if (!*dst) { + /* old GetValues semantics (storing directly into arglists) are bad, + * but preserve for compatibility as long as arglist contains NULL. + */ + union { + long longval; +#ifdef LONG64 + int intval; +#endif + short shortval; + char charval; + char* charptr; + XtPointer ptr; + } u; + if (size <= sizeof(XtArgVal)) { + (void) memmove((char*)&u, (char*)src, (int)size ); + if (size == sizeof(long)) *dst = (XtArgVal)u.longval; +#ifdef LONG64 + else if (size == sizeof(int)) *dst = (XtArgVal)u.intval; +#endif + else if (size == sizeof(short)) *dst = (XtArgVal)u.shortval; + else if (size == sizeof(char)) *dst = (XtArgVal)u.charval; + else if (size == sizeof(char*)) *dst = (XtArgVal)u.charptr; + else if (size == sizeof(XtPointer)) *dst = (XtArgVal)u.ptr; + else (void) memmove((char*)dst, (char*)src, (int)size ); + } + else + (void) memmove((char*)dst, (char*)src, (int)size ); + } + else { + /* proper GetValues semantics: argval is pointer to destination */ + (void) memmove((char*)*dst, (char*)src, (int)size ); + } +} /* CopyToArg */ + +#endif + +static Cardinal CountTreeDepth(w) + Widget w; +{ + Cardinal count; + + for (count = 1; w != NULL; w = (Widget) w->core.parent) + count++; + + return count; +} + +static void GetNamesAndClasses(w, names, classes) + register Widget w; + register XrmNameList names; + register XrmClassList classes; +{ + register Cardinal length, j; + register XrmQuark t; + WidgetClass class; + + /* Return null-terminated quark arrays, with length the number of + quarks (not including NULL) */ + + LOCK_PROCESS; + for (length = 0; w != NULL; w = (Widget) w->core.parent) { + names[length] = w->core.xrm_name; + class = XtClass(w); + /* KLUDGE KLUDGE KLUDGE KLUDGE */ + if (w->core.parent == NULL && XtIsApplicationShell(w)) { + classes[length] = + ((ApplicationShellWidget) w)->application.xrm_class; + } else classes[length] = class->core_class.xrm_class; + length++; + } + UNLOCK_PROCESS; + /* They're in backwards order, flop them around */ + for (j = 0; j < length/2; j++) { + t = names[j]; + names[j] = names[length-j-1]; + names[length-j-1] = t; + t = classes[j]; + classes[j] = classes[length-j-1]; + classes[length-j-1] = t; + } + names[length] = NULLQUARK; + classes[length] = NULLQUARK; +} /* GetNamesAndClasses */ + + +/* Spiffy fast compiled form of resource list. */ +/* XtResourceLists are compiled in-place into XrmResourceLists */ +/* All atoms are replaced by quarks, and offsets are -offset-1 to */ +/* indicate that this list has been compiled already */ + +void _XtCompileResourceList(resources, num_resources) + register XtResourceList resources; + Cardinal num_resources; +{ + register Cardinal count; + +#define xrmres ((XrmResourceList) resources) +#define PSToQ XrmPermStringToQuark + + for (count = 0; count < num_resources; resources++, count++) { + xrmres->xrm_name = PSToQ(resources->resource_name); + xrmres->xrm_class = PSToQ(resources->resource_class); + xrmres->xrm_type = PSToQ(resources->resource_type); +#if defined(CRAY1) && !defined(__STDC__) + xrmres->xrm_offset = -(resources->resource_offset * sizeof(long) + 1); +#else + xrmres->xrm_offset = (Cardinal) + (-(int)resources->resource_offset - 1); +#endif + xrmres->xrm_default_type = PSToQ(resources->default_type); + } +#undef PSToQ +#undef xrmres +} /* _XtCompileResourceList */ + +/* Like _XtCompileResourceList, but strings are not permanent */ +static void XrmCompileResourceListEphem(resources, num_resources) + register XtResourceList resources; + Cardinal num_resources; +{ + register Cardinal count; + +#define xrmres ((XrmResourceList) resources) + + for (count = 0; count < num_resources; resources++, count++) { + xrmres->xrm_name = StringToName(resources->resource_name); + xrmres->xrm_class = StringToClass(resources->resource_class); + xrmres->xrm_type = StringToQuark(resources->resource_type); +#if defined(CRAY1) && !defined(__STDC__) + xrmres->xrm_offset = -(resources->resource_offset * sizeof(long) + 1); +#else + xrmres->xrm_offset = (Cardinal) + (-(int)resources->resource_offset - 1); +#endif + xrmres->xrm_default_type = StringToQuark(resources->default_type); + } +#undef xrmres +} /* XrmCompileResourceListEphem */ + +static void BadSize(size, name) + Cardinal size; + XrmQuark name; +{ + String params[2]; + Cardinal num_params = 2; + + params[0] = (String) size; + params[1] = XrmQuarkToString(name); + XtWarningMsg("invalidSizeOverride", "xtDependencies", XtCXtToolkitError, + "Representation size %d must match superclass's to override %s", + params, &num_params); +} /* BadType */ + +/* + * Create a new resource list, with the class resources following the + * superclass's resources. If a resource in the class list overrides + * a superclass resource, then just replace the superclass entry in place. + * + * At the same time, add a level of indirection to the XtResourceList to + * create and XrmResourceList. + */ +void _XtDependencies(class_resp, class_num_resp, super_res, super_num_res, + super_widget_size) + XtResourceList *class_resp; /* VAR */ + Cardinal *class_num_resp; /* VAR */ + XrmResourceList *super_res; + Cardinal super_num_res; + Cardinal super_widget_size; +{ + register XrmResourceList *new_res; + Cardinal new_num_res; + XrmResourceList class_res = (XrmResourceList) *class_resp; + Cardinal class_num_res = *class_num_resp; + register Cardinal i, j; + Cardinal new_next; + + if (class_num_res == 0) { + /* Just point to superclass resource list */ + *class_resp = (XtResourceList) super_res; + *class_num_resp = super_num_res; + return; + } + + /* Allocate and initialize new_res with superclass resource pointers */ + new_num_res = super_num_res + class_num_res; + new_res = (XrmResourceList *) __XtMalloc(new_num_res*sizeof(XrmResourceList)); + if (super_num_res > 0) + XtMemmove(new_res, super_res, super_num_res * sizeof(XrmResourceList)); + + /* Put pointers to class resource entries into new_res */ + new_next = super_num_res; + for (i = 0; i < class_num_res; i++) { + if (-class_res[i].xrm_offset-1 < super_widget_size) { + /* Probably an override of superclass resources--look for overlap */ + for (j = 0; j < super_num_res; j++) { + if (class_res[i].xrm_offset == new_res[j]->xrm_offset) { + /* Spec is silent on what fields subclass can override. + * The only two of real concern are type & size. + * Although allowing type to be over-ridden introduces + * the possibility of errors, it's at present the only + * reasonable way to allow a subclass to force a private + * converter to be invoked for a subset of fields. + */ + /* We do insist that size be identical to superclass */ + if (class_res[i].xrm_size != new_res[j]->xrm_size) { + BadSize(class_res[i].xrm_size, + (XrmQuark) class_res[i].xrm_name); + class_res[i].xrm_size = new_res[j]->xrm_size; + } + new_res[j] = &(class_res[i]); + new_num_res--; + goto NextResource; + } + } /* for j */ + } + /* Not an overlap, add an entry to new_res */ + new_res[new_next++] = &(class_res[i]); +NextResource:; + } /* for i */ + + /* Okay, stuff new resources back into class record */ + *class_resp = (XtResourceList) new_res; + *class_num_resp = new_num_res; +} /* _XtDependencies */ + + +void _XtResourceDependencies(wc) + WidgetClass wc; +{ + WidgetClass sc; + + sc = wc->core_class.superclass; + if (sc == NULL) { + _XtDependencies(&(wc->core_class.resources), + &(wc->core_class.num_resources), + (XrmResourceList *) NULL, (unsigned)0, (unsigned)0); + } else { + _XtDependencies(&(wc->core_class.resources), + &(wc->core_class.num_resources), + (XrmResourceList *) sc->core_class.resources, + sc->core_class.num_resources, + sc->core_class.widget_size); + } +} /* _XtResourceDependencies */ + +void _XtConstraintResDependencies(wc) + ConstraintWidgetClass wc; +{ + ConstraintWidgetClass sc; + + if (wc == (ConstraintWidgetClass) constraintWidgetClass) { + _XtDependencies(&(wc->constraint_class.resources), + &(wc->constraint_class.num_resources), + (XrmResourceList *)NULL, (unsigned)0, (unsigned)0); + } else { + sc = (ConstraintWidgetClass) wc->core_class.superclass; + _XtDependencies(&(wc->constraint_class.resources), + &(wc->constraint_class.num_resources), + (XrmResourceList *) sc->constraint_class.resources, + sc->constraint_class.num_resources, + sc->constraint_class.constraint_size); + } +} /* _XtConstraintResDependencies */ + + + + +XrmResourceList* _XtCreateIndirectionTable (resources, num_resources) + XtResourceList resources; + Cardinal num_resources; +{ + register int idx; + XrmResourceList* table; + + table = (XrmResourceList*)__XtMalloc(num_resources * sizeof(XrmResourceList)); + for (idx = 0; idx < num_resources; idx++) + table[idx] = (XrmResourceList)(&(resources[idx])); + return table; +} + +static XtCacheRef *GetResources(widget, base, names, classes, + table, num_resources, quark_args, args, num_args, + typed_args, pNumTypedArgs, tm_hack) + Widget widget; /* Widget resources are associated with */ + char* base; /* Base address of memory to write to */ + XrmNameList names; /* Full inheritance name of widget */ + XrmClassList classes; /* Full inheritance class of widget */ + XrmResourceList* table; /* The list of resources required. */ + Cardinal num_resources; /* number of items in resource list */ + XrmQuarkList quark_args; /* Arg names quarkified */ + ArgList args; /* ArgList to override resources */ + Cardinal num_args; /* number of items in arg list */ + XtTypedArgList typed_args; /* Typed arg list to override resources */ + Cardinal* pNumTypedArgs; /* number of items in typed arg list */ + Boolean tm_hack; /* do baseTranslations */ +{ +/* + * assert: *pNumTypedArgs == 0 if num_args > 0 + * assert: num_args == 0 if *pNumTypedArgs > 0 + */ +#define SEARCHLISTLEN 100 +#define MAXRESOURCES 400 + + XrmValue value; + XrmQuark rawType; + XrmValue convValue; + XrmHashTable stackSearchList[SEARCHLISTLEN]; + XrmHashTable *searchList = stackSearchList; + unsigned int searchListSize = SEARCHLISTLEN; + Boolean found[MAXRESOURCES]; + int typed[MAXRESOURCES]; + XtCacheRef cache_ref[MAXRESOURCES]; + XtCacheRef *cache_ptr, *cache_base; + Boolean persistent_resources = True; + Boolean found_persistence = False; + int num_typed_args = *pNumTypedArgs; + XrmDatabase db; + Boolean do_tm_hack = False; + + if ((args == NULL) && (num_args != 0)) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidArgCount","getResources",XtCXtToolkitError, + "argument count > 0 on NULL argument list", + (String *)NULL, (Cardinal *)NULL); + num_args = 0; + } + if (num_resources == 0) { + return NULL; + } else if (num_resources >= MAXRESOURCES) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidResourceCount","getResources",XtCXtToolkitError, + "too many resources", + (String *)NULL, (Cardinal *)NULL); + return NULL; + } else if (table == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidResourceCount","getResources",XtCXtToolkitError, + "resource count > 0 on NULL resource list", + (String *)NULL, (Cardinal *)NULL); + return NULL; + } + + /* Mark each resource as not found on arg list */ + bzero((char *) found, (int) (num_resources * sizeof(Boolean))); + bzero((char *) typed, (int) (num_resources * sizeof(int))); + + /* Copy the args into the resources, mark each as found */ + { + register ArgList arg; + register XtTypedArgList typed_arg; + register XrmName argName; + register int j; + register int i; + register XrmResourceList rx; + register XrmResourceList *res; + for (arg = args, i = 0; i < num_args; i++, arg++) { + argName = quark_args[i]; + if (argName == QinitialResourcesPersistent) { + persistent_resources = (Boolean)arg->value; + found_persistence = True; + continue; + } + for (j = 0, res = table; j < num_resources; j++, res++) { + rx = *res; + if (argName == rx->xrm_name) { + _XtCopyFromArg( + arg->value, + base - rx->xrm_offset - 1, + rx->xrm_size); + found[j] = TRUE; + break; + } + } + } + for (typed_arg = typed_args, i = 0; i < num_typed_args; + i++, typed_arg++) { + register XrmRepresentation argType; + argName = quark_args[i]; + argType = (typed_arg->type == NULL) ? NULLQUARK + : XrmStringToRepresentation(typed_arg->type); + if (argName == QinitialResourcesPersistent) { + persistent_resources = (Boolean)typed_arg->value; + found_persistence = True; + break; + } + for (j = 0, res = table; j < num_resources; j++, res++) { + rx = *res; + if (argName == rx->xrm_name) { + if (argType != NULLQUARK && argType != rx->xrm_type) { + typed[j] = i + 1; + } else { + _XtCopyFromArg( + typed_arg->value, + base - rx->xrm_offset - 1, + rx->xrm_size); + } + found[j] = TRUE; + break; + } + } + } + } + + /* Ask resource manager for a list of database levels that we can + do a single-level search on each resource */ + + db = XtScreenDatabase(XtScreenOfObject(widget)); + while (!XrmQGetSearchList(db, names, classes, + searchList, searchListSize)) { + if (searchList == stackSearchList) + searchList = NULL; + searchList = (XrmHashTable*)XtRealloc((char*)searchList, + sizeof(XrmHashTable) * + (searchListSize *= 2)); + } + + if (persistent_resources) + cache_base = NULL; + else + cache_base = cache_ref; + /* geez, this is an ugly mess */ + if (XtIsShell(widget)) { + register XrmResourceList *res; + register int j; + Screen *oldscreen = widget->core.screen; + + /* look up screen resource first, since real rdb depends on it */ + for (res = table, j = 0; j < num_resources; j++, res++) { + if ((*res)->xrm_name != Qscreen) + continue; + if (typed[j]) { + register XtTypedArg* arg = typed_args + typed[j] - 1; + XrmQuark from_type; + XrmValue from_val, to_val; + + from_type = StringToQuark(arg->type); + from_val.size = arg->size; + if ((from_type == QString) || (arg->size > sizeof(XtArgVal))) + from_val.addr = (XPointer)arg->value; + else + from_val.addr = (XPointer)&arg->value; + to_val.size = sizeof(Screen*); + to_val.addr = (XPointer)&widget->core.screen; + found[j] = _XtConvert(widget, from_type, &from_val, + QScreen, &to_val, cache_base); + if (cache_base && *cache_base) + cache_base++; + } + if (!found[j]) { + if (XrmQGetSearchResource(searchList, Qscreen, QScreen, + &rawType, &value)) { + if (rawType != QScreen) { + convValue.size = sizeof(Screen*); + convValue.addr = (XPointer)&widget->core.screen; + (void)_XtConvert(widget, rawType, &value, + QScreen, &convValue, cache_base); + if (cache_base && *cache_base) + cache_base++; + } else { + widget->core.screen = *((Screen **)value.addr); + } + } + } + break; + } + /* now get the database to use for the rest of the resources */ + if (widget->core.screen != oldscreen) { + db = XtScreenDatabase(widget->core.screen); + while (!XrmQGetSearchList(db, names, classes, + searchList, searchListSize)) { + if (searchList == stackSearchList) + searchList = NULL; + searchList = (XrmHashTable*)XtRealloc((char*)searchList, + sizeof(XrmHashTable) * + (searchListSize *= 2)); + } + } + } + + /* go to the resource manager for those resources not found yet */ + /* if it's not in the resource database use the default value */ + + { + register XrmResourceList rx; + register XrmResourceList *res; + register int j; + register XrmRepresentation xrm_type; + register XrmRepresentation xrm_default_type; + char char_val; + short short_val; + int int_val; + long long_val; + char* char_ptr; + + if (!found_persistence) { + if (XrmQGetSearchResource(searchList, QinitialResourcesPersistent, + QInitialResourcesPersistent, &rawType, &value)) { + if (rawType != QBoolean) { + convValue.size = sizeof(Boolean); + convValue.addr = (XPointer)&persistent_resources; + (void)_XtConvert(widget, rawType, &value, QBoolean, + &convValue, NULL); + } + else + persistent_resources = *(Boolean*)value.addr; + } + } + if (persistent_resources) + cache_ptr = NULL; + else if (cache_base) + cache_ptr = cache_base; + else + cache_ptr = cache_ref; + + for (res = table, j = 0; j < num_resources; j++, res++) { + rx = *res; + xrm_type = rx->xrm_type; + if (typed[j]) { + register XtTypedArg* arg = typed_args + typed[j] - 1; + + /* + * This resource value has been specified as a typed arg and + * has to be converted. Typed arg conversions are done here + * to correctly interpose them with normal resource conversions. + */ + XrmQuark from_type; + XrmValue from_val, to_val; + Boolean converted; + + from_type = StringToQuark(arg->type); + from_val.size = arg->size; + if ((from_type == QString) || (arg->size > sizeof(XtArgVal))) + from_val.addr = (XPointer)arg->value; + else + from_val.addr = (XPointer)&arg->value; + to_val.size = rx->xrm_size; + to_val.addr = base - rx->xrm_offset - 1; + converted = _XtConvert(widget, from_type, &from_val, + xrm_type, &to_val, cache_ptr); + if (converted) { + + /* Copy the converted value back into the typed argument. + * normally the data should be <= sizeof(XtArgVal) and + * is stored directly into the 'value' field .... BUT + * if the resource size is greater than sizeof(XtArgVal) + * then we dynamically alloc a block of store to hold the + * data and zap a copy in there !!! .... freeing it later + * the size field in the typed arg is negated to indicate + * that the store pointed to by the value field is + * dynamic ....... + * "freeing" happens in the case of _XtCreate after the + * CallInitialize ..... other clients of GetResources + * using typed args should be aware of the need to free + * this store ..... + */ + + if(rx->xrm_size > sizeof(XtArgVal)) { + arg->value = (XtArgVal) __XtMalloc(rx->xrm_size); + arg->size = -(arg->size); + } else { /* will fit - copy directly into value field */ + arg->value = (XtArgVal) NULL; + } + CopyToArg((char *)(base - rx->xrm_offset - 1), + &arg->value, rx->xrm_size); + + } else { + /* Conversion failed. Get default value. */ + found[j] = False; + } + + if (cache_ptr && *cache_ptr) + cache_ptr++; + } + + if (!found[j]) { + Boolean already_copied = False; + Boolean have_value = False; + + if (XrmQGetSearchResource(searchList, + rx->xrm_name, rx->xrm_class, &rawType, &value)) { + if (rawType != xrm_type) { + convValue.size = rx->xrm_size; + convValue.addr = (XPointer)(base - rx->xrm_offset - 1); + already_copied = have_value = + _XtConvert(widget, rawType, &value, + xrm_type, &convValue, cache_ptr); + if (cache_ptr && *cache_ptr) + cache_ptr++; + } else have_value = True; + if (have_value && rx->xrm_name == Qtranslations) + do_tm_hack = True; + } + LOCK_PROCESS; + if (!have_value + && ((rx->xrm_default_type == QImmediate) + || (rx->xrm_default_type == xrm_type) + || (rx->xrm_default_addr != NULL))) { + /* Convert default value to proper type */ + xrm_default_type = rx->xrm_default_type; + if (xrm_default_type == QCallProc) { +#ifdef CRAY + if ( (int) Cjumpp != (int) Cjump) + (*(XtResourceDefaultProc) + (((int)(rx->xrm_default_addr))<<2))( + widget,-(rx->xrm_offset+1), &value); + else +#endif + (*(XtResourceDefaultProc)(rx->xrm_default_addr))( + widget,-(rx->xrm_offset+1), &value); + + } else if (xrm_default_type == QImmediate) { + /* XtRImmediate == XtRString for type XtRString */ + if (xrm_type == QString) { + value.addr = rx->xrm_default_addr; + } else if (rx->xrm_size == sizeof(int)) { + int_val = (int)(long)rx->xrm_default_addr; + value.addr = (XPointer) &int_val; + } else if (rx->xrm_size == sizeof(short)) { + short_val = (short)(long)rx->xrm_default_addr; + value.addr = (XPointer) &short_val; + } else if (rx->xrm_size == sizeof(char)) { + char_val = (char)(long)rx->xrm_default_addr; + value.addr = (XPointer) &char_val; + } else if (rx->xrm_size == sizeof(long)) { + long_val = (long)rx->xrm_default_addr; + value.addr = (XPointer) &long_val; + } else if (rx->xrm_size == sizeof(char*)) { + char_ptr = (char*)rx->xrm_default_addr; + value.addr = (XPointer) &char_ptr; + } else { + value.addr = (XPointer) &(rx->xrm_default_addr); + } + } else if (xrm_default_type == xrm_type) { + value.addr = rx->xrm_default_addr; + } else { + value.addr = rx->xrm_default_addr; + if (xrm_default_type == QString) { + value.size = strlen((char *)value.addr) + 1; + } else { + value.size = sizeof(XtPointer); + } + convValue.size = rx->xrm_size; + convValue.addr = (XPointer)(base - rx->xrm_offset - 1); + already_copied = + _XtConvert(widget, xrm_default_type, &value, + xrm_type, &convValue, cache_ptr); + if (!already_copied) + value.addr = NULL; + if (cache_ptr && *cache_ptr) + cache_ptr++; + } + } + if (!already_copied) { + if (xrm_type == QString) { + *((String*)(base - rx->xrm_offset - 1)) = value.addr; + } else { + if (value.addr != NULL) { + XtMemmove(base - rx->xrm_offset - 1, + value.addr, rx->xrm_size); + } else { + /* didn't get value, initialize to NULL... */ + XtBZero(base - rx->xrm_offset - 1, rx->xrm_size); + } + } + } + UNLOCK_PROCESS; + + if (typed[j]) { + /* + * This resource value was specified as a typed arg. + * However, the default value is being used here since + * type type conversion failed, so we compress the list. + */ + register XtTypedArg* arg = typed_args + typed[j] - 1; + register int i; + + for (i = num_typed_args - typed[j]; i; i--, arg++) { + *arg = *(arg+1); + } + num_typed_args--; + } + } + } + if (tm_hack) + widget->core.tm.current_state = NULL; + if (tm_hack && + (!widget->core.tm.translations || + (do_tm_hack && + widget->core.tm.translations->operation != XtTableReplace)) && + XrmQGetSearchResource(searchList, QbaseTranslations, + QTranslations, &rawType, &value)) { + if (rawType != QTranslationTable) { + convValue.size = sizeof(XtTranslations); + convValue.addr = (XPointer)&widget->core.tm.current_state; + (void)_XtConvert(widget, rawType, &value, + QTranslationTable, &convValue, cache_ptr); + if (cache_ptr && *cache_ptr) + cache_ptr++; + } else { + *((XtTranslations *)&widget->core.tm.current_state) = + *((XtTranslations *)value.addr); + } + } + } + if (num_typed_args != *pNumTypedArgs) *pNumTypedArgs = num_typed_args; + if (searchList != stackSearchList) XtFree((char*)searchList); + if (!cache_ptr) + cache_ptr = cache_base; + if (cache_ptr && cache_ptr != cache_ref) { + int cache_ref_size = cache_ptr - cache_ref; + XtCacheRef *refs = (XtCacheRef*) + __XtMalloc((unsigned)sizeof(XtCacheRef)*(cache_ref_size + 1)); + (void) memmove(refs, cache_ref, sizeof(XtCacheRef)*cache_ref_size ); + refs[cache_ref_size] = NULL; + return refs; + } + return (XtCacheRef*)NULL; +} + + + +static void CacheArgs(args, num_args, typed_args, num_typed_args, quark_cache, + num_quarks, pQuarks) + ArgList args; + Cardinal num_args; + XtTypedArgList typed_args; + Cardinal num_typed_args; + XrmQuarkList quark_cache; + Cardinal num_quarks; + XrmQuarkList *pQuarks; /* RETURN */ +{ + register XrmQuarkList quarks; + register Cardinal i; + register Cardinal count; + + count = (args != NULL) ? num_args : num_typed_args; + + if (num_quarks < count) { + quarks = (XrmQuarkList) __XtMalloc(count * sizeof(XrmQuark)); + } else { + quarks = quark_cache; + } + *pQuarks = quarks; + + if (args != NULL) { + for (i = count; i; i--) + *quarks++ = StringToQuark((args++)->name); + } + else { + for (i = count; i; i--) + *quarks++ = StringToQuark((typed_args++)->name); + } +} + +#define FreeCache(cache, pointer) \ + if (cache != pointer) XtFree((char *)pointer) + + +XtCacheRef *_XtGetResources(w, args, num_args, typed_args, num_typed_args) + register Widget w; + ArgList args; + Cardinal num_args; + XtTypedArgList typed_args; + Cardinal* num_typed_args; +{ + XrmName *names, names_s[50]; + XrmClass *classes, classes_s[50]; + XrmQuark quark_cache[100]; + XrmQuarkList quark_args; + WidgetClass wc; + ConstraintWidgetClass cwc; + XtCacheRef *cache_refs; + Cardinal count; + + wc = XtClass(w); + + count = CountTreeDepth(w); + names = (XrmName*) XtStackAlloc (count * sizeof(XrmName), names_s); + classes = (XrmClass*) XtStackAlloc (count * sizeof(XrmClass), classes_s); + if (names == NULL || classes == NULL) _XtAllocError(NULL); + + /* Get names, classes for widget and ancestors */ + GetNamesAndClasses(w, names, classes); + + /* Compile arg list into quarks */ + CacheArgs(args, num_args, typed_args, *num_typed_args, quark_cache, + XtNumber(quark_cache), &quark_args); + + /* Get normal resources */ + LOCK_PROCESS; + cache_refs = GetResources(w, (char*)w, names, classes, + (XrmResourceList *) wc->core_class.resources, + wc->core_class.num_resources, quark_args, args, num_args, + typed_args, num_typed_args, XtIsWidget(w)); + + if (w->core.constraints != NULL) { + cwc = (ConstraintWidgetClass) XtClass(w->core.parent); + (void) GetResources(w, (char*)w->core.constraints, names, classes, + (XrmResourceList *) cwc->constraint_class.resources, + cwc->constraint_class.num_resources, + quark_args, args, num_args, typed_args, num_typed_args, False); + } + FreeCache(quark_cache, quark_args); + UNLOCK_PROCESS; + XtStackFree((XtPointer)names, names_s); + XtStackFree((XtPointer)classes, classes_s); + return cache_refs; +} /* _XtGetResources */ + + +#if NeedFunctionPrototypes +void _XtGetSubresources ( + Widget w, + XtPointer base, + const char* name, + const char* class, + XtResourceList resources, + Cardinal num_resources, + ArgList args, + Cardinal num_args, + XtTypedArgList typed_args, + Cardinal num_typed_args + ) +#else +void _XtGetSubresources (w, base, name, class, resources, num_resources, + args, num_args) + Widget w; /* Widget "parent" of subobject */ + XtPointer base; /* Base address to write to */ + String name; /* name of subobject */ + String class; /* class of subobject */ + XtResourceList resources; /* resource list for subobject */ + Cardinal num_resources; + ArgList args; /* arg list to override resources */ + Cardinal num_args; + XtTypedArgsList typed_args; + Cardinal num_typed_args; +#endif +{ + XrmName *names, names_s[50]; + XrmClass *classes, classes_s[50]; + XrmQuark quark_cache[100]; + XrmQuarkList quark_args; + XrmResourceList* table; + Cardinal count, ntyped_args = num_typed_args; + WIDGET_TO_APPCON(w); + + if (num_resources == 0) return; + + LOCK_APP(app); + count = CountTreeDepth(w); + count++; /* make sure there's enough room for name and class */ + names = (XrmName*) XtStackAlloc(count * sizeof(XrmName), names_s); + classes = (XrmClass*) XtStackAlloc(count * sizeof(XrmClass), classes_s); + if (names == NULL || classes == NULL) _XtAllocError(NULL); + + /* Get full name, class of subobject */ + GetNamesAndClasses(w, names, classes); + count -= 2; + names[count] = StringToName(name); + classes[count] = StringToClass(class); + count++; + names[count] = NULLQUARK; + classes[count] = NULLQUARK; + + /* Compile arg list into quarks */ + CacheArgs(args, num_args, typed_args, num_typed_args, + quark_cache, XtNumber(quark_cache), &quark_args); + + /* Compile resource list if needed */ + if (((int) resources->resource_offset) >= 0) { + XrmCompileResourceListEphem(resources, num_resources); + } + table = _XtCreateIndirectionTable(resources, num_resources); + (void) GetResources(w, (char*)base, names, classes, table, num_resources, + quark_args, args, num_args, + typed_args, &ntyped_args, False); + FreeCache(quark_cache, quark_args); + XtFree((char *)table); + XtStackFree((XtPointer)names, names_s); + XtStackFree((XtPointer)classes, classes_s); + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +void XtGetSubresources ( + Widget w, + XtPointer base, + _Xconst char* name, + _Xconst char* class, + XtResourceList resources, + Cardinal num_resources, + ArgList args, + Cardinal num_args + ) +#else +void XtGetSubresources (w, base, name, class, resources, num_resources, + args, num_args) + Widget w; /* Widget "parent" of subobject */ + XtPointer base; /* Base address to write to */ + String name; /* name of subobject */ + String class; /* class of subobject */ + XtResourceList resources; /* resource list for subobject */ + Cardinal num_resources; + ArgList args; /* arg list to override resources */ + Cardinal num_args; +#endif +{ + _XtGetSubresources (w, base, name, class, resources, num_resources, args, num_args, NULL, 0); +} + + +void _XtGetApplicationResources + (w, base, resources, num_resources, args, num_args, typed_args, num_typed_args) + Widget w; /* Application shell widget */ + XtPointer base; /* Base address to write to */ + XtResourceList resources; /* resource list for subobject */ + Cardinal num_resources; + ArgList args; /* arg list to override resources */ + Cardinal num_args; + XtTypedArgList typed_args; + Cardinal num_typed_args; +{ + XrmName *names, names_s[50]; + XrmClass *classes, classes_s[50]; + XrmQuark quark_cache[100]; + XrmQuarkList quark_args; + XrmResourceList* table; + Cardinal count, ntyped_args = num_typed_args; + XtAppContext app; + + if (num_resources == 0) return; + + if (w == NULL) app = _XtDefaultAppContext(); + else app = XtWidgetToApplicationContext(w); + + LOCK_APP(app); + /* Get full name, class of application */ + if (w == NULL) { + /* hack for R2 compatibility */ + XtPerDisplay pd = _XtGetPerDisplay(_XtDefaultAppContext()->list[0]); + names = (XrmName*) XtStackAlloc (2 * sizeof(XrmName), names_s); + classes = (XrmClass*) XtStackAlloc (2 * sizeof(XrmClass), classes_s); + names[0] = pd->name; + names[1] = NULLQUARK; + classes[0] = pd->class; + classes[1] = NULLQUARK; + } + else { + count = CountTreeDepth(w); + names = (XrmName*) XtStackAlloc(count * sizeof(XrmName), names_s); + classes = (XrmClass*) XtStackAlloc(count * sizeof(XrmClass), classes_s); + if (names == NULL || classes == NULL) _XtAllocError(NULL); + GetNamesAndClasses(w, names, classes); + } + + /* Compile arg list into quarks */ + CacheArgs(args, num_args, typed_args, num_typed_args, quark_cache, + XtNumber(quark_cache), &quark_args); + /* Compile resource list if needed */ + if (((int) resources->resource_offset) >= 0) { +#ifdef CRAY2 + if (base == 0) { /* this client is non-portable, but... */ + int count; + XtResourceList res = resources; + for (count = 0; count < num_resources; res++, count++) { + res->resource_offset *= sizeof(long); + } + } +#endif /* CRAY2 */ + XrmCompileResourceListEphem(resources, num_resources); + } + table = _XtCreateIndirectionTable(resources,num_resources); + + (void) GetResources(w, (char*)base, names, classes, table, num_resources, + quark_args, args, num_args, + typed_args, &ntyped_args, False); + FreeCache(quark_cache, quark_args); + XtFree((char *)table); + if (w != NULL) { + XtStackFree((XtPointer)names, names_s); + XtStackFree((XtPointer)classes, classes_s); + } + UNLOCK_APP(app); +} + +void XtGetApplicationResources + (w, base, resources, num_resources, args, num_args) + Widget w; /* Application shell widget */ + XtPointer base; /* Base address to write to */ + XtResourceList resources; /* resource list for subobject */ + Cardinal num_resources; + ArgList args; /* arg list to override resources */ + Cardinal num_args; +{ + _XtGetApplicationResources(w, base, resources, num_resources, args, num_args, NULL, 0); +} + +static Boolean initialized = FALSE; + +void _XtResourceListInitialize() +{ + LOCK_PROCESS; + if (initialized) { + XtWarningMsg("initializationError","xtInitialize",XtCXtToolkitError, + "Initializing Resource Lists twice", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_PROCESS; + return; + } + initialized = TRUE; + UNLOCK_PROCESS; + + QBoolean = XrmPermStringToQuark(XtCBoolean); + QString = XrmPermStringToQuark(XtCString); + QCallProc = XrmPermStringToQuark(XtRCallProc); + QImmediate = XrmPermStringToQuark(XtRImmediate); + QinitialResourcesPersistent = XrmPermStringToQuark(XtNinitialResourcesPersistent); + QInitialResourcesPersistent = XrmPermStringToQuark(XtCInitialResourcesPersistent); + Qtranslations = XrmPermStringToQuark(XtNtranslations); + QbaseTranslations = XrmPermStringToQuark("baseTranslations"); + QTranslations = XrmPermStringToQuark(XtCTranslations); + QTranslationTable = XrmPermStringToQuark(XtRTranslationTable); + Qscreen = XrmPermStringToQuark(XtNscreen); + QScreen = XrmPermStringToQuark(XtCScreen); +} diff --git a/src/Selection.c b/src/Selection.c new file mode 100644 index 0000000..846b1bd --- /dev/null +++ b/src/Selection.c @@ -0,0 +1,2306 @@ +/* $Xorg: Selection.c,v 1.4 2001/02/09 02:03:56 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "StringDefs.h" +#include "SelectionI.h" +#include <X11/Xatom.h> + +void _XtSetDefaultSelectionTimeout(timeout) + unsigned long *timeout; +{ + *timeout = 5000; /* default to 5 seconds */ +} + +void XtSetSelectionTimeout(timeout) + unsigned long timeout; +{ + XtAppSetSelectionTimeout(_XtDefaultAppContext(), timeout); +} + +void XtAppSetSelectionTimeout(app, timeout) + XtAppContext app; + unsigned long timeout; +{ + LOCK_APP(app); + app->selectionTimeout = timeout; + UNLOCK_APP(app); +} + +unsigned long XtGetSelectionTimeout() +{ + return XtAppGetSelectionTimeout(_XtDefaultAppContext()); +} + +unsigned long XtAppGetSelectionTimeout(app) + XtAppContext app; +{ + unsigned long retval; + + LOCK_APP(app); + retval = app->selectionTimeout; + UNLOCK_APP(app); + return retval; +} + + +/* General utilities */ + +static void HandleSelectionReplies(); +static void ReqTimedOut(); +static void HandlePropertyGone(); +static void HandleGetIncrement(); +static void HandleIncremental(); + +static XContext selectPropertyContext = 0; +static XContext paramPropertyContext = 0; +static XContext multipleContext = 0; + +/* Multiple utilities */ +static void AddSelectionRequests(); +static Boolean IsGatheringRequest(); + +#define PREALLOCED 32 + +/* Parameter utilities */ +static void AddParamInfo(); +static void RemoveParamInfo(); +static Atom GetParamInfo(); + +static int StorageSize[3] = {1, sizeof(short), sizeof(long)}; +#define BYTELENGTH(length, format) ((length) * StorageSize[(format)>>4]) +#define NUMELEM(bytelength, format) ((bytelength) / StorageSize[(format)>>4]) + +/* Xlib and Xt are permitted to have different memory allocators, and in the + * XtSelectionCallbackProc the client is instructed to free the selection + * value with XtFree, so the selection value received from XGetWindowProperty + * should be copied to memory allocated through Xt. But copying is + * undesirable since the selection value may be large, and, under normal + * library configuration copying is unnecessary. + */ +#ifdef XTTRACEMEMORY +#define XT_COPY_SELECTION 1 +#endif + +/*ARGSUSED*/ +static void FreePropList(w, closure, callData) + Widget w; /* unused */ + XtPointer closure; + XtPointer callData; /* unused */ +{ + PropList sarray = (PropList)closure; + LOCK_PROCESS; + XDeleteContext(sarray->dpy, DefaultRootWindow(sarray->dpy), + selectPropertyContext); + UNLOCK_PROCESS; + XtFree((char*)sarray->list); + XtFree((char*)closure); +} + + +static PropList GetPropList(dpy) + Display *dpy; +{ + PropList sarray; + Atom atoms[4]; + static char* names[] = { + "INCR", + "MULTIPLE", + "TIMESTAMP", + "_XT_SELECTION_0" }; + + LOCK_PROCESS; + if (selectPropertyContext == 0) + selectPropertyContext = XUniqueContext(); + if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, + (XPointer *)&sarray)) { + XtPerDisplay pd = _XtGetPerDisplay(dpy); + sarray = (PropList) __XtMalloc((unsigned) sizeof(PropListRec)); + sarray->dpy = dpy; + XInternAtoms(dpy, names, 4, FALSE, atoms); + sarray->incr_atom = atoms[0]; + sarray->indirect_atom = atoms[1]; + sarray->timestamp_atom = atoms[2]; + sarray->propCount = 1; + sarray->list = + (SelectionProp)__XtMalloc((unsigned) sizeof(SelectionPropRec)); + sarray->list[0].prop = atoms[3]; + sarray->list[0].avail = TRUE; + (void) XSaveContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, + (char *) sarray); + _XtAddCallback( &pd->destroy_callbacks, + FreePropList, (XtPointer)sarray ); + } + UNLOCK_PROCESS; + return sarray; +} + + +static Atom GetSelectionProperty(dpy) +Display *dpy; +{ + SelectionProp p; + int propCount; + char propname[80]; + PropList sarray = GetPropList(dpy); + + for (p = sarray->list, propCount=sarray->propCount; + propCount; + p++, propCount--) { + if (p->avail) { + p->avail = FALSE; + return(p->prop); + } + } + propCount = sarray->propCount++; + sarray->list = (SelectionProp) XtRealloc((XtPointer)sarray->list, + (unsigned)(sarray->propCount*sizeof(SelectionPropRec))); + (void) sprintf(propname, "%s%d", "_XT_SELECTION_", propCount); + sarray->list[propCount].prop = XInternAtom(dpy, propname, FALSE); + sarray->list[propCount].avail = FALSE; + return(sarray->list[propCount].prop); +} + +static void FreeSelectionProperty(dpy, prop) +Display *dpy; +Atom prop; +{ + SelectionProp p; + PropList sarray; + if (prop == None) return; + LOCK_PROCESS; + if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext, + (XPointer *)&sarray)) + XtAppErrorMsg(XtDisplayToApplicationContext(dpy), + "noSelectionProperties", "freeSelectionProperty", XtCXtToolkitError, + "internal error: no selection property context for display", + (String *)NULL, (Cardinal *)NULL ); + UNLOCK_PROCESS; + for (p = sarray->list; p; p++) + if (p->prop == prop) { + p->avail = TRUE; + return; + } +} + +static void FreeInfo(info) + CallBackInfo info; +{ + XtFree((char*)info->incremental); + XtFree((char*)info->callbacks); + XtFree((char*)info->req_closure); + XtFree((char*)info->target); + XtFree((char*)info); +} + +static CallBackInfo MakeInfo(ctx, callbacks, closures, count, + widget, time, incremental, properties) +Select ctx; +XtSelectionCallbackProc *callbacks; +XtPointer *closures; +int count; +Widget widget; +Time time; +Boolean *incremental; +Atom *properties; +{ + CallBackInfo info = XtNew(CallBackInfoRec); + + info->ctx = ctx; + info->callbacks = (XtSelectionCallbackProc *) + __XtMalloc((unsigned) (count * sizeof(XtSelectionCallbackProc))); + (void) memmove((char*)info->callbacks, (char*)callbacks, + count * sizeof(XtSelectionCallbackProc)); + info->req_closure = + (XtPointer*)__XtMalloc((unsigned) (count * sizeof(XtPointer))); + (void) memmove((char*)info->req_closure, (char*)closures, + count * sizeof(XtPointer)); + if (count == 1 && properties != NULL && properties[0] != None) + info->property = properties[0]; + else { + info->property = GetSelectionProperty(XtDisplay(widget)); + XDeleteProperty(XtDisplay(widget), XtWindow(widget), + info->property); + } + info->proc = HandleSelectionReplies; + info->widget = widget; + info->time = time; + info->incremental = (Boolean*) __XtMalloc(count * sizeof(Boolean)); + (void) memmove((char*)info->incremental, (char*) incremental, + count * sizeof(Boolean)); + info->current = 0; + info->value = NULL; + return (info); +} + +static void RequestSelectionValue(info, selection, target) +CallBackInfo info; +Atom selection; +Atom target; +{ +#ifndef DEBUG_WO_TIMERS + XtAppContext app = XtWidgetToApplicationContext(info->widget); + info->timeout = XtAppAddTimeOut(app, + app->selectionTimeout, ReqTimedOut, (XtPointer)info); +#endif + XtAddEventHandler(info->widget, (EventMask)0, TRUE, + HandleSelectionReplies, (XtPointer)info); + XConvertSelection(info->ctx->dpy, selection, target, + info->property, XtWindow(info->widget), info->time); +} + + +static XContext selectContext = 0; + +static Select NewContext(dpy, selection) +Display *dpy; +Atom selection; +{ + /* assert(selectContext != 0) */ + Select ctx = XtNew(SelectRec); + ctx->dpy = dpy; + ctx->selection = selection; + ctx->widget = NULL; + ctx->prop_list = GetPropList(dpy); + ctx->ref_count = 0; + ctx->free_when_done = FALSE; + ctx->was_disowned = FALSE; + LOCK_PROCESS; + (void)XSaveContext(dpy, (Window)selection, selectContext, (char *)ctx); + UNLOCK_PROCESS; + return ctx; +} + +static Select FindCtx(dpy, selection) +Display *dpy; +Atom selection; +{ + Select ctx; + + LOCK_PROCESS; + if (selectContext == 0) + selectContext = XUniqueContext(); + if (XFindContext(dpy, (Window)selection, selectContext, (XPointer *)&ctx)) + ctx = NewContext(dpy, selection); + UNLOCK_PROCESS; + return ctx; +} + +/*ARGSUSED*/ +static void WidgetDestroyed(widget, closure, data) +Widget widget; +XtPointer closure, data; +{ + Select ctx = (Select) closure; + if (ctx->widget == widget) { + if (ctx->free_when_done) + XtFree((char*)ctx); + else + ctx->widget = NULL; + } +} + +/* Selection Owner code */ + +static void HandleSelectionEvents(); + +static Boolean LoseSelection(ctx, widget, selection, time) +Select ctx; +Widget widget; +Atom selection; +Time time; +{ + if ((ctx->widget == widget) && + (ctx->selection == selection) && /* paranoia */ + !ctx->was_disowned && + ((time == CurrentTime) || (time >= ctx->time))) + { + XtRemoveEventHandler(widget, (EventMask)0, TRUE, + HandleSelectionEvents, (XtPointer)ctx); + XtRemoveCallback(widget, XtNdestroyCallback, + WidgetDestroyed, (XtPointer)ctx); + ctx->was_disowned = TRUE; /* widget officially loses ownership */ + /* now inform widget */ + if (ctx->loses) { + if (ctx->incremental) + (*(XtLoseSelectionIncrProc)ctx->loses) + (widget, &ctx->selection, ctx->owner_closure); + else (*ctx->loses)(widget, &ctx->selection); + } + return(TRUE); + } + else return(FALSE); +} + +static XContext selectWindowContext = 0; + +/* %%% Xlib.h should make this public! */ +typedef int (*xErrorHandler)( +#if NeedFunctionPrototypes + Display*, XErrorEvent* +#endif + ); + +static xErrorHandler oldErrorHandler = NULL; +static unsigned long firstProtectRequest; +static Window errorWindow; + +static int LocalErrorHandler (dpy, error) +Display *dpy; +XErrorEvent *error; +{ + int retval; + + /* If BadWindow error on selection requestor, nothing to do but let + * the transfer timeout. Otherwise, invoke saved error handler. */ + + LOCK_PROCESS; + + if (error->error_code == BadWindow && error->resourceid == errorWindow && + error->serial >= firstProtectRequest) { + UNLOCK_PROCESS; + return 0; + } + + if (oldErrorHandler == NULL) { + UNLOCK_PROCESS; + return 0; /* should never happen */ + } + + retval = (*oldErrorHandler)(dpy, error); + UNLOCK_PROCESS; + return retval; +} + +static void StartProtectedSection(dpy, window) + Display *dpy; + Window window; +{ + /* protect ourselves against request window being destroyed + * before completion of transfer */ + + LOCK_PROCESS; + oldErrorHandler = XSetErrorHandler(LocalErrorHandler); + firstProtectRequest = NextRequest(dpy); + errorWindow = window; + UNLOCK_PROCESS; +} + +static void EndProtectedSection(dpy) + Display *dpy; +{ + /* flush any generated errors on requestor and + * restore original error handler */ + + XSync(dpy, False); + + LOCK_PROCESS; + XSetErrorHandler(oldErrorHandler); + oldErrorHandler = NULL; + UNLOCK_PROCESS; +} + +static void AddHandler(req, mask, proc, closure) +Request req; +EventMask mask; +XtEventHandler proc; +XtPointer closure; +{ + Display *dpy = req->ctx->dpy; + Window window = req->requestor; + Widget widget = XtWindowToWidget(dpy, window); + + if (widget != NULL) req->widget = widget; + else widget = req->widget; + + if (XtWindow(widget) == window) + XtAddEventHandler(widget, mask, False, proc, closure); + else { + RequestWindowRec *requestWindowRec; + LOCK_PROCESS; + if (selectWindowContext == 0) + selectWindowContext = XUniqueContext(); + if (XFindContext(dpy, window, selectWindowContext, + (XPointer *)&requestWindowRec)) { + requestWindowRec = XtNew(RequestWindowRec); + requestWindowRec->active_transfer_count = 0; + (void)XSaveContext(dpy, window, selectWindowContext, + (char *)requestWindowRec); + } + UNLOCK_PROCESS; + if (requestWindowRec->active_transfer_count++ == 0) { + XtRegisterDrawable(dpy, window, widget); + XSelectInput(dpy, window, mask); + } + XtAddRawEventHandler(widget, mask, FALSE, proc, closure); + } +} + +static void RemoveHandler(req, mask, proc, closure) +Request req; +EventMask mask; +XtEventHandler proc; +XtPointer closure; +{ + Display *dpy = req->ctx->dpy; + Window window = req->requestor; + Widget widget = req->widget; + + if ((XtWindowToWidget(dpy, window) == widget) && + (XtWindow(widget) != window)) { + /* we had to hang this window onto our widget; take it off */ + RequestWindowRec* requestWindowRec; + XtRemoveRawEventHandler(widget, mask, TRUE, proc, closure); + LOCK_PROCESS; + (void)XFindContext(dpy, window, selectWindowContext, + (XPointer *)&requestWindowRec); + UNLOCK_PROCESS; + if (--requestWindowRec->active_transfer_count == 0) { + XtUnregisterDrawable(dpy, window); + StartProtectedSection(dpy, window); + XSelectInput(dpy, window, 0L); + EndProtectedSection(dpy); + LOCK_PROCESS; + (void)XDeleteContext(dpy, window, selectWindowContext); + UNLOCK_PROCESS; + XtFree((char*)requestWindowRec); + } + } else { + XtRemoveEventHandler(widget, mask, TRUE, proc, closure); + } +} + +/* ARGSUSED */ +static void OwnerTimedOut(closure, id) +XtPointer closure; +XtIntervalId *id; +{ + Request req = (Request)closure; + Select ctx = req->ctx; + + if (ctx->incremental && (ctx->owner_cancel != NULL)) { + (*ctx->owner_cancel)(ctx->widget, &ctx->selection, + &req->target, (XtRequestId*)&req, + ctx->owner_closure); + } else { + if (ctx->notify == NULL) + XtFree((char*)req->value); + else { + /* the requestor hasn't deleted the property, but + * the owner needs to free the value. + */ + if (ctx->incremental) + (*(XtSelectionDoneIncrProc)ctx->notify) + (ctx->widget, &ctx->selection, &req->target, + (XtRequestId*)&req, ctx->owner_closure); + else + (*ctx->notify)(ctx->widget, &ctx->selection, &req->target); + } + } + + RemoveHandler(req, (EventMask)PropertyChangeMask, + HandlePropertyGone, closure); + XtFree((char*)req); + if (--ctx->ref_count == 0 && ctx->free_when_done) + XtFree((char*)ctx); +} + +static void SendIncrement(incr) + Request incr; +{ + Display *dpy = incr->ctx->dpy; + + int incrSize = MAX_SELECTION_INCR(dpy); + if (incrSize > incr->bytelength - incr->offset) + incrSize = incr->bytelength - incr->offset; + StartProtectedSection(dpy, incr->requestor); + XChangeProperty(dpy, incr->requestor, incr->property, + incr->type, incr->format, PropModeReplace, + (unsigned char *)incr->value + incr->offset, + NUMELEM(incrSize, incr->format)); + EndProtectedSection(dpy); + incr->offset += incrSize; +} + +static void AllSent(req) +Request req; +{ + Select ctx = req->ctx; + StartProtectedSection(ctx->dpy, req->requestor); + XChangeProperty(ctx->dpy, req->requestor, + req->property, req->type, req->format, + PropModeReplace, (unsigned char *) NULL, 0); + EndProtectedSection(ctx->dpy); + req->allSent = TRUE; + + if (ctx->notify == NULL) XtFree((char*)req->value); +} + +/*ARGSUSED*/ +static void HandlePropertyGone(widget, closure, ev, cont) +Widget widget; +XtPointer closure; +XEvent *ev; +Boolean *cont; +{ + XPropertyEvent *event = (XPropertyEvent *) ev; + Request req = (Request)closure; + Select ctx = req->ctx; + + if ((event->type != PropertyNotify) || + (event->state != PropertyDelete) || + (event->atom != req->property) || + (event->window != req->requestor)) + return; +#ifndef DEBUG_WO_TIMERS + XtRemoveTimeOut(req->timeout); +#endif + if (req->allSent) { + if (ctx->notify) + if (ctx->incremental) { + (*(XtSelectionDoneIncrProc)ctx->notify) + (ctx->widget, &ctx->selection, &req->target, + (XtRequestId*)&req, ctx->owner_closure); + } + else (*ctx->notify)(ctx->widget, &ctx->selection, &req->target); + RemoveHandler(req, (EventMask)PropertyChangeMask, + HandlePropertyGone, closure); + XtFree((char*)req); + if (--ctx->ref_count == 0 && ctx->free_when_done) + XtFree((char*)ctx); + } else { /* is this part of an incremental transfer? */ + if (ctx->incremental) { + if (req->bytelength == 0) + AllSent(req); + else { + unsigned long size = MAX_SELECTION_INCR(ctx->dpy); + SendIncrement(req); + (*(XtConvertSelectionIncrProc)ctx->convert) + (ctx->widget, &ctx->selection, &req->target, + &req->type, &req->value, + &req->bytelength, &req->format, + &size, ctx->owner_closure, (XtPointer*)&req); + if (req->bytelength) + req->bytelength = BYTELENGTH(req->bytelength, req->format); + req->offset = 0; + } + } else { + if (req->offset < req->bytelength) + SendIncrement(req); + else AllSent(req); + } +#ifndef DEBUG_WO_TIMERS + { + XtAppContext app = XtWidgetToApplicationContext(req->widget); + req->timeout = XtAppAddTimeOut(app, + app->selectionTimeout, OwnerTimedOut, (XtPointer)req); + } +#endif + } +} + +static void PrepareIncremental(req, widget, window, property, target, + targetType, value, length, format) +Request req; +Widget widget; +Window window; +Atom target; +Atom property; +Atom targetType; +XtPointer value; +unsigned long length; +int format; +{ + req->type = targetType; + req->value = value; + req->bytelength = BYTELENGTH(length,format); + req->format = format; + req->offset = 0; + req->target = target; + req->widget = widget; + req->allSent = FALSE; +#ifndef DEBUG_WO_TIMERS + { + XtAppContext app = XtWidgetToApplicationContext(widget); + req->timeout = XtAppAddTimeOut(app, + app->selectionTimeout, OwnerTimedOut, (XtPointer)req); + } +#endif + AddHandler(req, (EventMask)PropertyChangeMask, + HandlePropertyGone, (XtPointer)req); +/* now send client INCR property */ + XChangeProperty(req->ctx->dpy, window, req->property, + req->ctx->prop_list->incr_atom, + 32, PropModeReplace, + (unsigned char *)&req->bytelength, 1); +} + +static Boolean GetConversion(ctx, event, target, property, widget) +Select ctx; /* logical owner */ +XSelectionRequestEvent* event; +Atom target; +Atom property; /* requestor's property */ +Widget widget; /* physical owner (receives events) */ +{ + XtPointer value = NULL; + unsigned long length; + int format; + Atom targetType; + Request req = XtNew(RequestRec); + Boolean timestamp_target = (target == ctx->prop_list->timestamp_atom); + + req->ctx = ctx; + req->event = *event; + req->property = property; + req->requestor = event->requestor; + + if (timestamp_target) { + value = __XtMalloc(sizeof(long)); + *(long*)value = ctx->time; + targetType = XA_INTEGER; + length = 1; + format = 32; + } + else { + ctx->ref_count++; + if (ctx->incremental == TRUE) { + unsigned long size = MAX_SELECTION_INCR(ctx->dpy); + if ((*(XtConvertSelectionIncrProc)ctx->convert) + (ctx->widget, &event->selection, &target, + &targetType, &value, &length, &format, + &size, ctx->owner_closure, (XtRequestId*)&req) + == FALSE) { + XtFree((char*)req); + ctx->ref_count--; + return(FALSE); + } + StartProtectedSection(ctx->dpy, event->requestor); + PrepareIncremental(req, widget, event->requestor, property, + target, targetType, value, length, format); + return(TRUE); + } + ctx->req = req; + if ((*ctx->convert)(ctx->widget, &event->selection, &target, + &targetType, &value, &length, &format) == FALSE) { + XtFree((char*)req); + ctx->req = NULL; + ctx->ref_count--; + return(FALSE); + } + ctx->req = NULL; + } + StartProtectedSection(ctx->dpy, event->requestor); + if (BYTELENGTH(length,format) <= MAX_SELECTION_INCR(ctx->dpy)) { + if (! timestamp_target) { + if (ctx->notify != NULL) { + req->target = target; + req->widget = widget; + req->allSent = TRUE; +#ifndef DEBUG_WO_TIMERS + { + XtAppContext app = XtWidgetToApplicationContext(req->widget); + req->timeout = XtAppAddTimeOut(app, + app->selectionTimeout, OwnerTimedOut, (XtPointer)req); + } +#endif + AddHandler(req, (EventMask)PropertyChangeMask, + HandlePropertyGone, (XtPointer)req); + } + else ctx->ref_count--; + } + XChangeProperty(ctx->dpy, event->requestor, property, + targetType, format, PropModeReplace, + (unsigned char *)value, (int)length); + /* free storage for client if no notify proc */ + if (timestamp_target || ctx->notify == NULL) { + XtFree((char*)value); + XtFree((char*)req); + } + } else { + PrepareIncremental(req, widget, event->requestor, property, + target, targetType, value, length, format); + } + return(TRUE); +} + +/*ARGSUSED*/ +static void HandleSelectionEvents(widget, closure, event, cont) +Widget widget; +XtPointer closure; +XEvent *event; +Boolean *cont; +{ + Select ctx; + XSelectionEvent ev; + Atom target; + int count; + Boolean writeback = FALSE; + + ctx = (Select) closure; + switch (event->type) { + case SelectionClear: + /* if this event is not for the selection we registered for, + * don't do anything */ + if (ctx->selection != event->xselectionclear.selection || + ctx->serial > event->xselectionclear.serial) + break; + (void) LoseSelection(ctx, widget, event->xselectionclear.selection, + event->xselectionclear.time); + break; + case SelectionRequest: + /* if this event is not for the selection we registered for, + * don't do anything */ + if (ctx->selection != event->xselectionrequest.selection) + break; + ev.type = SelectionNotify; + ev.display = event->xselectionrequest.display; + ev.requestor = event->xselectionrequest.requestor; + ev.selection = event->xselectionrequest.selection; + ev.time = event->xselectionrequest.time; + ev.target = event->xselectionrequest.target; + if (event->xselectionrequest.property == None) /* obsolete requestor */ + event->xselectionrequest.property = event->xselectionrequest.target; + if (ctx->widget != widget || ctx->was_disowned + || ((event->xselectionrequest.time != CurrentTime) + && (event->xselectionrequest.time < ctx->time))) + ev.property = None; + else { + if (ev.target == ctx->prop_list->indirect_atom) { + IndirectPair *p; + int format; + unsigned long bytesafter, length; + unsigned char *value; + ev.property = event->xselectionrequest.property; + StartProtectedSection(ev.display, ev.requestor); + (void) XGetWindowProperty(ev.display, ev.requestor, + event->xselectionrequest.property, 0L, 1000000, + False,(Atom)AnyPropertyType, &target, &format, &length, + &bytesafter, &value); + count = BYTELENGTH(length, format) / sizeof(IndirectPair); + for (p = (IndirectPair *)value; count; p++, count--) { + EndProtectedSection(ctx->dpy); + if (!GetConversion(ctx, (XSelectionRequestEvent*)event, + p->target, p->property, widget)) { + + p->target = None; + writeback = TRUE; + StartProtectedSection(ctx->dpy, ev.requestor); + } + } + if (writeback) + XChangeProperty(ev.display, ev.requestor, + event->xselectionrequest.property, target, + format, PropModeReplace, value, (int)length); + XFree((char *)value); + } else /* not multiple */ { + if (GetConversion(ctx, (XSelectionRequestEvent*)event, + event->xselectionrequest.target, + event->xselectionrequest.property, + widget)) + ev.property = event->xselectionrequest.property; + else { + ev.property = None; + StartProtectedSection(ctx->dpy, ev.requestor); + } + } + } + (void) XSendEvent(ctx->dpy, ev.requestor, False, (unsigned long)NULL, + (XEvent *) &ev); + + EndProtectedSection(ctx->dpy); + + break; + } +} + +static Boolean OwnSelection(widget, selection, time, convert, lose, notify, + cancel, closure, incremental) +Widget widget; +Atom selection; +Time time; +XtConvertSelectionProc convert; +XtLoseSelectionProc lose; +XtSelectionDoneProc notify; +XtCancelConvertSelectionProc cancel; +XtPointer closure; +Boolean incremental; +{ + Select ctx; + Select oldctx = NULL; + + if (!XtIsRealized(widget)) return False; + + ctx = FindCtx(XtDisplay(widget), selection); + if (ctx->widget != widget || ctx->time != time || + ctx->ref_count || ctx->was_disowned) + { + Boolean replacement = FALSE; + Window window = XtWindow(widget); + unsigned long serial = XNextRequest(ctx->dpy); + XSetSelectionOwner(ctx->dpy, selection, window, time); + if (XGetSelectionOwner(ctx->dpy, selection) != window) + return FALSE; + if (ctx->ref_count) { /* exchange is in-progress */ +#ifdef DEBUG_ACTIVE + printf( "Active exchange for widget \"%s\"; selection=0x%lx, ref_count=%d\n", + XtName(widget), (long)selection, ctx->ref_count ); +#endif + if (ctx->widget != widget || + ctx->convert != convert || + ctx->loses != lose || + ctx->notify != notify || + ctx->owner_cancel != cancel || + ctx->incremental != incremental || + ctx->owner_closure != closure) + { + if (ctx->widget == widget) { + XtRemoveEventHandler(widget, (EventMask)0, TRUE, + HandleSelectionEvents, (XtPointer)ctx); + XtRemoveCallback(widget, XtNdestroyCallback, + WidgetDestroyed, (XtPointer)ctx); + replacement = TRUE; + } + else if (!ctx->was_disowned) { + oldctx = ctx; + } + ctx->free_when_done = TRUE; + ctx = NewContext(XtDisplay(widget), selection); + } + else if (!ctx->was_disowned) { /* current owner is new owner */ + ctx->time = time; + return TRUE; + } + } + if (ctx->widget != widget || ctx->was_disowned || replacement) { + if (ctx->widget && !ctx->was_disowned && !replacement) { + oldctx = ctx; + oldctx->free_when_done = TRUE; + ctx = NewContext(XtDisplay(widget), selection); + } + XtAddEventHandler(widget, (EventMask)0, TRUE, + HandleSelectionEvents, (XtPointer)ctx); + XtAddCallback(widget, XtNdestroyCallback, + WidgetDestroyed, (XtPointer)ctx); + } + ctx->widget = widget; /* Selection offically changes hands. */ + ctx->time = time; + ctx->serial = serial; + } + ctx->convert = convert; + ctx->loses = lose; + ctx->notify = notify; + ctx->owner_cancel = cancel; + ctx->incremental = incremental; + ctx->owner_closure = closure; + ctx->was_disowned = FALSE; + + /* Defer calling the previous selection owner's lose selection procedure + * until the new selection is established, to allow the previous + * selection owner to ask for the new selection to be converted in + * the lose selection procedure. The context pointer is the closure + * of the event handler and the destroy callback, so the old context + * pointer and the record contents must be preserved for LoseSelection. + */ + if (oldctx) { + (void) LoseSelection(oldctx, oldctx->widget, selection, oldctx->time); + if (!oldctx->ref_count && oldctx->free_when_done) + XtFree((char*)oldctx); + } + return TRUE; +} + + +Boolean XtOwnSelection(widget, selection, time, convert, lose, notify) +Widget widget; +Atom selection; +Time time; +XtConvertSelectionProc convert; +XtLoseSelectionProc lose; +XtSelectionDoneProc notify; +{ + Boolean retval; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + retval = OwnSelection(widget, selection, time, convert, lose, notify, + (XtCancelConvertSelectionProc)NULL, + (XtPointer)NULL, FALSE); + UNLOCK_APP(app); + return retval; +} + + +Boolean XtOwnSelectionIncremental(widget, selection, time, convert, + lose, notify, cancel, closure) +Widget widget; +Atom selection; +Time time; +XtConvertSelectionIncrProc convert; +XtLoseSelectionIncrProc lose; +XtSelectionDoneIncrProc notify; +XtCancelConvertSelectionProc cancel; +XtPointer closure; +{ + Boolean retval; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + retval = OwnSelection(widget, selection, time, + (XtConvertSelectionProc)convert, + (XtLoseSelectionProc)lose, + (XtSelectionDoneProc)notify, + cancel, closure, TRUE); + UNLOCK_APP(app); + return retval; +} + + +void XtDisownSelection(widget, selection, time) +Widget widget; +Atom selection; +Time time; +{ + Select ctx; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + ctx = FindCtx(XtDisplay(widget), selection); + if (LoseSelection(ctx, widget, selection, time)) + XSetSelectionOwner(XtDisplay(widget), selection, None, time); + UNLOCK_APP(app); +} + +/* Selection Requestor code */ + +static Boolean IsINCRtype(info, window, prop) + CallBackInfo info; + Window window; + Atom prop; +{ + unsigned long bytesafter; + unsigned long length; + int format; + Atom type; + unsigned char *value; + + if (prop == None) return False; + + (void)XGetWindowProperty(XtDisplay(info->widget), window, prop, 0L, 0L, + False, info->ctx->prop_list->incr_atom, + &type, &format, &length, &bytesafter, &value); + + return (type == info->ctx->prop_list->incr_atom); +} + +/*ARGSUSED*/ +static void ReqCleanup(widget, closure, ev, cont) +Widget widget; +XtPointer closure; +XEvent *ev; +Boolean *cont; +{ + CallBackInfo info = (CallBackInfo)closure; + unsigned long bytesafter, length; + char *value; + int format; + Atom target; + + if (ev->type == SelectionNotify) { + XSelectionEvent *event = (XSelectionEvent *) ev; + if (!MATCH_SELECT(event, info)) return; /* not really for us */ + XtRemoveEventHandler(widget, (EventMask)0, TRUE, + ReqCleanup, (XtPointer) info ); + if (IsINCRtype(info, XtWindow(widget), event->property)) { + info->proc = HandleGetIncrement; + XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, + FALSE, ReqCleanup, (XtPointer) info); + } else { + if (event->property != None) + XDeleteProperty(event->display, XtWindow(widget), + event->property); + FreeSelectionProperty(XtDisplay(widget), info->property); + FreeInfo(info); + } + } else if ((ev->type == PropertyNotify) && + (ev->xproperty.state == PropertyNewValue) && + (ev->xproperty.atom == info->property)) { + XPropertyEvent *event = (XPropertyEvent *) ev; + (void) XGetWindowProperty(event->display, XtWindow(widget), + event->atom, 0L, 1000000, True, AnyPropertyType, + &target, &format, &length, &bytesafter, + (unsigned char **) &value); + XFree(value); + if (length == 0) { + XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, + ReqCleanup, (XtPointer) info ); + FreeSelectionProperty(XtDisplay(widget), info->property); + XtFree(info->value); /* requestor never got this, so free now */ + FreeInfo(info); + } + } +} + +/* ARGSUSED */ +static void ReqTimedOut(closure, id) +XtPointer closure; +XtIntervalId *id; +{ + XtPointer value = NULL; + unsigned long length = 0; + int format = 8; + Atom resulttype = XT_CONVERT_FAIL; + CallBackInfo info = (CallBackInfo)closure; + unsigned long bytesafter; + unsigned long proplength; + Atom type; + IndirectPair *pairs; + XtPointer *c; + int i; + + if (*info->target == info->ctx->prop_list->indirect_atom) { + (void) XGetWindowProperty(XtDisplay(info->widget), + XtWindow(info->widget), info->property, 0L, + 10000000, True, AnyPropertyType, &type, &format, + &proplength, &bytesafter, (unsigned char **) &pairs); + XFree((char*)pairs); + for (proplength = proplength / IndirectPairWordSize, i = 0, c = info->req_closure; + proplength; proplength--, c++, i++) + (*info->callbacks[i])(info->widget, *c, + &info->ctx->selection, &resulttype, value, &length, &format); + } else { + (*info->callbacks[0])(info->widget, *info->req_closure, + &info->ctx->selection, &resulttype, value, &length, &format); + } + + /* change event handlers for straggler events */ + if (info->proc == (XtEventHandler)HandleSelectionReplies) { + XtRemoveEventHandler(info->widget, (EventMask)0, + TRUE, info->proc, (XtPointer) info); + XtAddEventHandler(info->widget, (EventMask)0, TRUE, + ReqCleanup, (XtPointer) info); + } else { + XtRemoveEventHandler(info->widget,(EventMask) PropertyChangeMask, + FALSE, info->proc, (XtPointer) info); + XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask, + FALSE, ReqCleanup, (XtPointer) info); + } + +} + +/*ARGSUSED*/ +static void HandleGetIncrement(widget, closure, ev, cont) +Widget widget; +XtPointer closure; +XEvent *ev; +Boolean *cont; +{ + XPropertyEvent *event = (XPropertyEvent *) ev; + CallBackInfo info = (CallBackInfo) closure; + Select ctx = info->ctx; + char *value; + unsigned long bytesafter; + unsigned long length; + int bad; + int n = info->current; + + if ((event->state != PropertyNewValue) || (event->atom != info->property)) + return; + + bad = XGetWindowProperty(event->display, XtWindow(widget), + event->atom, 0L, + 10000000, True, AnyPropertyType, &info->type, + &info->format, &length, &bytesafter, + (unsigned char **) &value); + if (bad) + return; +#ifndef DEBUG_WO_TIMERS + XtRemoveTimeOut(info->timeout); +#endif + if (length == 0) { + unsigned long u_offset = NUMELEM(info->offset, info->format); + (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection, + &info->type, + (info->offset == 0 ? value : info->value), + &u_offset, &info->format); + /* assert ((info->offset != 0) == (info->incremental[n]) */ + if (info->offset != 0) XFree(value); + XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, + HandleGetIncrement, (XtPointer) info); + FreeSelectionProperty(event->display, info->property); + FreeInfo(info); + } else { /* add increment to collection */ + if (info->incremental[n]) { +#ifdef XT_COPY_SELECTION + int size = BYTELENGTH(length, info->format) + 1; + char *tmp = __XtMalloc((Cardinal) size); + (void) memmove(tmp, value, size); + XFree(value); + value = tmp; +#endif + (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection, + &info->type, value, &length, &info->format); + } else { + int size = BYTELENGTH(length, info->format); + if (info->offset + size > info->bytelength) { + /* allocate enough for this and the next increment */ + info->bytelength = info->offset + size * 2; + info->value = XtRealloc(info->value, + (Cardinal) info->bytelength); + } + (void) memmove(&info->value[info->offset], value, size); + info->offset += size; + XFree(value); + } + /* reset timer */ +#ifndef DEBUG_WO_TIMERS + { + XtAppContext app = XtWidgetToApplicationContext(info->widget); + info->timeout = XtAppAddTimeOut(app, + app->selectionTimeout, ReqTimedOut, (XtPointer) info); + } +#endif + } +} + + +static void HandleNone(widget, callback, closure, selection) +Widget widget; +XtSelectionCallbackProc callback; +XtPointer closure; +Atom selection; +{ + unsigned long length = 0; + int format = 8; + Atom type = None; + + (*callback)(widget, closure, &selection, + &type, NULL, &length, &format); +} + + +static long IncrPropSize(widget, value, format, length) + Widget widget; + unsigned char* value; + int format; + unsigned long length; +{ + unsigned long size; + if (format == 32) { + size = ((long*)value)[length-1]; /* %%% what order for longs? */ + return size; + } + else { + XtAppWarningMsg( XtWidgetToApplicationContext(widget), + "badFormat","xtGetSelectionValue",XtCXtToolkitError, + "Selection owner returned type INCR property with format != 32", + (String*)NULL, (Cardinal*)NULL ); + return 0; + } +} + + +static +Boolean HandleNormal(dpy, widget, property, info, closure, selection) +Display *dpy; +Widget widget; +Atom property; +CallBackInfo info; +XtPointer closure; +Atom selection; +{ + unsigned long bytesafter; + unsigned long length; + int format; + Atom type; + unsigned char *value; + int number = info->current; + + (void) XGetWindowProperty(dpy, XtWindow(widget), property, 0L, + 10000000, False, AnyPropertyType, + &type, &format, &length, &bytesafter, &value); + + if (type == info->ctx->prop_list->incr_atom) { + unsigned long size = IncrPropSize(widget, value, format, length); + XFree((char *)value); + if (info->property != property) { + /* within MULTIPLE */ + CallBackInfo ninfo; + ninfo = MakeInfo(info->ctx, &info->callbacks[number], + &info->req_closure[number], 1, widget, + info->time, &info->incremental[number], &property); + ninfo->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom)); + *ninfo->target = info->target[number + 1]; + info = ninfo; + } + HandleIncremental(dpy, widget, property, info, size); + return FALSE; + } + + XDeleteProperty(dpy, XtWindow(widget), property); +#ifdef XT_COPY_SELECTION + if (value) { /* it could have been deleted after the SelectionNotify */ + int size = BYTELENGTH(length, info->format) + 1; + char *tmp = __XtMalloc((Cardinal) size); + (void) memmove(tmp, value, size); + XFree(value); + value = (unsigned char *) tmp; + } +#endif + (*info->callbacks[number])(widget, closure, &selection, + &type, (XtPointer)value, &length, &format); + + if (info->incremental[number]) { + /* let requestor know the whole thing has been received */ + value = (unsigned char*)__XtMalloc((unsigned)1); + length = 0; + (*info->callbacks[number])(widget, closure, &selection, + &type, (XtPointer)value, &length, &format); + } + return TRUE; +} + +static void HandleIncremental(dpy, widget, property, info, size) +Display *dpy; +Widget widget; +Atom property; +CallBackInfo info; +unsigned long size; +{ + XtAddEventHandler(widget, (EventMask) PropertyChangeMask, FALSE, + HandleGetIncrement, (XtPointer) info); + + /* now start the transfer */ + XDeleteProperty(dpy, XtWindow(widget), property); + XFlush(dpy); + + info->bytelength = size; + if (info->incremental[info->current]) /* requestor wants incremental too */ + info->value = NULL; /* so no need for buffer to assemble value */ + else + info->value = (char *) __XtMalloc((unsigned) info->bytelength); + info->offset = 0; + + /* reset the timer */ + info->proc = HandleGetIncrement; +#ifndef DEBUG_WO_TIMERS + { + XtAppContext app = XtWidgetToApplicationContext(info->widget); + info->timeout = XtAppAddTimeOut(app, + app->selectionTimeout, ReqTimedOut, (XtPointer) info); + } +#endif +} + +/*ARGSUSED*/ +static void HandleSelectionReplies(widget, closure, ev, cont) +Widget widget; +XtPointer closure; +XEvent *ev; +Boolean *cont; +{ + XSelectionEvent *event = (XSelectionEvent *) ev; + Display *dpy = event->display; + CallBackInfo info = (CallBackInfo) closure; + Select ctx = info->ctx; + IndirectPair *pairs, *p; + unsigned long bytesafter; + unsigned long length; + int format; + Atom type; + XtPointer *c; + + if (event->type != SelectionNotify) return; + if (!MATCH_SELECT(event, info)) return; /* not really for us */ +#ifndef DEBUG_WO_TIMERS + XtRemoveTimeOut(info->timeout); +#endif + XtRemoveEventHandler(widget, (EventMask)0, TRUE, + HandleSelectionReplies, (XtPointer) info ); + if (event->target == ctx->prop_list->indirect_atom) { + (void) XGetWindowProperty(dpy, XtWindow(widget), info->property, 0L, + 10000000, True, AnyPropertyType, &type, &format, + &length, &bytesafter, (unsigned char **) &pairs); + for (length = length / IndirectPairWordSize, p = pairs, + c = info->req_closure; + length; length--, p++, c++, info->current++) { + if (event->property == None || format != 32 || p->target == None + || /* bug compatibility */ p->property == None) { + HandleNone(widget, info->callbacks[info->current], + *c, event->selection); + if (p->property != None) + FreeSelectionProperty(XtDisplay(widget), p->property); + } else { + if (HandleNormal(dpy, widget, p->property, info, *c, + event->selection)) { + FreeSelectionProperty(XtDisplay(widget), p->property); + } + } + } + XFree((char*)pairs); + FreeSelectionProperty(dpy, info->property); + FreeInfo(info); + } else if (event->property == None) { + HandleNone(widget, info->callbacks[0], *info->req_closure, event->selection); + FreeSelectionProperty(XtDisplay(widget), info->property); + FreeInfo(info); + } else { + if (HandleNormal(dpy, widget, event->property, info, + *info->req_closure, event->selection)) { + FreeSelectionProperty(XtDisplay(widget), info->property); + FreeInfo(info); + } + } +} + +static void DoLocalTransfer(req, selection, target, widget, + callback, closure, incremental, property) +Request req; +Atom selection; +Atom target; +Widget widget; /* The widget requesting the value. */ +XtSelectionCallbackProc callback; +XtPointer closure; /* the closure for the callback, not the conversion */ +Boolean incremental; +Atom property; +{ + Select ctx = req->ctx; + XtPointer value = NULL, temp, total = NULL; + unsigned long length; + int format; + Atom resulttype; + unsigned long totallength = 0; + + req->event.type = 0; + req->event.target = target; + req->event.property = req->property = property; + req->event.requestor = req->requestor = XtWindow(widget); + + if (ctx->incremental) { + unsigned long size = MAX_SELECTION_INCR(ctx->dpy); + if (!(*(XtConvertSelectionIncrProc)ctx->convert) + (ctx->widget, &selection, &target, + &resulttype, &value, &length, &format, + &size, ctx->owner_closure, (XtRequestId*)&req)) { + HandleNone(widget, callback, closure, selection); + } + else { + if (incremental) { + Boolean allSent = FALSE; + while (!allSent) { + if (ctx->notify && (value != NULL)) { + int bytelength = BYTELENGTH(length,format); + /* both sides think they own this storage */ + temp = __XtMalloc((unsigned)bytelength); + (void) memmove(temp, value, bytelength); + value = temp; + } + /* use care; older clients were never warned that + * they must return a value even if length==0 + */ + if (value == NULL) value = __XtMalloc((unsigned)1); + (*callback)(widget, closure, &selection, + &resulttype, value, &length, &format); + if (length) { + /* should owner be notified on end-of-piece? + * Spec is unclear, but non-local transfers don't. + */ + (*(XtConvertSelectionIncrProc)ctx->convert) + (ctx->widget, &selection, &target, + &resulttype, &value, &length, &format, + &size, ctx->owner_closure, + (XtRequestId*)&req); + } + else allSent = TRUE; + } + } else { + while (length) { + int bytelength = BYTELENGTH(length, format); + total = XtRealloc(total, + (unsigned) (totallength += bytelength)); + (void) memmove((char*)total + totallength - bytelength, + value, + bytelength); + (*(XtConvertSelectionIncrProc)ctx->convert) + (ctx->widget, &selection, &target, + &resulttype, &value, &length, &format, + &size, ctx->owner_closure, (XtRequestId*)&req); + } + if (total == NULL) total = __XtMalloc(1); + totallength = NUMELEM(totallength, format); + (*callback)(widget, closure, &selection, &resulttype, + total, &totallength, &format); + } + if (ctx->notify) + (*(XtSelectionDoneIncrProc)ctx->notify) + (ctx->widget, &selection, &target, + (XtRequestId*)&req, ctx->owner_closure); + else XtFree((char*)value); + } + } else { /* not incremental owner */ + if (!(*ctx->convert)(ctx->widget, &selection, &target, + &resulttype, &value, &length, &format)) { + HandleNone(widget, callback, closure, selection); + } else { + if (ctx->notify && (value != NULL)) { + int bytelength = BYTELENGTH(length,format); + /* both sides think they own this storage; better copy */ + temp = __XtMalloc((unsigned)bytelength); + (void) memmove(temp, value, bytelength); + value = temp; + } + if (value == NULL) value = __XtMalloc((unsigned)1); + (*callback)(widget, closure, &selection, &resulttype, + value, &length, &format); + if (ctx->notify) + (*ctx->notify)(ctx->widget, &selection, &target); + } + } +} + +static void GetSelectionValue(widget, selection, target, callback, + closure, time, incremental, property) +Widget widget; +Atom selection; +Atom target; +XtSelectionCallbackProc callback; +XtPointer closure; +Time time; +Boolean incremental; +Atom property; +{ + Select ctx; + CallBackInfo info; + Atom properties[1]; + + properties[0] = property; + + ctx = FindCtx(XtDisplay(widget), selection); + if (ctx->widget && !ctx->was_disowned) { + RequestRec req; + ctx->req = &req; + req.ctx = ctx; + req.event.time = time; + ctx->ref_count++; + DoLocalTransfer(&req, selection, target, widget, + callback, closure, incremental, property); + if (--ctx->ref_count == 0 && ctx->free_when_done) + XtFree((char*)ctx); + else + ctx->req = NULL; + } + else { + info = MakeInfo(ctx, &callback, &closure, 1, widget, + time, &incremental, properties); + info->target = (Atom *)__XtMalloc((unsigned) sizeof(Atom)); + *(info->target) = target; + RequestSelectionValue(info, selection, target); + } +} + + +void XtGetSelectionValue(widget, selection, target, callback, closure, time) +Widget widget; +Atom selection; +Atom target; +XtSelectionCallbackProc callback; +XtPointer closure; +Time time; +{ + Atom property; + Boolean incr = False; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + property = GetParamInfo(widget, selection); + RemoveParamInfo(widget, selection); + + if (IsGatheringRequest(widget, selection)) { + AddSelectionRequests(widget, selection, 1, &target, &callback, 1, + &closure, &incr, &property); + } else { + GetSelectionValue(widget, selection, target, callback, + closure, time, FALSE, property); + } + UNLOCK_APP(app); +} + + +void XtGetSelectionValueIncremental(widget, selection, target, callback, + closure, time) +Widget widget; +Atom selection; +Atom target; +XtSelectionCallbackProc callback; +XtPointer closure; +Time time; +{ + Atom property; + Boolean incr = TRUE; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + property = GetParamInfo(widget, selection); + RemoveParamInfo(widget, selection); + + if (IsGatheringRequest(widget, selection)) { + AddSelectionRequests(widget, selection, 1, &target, &callback, 1, + &closure, &incr, &property); + } else { + GetSelectionValue(widget, selection, target, callback, + closure, time, TRUE, property); + } + + UNLOCK_APP(app); +} + + +static void GetSelectionValues(widget, selection, targets, count, callbacks, + num_callbacks, closures, time, incremental, + properties) +Widget widget; +Atom selection; +Atom *targets; +int count; +XtSelectionCallbackProc *callbacks; +int num_callbacks; +XtPointer *closures; +Time time; +Boolean *incremental; +Atom *properties; +{ + Select ctx; + CallBackInfo info; + IndirectPair *pairs, *p; + Atom *t; + + if (count == 0) return; + ctx = FindCtx(XtDisplay(widget), selection); + if (ctx->widget && !ctx->was_disowned) { + int j, i; + RequestRec req; + ctx->req = &req; + req.ctx = ctx; + req.event.time = time; + ctx->ref_count++; + for (i = 0, j = 0; count; count--, i++, j++ ) { + if (j >= num_callbacks) j = 0; + + DoLocalTransfer(&req, selection, targets[i], widget, + callbacks[j], closures[i], incremental[i], + properties ? properties[i] : None); + + } + if (--ctx->ref_count == 0 && ctx->free_when_done) + XtFree((char*)ctx); + else + ctx->req = NULL; + } else { + XtSelectionCallbackProc *passed_callbacks; + XtSelectionCallbackProc stack_cbs[32]; + int i = 0, j = 0; + + passed_callbacks = (XtSelectionCallbackProc *) + XtStackAlloc(sizeof(XtSelectionCallbackProc) * count, stack_cbs); + + /* To deal with the old calls from XtGetSelectionValues* we + will repeat however many callbacks have been passed into + the array */ + for(i = 0; i < count; i++) { + if (j >= num_callbacks) j = 0; + passed_callbacks[i] = callbacks[j]; + j++; + } + info = MakeInfo(ctx, passed_callbacks, closures, count, widget, + time, incremental, properties); + XtStackFree((XtPointer) passed_callbacks, stack_cbs); + + info->target = (Atom *)__XtMalloc((unsigned) ((count+1) * sizeof(Atom))); + (*info->target) = ctx->prop_list->indirect_atom; + (void) memmove((char *) info->target+sizeof(Atom), (char *) targets, + count * sizeof(Atom)); + pairs = (IndirectPair*)__XtMalloc((unsigned)(count*sizeof(IndirectPair))); + for (p = &pairs[count-1], t = &targets[count-1], i = count - 1; + p >= pairs; p--, t--, i--) { + p->target = *t; + if (properties == NULL || properties[i] == None) { + p->property = GetSelectionProperty(XtDisplay(widget)); + XDeleteProperty(XtDisplay(widget), XtWindow(widget), + p->property); + } else { + p->property = properties[i]; + } + } + XChangeProperty(XtDisplay(widget), XtWindow(widget), + info->property, info->property, + 32, PropModeReplace, (unsigned char *) pairs, + count * IndirectPairWordSize); + XtFree((char*)pairs); + RequestSelectionValue(info, selection, ctx->prop_list->indirect_atom); + } +} + + +void XtGetSelectionValues(widget, selection, targets, count, callback, + closures, time) +Widget widget; +Atom selection; +Atom *targets; +int count; +XtSelectionCallbackProc callback; +XtPointer *closures; +Time time; +{ + Boolean incremental_values[32]; + Boolean *incremental; + int i; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values); + for(i = 0; i < count; i++) incremental[i] = FALSE; + if (IsGatheringRequest(widget, selection)) { + AddSelectionRequests(widget, selection, count, targets, &callback, + 1, closures, incremental, NULL); + } else { + GetSelectionValues(widget, selection, targets, count, &callback, 1, + closures, time, incremental, NULL); + } + XtStackFree((XtPointer) incremental, incremental_values); + UNLOCK_APP(app); +} + + +void XtGetSelectionValuesIncremental(widget, selection, targets, count, + callback, closures, time) +Widget widget; +Atom selection; +Atom *targets; +int count; +XtSelectionCallbackProc callback; +XtPointer *closures; +Time time; +{ + Boolean incremental_values[32]; + Boolean *incremental; + int i; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values); + for(i = 0; i < count; i++) incremental[i] = TRUE; + if (IsGatheringRequest(widget, selection)) { + AddSelectionRequests(widget, selection, count, targets, &callback, + 1, closures, incremental, NULL); + } else { + GetSelectionValues(widget, selection, targets, count, + &callback, 1, closures, time, incremental, NULL); + } + XtStackFree((XtPointer) incremental, incremental_values); + UNLOCK_APP(app); +} + + +static Request GetRequestRecord(widget, selection, id) + Widget widget; + Atom selection; + XtRequestId id; +{ + Request req = (Request)id; + Select ctx = NULL; + + if ( (req == NULL + && ((ctx = FindCtx( XtDisplay(widget), selection )) == NULL + || ctx->req == NULL + || ctx->selection != selection + || ctx->widget == NULL)) + || (req != NULL + && (req->ctx == NULL + || req->ctx->selection != selection + || req->ctx->widget != widget))) + { + String params = XtName(widget); + Cardinal num_params = 1; + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "notInConvertSelection", "xtGetSelectionRequest", + XtCXtToolkitError, + "XtGetSelectionRequest or XtGetSelectionParameters called for widget \"%s\" outside of ConvertSelection proc", + ¶ms, &num_params + ); + return NULL; + } + + if (req == NULL) { + /* non-incremental owner; only one request can be + * outstanding at a time, so it's safe to keep ptr in ctx */ + req = ctx->req; + } + return req; +} + +XSelectionRequestEvent *XtGetSelectionRequest(widget, selection, id) + Widget widget; + Atom selection; + XtRequestId id; +{ + Request req = (Request)id; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + + req = GetRequestRecord(widget, selection, id); + + if (! req) { + UNLOCK_APP(app); + return (XSelectionRequestEvent*) NULL; + } + + if (req->event.type == 0) { + /* owner is local; construct the remainder of the event */ + req->event.type = SelectionRequest; + req->event.serial = LastKnownRequestProcessed(XtDisplay(widget)); + req->event.send_event = True; + req->event.display = XtDisplay(widget); + req->event.owner = XtWindow(req->ctx->widget); + req->event.selection = selection; + } + UNLOCK_APP(app); + return &req->event; +} + +/* Property atom access */ +Atom XtReservePropertyAtom(w) + Widget w; +{ + return(GetSelectionProperty(XtDisplay(w))); +} + +void XtReleasePropertyAtom(w, atom) + Widget w; + Atom atom; +{ + FreeSelectionProperty(XtDisplay(w), atom); +} + + +/* Multiple utilities */ + +/* All requests are put in a single list per widget. It is + very unlikely anyone will be gathering multiple MULTIPLE + requests at the same time, so the loss in efficiency for + this case is acceptable */ + +/* Queue one or more requests to the one we're gathering */ +static void AddSelectionRequests(wid, sel, count, targets, callbacks, + num_cb, closures, incrementals, properties) + Widget wid; + Atom sel; + int count; + Atom *targets; + XtSelectionCallbackProc *callbacks; + int num_cb; + XtPointer *closures; + Boolean *incrementals; + Atom *properties; +{ + QueuedRequestInfo qi; + Window window = XtWindow(wid); + Display *dpy = XtDisplay(wid); + + LOCK_PROCESS; + if (multipleContext == 0) multipleContext = XUniqueContext(); + + qi = NULL; + (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi); + + if (qi != NULL) { + QueuedRequest *req = qi->requests; + int start = qi->count; + int i = 0; + int j = 0; + + qi->count += count; + req = (QueuedRequest*) XtRealloc((char*) req, + (start + count) * + sizeof(QueuedRequest)); + while(i < count) { + QueuedRequest newreq = (QueuedRequest) + __XtMalloc(sizeof(QueuedRequestRec)); + newreq->selection = sel; + newreq->target = targets[i]; + if (properties != NULL) + newreq->param = properties[i]; + else { + newreq->param = GetSelectionProperty(dpy); + XDeleteProperty(dpy, window, newreq->param); + } + newreq->callback = callbacks[j]; + newreq->closure = closures[i]; + newreq->incremental = incrementals[i]; + + req[start] = newreq; + start++; + i++; + j++; + if (j > num_cb) j = 0; + } + + qi->requests = req; + } else { + /* Impossible */ + } + + UNLOCK_PROCESS; +} + +/* Only call IsGatheringRequest when we have a lock already */ + +static Boolean IsGatheringRequest(wid, sel) + Widget wid; + Atom sel; +{ + QueuedRequestInfo qi; + Window window = XtWindow(wid); + Display *dpy = XtDisplay(wid); + Boolean found = False; + int i; + + if (multipleContext == 0) multipleContext = XUniqueContext(); + + qi = NULL; + (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi); + + if (qi != NULL) { + i = 0; + while(qi->selections[i] != None) { + if (qi->selections[i] == sel) { + found = True; + break; + } + i++; + } + } + + return(found); +} + +/* Cleanup request scans the request queue and releases any + properties queued, and removes any requests queued */ +static void CleanupRequest(dpy, qi, sel) + Display *dpy; + QueuedRequestInfo qi; + Atom sel; +{ + int i, j, n; + + i = 0; + + /* Remove this selection from the list */ + n = 0; + while(qi->selections[n] != sel && + qi->selections[n] != None) n++; + if (qi->selections[n] == sel) { + while(qi->selections[n] != None) { + qi->selections[n] = qi->selections[n + 1]; + n++; + } + } + + while(i < qi->count) { + QueuedRequest req = qi->requests[i]; + + if (req->selection == sel) { + /* Match */ + if (req->param != None) + FreeSelectionProperty(dpy, req->param); + qi->count--; + + for(j = i; j < qi->count; j++) + qi->requests[j] = qi->requests[j + 1]; + + XtFree((char*) req); + } else { + i++; + } + } +} + +extern void XtCreateSelectionRequest(widget, selection) + Widget widget; + Atom selection; +{ + QueuedRequestInfo queueInfo; + Window window = XtWindow(widget); + Display *dpy = XtDisplay(widget); + int n; + + LOCK_PROCESS; + if (multipleContext == 0) multipleContext = XUniqueContext(); + + queueInfo = NULL; + (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo); + + /* If there is one, then cancel it */ + if (queueInfo != 0) + CleanupRequest(dpy, queueInfo, selection); + else { + /* Create it */ + queueInfo = (QueuedRequestInfo) __XtMalloc(sizeof(QueuedRequestInfoRec)); + queueInfo->count = 0; + queueInfo->selections = (Atom*) __XtMalloc(sizeof(Atom) * 2); + queueInfo->selections[0] = None; + queueInfo->requests = (QueuedRequest *) + __XtMalloc(sizeof(QueuedRequest)); + } + + /* Append this selection to list */ + n = 0; + while(queueInfo->selections[n] != None) n++; + queueInfo->selections = + (Atom*) XtRealloc((char*) queueInfo->selections, + (n + 2) * sizeof(Atom)); + queueInfo->selections[n] = selection; + queueInfo->selections[n + 1] = None; + + (void) XSaveContext(dpy, window, multipleContext, (char*) queueInfo); + UNLOCK_PROCESS; +} + +extern void XtSendSelectionRequest(widget, selection, time) + Widget widget; + Atom selection; + Time time; +{ + QueuedRequestInfo queueInfo; + Window window = XtWindow(widget); + Display *dpy = XtDisplay(widget); + + LOCK_PROCESS; + if (multipleContext == 0) multipleContext = XUniqueContext(); + + queueInfo = NULL; + (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo); + if (queueInfo != NULL) { + int count = 0; + int i; + QueuedRequest *req = queueInfo->requests; + + /* Construct the requests and send it using + GetSelectionValues */ + for(i = 0; i < queueInfo->count; i++) + if (req[i]->selection == selection) count++; + + if (count > 0) { + if (count == 1) { + for(i = 0; i < queueInfo->count; i++) + if (req[i]->selection == selection) break; + + /* special case a multiple which isn't needed */ + GetSelectionValue(widget, selection, req[i]->target, + req[i]->callback, req[i]->closure, time, + req[i]->incremental, req[i]->param); + } else { + Atom *targets; + Atom t[PREALLOCED]; + XtSelectionCallbackProc *cbs; + XtSelectionCallbackProc c[PREALLOCED]; + XtPointer *closures; + XtPointer cs[PREALLOCED]; + Boolean *incrs; + Boolean ins[PREALLOCED]; + Atom *props; + Atom p[PREALLOCED]; + int i = 0; + int j = 0; + + /* Allocate */ + targets = (Atom *) XtStackAlloc(count * sizeof(Atom), t); + cbs = (XtSelectionCallbackProc *) + XtStackAlloc(count * sizeof(XtSelectionCallbackProc), c); + closures = (XtPointer *) XtStackAlloc(count * sizeof(XtPointer), cs); + incrs = (Boolean *) XtStackAlloc(count * sizeof(Boolean), ins); + props = (Atom *) XtStackAlloc(count * sizeof(Atom), p); + + /* Copy */ + for(i = 0; i < queueInfo->count; i++) { + if (req[i]->selection == selection) { + targets[j] = req[i]->target; + cbs[j] = req[i]->callback; + closures[j] = req[i]->closure; + incrs[j] = req[i]->incremental; + props[j] = req[i]->param; + j++; + } + } + + /* Make the request */ + GetSelectionValues(widget, selection, targets, count, + cbs, count, closures, time, incrs, props); + + /* Free */ + XtStackFree((XtPointer) targets, t); + XtStackFree((XtPointer) cbs, c); + XtStackFree((XtPointer) closures, cs); + XtStackFree((XtPointer) incrs, ins); + XtStackFree((XtPointer) props, p); + } + } + } + + CleanupRequest(dpy, queueInfo, selection); + UNLOCK_PROCESS; +} + +extern void XtCancelSelectionRequest(widget, selection) + Widget widget; + Atom selection; +{ + QueuedRequestInfo queueInfo; + Window window = XtWindow(widget); + Display *dpy = XtDisplay(widget); + + LOCK_PROCESS; + if (multipleContext == 0) multipleContext = XUniqueContext(); + + queueInfo = NULL; + (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo); + /* If there is one, then cancel it */ + if (queueInfo != 0) + CleanupRequest(dpy, queueInfo, selection); + UNLOCK_PROCESS; +} + +/* Parameter utilities */ + +/* Parameters on a selection request */ +/* Places data on allocated parameter atom, then records the + parameter atom data for use in the next call to one of + the XtGetSelectionValue functions. */ +void XtSetSelectionParameters(requestor, selection, type, value, length, format) + Widget requestor; + Atom selection; + Atom type; + XtPointer value; + unsigned long length; + int format; +{ + Display *dpy = XtDisplay(requestor); + Window window = XtWindow(requestor); + Atom property = GetParamInfo(requestor, selection); + + if (property == None) { + property = GetSelectionProperty(dpy); + AddParamInfo(requestor, selection, property); + } + + XChangeProperty(dpy, window, property, + type, format, PropModeReplace, + (unsigned char *) value, length); +} + +/* Retrieves data passed in a parameter. Data for this is stored + on the originator's window */ +void XtGetSelectionParameters(owner, selection, request_id, type_return, + value_return, length_return, format_return) + Widget owner; + Atom selection; + XtRequestId request_id; + Atom* type_return; + XtPointer* value_return; + unsigned long* length_return; + int* format_return; +{ + Request req; + Display *dpy = XtDisplay(owner); + WIDGET_TO_APPCON(owner); + + *value_return = NULL; + *length_return = *format_return = 0; + *type_return = None; + + LOCK_APP(app); + + req = GetRequestRecord(owner, selection, request_id); + + if (req && req->property) { + unsigned long bytes_after; /* unused */ + StartProtectedSection(dpy, req->requestor); + XGetWindowProperty(dpy, req->requestor, req->property, 0L, 10000000, + False, AnyPropertyType, type_return, format_return, + length_return, &bytes_after, + (unsigned char**) value_return); + EndProtectedSection(dpy); +#ifdef XT_COPY_SELECTION + if (*value_return) { + int size = BYTELENGTH(*length_return, *format_return) + 1; + char *tmp = __XtMalloc((Cardinal) size); + (void) memmove(tmp, *value_return, size); + XFree(*value_return); + *value_return = tmp; + } +#endif + } + UNLOCK_APP(app); +} + +/* Parameters are temporarily stashed in an XContext. A list is used because + * there may be more than one selection request in progress. The context + * data is deleted when the list is empty. In the future, the parameter + * context could be merged with other contexts used during selections. + */ + +static void AddParamInfo(w, selection, param_atom) + Widget w; + Atom selection; + Atom param_atom; +{ + int n; + Param p; + ParamInfo pinfo; + + LOCK_PROCESS; + if (paramPropertyContext == 0) + paramPropertyContext = XUniqueContext(); + + if (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, + (XPointer *) &pinfo)) { + pinfo = (ParamInfo) __XtMalloc(sizeof(ParamInfoRec)); + pinfo->count = 1; + pinfo->paramlist = XtNew(ParamRec); + p = pinfo->paramlist; + (void) XSaveContext(XtDisplay(w), XtWindow(w), paramPropertyContext, + (char *)pinfo); + } + else { + for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) { + if (p->selection == None || p->selection == selection) + break; + } + if (n == 0) { + pinfo->count++; + pinfo->paramlist = (Param) + XtRealloc((char*) pinfo->paramlist, + pinfo->count * sizeof(ParamRec)); + p = &pinfo->paramlist[pinfo->count - 1]; + (void) XSaveContext(XtDisplay(w), XtWindow(w), + paramPropertyContext, (char *)pinfo); + } + } + p->selection = selection; + p->param = param_atom; + UNLOCK_PROCESS; +} + +static void RemoveParamInfo(w, selection) + Widget w; + Atom selection; +{ + int n; + Param p; + ParamInfo pinfo; + Boolean retain = False; + + LOCK_PROCESS; + if (paramPropertyContext + && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, + (XPointer *) &pinfo) == 0)) { + + /* Find and invalidate the parameter data. */ + for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) { + if (p->selection != None) { + if (p->selection == selection) + p->selection = None; + else + retain = True; + } + } + /* If there's no valid data remaining, release the context entry. */ + if (! retain) { + XtFree((char*) pinfo->paramlist); + XtFree((char*) pinfo); + XDeleteContext(XtDisplay(w), XtWindow(w), paramPropertyContext); + } + } + UNLOCK_PROCESS; +} + +static Atom GetParamInfo(w, selection) + Widget w; + Atom selection; +{ + int n; + Param p; + ParamInfo pinfo; + Atom atom = None; + + LOCK_PROCESS; + if (paramPropertyContext + && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext, + (XPointer *) &pinfo) == 0)) { + + for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) + if (p->selection == selection) { + atom = p->param; + break; + } + } + UNLOCK_PROCESS; + return atom; +} diff --git a/src/SetSens.c b/src/SetSens.c new file mode 100644 index 0000000..3a5e95e --- /dev/null +++ b/src/SetSens.c @@ -0,0 +1,131 @@ +/* $Xorg: SetSens.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "StringDefs.h" + +/* + * XtSetSensitive() + */ + +static void SetAncestorSensitive(widget, ancestor_sensitive) + register Widget widget; + Boolean ancestor_sensitive; +{ + Arg args[1]; + register Cardinal i; + register WidgetList children; + + if (widget->core.ancestor_sensitive == ancestor_sensitive) return; + + XtSetArg(args[0], XtNancestorSensitive, ancestor_sensitive); + XtSetValues(widget, args, XtNumber(args)); + + /* If widget's sensitive is TRUE, propagate new ancestor_sensitive to + children's ancestor_sensitive; else do nothing as children's + ancestor_sensitive is already FALSE */ + + if (widget->core.sensitive && XtIsComposite(widget)) { + children = ((CompositeWidget) widget)->composite.children; + for (i=0; i < ((CompositeWidget)widget)->composite.num_children; i++) { + SetAncestorSensitive (children[i], ancestor_sensitive); + } + } +} /* SetAncestorSensitive */ + + +#if NeedFunctionPrototypes +void XtSetSensitive( + register Widget widget, + _XtBoolean sensitive + ) +#else +void XtSetSensitive(widget, sensitive) + register Widget widget; + Boolean sensitive; +#endif +{ + Arg args[1]; + register Cardinal i; + register WidgetList children; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + if (widget->core.sensitive == sensitive) { + UNLOCK_APP(app); + return; + } + + XtSetArg(args[0], XtNsensitive, sensitive); + XtSetValues(widget, args, XtNumber(args)); + + /* If widget's ancestor_sensitive is TRUE, propagate new sensitive to + children's ancestor_sensitive; else do nothing as children's + ancestor_sensitive is already FALSE */ + + if (widget->core.ancestor_sensitive && XtIsComposite (widget)) { + children = ((CompositeWidget) widget)->composite.children; + for (i = 0; i < ((CompositeWidget)widget)->composite.num_children; i++){ + SetAncestorSensitive (children[i], sensitive); + } + } + UNLOCK_APP(app); +} /* XtSetSensitive */ diff --git a/src/SetValues.c b/src/SetValues.c new file mode 100644 index 0000000..e7f0c2e --- /dev/null +++ b/src/SetValues.c @@ -0,0 +1,438 @@ +/* $Xorg: SetValues.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" + +/* + * XtSetValues(), XtSetSubvalues() + */ + + +extern void _XtCopyFromArg(); +extern XrmResourceList* _XtCreateIndirectionTable(); + +static void SetValues(base, res, num_resources, args, num_args) + char* base; /* Base address to write values to */ + XrmResourceList* res; /* The current resource values. */ + register Cardinal num_resources; /* number of items in resources */ + ArgList args; /* The resource values to set */ + Cardinal num_args; /* number of items in arg list */ +{ + register ArgList arg; + register int i; + register XrmName argName; + register XrmResourceList* xrmres; + + /* Resource lists are assumed to be in compiled form already via the + initial XtGetResources, XtGetSubresources calls */ + + for (arg = args ; num_args != 0; num_args--, arg++) { + argName = StringToName(arg->name); + for (xrmres = res, i = 0; i < num_resources; i++, xrmres++) { + if (argName == (*xrmres)->xrm_name) { + _XtCopyFromArg(arg->value, + base - (*xrmres)->xrm_offset - 1, + (*xrmres)->xrm_size); + break; + } + } + } +} /* SetValues */ + +static Boolean CallSetValues (class, current, request, new, args, num_args) + WidgetClass class; + Widget current, request, new; + ArgList args; + Cardinal num_args; +{ + Boolean redisplay = FALSE; + WidgetClass superclass; + XtArgsFunc set_values_hook; + XtSetValuesFunc set_values; + + LOCK_PROCESS; + superclass = class->core_class.superclass; + UNLOCK_PROCESS; + if (superclass) + redisplay = + CallSetValues(superclass, current, request, new, args, num_args); + + LOCK_PROCESS; + set_values = class->core_class.set_values; + UNLOCK_PROCESS; + if (set_values) + redisplay |= (*set_values) (current, request, new, args, &num_args); + + LOCK_PROCESS; + set_values_hook = class->core_class.set_values_hook; + UNLOCK_PROCESS; + if (set_values_hook) + redisplay |= (*set_values_hook) (new, args, &num_args); + return (redisplay); +} + +static Boolean +CallConstraintSetValues (class, current, request, new, args, num_args) + ConstraintWidgetClass class; + Widget current, request, new; + ArgList args; + Cardinal num_args; +{ + Boolean redisplay = FALSE; + XtSetValuesFunc set_values; + ConstraintWidgetClass superclass; + + if ((WidgetClass)class != constraintWidgetClass) { + if (class == NULL) + XtAppErrorMsg(XtWidgetToApplicationContext(current), + "invalidClass","constraintSetValue",XtCXtToolkitError, + "Subclass of Constraint required in CallConstraintSetValues", + (String *)NULL, (Cardinal *)NULL); + LOCK_PROCESS; + superclass = (ConstraintWidgetClass) class->core_class.superclass; + UNLOCK_PROCESS; + redisplay = + CallConstraintSetValues(superclass, + current, request, new, args, num_args); + } + LOCK_PROCESS; + set_values = class->constraint_class.set_values; + UNLOCK_PROCESS; + if (set_values) + redisplay |= (*set_values) (current, request, new, args, &num_args); + return (redisplay); +} + +void XtSetSubvalues(base, resources, num_resources, args, num_args) + XtPointer base; /* Base address to write values to */ + register XtResourceList resources; /* The current resource values. */ + register Cardinal num_resources; /* number of items in resources */ + ArgList args; /* The resource values to set */ + Cardinal num_args; /* number of items in arg list */ +{ + register XrmResourceList* xrmres; + xrmres = _XtCreateIndirectionTable (resources, num_resources); + SetValues((char*)base,xrmres,num_resources, args, num_args); + XtFree((char *)xrmres); +} + + +void XtSetValues(w, args, num_args) + register Widget w; + ArgList args; + Cardinal num_args; +{ + register Widget oldw, reqw; + /* need to use strictest alignment rules possible in next two decls. */ + double oldwCache[100], reqwCache[100]; + double oldcCache[20], reqcCache[20]; + Cardinal widgetSize, constraintSize; + Boolean redisplay, cleared_rect_obj = False; + XtGeometryResult result; + XtWidgetGeometry geoReq, geoReply; + WidgetClass wc; + ConstraintWidgetClass cwc; + Boolean hasConstraints; + XtAlmostProc set_values_almost; + XtAppContext app = XtWidgetToApplicationContext(w); + Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(w)); + + LOCK_APP(app); + wc = XtClass(w); + if ((args == NULL) && (num_args != 0)) { + XtAppErrorMsg(app, + "invalidArgCount","xtSetValues",XtCXtToolkitError, + "Argument count > 0 on NULL argument list in XtSetValues", + (String *)NULL, (Cardinal *)NULL); + } + + /* Allocate and copy current widget into old widget */ + + LOCK_PROCESS; + widgetSize = wc->core_class.widget_size; + UNLOCK_PROCESS; + oldw = (Widget) XtStackAlloc(widgetSize, oldwCache); + reqw = (Widget) XtStackAlloc (widgetSize, reqwCache); + (void) memmove((char *) oldw, (char *) w, (int) widgetSize); + + /* Set resource values */ + + LOCK_PROCESS; + SetValues((char*)w, (XrmResourceList *) wc->core_class.resources, + wc->core_class.num_resources, args, num_args); + UNLOCK_PROCESS; + + (void) memmove ((char *) reqw, (char *) w, (int) widgetSize); + + hasConstraints = (XtParent(w) != NULL && !XtIsShell(w) && XtIsConstraint(XtParent(w))); + + /* Some widget sets apparently do ugly things by freeing the + * constraints on some children, thus the extra test here */ + if (hasConstraints) { + cwc = (ConstraintWidgetClass) XtClass(w->core.parent); + if (w->core.constraints) { + LOCK_PROCESS; + constraintSize = cwc->constraint_class.constraint_size; + UNLOCK_PROCESS; + } else constraintSize = 0; + } else constraintSize = 0; + + if (constraintSize) { + /* Allocate and copy current constraints into oldw */ + oldw->core.constraints = XtStackAlloc(constraintSize, oldcCache); + reqw->core.constraints = XtStackAlloc(constraintSize, reqcCache); + (void) memmove((char *) oldw->core.constraints, + (char *) w->core.constraints, (int) constraintSize); + + /* Set constraint values */ + LOCK_PROCESS; + SetValues((char*)w->core.constraints, + (XrmResourceList *)(cwc->constraint_class.resources), + cwc->constraint_class.num_resources, args, num_args); + UNLOCK_PROCESS; + (void) memmove((char *) reqw->core.constraints, + (char *) w->core.constraints, (int) constraintSize); + } + + /* Inform widget of changes, then inform parent of changes */ + redisplay = CallSetValues (wc, oldw, reqw, w, args, num_args); + if (hasConstraints) { + redisplay |= CallConstraintSetValues(cwc, oldw, reqw, w, args, num_args); + } + + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + XtChangeHookSetValuesDataRec set_val; + + set_val.old = oldw; + set_val.req = reqw; + set_val.args = args; + set_val.num_args = num_args; + call_data.type = XtHsetValues; + call_data.widget = w; + call_data.event_data = (XtPointer) &set_val; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + + if (XtIsRectObj(w)) { + /* Now perform geometry request if needed */ + geoReq.request_mode = 0; + if (oldw->core.x != w->core.x) { + geoReq.x = w->core.x; + w->core.x = oldw->core.x; + geoReq.request_mode |= CWX; + } + if (oldw->core.y != w->core.y) { + geoReq.y = w->core.y; + w->core.y = oldw->core.y; + geoReq.request_mode |= CWY; + } + if (oldw->core.width != w->core.width) { + geoReq.width = w->core.width; + w->core.width = oldw->core.width; + geoReq.request_mode |= CWWidth; + } + if (oldw->core.height != w->core.height) { + geoReq.height = w->core.height; + w->core.height = oldw->core.height; + geoReq.request_mode |= CWHeight; + } + if (oldw->core.border_width != w->core.border_width) { + geoReq.border_width = w->core.border_width; + w->core.border_width = oldw->core.border_width; + geoReq.request_mode |= CWBorderWidth; + } + + if (geoReq.request_mode != 0) { + /* Pass on any requests for unchanged geometry values */ + if (geoReq.request_mode != + (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)) { + for ( ; num_args != 0; num_args--, args++) { + if (! (geoReq.request_mode & CWX) && + strcmp(XtNx, args->name) == 0) { + geoReq.x = w->core.x; + geoReq.request_mode |= CWX; + } else if (! (geoReq.request_mode & CWY) && + strcmp(XtNy, args->name) == 0) { + geoReq.y = w->core.y; + geoReq.request_mode |= CWY; + } else if (! (geoReq.request_mode & CWWidth) && + strcmp(XtNwidth, args->name) == 0) { + geoReq.width = w->core.width; + geoReq.request_mode |= CWWidth; + } else if (! (geoReq.request_mode & CWHeight) && + strcmp(XtNheight, args->name) == 0) { + geoReq.height = w->core.height; + geoReq.request_mode |= CWHeight; + } else if (! (geoReq.request_mode & CWBorderWidth) && + strcmp(XtNborderWidth, args->name) == 0) { + geoReq.border_width = w->core.border_width; + geoReq.request_mode |= CWBorderWidth; + } + } + } + CALLGEOTAT(_XtGeoTrace(w, + "\nXtSetValues sees some geometry changes for \"%s\".\n", + XtName(w))); + CALLGEOTAT(_XtGeoTab(1)); + do { + XtGeometryHookDataRec call_data; + + if (XtHasCallbacks(hookobj, XtNgeometryHook) == XtCallbackHasSome) { + call_data.type = XtHpreGeometry; + call_data.widget = w; + call_data.request = &geoReq; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.geometryhook_callbacks, + (XtPointer)&call_data); + call_data.result = result = + _XtMakeGeometryRequest(w, &geoReq, &geoReply, + &cleared_rect_obj); + call_data.type = XtHpostGeometry; + call_data.reply = &geoReply; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.geometryhook_callbacks, + (XtPointer)&call_data); + } else { + result = _XtMakeGeometryRequest(w, &geoReq, &geoReply, + &cleared_rect_obj); + } + if (result == XtGeometryYes || result == XtGeometryDone) + break; + + /* An Almost or No reply. Call widget and let it munge + request, reply */ + LOCK_PROCESS; + set_values_almost = wc->core_class.set_values_almost; + UNLOCK_PROCESS; + if (set_values_almost == NULL) { + XtAppWarningMsg(app, + "invalidProcedure","set_values_almost", + XtCXtToolkitError, + "set_values_almost procedure shouldn't be NULL", + (String *)NULL, (Cardinal *)NULL); + break; + } + if (result == XtGeometryNo) geoReply.request_mode = 0; + CALLGEOTAT(_XtGeoTrace(w,"calling SetValuesAlmost.\n")); + (*set_values_almost) (oldw, w, &geoReq, &geoReply); + } while (geoReq.request_mode != 0); + /* call resize proc if we changed size and parent + * didn't already invoke resize */ + { + XtWidgetProc resize; + LOCK_PROCESS; + resize = wc->core_class.resize; + UNLOCK_PROCESS; + if ((w->core.width != oldw->core.width || + w->core.height != oldw->core.height) + && result != XtGeometryDone + && resize != (XtWidgetProc) NULL) { + CALLGEOTAT(_XtGeoTrace(w, + "XtSetValues calls \"%s\"'s resize proc.\n", + XtName(w))); + (*resize)(w); + } + } + CALLGEOTAT(_XtGeoTab(-1)); + } + /* Redisplay if needed. No point in clearing if the window is + * about to disappear, as the Expose event will just go straight + * to the bit bucket. */ + if (XtIsWidget(w)) { + /* widgets can distinguish between redisplay and resize, since + the server will cause an expose on resize */ + if (redisplay && XtIsRealized(w) && !w->core.being_destroyed) { + CALLGEOTAT(_XtGeoTrace(w, + "XtSetValues calls ClearArea on \"%s\".\n", + XtName(w))); + XClearArea (XtDisplay(w), XtWindow(w), 0, 0, 0, 0, TRUE); + } + } else { /*non-window object */ + if (redisplay && ! cleared_rect_obj ) { + Widget pw = _XtWindowedAncestor(w); + if (XtIsRealized(pw) && !pw->core.being_destroyed) { + RectObj r = (RectObj)w; + int bw2 = r->rectangle.border_width << 1; + CALLGEOTAT(_XtGeoTrace(w, + "XtSetValues calls ClearArea on \"%s\"'s parent \"%s\".\n", + XtName(w),XtName(pw))); + XClearArea (XtDisplay (pw), XtWindow (pw), + r->rectangle.x, r->rectangle.y, + r->rectangle.width + bw2, + r->rectangle.height + bw2,TRUE); + } + } + } + } + + + /* Free dynamic storage */ + if (constraintSize) { + XtStackFree(oldw->core.constraints, oldcCache); + XtStackFree(reqw->core.constraints, reqcCache); + } + XtStackFree((XtPointer)oldw, oldwCache); + XtStackFree((XtPointer)reqw, reqwCache); + UNLOCK_APP(app); +} /* XtSetValues */ diff --git a/src/SetWMCW.c b/src/SetWMCW.c new file mode 100644 index 0000000..56ba936 --- /dev/null +++ b/src/SetWMCW.c @@ -0,0 +1,152 @@ +/* $Xorg: SetWMCW.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */ + +/* + * Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + * + * SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- + * NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- + * ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH + * THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris D. Peterson, MIT X Consortium + */ + +/* + +Copyright 1989, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include <X11/Xatom.h> + +/* Function Name: XtSetWMColormapWindows + * + * Description: Sets the value of the WM_COLORMAP_WINDOWS + * property on a widget's window. + * + * Arguments: widget - specifies the widget on whose window the + * - WM_COLORMAP_WINDOWS property will be stored. + * + * list - Specifies a list of widgets whose windows are to be + * listed in the WM_COLORMAP_WINDOWS property. + * count - Specifies the number of widgets in list. + * + * Returns: none. + */ + +void +XtSetWMColormapWindows(widget, list, count) +Widget widget, *list; +Cardinal count; +{ + Window *data; + Widget *checked, *top, *temp, hookobj; + Cardinal i, j, checked_count; + Boolean match; + Atom xa_wm_colormap_windows; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + if ( !XtIsRealized(widget) || (count == 0) ) { + UNLOCK_APP(app); + return; + } + + top = checked = (Widget *) __XtMalloc( (Cardinal) sizeof(Widget) * count); + + +/* + * The specification calls for only adding the windows that have unique + * colormaps to the property to this function, so we will make a pass through + * the widget list removing all the widgets with non-unique colormaps. + * + * We will also remove any unrealized widgets from the list at this time. + */ + + for (checked_count = 0, i = 0; i < count; i++) { + if (!XtIsRealized(list[i])) continue; + + *checked = list[i]; + match = FALSE; + +/* + * Don't check first element for matching colormap since there is nothing + * to check it against. + */ + + if (checked != top) + for (j = 0, temp = top; j < checked_count ; j++, temp++) + if ( (*temp)->core.colormap == (*checked)->core.colormap) { + match = TRUE; + break; + } + +/* + * If no colormap was found to match then add this widget to the linked list. + */ + + if (!match) { + checked++; + checked_count++; + } + } + +/* + * Now that we have the list of widgets we need to convert it to a list of + * windows and set the property. + */ + + data = (Window *) __XtMalloc( (Cardinal) sizeof(Window) * checked_count); + + for ( i = 0 ; i < checked_count ; i++) + data[i] = XtWindow(top[i]); + + xa_wm_colormap_windows = XInternAtom(XtDisplay(widget), + "WM_COLORMAP_WINDOWS", FALSE); + + XChangeProperty(XtDisplay(widget), XtWindow(widget), + xa_wm_colormap_windows, XA_WINDOW, 32, + PropModeReplace, (unsigned char *) data, (int) i); + + hookobj = XtHooksOfDisplay(XtDisplay(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHsetWMColormapWindows; + call_data.widget = widget; + call_data.event_data = (XtPointer) list; + call_data.num_event_data = count; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + + XtFree( (char *) data); + XtFree( (char *) top); + UNLOCK_APP(app); +} diff --git a/src/Shell.c b/src/Shell.c new file mode 100644 index 0000000..cf9a3df --- /dev/null +++ b/src/Shell.c @@ -0,0 +1,3416 @@ +/* $Xorg: Shell.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#define SHELL + +#ifndef DEFAULT_WM_TIMEOUT +#define DEFAULT_WM_TIMEOUT 5000 +#endif + +#include "IntrinsicI.h" +#include "StringDefs.h" +#include "Shell.h" +#include "ShellP.h" +#include "Vendor.h" +#include "VendorP.h" +#include <X11/Xatom.h> +#include <X11/Xlocale.h> +#include <X11/ICE/ICElib.h> +#include <stdio.h> + +#ifdef EDITRES +#include <X11/Xmu/Editres.h> +#endif + +/*************************************************************************** + * + * Note: per the Xt spec, the Shell geometry management assumes in + * several places that there is only one managed child. This is + * *not* a bug. Any subclass that assumes otherwise is broken. + * + ***************************************************************************/ + +#define BIGSIZE ((Dimension)32767) + +/*************************************************************************** + * + * Default values for resource lists + * + ***************************************************************************/ + +#ifdef CRAY +void _XtShellDepth(); +void _XtShellColormap(); +void _XtShellAncestorSensitive(); +void _XtTitleEncoding(); +#else +static void _XtShellDepth(); +static void _XtShellColormap(); +static void _XtShellAncestorSensitive(); +static void _XtTitleEncoding(); +#endif + +/*************************************************************************** + * + * Shell class record + * + ***************************************************************************/ + +#define Offset(x) (XtOffsetOf(ShellRec, x)) +static XtResource shellResources[]= +{ + {XtNx, XtCPosition, XtRPosition, sizeof(Position), + Offset(core.x), XtRImmediate, (XtPointer)BIGSIZE}, + {XtNy, XtCPosition, XtRPosition, sizeof(Position), + Offset(core.y), XtRImmediate, (XtPointer)BIGSIZE}, + { XtNdepth, XtCDepth, XtRInt, sizeof(int), + Offset(core.depth), XtRCallProc, (XtPointer) _XtShellDepth}, + { XtNcolormap, XtCColormap, XtRColormap, sizeof(Colormap), + Offset(core.colormap), XtRCallProc, (XtPointer) _XtShellColormap}, + { XtNancestorSensitive, XtCSensitive, XtRBoolean, sizeof(Boolean), + Offset(core.ancestor_sensitive), XtRCallProc, + (XtPointer) _XtShellAncestorSensitive}, + { XtNallowShellResize, XtCAllowShellResize, XtRBoolean, + sizeof(Boolean), Offset(shell.allow_shell_resize), + XtRImmediate, (XtPointer)False}, + { XtNgeometry, XtCGeometry, XtRString, sizeof(String), + Offset(shell.geometry), XtRString, (XtPointer)NULL}, + { XtNcreatePopupChildProc, XtCCreatePopupChildProc, XtRFunction, + sizeof(XtCreatePopupChildProc), Offset(shell.create_popup_child_proc), + XtRFunction, NULL}, + { XtNsaveUnder, XtCSaveUnder, XtRBoolean, sizeof(Boolean), + Offset(shell.save_under), XtRImmediate, (XtPointer)False}, + { XtNpopupCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + Offset(shell.popup_callback), XtRCallback, (XtPointer) NULL}, + { XtNpopdownCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + Offset(shell.popdown_callback), XtRCallback, (XtPointer) NULL}, + { XtNoverrideRedirect, XtCOverrideRedirect, + XtRBoolean, sizeof(Boolean), Offset(shell.override_redirect), + XtRImmediate, (XtPointer)False}, + { XtNvisual, XtCVisual, XtRVisual, sizeof(Visual*), + Offset(shell.visual), XtRImmediate, CopyFromParent} +}; + +static void ClassPartInitialize(), Initialize(); +static void Realize(); +static void Resize(); +static Boolean SetValues(); +static void GetValuesHook(); +static void ChangeManaged(); /* XXX */ +static XtGeometryResult GeometryManager(), RootGeometryManager(); +static void Destroy(); + +static ShellClassExtensionRec shellClassExtRec = { + NULL, + NULLQUARK, + XtShellExtensionVersion, + sizeof(ShellClassExtensionRec), + RootGeometryManager +}; + +externaldef(shellclassrec) ShellClassRec shellClassRec = { + { /* Core */ + /* superclass */ (WidgetClass) &compositeClassRec, + /* class_name */ "Shell", + /* size */ sizeof(ShellRec), + /* Class Initializer */ NULL, + /* class_part_initialize*/ ClassPartInitialize, + /* Class init'ed ? */ FALSE, + /* initialize */ Initialize, + /* initialize_notify */ NULL, + /* realize */ Realize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ shellResources, + /* resource_count */ XtNumber(shellResources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ Destroy, + /* resize */ Resize, + /* expose */ NULL, + /* set_values */ SetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ GetValuesHook, + /* accept_focus */ NULL, + /* intrinsics version */ XtVersion, + /* callback offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator*/ NULL, + /* extension */ NULL + },{ /* Composite */ + /* geometry_manager */ GeometryManager, + /* change_managed */ ChangeManaged, + /* insert_child */ XtInheritInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ NULL + },{ /* Shell */ + /* extension */ (XtPointer)&shellClassExtRec + } +}; + +externaldef(shellwidgetclass) WidgetClass shellWidgetClass = (WidgetClass) (&shellClassRec); + +/*************************************************************************** + * + * OverrideShell class record + * + ***************************************************************************/ + +static XtResource overrideResources[]= +{ + { XtNoverrideRedirect, XtCOverrideRedirect, + XtRBoolean, sizeof(Boolean), Offset(shell.override_redirect), + XtRImmediate, (XtPointer)True}, + { XtNsaveUnder, XtCSaveUnder, XtRBoolean, sizeof(Boolean), + Offset(shell.save_under), XtRImmediate, (XtPointer)True}, +}; + +externaldef(overrideshellclassrec) OverrideShellClassRec overrideShellClassRec = { + { + /* superclass */ (WidgetClass) &shellClassRec, + /* class_name */ "OverrideShell", + /* size */ sizeof(OverrideShellRec), + /* Class Initializer */ NULL, + /* class_part_initialize*/ NULL, + /* Class init'ed ? */ FALSE, + /* initialize */ NULL, + /* initialize_notify */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ overrideResources, + /* resource_count */ XtNumber(overrideResources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ XtInheritResize, + /* expose */ NULL, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* intrinsics version */ XtVersion, + /* callback offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + },{ + /* geometry_manager */ XtInheritGeometryManager, + /* change_managed */ XtInheritChangeManaged, + /* insert_child */ XtInheritInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + } +}; + +externaldef(overrideshellwidgetclass) WidgetClass overrideShellWidgetClass = + (WidgetClass) (&overrideShellClassRec); + +/*************************************************************************** + * + * WMShell class record + * + ***************************************************************************/ + +#undef Offset +#define Offset(x) (XtOffsetOf(WMShellRec, x)) + +static int default_unspecified_shell_int = XtUnspecifiedShellInt; +/* + * Warning, casting XtUnspecifiedShellInt (which is -1) to an (XtPointer) + * can result is loss of bits on some machines (i.e. crays) + */ + +static XtResource wmResources[]= +{ + { XtNtitle, XtCTitle, XtRString, sizeof(String), + Offset(wm.title), XtRString, NULL}, + { XtNtitleEncoding, XtCTitleEncoding, XtRAtom, sizeof(Atom), + Offset(wm.title_encoding), + XtRCallProc, (XtPointer) _XtTitleEncoding}, + { XtNwmTimeout, XtCWmTimeout, XtRInt, sizeof(int), + Offset(wm.wm_timeout), XtRImmediate,(XtPointer)DEFAULT_WM_TIMEOUT}, + { XtNwaitForWm, XtCWaitForWm, XtRBoolean, sizeof(Boolean), + Offset(wm.wait_for_wm), XtRImmediate, (XtPointer)True}, + { XtNtransient, XtCTransient, XtRBoolean, sizeof(Boolean), + Offset(wm.transient), XtRImmediate, (XtPointer)False}, +/* size_hints minus things stored in core */ + { XtNbaseWidth, XtCBaseWidth, XtRInt, sizeof(int), + Offset(wm.base_width), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNbaseHeight, XtCBaseHeight, XtRInt, sizeof(int), + Offset(wm.base_height), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNwinGravity, XtCWinGravity, XtRGravity, sizeof(int), + Offset(wm.win_gravity), + XtRGravity, (XtPointer) &default_unspecified_shell_int}, + { XtNminWidth, XtCMinWidth, XtRInt, sizeof(int), + Offset(wm.size_hints.min_width), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNminHeight, XtCMinHeight, XtRInt, sizeof(int), + Offset(wm.size_hints.min_height), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNmaxWidth, XtCMaxWidth, XtRInt, sizeof(int), + Offset(wm.size_hints.max_width), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNmaxHeight, XtCMaxHeight, XtRInt, sizeof(int), + Offset(wm.size_hints.max_height), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNwidthInc, XtCWidthInc, XtRInt, sizeof(int), + Offset(wm.size_hints.width_inc), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNheightInc, XtCHeightInc, XtRInt, sizeof(int), + Offset(wm.size_hints.height_inc), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNminAspectX, XtCMinAspectX, XtRInt, sizeof(int), + Offset(wm.size_hints.min_aspect.x), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNminAspectY, XtCMinAspectY, XtRInt, sizeof(int), + Offset(wm.size_hints.min_aspect.y), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNmaxAspectX, XtCMaxAspectX, XtRInt, sizeof(int), + Offset(wm.size_hints.max_aspect.x), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNmaxAspectY, XtCMaxAspectY, XtRInt, sizeof(int), + Offset(wm.size_hints.max_aspect.y), + XtRInt, (XtPointer) &default_unspecified_shell_int}, +/* wm_hints */ + { XtNinput, XtCInput, XtRBool, sizeof(Bool), + Offset(wm.wm_hints.input), XtRImmediate, (XtPointer)False}, + { XtNinitialState, XtCInitialState, XtRInitialState, sizeof(int), + Offset(wm.wm_hints.initial_state), + XtRImmediate, (XtPointer)NormalState}, + { XtNiconPixmap, XtCIconPixmap, XtRBitmap, sizeof(Pixmap), + Offset(wm.wm_hints.icon_pixmap), XtRPixmap, NULL}, + { XtNiconWindow, XtCIconWindow, XtRWindow, sizeof(Window), + Offset(wm.wm_hints.icon_window), XtRWindow, (XtPointer) NULL}, + { XtNiconX, XtCIconX, XtRInt, sizeof(int), + Offset(wm.wm_hints.icon_x), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNiconY, XtCIconY, XtRInt, sizeof(int), + Offset(wm.wm_hints.icon_y), + XtRInt, (XtPointer) &default_unspecified_shell_int}, + { XtNiconMask, XtCIconMask, XtRBitmap, sizeof(Pixmap), + Offset(wm.wm_hints.icon_mask), XtRPixmap, NULL}, + { XtNwindowGroup, XtCWindowGroup, XtRWindow, sizeof(Window), + Offset(wm.wm_hints.window_group), + XtRImmediate, (XtPointer)XtUnspecifiedWindow}, + { XtNclientLeader, XtCClientLeader, XtRWidget, sizeof(Widget), + Offset(wm.client_leader), XtRWidget, NULL}, + { XtNwindowRole, XtCWindowRole, XtRString, sizeof(String), + Offset(wm.window_role), XtRString, (XtPointer) NULL}, + { XtNurgency, XtCUrgency, XtRBoolean, sizeof(Boolean), + Offset(wm.urgency), XtRImmediate, (XtPointer) False} +}; + +static void WMInitialize(); +static Boolean WMSetValues(); +static void WMDestroy(); + +externaldef(wmshellclassrec) WMShellClassRec wmShellClassRec = { + { + /* superclass */ (WidgetClass) &shellClassRec, + /* class_name */ "WMShell", + /* size */ sizeof(WMShellRec), + /* Class Initializer */ NULL, + /* class_part_initialize*/ NULL, + /* Class init'ed ? */ FALSE, + /* initialize */ WMInitialize, + /* initialize_notify */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ wmResources, + /* resource_count */ XtNumber(wmResources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ WMDestroy, + /* resize */ XtInheritResize, + /* expose */ NULL, + /* set_values */ WMSetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* intrinsics version */ XtVersion, + /* callback offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + },{ + /* geometry_manager */ XtInheritGeometryManager, + /* change_managed */ XtInheritChangeManaged, + /* insert_child */ XtInheritInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + } +}; + +externaldef(wmshellwidgetclass) WidgetClass wmShellWidgetClass = (WidgetClass) (&wmShellClassRec); + +/*************************************************************************** + * + * TransientShell class record + * + ***************************************************************************/ + +#undef Offset +#define Offset(x) (XtOffsetOf(TransientShellRec, x)) + +static XtResource transientResources[]= +{ + { XtNtransient, XtCTransient, XtRBoolean, sizeof(Boolean), + Offset(wm.transient), XtRImmediate, (XtPointer)True}, + { XtNtransientFor, XtCTransientFor, XtRWidget, sizeof(Widget), + Offset(transient.transient_for), XtRWidget, NULL}, + { XtNsaveUnder, XtCSaveUnder, XtRBoolean, sizeof(Boolean), + Offset(shell.save_under), XtRImmediate, (XtPointer)True}, +}; + +static void TransientRealize(); +static Boolean TransientSetValues(); + +externaldef(transientshellclassrec) TransientShellClassRec transientShellClassRec = { + { + /* superclass */ (WidgetClass) &vendorShellClassRec, + /* class_name */ "TransientShell", + /* size */ sizeof(TransientShellRec), + /* Class Initializer */ NULL, + /* class_part_initialize*/ NULL, + /* Class init'ed ? */ FALSE, + /* initialize */ NULL, + /* initialize_notify */ NULL, + /* realize */ TransientRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ transientResources, + /* resource_count */ XtNumber(transientResources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ XtInheritResize, + /* expose */ NULL, + /* set_values */ TransientSetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* intrinsics version */ XtVersion, + /* callback offsets */ NULL, + /* tm_table */ XtInheritTranslations, + /* query_geometry */ NULL, + /* display_accelerator*/ NULL, + /* extension */ NULL + },{ + /* geometry_manager */ XtInheritGeometryManager, + /* change_managed */ XtInheritChangeManaged, + /* insert_child */ XtInheritInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + } +}; + +externaldef(transientshellwidgetclass) WidgetClass transientShellWidgetClass = + (WidgetClass) (&transientShellClassRec); + +/*************************************************************************** + * + * TopLevelShell class record + * + ***************************************************************************/ + +#undef Offset +#define Offset(x) (XtOffsetOf(TopLevelShellRec, x)) + +static XtResource topLevelResources[]= +{ + { XtNiconName, XtCIconName, XtRString, sizeof(String), + Offset(topLevel.icon_name), XtRString, (XtPointer) NULL}, + { XtNiconNameEncoding, XtCIconNameEncoding, XtRAtom, sizeof(Atom), + Offset(topLevel.icon_name_encoding), + XtRCallProc, (XtPointer) _XtTitleEncoding}, + { XtNiconic, XtCIconic, XtRBoolean, sizeof(Boolean), + Offset(topLevel.iconic), XtRImmediate, (XtPointer)False} +}; + +static void TopLevelInitialize(); +static Boolean TopLevelSetValues(); +static void TopLevelDestroy(); + +externaldef(toplevelshellclassrec) TopLevelShellClassRec topLevelShellClassRec = { + { + /* superclass */ (WidgetClass) &vendorShellClassRec, + /* class_name */ "TopLevelShell", + /* size */ sizeof(TopLevelShellRec), + /* Class Initializer */ NULL, + /* class_part_initialize*/ NULL, + /* Class init'ed ? */ FALSE, + /* initialize */ TopLevelInitialize, + /* initialize_notify */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ topLevelResources, + /* resource_count */ XtNumber(topLevelResources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ TopLevelDestroy, + /* resize */ XtInheritResize, + /* expose */ NULL, + /* set_values */ TopLevelSetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* intrinsics version */ XtVersion, + /* callback offsets */ NULL, + /* tm_table */ XtInheritTranslations, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + },{ + /* geometry_manager */ XtInheritGeometryManager, + /* change_managed */ XtInheritChangeManaged, + /* insert_child */ XtInheritInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + } +}; + +externaldef(toplevelshellwidgetclass) WidgetClass topLevelShellWidgetClass = + (WidgetClass) (&topLevelShellClassRec); + +/*************************************************************************** + * + * ApplicationShell class record + * + ***************************************************************************/ + +#undef Offset +#define Offset(x) (XtOffsetOf(ApplicationShellRec, x)) + +static XtResource applicationResources[]= +{ + {XtNargc, XtCArgc, XtRInt, sizeof(int), + Offset(application.argc), XtRImmediate, (XtPointer)0}, + {XtNargv, XtCArgv, XtRStringArray, sizeof(String*), + Offset(application.argv), XtRPointer, (XtPointer) NULL} +}; +#undef Offset + +static void ApplicationInitialize(); +static void ApplicationDestroy(); +static Boolean ApplicationSetValues(); +static void ApplicationShellInsertChild(); + +static CompositeClassExtensionRec compositeClassExtension = { + /* next_extension */ NULL, + /* record_type */ NULLQUARK, + /* version */ XtCompositeExtensionVersion, + /* record_size */ sizeof(CompositeClassExtensionRec), + /* accepts_objects */ TRUE, + /* allows_change_managed_set */ FALSE +}; + + +externaldef(applicationshellclassrec) ApplicationShellClassRec applicationShellClassRec = { + { + /* superclass */ (WidgetClass) &topLevelShellClassRec, + /* class_name */ "ApplicationShell", + /* size */ sizeof(ApplicationShellRec), + /* Class Initializer */ NULL, + /* class_part_initialize*/ NULL, + /* Class init'ed ? */ FALSE, + /* initialize */ ApplicationInitialize, + /* initialize_notify */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ applicationResources, + /* resource_count */ XtNumber(applicationResources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ ApplicationDestroy, + /* resize */ XtInheritResize, + /* expose */ NULL, + /* set_values */ ApplicationSetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* intrinsics version */ XtVersion, + /* callback offsets */ NULL, + /* tm_table */ XtInheritTranslations, + /* query_geometry */ NULL, + /* display_accelerator*/ NULL, + /* extension */ NULL + },{ + /* geometry_manager */ XtInheritGeometryManager, + /* change_managed */ XtInheritChangeManaged, + /* insert_child */ ApplicationShellInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ (XtPointer)&compositeClassExtension + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + } +}; + +externaldef(applicationshellwidgetclass) WidgetClass applicationShellWidgetClass = + (WidgetClass) (&applicationShellClassRec); + +/*************************************************************************** + * + * SessionShell class record + * + ***************************************************************************/ + +#undef Offset +#define Offset(x) (XtOffsetOf(SessionShellRec, x)) + +static XtResource sessionResources[]= +{ + {XtNconnection, XtCConnection, XtRSmcConn, sizeof(SmcConn), + Offset(session.connection), XtRSmcConn, (XtPointer) NULL}, + {XtNsessionID, XtCSessionID, XtRString, sizeof(String), + Offset(session.session_id), XtRString, (XtPointer) NULL}, + {XtNrestartCommand, XtCRestartCommand, XtRCommandArgArray, sizeof(String*), + Offset(session.restart_command), XtRPointer, (XtPointer) NULL}, + {XtNcloneCommand, XtCCloneCommand, XtRCommandArgArray, sizeof(String*), + Offset(session.clone_command), XtRPointer, (XtPointer) NULL}, + {XtNdiscardCommand, XtCDiscardCommand, XtRCommandArgArray, sizeof(String*), + Offset(session.discard_command), XtRPointer, (XtPointer) NULL}, + {XtNresignCommand, XtCResignCommand, XtRCommandArgArray, sizeof(String*), + Offset(session.resign_command), XtRPointer, (XtPointer) NULL}, + {XtNshutdownCommand, XtCShutdownCommand, XtRCommandArgArray, sizeof(String*), + Offset(session.shutdown_command), XtRPointer, (XtPointer) NULL}, + {XtNenvironment, XtCEnvironment, XtREnvironmentArray, sizeof(String*), + Offset(session.environment), XtRPointer, (XtPointer) NULL}, + {XtNcurrentDirectory, XtCCurrentDirectory, XtRDirectoryString, sizeof(String), + Offset(session.current_dir), XtRString, (XtPointer) NULL}, + {XtNprogramPath, XtCProgramPath, XtRString, sizeof(String), + Offset(session.program_path), XtRString, (XtPointer) NULL}, + {XtNrestartStyle, XtCRestartStyle, XtRRestartStyle, sizeof(unsigned char), + Offset(session.restart_style), XtRImmediate, + (XtPointer) SmRestartIfRunning}, + {XtNjoinSession, XtCJoinSession, XtRBoolean, sizeof(Boolean), + Offset(session.join_session), XtRImmediate, (XtPointer) True}, + {XtNsaveCallback, XtCCallback, XtRCallback, sizeof(XtPointer), + Offset(session.save_callbacks), XtRCallback, (XtPointer) NULL}, + {XtNinteractCallback, XtCCallback, XtRCallback, sizeof(XtPointer), + Offset(session.interact_callbacks), XtRCallback, (XtPointer)NULL}, + {XtNcancelCallback, XtCCallback, XtRCallback, sizeof(XtPointer), + Offset(session.cancel_callbacks), XtRCallback, (XtPointer) NULL}, + {XtNsaveCompleteCallback, XtCCallback, XtRCallback, sizeof(XtPointer), + Offset(session.save_complete_callbacks), XtRCallback, (XtPointer) NULL}, + {XtNdieCallback, XtCCallback, XtRCallback, sizeof(XtPointer), + Offset(session.die_callbacks), XtRCallback, (XtPointer) NULL}, + {XtNerrorCallback, XtCCallback, XtRCallback, sizeof(XtPointer), + Offset(session.error_callbacks), XtRCallback, (XtPointer) NULL} +}; +#undef Offset + +static void SessionInitialize(); +static void SessionDestroy(); +static Boolean SessionSetValues(); + +static CompositeClassExtensionRec sessionCompositeClassExtension = { + /* next_extension */ NULL, + /* record_type */ NULLQUARK, + /* version */ XtCompositeExtensionVersion, + /* record_size */ sizeof(CompositeClassExtensionRec), + /* accepts_objects */ TRUE, + /* allows_change_managed_set */ FALSE +}; + + +externaldef(sessionshellclassrec) SessionShellClassRec sessionShellClassRec = { + { + /* superclass */ (WidgetClass) &applicationShellClassRec, + /* class_name */ "SessionShell", + /* size */ sizeof(SessionShellRec), + /* Class Initializer */ NULL, + /* class_part_initialize*/ NULL, + /* Class init'ed ? */ FALSE, + /* initialize */ SessionInitialize, + /* initialize_notify */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ sessionResources, + /* resource_count */ XtNumber(sessionResources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ SessionDestroy, + /* resize */ XtInheritResize, + /* expose */ NULL, + /* set_values */ SessionSetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* intrinsics version */ XtVersion, + /* callback offsets */ NULL, + /* tm_table */ XtInheritTranslations, + /* query_geometry */ NULL, + /* display_accelerator*/ NULL, + /* extension */ NULL + },{ + /* geometry_manager */ XtInheritGeometryManager, + /* change_managed */ XtInheritChangeManaged, + /* insert_child */ XtInheritInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ (XtPointer)&sessionCompositeClassExtension + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + } +}; + +externaldef(sessionshellwidgetclass) WidgetClass sessionShellWidgetClass = + (WidgetClass) (&sessionShellClassRec); + +/**************************************************************************** + * Whew! + ****************************************************************************/ + +static void ComputeWMSizeHints(w, hints) + WMShellWidget w; + XSizeHints *hints; +{ + register long flags; + hints->flags = flags = w->wm.size_hints.flags; +#define copy(field) hints->field = w->wm.size_hints.field + if (flags & (USPosition | PPosition)) { + copy(x); + copy(y); + } + if (flags & (USSize | PSize)) { + copy(width); + copy(height); + } + if (flags & PMinSize) { + copy(min_width); + copy(min_height); + } + if (flags & PMaxSize) { + copy(max_width); + copy(max_height); + } + if (flags & PResizeInc) { + copy(width_inc); + copy(height_inc); + } + if (flags & PAspect) { + copy(min_aspect.x); + copy(min_aspect.y); + copy(max_aspect.x); + copy(max_aspect.y); + } +#undef copy +#define copy(field) hints->field = w->wm.field + if (flags & PBaseSize) { + copy(base_width); + copy(base_height); + } + if (flags & PWinGravity) + copy(win_gravity); +#undef copy +} + +static void _SetWMSizeHints(w) + WMShellWidget w; +{ + XSizeHints *size_hints = XAllocSizeHints(); + + if (size_hints == NULL) _XtAllocError("XAllocSizeHints"); + ComputeWMSizeHints(w, size_hints); + XSetWMNormalHints(XtDisplay((Widget)w), XtWindow((Widget)w), size_hints); + XFree((char*)size_hints); +} + +static ShellClassExtension _FindClassExtension(widget_class) + WidgetClass widget_class; +{ + ShellClassExtension ext; + for (ext = (ShellClassExtension)((ShellWidgetClass)widget_class) + ->shell_class.extension; + ext != NULL && ext->record_type != NULLQUARK; + ext = (ShellClassExtension)ext->next_extension); + + if (ext != NULL) { + if ( ext->version == XtShellExtensionVersion + && ext->record_size == sizeof(ShellClassExtensionRec)) { + /* continue */ + } else { + String params[1]; + Cardinal num_params = 1; + params[0] = widget_class->core_class.class_name; + XtErrorMsg( "invalidExtension", "shellClassPartInitialize", + XtCXtToolkitError, + "widget class %s has invalid ShellClassExtension record", + params, &num_params); + } + } + return ext; +} + +static void ClassPartInitialize(widget_class) + WidgetClass widget_class; +{ + ShellClassExtension ext = _FindClassExtension(widget_class); + if (ext != NULL) { + if (ext->root_geometry_manager == XtInheritRootGeometryManager) { + ext->root_geometry_manager = + _FindClassExtension(widget_class->core_class.superclass) + ->root_geometry_manager; + } + } else { + /* if not found, spec requires XtInheritRootGeometryManager */ + XtPointer *extP + = &((ShellWidgetClass)widget_class)->shell_class.extension; + ext = XtNew(ShellClassExtensionRec); + (void) memmove((char*)ext, + (char*)_FindClassExtension(widget_class->core_class.superclass), + sizeof(ShellClassExtensionRec)); + ext->next_extension = *extP; + *extP = (XtPointer)ext; + } +} + + +static void EventHandler(); +static void _popup_set_prop(); + + +/*ARGSUSED*/ +static void XtCopyDefaultDepth(widget, offset, value) + Widget widget; + int offset; + XrmValue *value; +{ + value->addr = (XPointer)(&DefaultDepthOfScreen(XtScreenOfObject(widget))); +} + +#ifndef CRAY +static +#endif +void _XtShellDepth(widget,closure,value) + Widget widget; + int closure; + XrmValue *value; +{ + if (widget->core.parent == NULL) XtCopyDefaultDepth(widget,closure,value); + else _XtCopyFromParent (widget,closure,value); +} + +/*ARGSUSED*/ +static void XtCopyDefaultColormap(widget, offset, value) + Widget widget; + int offset; + XrmValue *value; +{ + value->addr = (XPointer)(&DefaultColormapOfScreen(XtScreenOfObject(widget))); +} + +#ifndef CRAY +static +#endif +void _XtShellColormap(widget,closure,value) + Widget widget; + int closure; + XrmValue *value; +{ + if (widget->core.parent == NULL) + XtCopyDefaultColormap(widget,closure,value); + else _XtCopyFromParent (widget,closure,value); +} + +#ifndef CRAY +static +#endif +void _XtShellAncestorSensitive(widget,closure,value) + Widget widget; + int closure; + XrmValue *value; +{ + static Boolean true = True; + if (widget->core.parent == NULL) value->addr = (XPointer)(&true); + else _XtCopyFromParent (widget,closure,value); +} + +/*ARGSUSED*/ +#ifndef CRAY +static +#endif +void _XtTitleEncoding(widget, offset, value) + Widget widget; + int offset; + XrmValue *value; +{ + static Atom atom; + if (XtWidgetToApplicationContext(widget)->langProcRec.proc) atom = None; + else atom = XA_STRING; + value->addr = (XPointer) &atom; +} + + +/* ARGSUSED */ +static void Initialize(req, new, args, num_args) + Widget req, new; + ArgList args; /* unused */ + Cardinal *num_args; /* unused */ +{ + ShellWidget w = (ShellWidget) new; + + w->shell.popped_up = FALSE; + w->shell.client_specified = + _XtShellNotReparented | _XtShellPositionValid; + + if (w->core.x == BIGSIZE) { + w->core.x = 0; + if (w->core.y == BIGSIZE) w->core.y = 0; + } else { + if (w->core.y == BIGSIZE) w->core.y = 0; + else w->shell.client_specified |= _XtShellPPositionOK; + } + + XtAddEventHandler(new, (EventMask) StructureNotifyMask, + TRUE, EventHandler, (XtPointer) NULL); + +#ifdef EDITRES + XtAddEventHandler(new, (EventMask) 0, TRUE, + _XEditResCheckMessages, NULL); +#endif +} + +/* ARGSUSED */ +static void WMInitialize(req, new, args, num_args) + Widget req,new; + ArgList args; /* unused */ + Cardinal *num_args; /* unused */ +{ + WMShellWidget w = (WMShellWidget) new; + TopLevelShellWidget tls = (TopLevelShellWidget) new; /* maybe */ + + if(w->wm.title == NULL) { + if (XtIsTopLevelShell(new) && + tls->topLevel.icon_name != NULL && + strlen(tls->topLevel.icon_name) != 0) { + w->wm.title = XtNewString(tls->topLevel.icon_name); + } else { + w->wm.title = XtNewString(w->core.name); + } + } else { + w->wm.title = XtNewString(w->wm.title); + } + w->wm.size_hints.flags = 0; + w->wm.wm_hints.flags = 0; + if (w->wm.window_role) + w->wm.window_role = XtNewString(w->wm.window_role); +} + + +/* ARGSUSED */ +static void TopLevelInitialize(req, new, args, num_args) + Widget req, new; + ArgList args; /* unused */ + Cardinal *num_args; /* unused */ +{ + TopLevelShellWidget w = (TopLevelShellWidget) new; + + if (w->topLevel.icon_name == NULL) { + w->topLevel.icon_name = XtNewString(w->core.name); + } else { + w->topLevel.icon_name = XtNewString(w->topLevel.icon_name); + } + + if (w->topLevel.iconic) + w->wm.wm_hints.initial_state = IconicState; +} + +static String *NewArgv(); +static String *NewStringArray(); +static void FreeStringArray(); + +/* ARGSUSED */ +static void ApplicationInitialize(req, new, args, num_args) + Widget req, new; + ArgList args; /* unused */ + Cardinal *num_args; /* unused */ +{ + ApplicationShellWidget w = (ApplicationShellWidget)new; + + if (w->application.argc > 0) + w->application.argv = NewArgv(w->application.argc, + w->application.argv); +} + +#define XtSaveInactive 0 +#define XtSaveActive 1 +#define XtInteractPending 2 +#define XtInteractActive 3 + +#define XtCloneCommandMask (1L<<0) +#define XtCurrentDirectoryMask (1L<<1) +#define XtDiscardCommandMask (1L<<2) +#define XtEnvironmentMask (1L<<3) +#define XtProgramMask (1L<<4) +#define XtResignCommandMask (1L<<5) +#define XtRestartCommandMask (1L<<6) +#define XtRestartStyleHintMask (1L<<7) +#define XtShutdownCommandMask (1L<<8) + +extern char *getenv(); + +static void JoinSession(); +static void SetSessionProperties(); +static void StopManagingSession(); + +typedef struct _XtSaveYourselfRec { + XtSaveYourself next; + int save_type; + int interact_style; + Boolean shutdown; + Boolean fast; + Boolean cancel_shutdown; + int phase; + int interact_dialog_type; + Boolean request_cancel; + Boolean request_next_phase; + Boolean save_success; + int save_tokens; + int interact_tokens; +} XtSaveYourselfRec; + +/* ARGSUSED */ +static void SessionInitialize(req, new, args, num_args) + Widget req, new; + ArgList args; /* unused */ + Cardinal *num_args; /* unused */ +{ + SessionShellWidget w = (SessionShellWidget)new; + + if (w->session.session_id) w->session.session_id = + XtNewString(w->session.session_id); + if (w->session.restart_command) w->session.restart_command = + NewStringArray(w->session.restart_command); + if (w->session.clone_command) w->session.clone_command = + NewStringArray(w->session.clone_command); + if (w->session.discard_command) w->session.discard_command = + NewStringArray(w->session.discard_command); + if (w->session.resign_command) w->session.resign_command = + NewStringArray(w->session.resign_command); + if (w->session.shutdown_command) w->session.shutdown_command = + NewStringArray(w->session.shutdown_command); + if (w->session.environment) w->session.environment = + NewStringArray(w->session.environment); + if (w->session.current_dir) w->session.current_dir = + XtNewString(w->session.current_dir); + if (w->session.program_path) w->session.program_path = + XtNewString(w->session.program_path); + + w->session.checkpoint_state = XtSaveInactive; + w->session.input_id = 0; + w->session.save = NULL; + + if ((w->session.join_session) && + (w->application.argv || w->session.restart_command)) + JoinSession(w); + + if (w->session.connection) + SetSessionProperties(w, True, 0L, 0L); +} + +static void Resize(w) + Widget w; +{ + register ShellWidget sw = (ShellWidget)w; + Widget childwid; + int i; + for(i = 0; i < sw->composite.num_children; i++) { + if (XtIsManaged(sw->composite.children[i])) { + childwid = sw->composite.children[i]; + XtResizeWidget(childwid, sw->core.width, sw->core.height, + childwid->core.border_width); + break; /* can only be one managed child */ + } + } +} + +static void GetGeometry(); + +static void Realize(wid, vmask, attr) + Widget wid; + Mask *vmask; + XSetWindowAttributes *attr; +{ + ShellWidget w = (ShellWidget) wid; + Mask mask = *vmask; + + if (! (w->shell.client_specified & _XtShellGeometryParsed)) { + /* we'll get here only if there was no child the first + time we were realized. If the shell was Unrealized + and then re-Realized, we probably don't want to + re-evaluate the defaults anyway. + */ + GetGeometry(wid, (Widget)NULL); + } + else if (w->core.background_pixmap == XtUnspecifiedPixmap) { + /* I attempt to inherit my child's background to avoid screen flash + * if there is latency between when I get resized and when my child + * is resized. Background=None is not satisfactory, as I want the + * user to get immediate feedback on the new dimensions (most + * particularly in the case of a non-reparenting wm). It is + * especially important to have the server clear any old cruft + * from the display when I am resized larger. + */ + register Widget *childP = w->composite.children; + int i; + for (i = w->composite.num_children; i; i--, childP++) { + if (XtIsWidget(*childP) && XtIsManaged(*childP)) { + if ((*childP)->core.background_pixmap + != XtUnspecifiedPixmap) { + mask &= ~(CWBackPixel); + mask |= CWBackPixmap; + attr->background_pixmap = + w->core.background_pixmap = + (*childP)->core.background_pixmap; + } else { + attr->background_pixel = + w->core.background_pixel = + (*childP)->core.background_pixel; + } + break; + } + } + } + + if(w->shell.save_under) { + mask |= CWSaveUnder; + attr->save_under = TRUE; + } + if(w->shell.override_redirect) { + mask |= CWOverrideRedirect; + attr->override_redirect = TRUE; + } + if (wid->core.width == 0 || wid->core.height == 0) { + Cardinal count = 1; + XtErrorMsg("invalidDimension", "shellRealize", XtCXtToolkitError, + "Shell widget %s has zero width and/or height", + &wid->core.name, &count); + } + wid->core.window = XCreateWindow(XtDisplay(wid), + wid->core.screen->root, (int)wid->core.x, (int)wid->core.y, + (unsigned int)wid->core.width, (unsigned int)wid->core.height, + (unsigned int)wid->core.border_width, (int) wid->core.depth, + (unsigned int) InputOutput, w->shell.visual, + mask, attr); + + _popup_set_prop(w); +} + + +static void _SetTransientForHint(w, delete) + TransientShellWidget w; + Boolean delete; +{ + Window window_group; + + if (w->wm.transient) { + if (w->transient.transient_for != NULL + && XtIsRealized(w->transient.transient_for)) + window_group = XtWindow(w->transient.transient_for); + else if ((window_group = w->wm.wm_hints.window_group) + == XtUnspecifiedWindowGroup) { + if (delete) + XDeleteProperty( XtDisplay((Widget)w), + XtWindow((Widget)w), + XA_WM_TRANSIENT_FOR + ); + return; + } + + XSetTransientForHint( XtDisplay((Widget)w), + XtWindow((Widget)w), + window_group + ); + } +} + + +static void TransientRealize(w, vmask, attr) + Widget w; + Mask *vmask; + XSetWindowAttributes *attr; +{ + XtRealizeProc realize; + + LOCK_PROCESS; + realize = + transientShellWidgetClass->core_class.superclass->core_class.realize; + UNLOCK_PROCESS; + (*realize) (w, vmask, attr); + + _SetTransientForHint((TransientShellWidget)w, False); +} + +static Widget GetClientLeader(w) + Widget w; +{ + while ((! XtIsWMShell(w) || ! ((WMShellWidget)w)->wm.client_leader) + && w->core.parent) + w = w->core.parent; + + /* ASSERT: w is a WMshell with client_leader set, or w has no parent */ + + if (XtIsWMShell(w) && ((WMShellWidget)w)->wm.client_leader) + w = ((WMShellWidget)w)->wm.client_leader; + return w; +} + +static void EvaluateWMHints(w) + WMShellWidget w; +{ + XWMHints *hintp = &w->wm.wm_hints; + + hintp->flags = StateHint | InputHint; + + if (hintp->icon_x == XtUnspecifiedShellInt) + hintp->icon_x = -1; + else + hintp->flags |= IconPositionHint; + + if (hintp->icon_y == XtUnspecifiedShellInt) + hintp->icon_y = -1; + else + hintp->flags |= IconPositionHint; + + if (hintp->icon_pixmap != None) hintp->flags |= IconPixmapHint; + if (hintp->icon_mask != None) hintp->flags |= IconMaskHint; + if (hintp->icon_window != None) hintp->flags |= IconWindowHint; + + if (hintp->window_group == XtUnspecifiedWindow) { + if(w->core.parent) { + Widget p; + for (p = w->core.parent; p->core.parent; p = p->core.parent); + if (XtIsRealized(p)) { + hintp->window_group = XtWindow(p); + hintp->flags |= WindowGroupHint; + } + } + } else if (hintp->window_group != XtUnspecifiedWindowGroup) + hintp->flags |= WindowGroupHint; + + if (w->wm.urgency) hintp->flags |= XUrgencyHint; +} + + +static void EvaluateSizeHints(w) + WMShellWidget w; +{ + struct _OldXSizeHints *sizep = &w->wm.size_hints; + + sizep->x = w->core.x; + sizep->y = w->core.y; + sizep->width = w->core.width; + sizep->height = w->core.height; + + if (sizep->flags & USSize) { + if (sizep->flags & PSize) sizep->flags &= ~PSize; + } else + sizep->flags |= PSize; + + if (sizep->flags & USPosition) { + if (sizep->flags & PPosition) sizep->flags &= ~PPosition; + } else if (w->shell.client_specified & _XtShellPPositionOK) + sizep->flags |= PPosition; + + if (sizep->min_aspect.x != XtUnspecifiedShellInt + || sizep->min_aspect.y != XtUnspecifiedShellInt + || sizep->max_aspect.x != XtUnspecifiedShellInt + || sizep->max_aspect.y != XtUnspecifiedShellInt) { + sizep->flags |= PAspect; + } + if (sizep->flags & PBaseSize + || w->wm.base_width != XtUnspecifiedShellInt + || w->wm.base_height != XtUnspecifiedShellInt) { + sizep->flags |= PBaseSize; + if (w->wm.base_width == XtUnspecifiedShellInt) + w->wm.base_width = 0; + if (w->wm.base_height == XtUnspecifiedShellInt) + w->wm.base_height = 0; + } + if (sizep->flags & PResizeInc + || sizep->width_inc != XtUnspecifiedShellInt + || sizep->height_inc != XtUnspecifiedShellInt) { + if (sizep->width_inc < 1) sizep->width_inc = 1; + if (sizep->height_inc < 1) sizep->height_inc = 1; + sizep->flags |= PResizeInc; + } + if (sizep->flags & PMaxSize + || sizep->max_width != XtUnspecifiedShellInt + || sizep->max_height != XtUnspecifiedShellInt) { + sizep->flags |= PMaxSize; + if (sizep->max_width == XtUnspecifiedShellInt) + sizep->max_width = BIGSIZE; + if (sizep->max_height == XtUnspecifiedShellInt) + sizep->max_height = BIGSIZE; + } + if (sizep->flags & PMinSize + || sizep->min_width != XtUnspecifiedShellInt + || sizep->min_height != XtUnspecifiedShellInt) { + sizep->flags |= PMinSize; + if (sizep->min_width == XtUnspecifiedShellInt) + sizep->min_width = 1; + if (sizep->min_height == XtUnspecifiedShellInt) + sizep->min_height = 1; + } +} + +static void _popup_set_prop(w) + ShellWidget w; +{ + Widget p; + WMShellWidget wmshell = (WMShellWidget) w; + TopLevelShellWidget tlshell = (TopLevelShellWidget) w; + ApplicationShellWidget appshell = (ApplicationShellWidget) w; + XTextProperty icon_name; + XTextProperty window_name; + char **argv; + int argc; + XSizeHints *size_hints; + Window window_group; + XClassHint classhint; + Boolean copied_iname, copied_wname; + + if (!XtIsWMShell((Widget)w) || w->shell.override_redirect) return; + + if ((size_hints = XAllocSizeHints()) == NULL) + _XtAllocError("XAllocSizeHints"); + + copied_iname = copied_wname = False; + if (wmshell->wm.title_encoding == None && + XmbTextListToTextProperty(XtDisplay((Widget)w), + (char**)&wmshell->wm.title, + 1, XStdICCTextStyle, + &window_name) >= Success) { + copied_wname = True; + } else { + window_name.value = (unsigned char*)wmshell->wm.title; + window_name.encoding = wmshell->wm.title_encoding ? + wmshell->wm.title_encoding : XA_STRING; + window_name.format = 8; + window_name.nitems = strlen((char *)window_name.value); + } + + if (XtIsTopLevelShell((Widget)w)) { + if (tlshell->topLevel.icon_name_encoding == None && + XmbTextListToTextProperty(XtDisplay((Widget)w), + (char**)&tlshell->topLevel.icon_name, + 1, XStdICCTextStyle, + &icon_name) >= Success) { + copied_iname = True; + } else { + icon_name.value = (unsigned char*)tlshell->topLevel.icon_name; + icon_name.encoding = tlshell->topLevel.icon_name_encoding ? + tlshell->topLevel.icon_name_encoding : XA_STRING; + icon_name.format = 8; + icon_name.nitems = strlen((char *)icon_name.value); + } + } + + EvaluateWMHints(wmshell); + EvaluateSizeHints(wmshell); + ComputeWMSizeHints(wmshell, size_hints); + + if (wmshell->wm.transient + && !XtIsTransientShell((Widget)w) + && (window_group = wmshell->wm.wm_hints.window_group) + != XtUnspecifiedWindowGroup) { + + XSetTransientForHint(XtDisplay((Widget)w), + XtWindow((Widget)w), + window_group + ); + } + + classhint.res_name = w->core.name; + /* For the class, look up to the top of the tree */ + for (p = (Widget)w; p->core.parent != NULL; p = p->core.parent); + if (XtIsApplicationShell(p)) { + classhint.res_class = + ((ApplicationShellWidget)p)->application.class; + } else { + LOCK_PROCESS; + classhint.res_class = XtClass(p)->core_class.class_name; + UNLOCK_PROCESS; + } + + if (XtIsApplicationShell((Widget)w) + && (argc = appshell->application.argc) != -1) + argv = (char**)appshell->application.argv; + else { + argv = NULL; + argc = 0; + } + + XSetWMProperties(XtDisplay((Widget)w), XtWindow((Widget)w), + &window_name, + (XtIsTopLevelShell((Widget)w)) ? &icon_name : NULL, + argv, argc, + size_hints, + &wmshell->wm.wm_hints, + &classhint); + XFree((char*)size_hints); + if (copied_wname) + XFree((XPointer)window_name.value); + if (copied_iname) + XFree((XPointer)icon_name.value); + + LOCK_PROCESS; + if (XtWidgetToApplicationContext((Widget)w)->langProcRec.proc) { + char *locale = setlocale(LC_CTYPE, (char *)NULL); + if (locale) + XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w), + XInternAtom(XtDisplay((Widget)w), + "WM_LOCALE_NAME", False), + XA_STRING, 8, PropModeReplace, + (unsigned char *)locale, strlen(locale)); + } + UNLOCK_PROCESS; + + p = GetClientLeader((Widget)w); + if (XtWindow(p)) + XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w), + XInternAtom(XtDisplay((Widget)w), + "WM_CLIENT_LEADER", False), + XA_WINDOW, 32, PropModeReplace, + (unsigned char *)(&(p->core.window)), 1); + if (p == (Widget) w) { + for ( ; p->core.parent != NULL; p = p->core.parent); + if (XtIsSubclass(p, sessionShellWidgetClass)) { + String sm_client_id = + ((SessionShellWidget)p)->session.session_id; + if (sm_client_id != NULL) { + XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w), + XInternAtom(XtDisplay((Widget)w), + "SM_CLIENT_ID", False), + XA_STRING, 8, PropModeReplace, + (unsigned char *) sm_client_id, + strlen(sm_client_id)); + } + } + } + + if (wmshell->wm.window_role) + XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w), + XInternAtom(XtDisplay((Widget)w), + "WM_WINDOW_ROLE", False), + XA_STRING, 8, PropModeReplace, + (unsigned char *)wmshell->wm.window_role, + strlen(wmshell->wm.window_role)); +} + +/* ARGSUSED */ +static void EventHandler(wid, closure, event, continue_to_dispatch) + Widget wid; + XtPointer closure; /* unused */ + XEvent *event; + Boolean *continue_to_dispatch; /* unused */ +{ + register ShellWidget w = (ShellWidget) wid; + WMShellWidget wmshell = (WMShellWidget) w; + Boolean sizechanged = FALSE; + + if(w->core.window != event->xany.window) { + XtAppErrorMsg(XtWidgetToApplicationContext(wid), + "invalidWindow","eventHandler",XtCXtToolkitError, + "Event with wrong window", + (String *)NULL, (Cardinal *)NULL); + return; + } + + switch(event->type) { + case ConfigureNotify: + if (w->core.window != event->xconfigure.window) + return; /* in case of SubstructureNotify */ +#define NEQ(x) ( w->core.x != event->xconfigure.x ) + if( NEQ(width) || NEQ(height) || NEQ(border_width) ) { + sizechanged = TRUE; +#undef NEQ + w->core.width = event->xconfigure.width; + w->core.height = event->xconfigure.height; + w->core.border_width = event->xconfigure.border_width; + } + if (event->xany.send_event /* ICCCM compliant synthetic ev */ + /* || w->shell.override_redirect */ + || w->shell.client_specified & _XtShellNotReparented) + { + w->core.x = event->xconfigure.x; + w->core.y = event->xconfigure.y; + w->shell.client_specified |= _XtShellPositionValid; + } + else w->shell.client_specified &= ~_XtShellPositionValid; + if (XtIsWMShell(wid) && !wmshell->wm.wait_for_wm) { + /* Consider trusting the wm again */ + register struct _OldXSizeHints *hintp + = &wmshell->wm.size_hints; +#define EQ(x) (hintp->x == w->core.x) + if (EQ(x) && EQ(y) && EQ(width) && EQ(height)) { + wmshell->wm.wait_for_wm = TRUE; + } +#undef EQ + } + break; + + case ReparentNotify: + if (event->xreparent.window == XtWindow(w)) { + if (event->xreparent.parent != + RootWindowOfScreen(XtScreen(w))) + w->shell.client_specified &= + ~(_XtShellNotReparented | _XtShellPositionValid); + else { + w->core.x = event->xreparent.x; + w->core.y = event->xreparent.y; + w->shell.client_specified |= + (_XtShellNotReparented | _XtShellPositionValid); + } + } + return; + + case MapNotify: + if (XtIsTopLevelShell(wid)) { + ((TopLevelShellWidget)wid)->topLevel.iconic = FALSE; + } + return; + + case UnmapNotify: + { + XtPerDisplayInput pdi; + XtDevice device; + Widget p; + + if (XtIsTopLevelShell(wid)) + ((TopLevelShellWidget)wid)->topLevel.iconic = TRUE; + + pdi = _XtGetPerDisplayInput(event->xunmap.display); + + device = &pdi->pointer; + if (device->grabType == XtPassiveServerGrab) { + p = device->grab.widget; + while (p && !(XtIsShell(p))) + p = p->core.parent; + if (p == wid) + device->grabType = XtNoServerGrab; + } + + device = &pdi->keyboard; + if (IsEitherPassiveGrab(device->grabType)) { + p = device->grab.widget; + while (p && !(XtIsShell(p))) + p = p->core.parent; + if (p == wid) { + device->grabType = XtNoServerGrab; + pdi->activatingKey = 0; + } + } + + return; + } + default: + return; + } + { + XtWidgetProc resize; + + LOCK_PROCESS; + resize = XtClass(wid)->core_class.resize; + UNLOCK_PROCESS; + + if (sizechanged && resize) { + CALLGEOTAT(_XtGeoTrace((Widget)w, + "Shell \"%s\" is being resized to %d %d.\n", + XtName(wid), wid->core.width, wid->core.height )); + (*resize)(wid); + } + } +} + +static void Destroy(wid) + Widget wid; +{ + if (XtIsRealized(wid)) + XDestroyWindow( XtDisplay(wid), XtWindow(wid) ); +} + +static void WMDestroy(wid) + Widget wid; +{ + WMShellWidget w = (WMShellWidget) wid; + + XtFree((char *) w->wm.title); + XtFree((char *) w->wm.window_role); +} + +static void TopLevelDestroy(wid) + Widget wid; +{ + TopLevelShellWidget w = (TopLevelShellWidget) wid; + + XtFree((char *) w->topLevel.icon_name); +} + +static void ApplicationDestroy(wid) + Widget wid; +{ + ApplicationShellWidget w = (ApplicationShellWidget) wid; + if (w->application.argc > 0) + FreeStringArray(w->application.argv); +} + +static void SessionDestroy(wid) + Widget wid; +{ + SessionShellWidget w = (SessionShellWidget) wid; + + StopManagingSession(w, w->session.connection); + XtFree(w->session.session_id); + FreeStringArray(w->session.restart_command); + FreeStringArray(w->session.clone_command); + FreeStringArray(w->session.discard_command); + FreeStringArray(w->session.resign_command); + FreeStringArray(w->session.shutdown_command); + FreeStringArray(w->session.environment); + XtFree(w->session.current_dir); + XtFree(w->session.program_path); +} + +/* + * If the Shell has a width and a height which are zero, and as such + * suspect, and it has not yet been realized then it will grow to + * match the child before parsing the geometry resource. + * + */ +static void GetGeometry(W, child) + Widget W, child; +{ + register ShellWidget w = (ShellWidget)W; + Boolean is_wmshell = XtIsWMShell(W); + int x, y, width, height, win_gravity = -1, flag; + XSizeHints hints; + + if (child != NULL) { + /* we default to our child's size */ + if (is_wmshell && (w->core.width == 0 || w->core.height == 0)) + ((WMShellWidget)W)->wm.size_hints.flags |= PSize; + if (w->core.width == 0) w->core.width = child->core.width; + if (w->core.height == 0) w->core.height = child->core.height; + } + if(w->shell.geometry != NULL) { + char def_geom[64]; + x = w->core.x; + y = w->core.y; + width = w->core.width; + height = w->core.height; + if (is_wmshell) { + WMShellPart* wm = &((WMShellWidget)w)->wm; + EvaluateSizeHints((WMShellWidget)w); + (void) memmove((char*)&hints, (char*)&wm->size_hints, + sizeof(struct _OldXSizeHints)); + hints.win_gravity = wm->win_gravity; + if (wm->size_hints.flags & PBaseSize) { + width -= wm->base_width; + height -= wm->base_height; + hints.base_width = wm->base_width; + hints.base_height = wm->base_height; + } + else if (wm->size_hints.flags & PMinSize) { + width -= wm->size_hints.min_width; + height -= wm->size_hints.min_height; + } + if (wm->size_hints.flags & PResizeInc) { + width /= wm->size_hints.width_inc; + height /= wm->size_hints.height_inc; + } + } + else hints.flags = 0; + + sprintf( def_geom, "%dx%d+%d+%d", width, height, x, y ); + flag = XWMGeometry( XtDisplay(W), + XScreenNumberOfScreen(XtScreen(W)), + w->shell.geometry, def_geom, + (unsigned int)w->core.border_width, + &hints, &x, &y, &width, &height, + &win_gravity + ); + if (flag) { + if (flag & XValue) w->core.x = (Position)x; + if (flag & YValue) w->core.y = (Position)y; + if (flag & WidthValue) w->core.width = (Dimension)width; + if (flag & HeightValue) w->core.height = (Dimension)height; + } + else { + String params[2]; + Cardinal num_params = 2; + params[0] = XtName(W); + params[1] = w->shell.geometry; + XtAppWarningMsg(XtWidgetToApplicationContext(W), + "badGeometry", "shellRealize", XtCXtToolkitError, + "Shell widget \"%s\" has an invalid geometry specification: \"%s\"", + params, &num_params); + } + } + else + flag = 0; + + if (is_wmshell) { + WMShellWidget wmshell = (WMShellWidget) w; + if (wmshell->wm.win_gravity == XtUnspecifiedShellInt) { + if (win_gravity != -1) + wmshell->wm.win_gravity = win_gravity; + else + wmshell->wm.win_gravity = NorthWestGravity; + } + wmshell->wm.size_hints.flags |= PWinGravity; + if ((flag & (XValue|YValue)) == (XValue|YValue)) + wmshell->wm.size_hints.flags |= USPosition; + if ((flag & (WidthValue|HeightValue)) == (WidthValue|HeightValue)) + wmshell->wm.size_hints.flags |= USSize; + } + w->shell.client_specified |= _XtShellGeometryParsed; +} + + +static void ChangeManaged(wid) + Widget wid; +{ + ShellWidget w = (ShellWidget) wid; + Widget child = NULL; + int i; + + for (i = 0; i < w->composite.num_children; i++) { + if (XtIsManaged(w->composite.children[i])) { + child = w->composite.children[i]; + break; /* there can only be one of them! */ + } + } + + if (!XtIsRealized (wid)) /* then we're about to be realized... */ + GetGeometry(wid, child); + + if (child != NULL) + XtConfigureWidget (child, (Position)0, (Position)0, + w->core.width, w->core.height, (Dimension)0 ); +} + +/* + * This is gross, I can't wait to see if the change happened so I will ask + * the window manager to change my size and do the appropriate X work. + * I will then tell the requester that he can. Care must be taken because + * it is possible that some time in the future the request will be + * asynchronusly denied and the window reverted to it's old size/shape. + */ + +/*ARGSUSED*/ +static XtGeometryResult GeometryManager( wid, request, reply ) + Widget wid; + XtWidgetGeometry *request; + XtWidgetGeometry *reply; +{ + ShellWidget shell = (ShellWidget)(wid->core.parent); + XtWidgetGeometry my_request; + + if(shell->shell.allow_shell_resize == FALSE && XtIsRealized(wid)) + return(XtGeometryNo); + + if (request->request_mode & (CWX | CWY)) + return(XtGeometryNo); + + my_request.request_mode = (request->request_mode & XtCWQueryOnly); + if (request->request_mode & CWWidth) { + my_request.width = request->width; + my_request.request_mode |= CWWidth; + } + if (request->request_mode & CWHeight) { + my_request.height = request->height; + my_request.request_mode |= CWHeight; + } + if (request->request_mode & CWBorderWidth) { + my_request.border_width = request->border_width; + my_request.request_mode |= CWBorderWidth; + } + if (XtMakeGeometryRequest((Widget)shell, &my_request, NULL) + == XtGeometryYes) { + /* assert: if (request->request_mode & CWWidth) then + * shell->core.width == request->width + * assert: if (request->request_mode & CWHeight) then + * shell->core.height == request->height + * + * so, whatever the WM sized us to (if the Shell requested + * only one of the two) is now the correct child size + */ + + if (!(request->request_mode & XtCWQueryOnly)) { + wid->core.width = shell->core.width; + wid->core.height = shell->core.height; + if (request->request_mode & CWBorderWidth) { + wid->core.x = wid->core.y = -request->border_width; + } + } + return XtGeometryYes; + } else return XtGeometryNo; +} + +typedef struct { + Widget w; + unsigned long request_num; + Boolean done; +} QueryStruct; + +static Bool isMine(dpy, event, arg) + Display *dpy; + register XEvent *event; + char *arg; +{ + QueryStruct *q = (QueryStruct *) arg; + register Widget w = q->w; + + if ( (dpy != XtDisplay(w)) || (event->xany.window != XtWindow(w)) ) { + return FALSE; + } + if (event->xany.serial >= q->request_num) { + if (event->type == ConfigureNotify) { + q->done = TRUE; + return TRUE; + } + } + else if (event->type == ConfigureNotify) + return TRUE; /* flush old events */ + if (event->type == ReparentNotify + && event->xreparent.window == XtWindow(w)) { + /* we might get ahead of this event, so just in case someone + * asks for coordinates before this event is dispatched... + */ + register ShellWidget s = (ShellWidget)w; + if (event->xreparent.parent != RootWindowOfScreen(XtScreen(w))) + s->shell.client_specified &= ~_XtShellNotReparented; + else + s->shell.client_specified |= _XtShellNotReparented; + } + return FALSE; +} + +static _wait_for_response(w, event, request_num) + ShellWidget w; + XEvent *event; + unsigned long request_num; +{ + XtAppContext app = XtWidgetToApplicationContext((Widget) w); + QueryStruct q; + unsigned long timeout; + + if (XtIsWMShell((Widget)w)) + timeout = ((WMShellWidget)w)->wm.wm_timeout; + else + timeout = DEFAULT_WM_TIMEOUT; + + XFlush(XtDisplay(w)); + q.w = (Widget) w; + q.request_num = request_num; + q.done = FALSE; + + /* + * look for match event and discard all prior configures + */ + while (XCheckIfEvent(XtDisplay(w),event,isMine,(char*)&q)) { + if (q.done) return TRUE; + } + + while (timeout > 0) { + if (_XtWaitForSomething (app, + FALSE, TRUE, TRUE, TRUE, + TRUE, +#ifdef XTHREADS + FALSE, +#endif + &timeout) != -1) { + while (XCheckIfEvent(XtDisplay(w),event,isMine,(char*)&q)) { + if (q.done) return TRUE; + } + } + } + return FALSE; +} + +/*ARGSUSED*/ +static XtGeometryResult RootGeometryManager(gw, request, reply) + Widget gw; + XtWidgetGeometry *request, *reply; +{ + register ShellWidget w = (ShellWidget)gw; + XWindowChanges values; + unsigned int mask = request->request_mode; + XEvent event; + Boolean wm; + register struct _OldXSizeHints *hintp; + int oldx, oldy, oldwidth, oldheight, oldborder_width; + unsigned long request_num; + + CALLGEOTAT(_XtGeoTab(1)); + + if (XtIsWMShell(gw)) { + wm = True; + hintp = &((WMShellWidget)w)->wm.size_hints; + /* for draft-ICCCM wm's, need to make sure hints reflect + (current) reality so client can move and size separately. */ + hintp->x = w->core.x; + hintp->y = w->core.y; + hintp->width = w->core.width; + hintp->height = w->core.height; + } else + wm = False; + + oldx = w->core.x; + oldy = w->core.y; + oldwidth = w->core.width; + oldheight = w->core.height; + oldborder_width = w->core.border_width; + +#define PutBackGeometry() \ + { w->core.x = oldx; \ + w->core.y = oldy; \ + w->core.width = oldwidth; \ + w->core.height = oldheight; \ + w->core.border_width = oldborder_width; } + + if (mask & CWX) { + if (w->core.x == request->x) mask &= ~CWX; + else { + w->core.x = values.x = request->x; + if (wm) { + hintp->flags &= ~USPosition; + hintp->flags |= PPosition; + hintp->x = values.x; + } + } + } + if (mask & CWY) { + if (w->core.y == request->y) mask &= ~CWY; + else { + w->core.y = values.y = request->y; + if (wm) { + hintp->flags &= ~USPosition; + hintp->flags |= PPosition; + hintp->y = values.y; + } + } + } + if (mask & CWBorderWidth) { + if (w->core.border_width == request->border_width) { + mask &= ~CWBorderWidth; + } else + w->core.border_width = + values.border_width = + request->border_width; + } + if (mask & CWWidth) { + if (w->core.width == request->width) mask &= ~CWWidth; + else { + w->core.width = values.width = request->width; + if (wm) { + hintp->flags &= ~USSize; + hintp->flags |= PSize; + hintp->width = values.width; + } + } + } + if (mask & CWHeight) { + if (w->core.height == request->height) mask &= ~CWHeight; + else { + w->core.height = values.height = request->height; + if (wm) { + hintp->flags &= ~USSize; + hintp->flags |= PSize; + hintp->height = values.height; + } + } + } + if (mask & CWStackMode) { + values.stack_mode = request->stack_mode; + if (mask & CWSibling) + values.sibling = XtWindow(request->sibling); + } + + if (!XtIsRealized((Widget)w)) { + CALLGEOTAT(_XtGeoTrace((Widget)w, + "Shell \"%s\" is not realized, return XtGeometryYes.\n", + XtName((Widget)w))); + CALLGEOTAT(_XtGeoTab(-1)); + return XtGeometryYes; + } + + request_num = NextRequest(XtDisplay(w)); + + CALLGEOTAT(_XtGeoTrace((Widget)w,"XConfiguring the Shell X window :\n")); + CALLGEOTAT(_XtGeoTab(1)); +#ifdef XT_GEO_TATTLER + if (mask & CWX) { CALLGEOTAT(_XtGeoTrace((Widget)w,"x = %d\n",values.x));} + if (mask & CWY) { CALLGEOTAT(_XtGeoTrace((Widget)w,"y = %d\n",values.y));} + if (mask & CWWidth) { CALLGEOTAT(_XtGeoTrace((Widget)w, + "width = %d\n",values.width));} + if (mask & CWHeight) { CALLGEOTAT(_XtGeoTrace((Widget)w, + "height = %d\n",values.height));} + if (mask & CWBorderWidth) { CALLGEOTAT(_XtGeoTrace((Widget)w, + "border_width = %d\n",values.border_width));} +#endif + CALLGEOTAT(_XtGeoTab(-1)); + + XConfigureWindow(XtDisplay((Widget)w), XtWindow((Widget)w), mask,&values); + + if (wm && !w->shell.override_redirect + && mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)) { + _SetWMSizeHints((WMShellWidget)w); + } + + if (w->shell.override_redirect) { + CALLGEOTAT(_XtGeoTrace((Widget)w,"Shell \"%s\" is override redirect, return XtGeometryYes.\n", XtName((Widget)w))); + CALLGEOTAT(_XtGeoTab(-1)); + return XtGeometryYes; + } + + + /* If no non-stacking bits are set, there's no way to tell whether + or not this worked, so assume it did */ + + if (!(mask & ~(CWStackMode | CWSibling))) return XtGeometryYes; + + if (wm && ((WMShellWidget)w)->wm.wait_for_wm == FALSE) { + /* the window manager is sick + * so I will do the work and + * say no so if a new WM starts up, + * or the current one recovers + * my size requests will be visible + */ + CALLGEOTAT(_XtGeoTrace((Widget)w,"Shell \"%s\" has wait_for_wm == FALSE, return XtGeometryNo.\n", + XtName((Widget)w))); + CALLGEOTAT(_XtGeoTab(-1)); + + PutBackGeometry(); + return XtGeometryNo; + } + + if (_wait_for_response(w, &event, request_num)) { + /* got an event */ + if (event.type == ConfigureNotify) { + +#define NEQ(x, msk) ((mask & msk) && (values.x != event.xconfigure.x)) + if (NEQ(x, CWX) || + NEQ(y, CWY) || + NEQ(width, CWWidth) || + NEQ(height, CWHeight) || + NEQ(border_width, CWBorderWidth)) { +#ifdef XT_GEO_TATTLER + if (NEQ(x, CWX)) { + CALLGEOTAT(_XtGeoTrace((Widget)w, + "received Configure X %d\n", + event.xconfigure.x)); + } + if (NEQ(y, CWY)) { + CALLGEOTAT(_XtGeoTrace((Widget)w, + "received Configure Y %d\n", + event.xconfigure.y)); + } + if (NEQ(width, CWWidth)) { + CALLGEOTAT(_XtGeoTrace((Widget)w, + "received Configure Width %d\n", + event.xconfigure.width)); + } + if (NEQ(height, CWHeight)) { + CALLGEOTAT(_XtGeoTrace((Widget)w, + "received Configure Height %d\n", + event.xconfigure.height)); + } + if (NEQ(border_width, CWBorderWidth)) { + CALLGEOTAT(_XtGeoTrace((Widget)w, + "received Configure BorderWidth %d\n", + event.xconfigure.border_width)); + } +#endif +#undef NEQ + XPutBackEvent(XtDisplay(w), &event); + PutBackGeometry(); + /* + * We just potentially re-ordered the event queue + * w.r.t. ConfigureNotifies with some trepidation. + * But this is probably a Good Thing because we + * will know the new true state of the world sooner + * this way. + */ + CALLGEOTAT(_XtGeoTrace((Widget)w, + "ConfigureNotify failed, return XtGeometryNo.\n")); + CALLGEOTAT(_XtGeoTab(-1)); + + return XtGeometryNo; + } + else { + w->core.width = event.xconfigure.width; + w->core.height = event.xconfigure.height; + w->core.border_width = event.xconfigure.border_width; + if (event.xany.send_event || /* ICCCM compliant synth */ + w->shell.client_specified & _XtShellNotReparented) { + + w->core.x = event.xconfigure.x; + w->core.y = event.xconfigure.y; + w->shell.client_specified |= _XtShellPositionValid; + } + else w->shell.client_specified &= ~_XtShellPositionValid; + CALLGEOTAT(_XtGeoTrace((Widget)w, + "ConfigureNotify succeed, return XtGeometryYes.\n")); + CALLGEOTAT(_XtGeoTab(-1)); + return XtGeometryYes; + } + } else if (!wm) { + PutBackGeometry(); + CALLGEOTAT(_XtGeoTrace((Widget)w, + "Not wm, return XtGeometryNo.\n")); + CALLGEOTAT(_XtGeoTab(-1)); + return XtGeometryNo; + } else XtAppWarningMsg(XtWidgetToApplicationContext((Widget)w), + "internalError", "shell", XtCXtToolkitError, + "Shell's window manager interaction is broken", + (String *)NULL, (Cardinal *)NULL); + } else if (wm) { /* no event */ + ((WMShellWidget)w)->wm.wait_for_wm = FALSE; /* timed out; must be broken */ + } + PutBackGeometry(); +#undef PutBackGeometry + CALLGEOTAT(_XtGeoTrace((Widget)w, + "Timeout passed?, return XtGeometryNo.\n")); + CALLGEOTAT(_XtGeoTab(-1)); + return XtGeometryNo; + } + +/* ARGSUSED */ +static Boolean SetValues(old, ref, new, args, num_args) + Widget old, ref, new; + ArgList args; + Cardinal *num_args; +{ + ShellWidget nw = (ShellWidget) new; + ShellWidget ow = (ShellWidget) old; + Mask mask = 0; + XSetWindowAttributes attr; + + if (!XtIsRealized(new)) + return False; + + if (ow->shell.save_under != nw->shell.save_under) { + mask = CWSaveUnder; + attr.save_under = nw->shell.save_under; + } + + if (ow->shell.override_redirect != nw->shell.override_redirect) { + mask |= CWOverrideRedirect; + attr.override_redirect = nw->shell.override_redirect; + } + + if (mask) { + XChangeWindowAttributes(XtDisplay(new),XtWindow(new), mask, &attr); + if ((mask & CWOverrideRedirect) && !nw->shell.override_redirect) + _popup_set_prop(nw); + } + + if (! (ow->shell.client_specified & _XtShellPositionValid)) { + Cardinal n; + void _XtShellGetCoordinates(); + + for (n = *num_args; n; n--, args++) { + if (strcmp(XtNx, args->name) == 0) { + _XtShellGetCoordinates(ow, &ow->core.x, &ow->core.y); + } else if (strcmp(XtNy, args->name) == 0) { + _XtShellGetCoordinates(ow, &ow->core.x, &ow->core.y); + } + } + } + return FALSE; +} + +/* ARGSUSED */ +static Boolean WMSetValues(old, ref, new, args, num_args) + Widget old, ref, new; + ArgList args; /* unused */ + Cardinal *num_args; /* unused */ +{ + WMShellWidget nwmshell = (WMShellWidget) new; + WMShellWidget owmshell = (WMShellWidget) old; + Boolean set_prop + = XtIsRealized(new) && !nwmshell->shell.override_redirect; + Boolean title_changed; + + EvaluateSizeHints(nwmshell); + +#define NEQ(f) (nwmshell->wm.size_hints.f != owmshell->wm.size_hints.f) + + if (set_prop + && (NEQ(flags) || NEQ(min_width) || NEQ(min_height) + || NEQ(max_width) || NEQ(max_height) + || NEQ(width_inc) || NEQ(height_inc) + || NEQ(min_aspect.x) || NEQ(min_aspect.y) + || NEQ(max_aspect.x) || NEQ(max_aspect.y) +#undef NEQ +#define NEQ(f) (nwmshell->wm.f != owmshell->wm.f) + + || NEQ(base_width) || NEQ(base_height) || NEQ(win_gravity))) { + _SetWMSizeHints(nwmshell); + } +#undef NEQ + + if (nwmshell->wm.title != owmshell->wm.title) { + XtFree(owmshell->wm.title); + if (! nwmshell->wm.title) nwmshell->wm.title = ""; + nwmshell->wm.title = XtNewString(nwmshell->wm.title); + title_changed = True; + } else + title_changed = False; + + if (set_prop + && (title_changed || + nwmshell->wm.title_encoding != owmshell->wm.title_encoding)) { + + XTextProperty title; + Boolean copied = False; + + if (nwmshell->wm.title_encoding == None && + XmbTextListToTextProperty(XtDisplay(new), + (char**)&nwmshell->wm.title, + 1, XStdICCTextStyle, + &title) >= Success) { + copied = True; + } else { + title.value = (unsigned char*)nwmshell->wm.title; + title.encoding = nwmshell->wm.title_encoding ? + nwmshell->wm.title_encoding : XA_STRING; + title.format = 8; + title.nitems = strlen(nwmshell->wm.title); + } + XSetWMName(XtDisplay(new), XtWindow(new), &title); + if (copied) + XFree((XPointer)title.value); + } + + EvaluateWMHints(nwmshell); + +#define NEQ(f) (nwmshell->wm.wm_hints.f != owmshell->wm.wm_hints.f) + + if (set_prop + && (NEQ(flags) || NEQ(input) || NEQ(initial_state) + || NEQ(icon_x) || NEQ(icon_y) + || NEQ(icon_pixmap) || NEQ(icon_mask) || NEQ(icon_window) + || NEQ(window_group))) { + + XSetWMHints(XtDisplay(new), XtWindow(new), &nwmshell->wm.wm_hints); + } +#undef NEQ + + if (XtIsRealized(new) && + nwmshell->wm.transient != owmshell->wm.transient) { + if (nwmshell->wm.transient) { + if (!XtIsTransientShell(new) && + !nwmshell->shell.override_redirect && + nwmshell->wm.wm_hints.window_group != + XtUnspecifiedWindowGroup) + XSetTransientForHint(XtDisplay(new), XtWindow(new), + nwmshell->wm.wm_hints.window_group); + } + else XDeleteProperty(XtDisplay(new), XtWindow(new), + XA_WM_TRANSIENT_FOR); + } + + if (nwmshell->wm.client_leader != owmshell->wm.client_leader + && XtWindow(new) && !nwmshell->shell.override_redirect) { + Widget leader = GetClientLeader(new); + if (XtWindow(leader)) + XChangeProperty(XtDisplay(new), XtWindow(new), + XInternAtom(XtDisplay(new), + "WM_CLIENT_LEADER", False), + XA_WINDOW, 32, PropModeReplace, + (unsigned char *) &(leader->core.window), 1); + } + + if (nwmshell->wm.window_role != owmshell->wm.window_role) { + XtFree(owmshell->wm.window_role); + if (set_prop && nwmshell->wm.window_role) { + XChangeProperty(XtDisplay(new), XtWindow(new), + XInternAtom(XtDisplay(new), "WM_WINDOW_ROLE", + False), + XA_STRING, 8, PropModeReplace, + (unsigned char *)nwmshell->wm.window_role, + strlen(nwmshell->wm.window_role)); + } else if (XtIsRealized(new) && ! nwmshell->wm.window_role) { + XDeleteProperty(XtDisplay(new), XtWindow(new), + XInternAtom(XtDisplay(new), "WM_WINDOW_ROLE", + False)); + } + } + + return FALSE; +} + +/*ARGSUSED*/ +static Boolean TransientSetValues(oldW, refW, newW, args, num_args) + Widget oldW, refW, newW; + ArgList args; /* unused */ + Cardinal *num_args; /* unused */ +{ + TransientShellWidget old = (TransientShellWidget)oldW; + TransientShellWidget new = (TransientShellWidget)newW; + + if (XtIsRealized(newW) + && ((new->wm.transient && !old->wm.transient) + || ((new->transient.transient_for != old->transient.transient_for) + || (new->transient.transient_for == NULL + && (new->wm.wm_hints.window_group + != old->wm.wm_hints.window_group))))) { + + _SetTransientForHint(new, True); + } + return False; +} + + +/* ARGSUSED */ +static Boolean TopLevelSetValues(oldW, refW, newW, args, num_args) + Widget oldW, refW, newW; + ArgList args; /* unused */ + Cardinal *num_args; /* unused */ +{ + TopLevelShellWidget old = (TopLevelShellWidget)oldW; + TopLevelShellWidget new = (TopLevelShellWidget)newW; + Boolean name_changed; + + if (old->topLevel.icon_name != new->topLevel.icon_name) { + XtFree((XtPointer)old->topLevel.icon_name); + if (! new->topLevel.icon_name) new->topLevel.icon_name = ""; + new->topLevel.icon_name = XtNewString(new->topLevel.icon_name); + name_changed = True; + } else + name_changed = False; + + if (XtIsRealized(newW)) { + if (new->topLevel.iconic != old->topLevel.iconic) { + if (new->topLevel.iconic) + XIconifyWindow(XtDisplay(newW), + XtWindow(newW), + XScreenNumberOfScreen(XtScreen(newW)) + ); + else { + Boolean map = new->shell.popped_up; + XtPopup(newW, XtGrabNone); + if (map) XMapWindow(XtDisplay(newW), XtWindow(newW)); + } + } + + if (!new->shell.override_redirect && + (name_changed || + (old->topLevel.icon_name_encoding + != new->topLevel.icon_name_encoding))) { + + XTextProperty icon_name; + Boolean copied = False; + + if (new->topLevel.icon_name_encoding == None && + XmbTextListToTextProperty(XtDisplay(newW), + (char**) &new->topLevel.icon_name, + 1, XStdICCTextStyle, + &icon_name) >= Success) { + copied = True; + } else { + icon_name.value = (unsigned char *)new->topLevel.icon_name; + icon_name.encoding = new->topLevel.icon_name_encoding ? + new->topLevel.icon_name_encoding : XA_STRING; + icon_name.format = 8; + icon_name.nitems = strlen((char *)icon_name.value); + } + XSetWMIconName(XtDisplay(newW), XtWindow(newW), &icon_name); + if (copied) + XFree((XPointer)icon_name.value); + } + } + return False; +} + +static String * NewArgv(count, str) + int count; + String *str; /* do not assume it's terminated by a NULL element */ +{ + Cardinal nbytes = 0; + Cardinal num = 0; + String *newarray, *new; + String *strarray = str; + String sptr; + + if (count <= 0 || !str) return NULL; + + for (num = count; num--; str++) { + nbytes += strlen(*str); + nbytes++; + } + num = (count+1) * sizeof(String); + new = newarray = (String *) __XtMalloc(num + nbytes); + sptr = ((char *) new) + num; + + for (str = strarray; count--; str++) { + *new = sptr; + strcpy(*new, *str); + new++; + sptr = strchr(sptr, '\0'); + sptr++; + } + *new = NULL; + return newarray; +} + + +/*ARGSUSED*/ +static Boolean ApplicationSetValues(current, request, new, args, num_args) + Widget current, request, new; + ArgList args; + Cardinal *num_args; +{ + ApplicationShellWidget nw = (ApplicationShellWidget) new; + ApplicationShellWidget cw = (ApplicationShellWidget) current; + + if (cw->application.argc != nw->application.argc || + cw->application.argv != nw->application.argv) { + + if (nw->application.argc > 0) + nw->application.argv = NewArgv(nw->application.argc, + nw->application.argv); + if (cw->application.argc > 0) + FreeStringArray(cw->application.argv); + + if (XtIsRealized(new) && !nw->shell.override_redirect) { + if (nw->application.argc >= 0 && nw->application.argv) + XSetCommand(XtDisplay(new), XtWindow(new), + nw->application.argv, nw->application.argc); + else + XDeleteProperty(XtDisplay(new), XtWindow(new), XA_WM_COMMAND); + } + } + return False; +} + +/*ARGSUSED*/ +static Boolean SessionSetValues(current, request, new, args, num_args) + Widget current, request, new; + ArgList args; + Cardinal *num_args; +{ + SessionShellWidget nw = (SessionShellWidget) new; + SessionShellWidget cw = (SessionShellWidget) current; + unsigned long set_mask = 0L; + unsigned long unset_mask = 0L; + Boolean initialize = False; + + if (cw->session.session_id != nw->session.session_id) { + nw->session.session_id = XtNewString(nw->session.session_id); + XtFree(cw->session.session_id); + } + + if (cw->session.clone_command != nw->session.clone_command) { + if (nw->session.clone_command) { + nw->session.clone_command = + NewStringArray(nw->session.clone_command); + set_mask |= XtCloneCommandMask; + } else unset_mask |= XtCloneCommandMask; + FreeStringArray(cw->session.clone_command); + } + + if (cw->session.current_dir != nw->session.current_dir) { + if (nw->session.current_dir) { + nw->session.current_dir = + XtNewString(nw->session.current_dir); + set_mask |= XtCurrentDirectoryMask; + } else unset_mask |= XtCurrentDirectoryMask; + XtFree((char *) cw->session.current_dir); + } + + if (cw->session.discard_command != nw->session.discard_command) { + if (nw->session.discard_command) { + nw->session.discard_command = + NewStringArray(nw->session.discard_command); + set_mask |= XtDiscardCommandMask; + } else unset_mask |= XtDiscardCommandMask; + FreeStringArray(cw->session.discard_command); + } + + if (cw->session.environment != nw->session.environment) { + if (nw->session.environment) { + nw->session.environment = + NewStringArray(nw->session.environment); + set_mask |= XtEnvironmentMask; + } else unset_mask |= XtEnvironmentMask; + FreeStringArray(cw->session.environment); + } + + if (cw->session.program_path != nw->session.program_path) { + if (nw->session.program_path) { + nw->session.program_path = + XtNewString(nw->session.program_path); + set_mask |= XtProgramMask; + } else unset_mask |= XtProgramMask; + XtFree((char *) cw->session.program_path); + } + + if (cw->session.resign_command != nw->session.resign_command) { + if (nw->session.resign_command) { + nw->session.resign_command = + NewStringArray(nw->session.resign_command); + set_mask |= XtResignCommandMask; + } else set_mask |= XtResignCommandMask; + FreeStringArray(cw->session.resign_command); + } + + if (cw->session.restart_command != nw->session.restart_command) { + if (nw->session.restart_command) { + nw->session.restart_command = + NewStringArray(nw->session.restart_command); + set_mask |= XtRestartCommandMask; + } else unset_mask |= XtRestartCommandMask; + FreeStringArray(cw->session.restart_command); + } + + if (cw->session.restart_style != nw->session.restart_style) + set_mask |= XtRestartStyleHintMask; + + if (cw->session.shutdown_command != nw->session.shutdown_command) { + if (nw->session.shutdown_command) { + nw->session.shutdown_command = + NewStringArray(nw->session.shutdown_command); + set_mask |= XtShutdownCommandMask; + } else unset_mask |= XtShutdownCommandMask; + FreeStringArray(cw->session.shutdown_command); + } + + if ((!cw->session.join_session && nw->session.join_session) || + (!cw->session.connection && nw->session.connection)) { + JoinSession(nw); + initialize = True; + } + + if (nw->session.connection && (set_mask || unset_mask || initialize)) + SetSessionProperties(new, initialize, set_mask, unset_mask); + + if ((cw->session.join_session && !nw->session.join_session) || + (cw->session.connection && !nw->session.connection)) + StopManagingSession(nw, nw->session.connection); + + if (cw->wm.client_leader != nw->wm.client_leader || + cw->session.session_id != nw->session.session_id) { + Widget leader; + if (cw->session.session_id) { + leader = GetClientLeader(current); + if (XtWindow(leader)) + XDeleteProperty(XtDisplay(leader), XtWindow(leader), + XInternAtom(XtDisplay(leader), "SM_CLIENT_ID", + False)); + } + if (nw->session.session_id) { + leader = GetClientLeader(new); + if (XtWindow(leader)) + XChangeProperty(XtDisplay(leader), XtWindow(leader), + XInternAtom(XtDisplay(leader), "SM_CLIENT_ID", + False), + XA_STRING, 8, PropModeReplace, + (unsigned char *) nw->session.session_id, + strlen(nw->session.session_id)); + } + } + return False; +} + +void _XtShellGetCoordinates( widget, x, y) + Widget widget; + Position* x; + Position* y; +{ + ShellWidget w = (ShellWidget)widget; + if (XtIsRealized(widget) && + !(w->shell.client_specified & _XtShellPositionValid)) { + int tmpx, tmpy; + Window tmpchild; + (void) XTranslateCoordinates(XtDisplay(w), XtWindow(w), + RootWindowOfScreen(XtScreen(w)), + (int) -w->core.border_width, + (int) -w->core.border_width, + &tmpx, &tmpy, &tmpchild); + w->core.x = tmpx; + w->core.y = tmpy; + w->shell.client_specified |= _XtShellPositionValid; + } + *x = w->core.x; + *y = w->core.y; +} + +static void GetValuesHook(widget, args, num_args) + Widget widget; + ArgList args; + Cardinal* num_args; +{ + ShellWidget w = (ShellWidget) widget; + extern void _XtCopyToArg(); + + /* x and y resource values may be invalid after a shell resize */ + if (XtIsRealized(widget) && + !(w->shell.client_specified & _XtShellPositionValid)) { + Cardinal n; + Position x, y; + + for (n = *num_args; n; n--, args++) { + if (strcmp(XtNx, args->name) == 0) { + _XtShellGetCoordinates(widget, &x, &y); + _XtCopyToArg((char *) &x, &args->value, sizeof(Position)); + } else if (strcmp(XtNy, args->name) == 0) { + _XtShellGetCoordinates(widget, &x, &y); + _XtCopyToArg((char *) &y, &args->value, sizeof(Position)); + } + } + } +} + +static void ApplicationShellInsertChild(widget) + Widget widget; +{ + if (! XtIsWidget(widget) && XtIsRectObj(widget)) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidClass", "applicationShellInsertChild", XtCXtToolkitError, + "ApplicationShell does not accept RectObj children; ignored", + (String*)NULL, (Cardinal*)NULL); + } + else { + XtWidgetProc insert_child; + + LOCK_PROCESS; + insert_child = + ((CompositeWidgetClass)applicationShellClassRec.core_class. + superclass)->composite_class.insert_child; + UNLOCK_PROCESS; + (*insert_child) (widget); + } +} + +/************************************************************************** + + Session Protocol Participation + + *************************************************************************/ + +#define XtSessionCheckpoint 0 +#define XtSessionInteract 1 + +extern String _XtGetUserName( +#if NeedFunctionPrototypes + String /* dest_dir */, + int /* len */ +#endif +); + +static void CallSaveCallbacks(); +static String *EditCommand(); +static Boolean ExamineToken(); +static void GetIceEvent(); +static XtCheckpointToken GetToken(); +static void XtCallCancelCallbacks(); +static void XtCallDieCallbacks(); +static void XtCallSaveCallbacks(); +static void XtCallSaveCompleteCallbacks(); + +static void StopManagingSession(w, connection) + SessionShellWidget w; + SmcConn connection; /* connection to close, if any */ +{ + if (connection) + SmcCloseConnection(connection, 0, NULL); + + if (w->session.input_id) { + XtRemoveInput(w->session.input_id); + w->session.input_id = 0; + } + w->session.connection = NULL; +} + +#define XT_MSG_LENGTH 256 +static void JoinSession(w) + SessionShellWidget w; +{ + IceConn ice_conn; + SmcCallbacks smcb; + char * sm_client_id; + unsigned long mask; + static char context; /* used to guarantee the connection isn't shared */ + + smcb.save_yourself.callback = XtCallSaveCallbacks; + smcb.die.callback = XtCallDieCallbacks; + smcb.save_complete.callback = XtCallSaveCompleteCallbacks; + smcb.shutdown_cancelled.callback = XtCallCancelCallbacks; + smcb.save_yourself.client_data = smcb.die.client_data = + smcb.save_complete.client_data = + smcb.shutdown_cancelled.client_data = (SmPointer) w; + mask = SmcSaveYourselfProcMask | SmcDieProcMask | + SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask; + + if (w->session.connection) { + SmcModifyCallbacks(w->session.connection, mask, &smcb); + sm_client_id = SmcClientID(w->session.connection); + } else if (getenv("SESSION_MANAGER")) { + char error_msg[XT_MSG_LENGTH]; + error_msg[0] = '\0'; + w->session.connection = + SmcOpenConnection(NULL, &context, SmProtoMajor, SmProtoMinor, + mask, &smcb, w->session.session_id, + &sm_client_id, XT_MSG_LENGTH, error_msg); + if (error_msg[0]) { + String params[1]; + Cardinal num_params = 1; + params[0] = error_msg; + XtAppWarningMsg(XtWidgetToApplicationContext((Widget) w), + "sessionManagement", "SmcOpenConnection", + XtCXtToolkitError, + "Tried to connect to session manager, %s", + params, &num_params); + } + } + + if (w->session.connection) { + if (w->session.session_id == NULL + || (strcmp(w->session.session_id, sm_client_id) != 0)) { + XtFree(w->session.session_id); + w->session.session_id = XtNewString(sm_client_id); + } + free(sm_client_id); + ice_conn = SmcGetIceConnection(w->session.connection); + w->session.input_id = + XtAppAddInput(XtWidgetToApplicationContext((Widget)w), + IceConnectionNumber(ice_conn), + (XtPointer) XtInputReadMask, + GetIceEvent, (XtPointer) w); + + w->session.restart_command = + EditCommand(w->session.session_id, w->session.restart_command, + w->application.argv); + + if (! w->session.clone_command) w->session.clone_command = + EditCommand(NULL, NULL, w->session.restart_command); + + if (! w->session.program_path) + w->session.program_path = w->session.restart_command + ? XtNewString(w->session.restart_command[0]) : NULL; + } +} +#undef XT_MSG_LENGTH + +static String * NewStringArray(str) + String *str; +{ + Cardinal nbytes = 0; + Cardinal num = 0; + String *newarray, *new; + String *strarray = str; + String sptr; + + if (!str) return NULL; + + for (num = 0; *str; num++, str++) { + nbytes += strlen(*str); + nbytes++; + } + num = (num + 1) * sizeof(String); + new = newarray = (String *) __XtMalloc(num + nbytes); + sptr = ((char *) new) + num; + + for (str = strarray; *str; str++) { + *new = sptr; + strcpy(*new, *str); + new++; + sptr = strchr(sptr, '\0'); + sptr++; + } + *new = NULL; + return newarray; +} + +static void FreeStringArray(str) + String *str; +{ + if (str) + XtFree((char *) str); +} + + +static SmProp * CardPack(name, closure) + char *name; + XtPointer closure; +{ + unsigned char *prop = (unsigned char *) closure; + SmProp *p; + + p = (SmProp *) __XtMalloc(sizeof(SmProp) + sizeof(SmPropValue)); + p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp)); + p->num_vals = 1; + p->type = SmCARD8; + p->name = name; + p->vals->length = 1; + p->vals->value = (SmPointer) prop; + return p; +} + +static SmProp * ArrayPack(name, closure) + char *name; + XtPointer closure; +{ + String prop = *(String *) closure; + SmProp *p; + + p = (SmProp *) __XtMalloc(sizeof(SmProp) + sizeof(SmPropValue)); + p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp)); + p->num_vals = 1; + p->type = SmARRAY8; + p->name = name; + p->vals->length = strlen(prop) + 1; + p->vals->value = prop; + return p; +} + +static SmProp * ListPack(name, closure) + char *name; + XtPointer closure; +{ + String *prop = *(String **) closure; + SmProp *p; + String *ptr; + SmPropValue *vals; + int n = 0; + + for (ptr = prop; *ptr; ptr++) + n++; + p = (SmProp*) __XtMalloc(sizeof(SmProp) + (Cardinal)(n*sizeof(SmPropValue))); + p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp)); + p->num_vals = n; + p->type = SmLISTofARRAY8; + p->name = name; + for (ptr = prop, vals = p->vals; *ptr; ptr++, vals++) { + vals->length = strlen(*ptr) + 1; + vals->value = *ptr; + } + return p; +} + +static void FreePacks(props, num_props) + SmProp **props; + int num_props; +{ + while (--num_props >= 0) + XtFree((char *) props[num_props]); +} + +typedef SmProp* (*PackProc)(); + +typedef struct PropertyRec { + char * name; + int offset; + PackProc proc; +} PropertyRec, *PropertyTable; + +#define Offset(x) (XtOffsetOf(SessionShellRec, x)) +static PropertyRec propertyTable[] = { + {SmCloneCommand, Offset(session.clone_command), ListPack}, + {SmCurrentDirectory, Offset(session.current_dir), ArrayPack}, + {SmDiscardCommand, Offset(session.discard_command), ListPack}, + {SmEnvironment, Offset(session.environment), ListPack}, + {SmProgram, Offset(session.program_path), ArrayPack}, + {SmResignCommand, Offset(session.resign_command), ListPack}, + {SmRestartCommand, Offset(session.restart_command), ListPack}, + {SmRestartStyleHint, Offset(session.restart_style), CardPack}, + {SmShutdownCommand, Offset(session.shutdown_command), ListPack} +}; +#undef Offset + +#define XT_NUM_SM_PROPS 11 + +static void SetSessionProperties(w, initialize, set_mask, unset_mask) + SessionShellWidget w; + Boolean initialize; + unsigned long set_mask; + unsigned long unset_mask; +{ + PropertyTable p = propertyTable; + int n; + int num_props = 0; + XtPointer *addr; + unsigned long mask; + SmProp *props[XT_NUM_SM_PROPS]; + char *pnames[XT_NUM_SM_PROPS]; + + if (w->session.connection == NULL) + return; + + if (initialize) { + char nam_buf[32]; + char pid[12]; + String user_name; + String pidp = pid; + + /* set all non-NULL session properties, the UserID and the ProcessID */ + for (n = XtNumber(propertyTable); n; n--, p++) { + addr = (XtPointer *) ((char *) w + p->offset); + if (p->proc == CardPack) { + if (*(unsigned char *)addr) + props[num_props++] =(*(p->proc))(p->name, (XtPointer)addr); + } + else if (* addr) + props[num_props++] = (*(p->proc))(p->name, (XtPointer)addr); + + } + user_name = _XtGetUserName(nam_buf, sizeof nam_buf); + if (user_name) + props[num_props++] = ArrayPack(SmUserID, &user_name); + sprintf(pid, "%d", getpid()); + props[num_props++] = ArrayPack(SmProcessID, &pidp); + + if (num_props) { + SmcSetProperties(w->session.connection, num_props, props); + FreePacks(props, num_props); + } + return; + } + + if (set_mask) { + mask = 1L; + for (n = XtNumber(propertyTable); n; n--, p++, mask <<= 1) + if (mask & set_mask) { + addr = (XtPointer *) ((char *) w + p->offset); + props[num_props++] = (*(p->proc))(p->name, (XtPointer)addr); + } + SmcSetProperties(w->session.connection, num_props, props); + FreePacks(props, num_props); + } + + if (unset_mask) { + mask = 1L; + num_props = 0; + for (n = XtNumber(propertyTable); n; n--, p++, mask <<= 1) + if (mask & unset_mask) + pnames[num_props++] = p->name; + SmcDeleteProperties(w->session.connection, num_props, pnames); + } +} + +/*ARGSUSED*/ +static void GetIceEvent(client_data, source, id) + XtPointer client_data; + int * source; + XtInputId * id; +{ + SessionShellWidget w = (SessionShellWidget) client_data; + IceProcessMessagesStatus status; + + status = IceProcessMessages(SmcGetIceConnection(w->session.connection), + NULL, NULL); + + if (status == IceProcessMessagesIOError) { + StopManagingSession(w, w->session.connection); + XtCallCallbackList((Widget)w, w->session.error_callbacks, + (XtPointer) NULL); + } +} + +static void CleanUpSave(w) + SessionShellWidget w; +{ + XtSaveYourself next = w->session.save->next; + XtFree((char *)w->session.save); + w->session.save = next; + if (w->session.save) + CallSaveCallbacks(w); +} + +static void CallSaveCallbacks(w) + SessionShellWidget w; +{ + XtCheckpointToken token; + + if (XtHasCallbacks((Widget) w, XtNsaveCallback) != XtCallbackHasSome) { + /* if the application makes no attempt to save state, report failure */ + SmcSaveYourselfDone(w->session.connection, False); + CleanUpSave(w); + } else { + w->session.checkpoint_state = XtSaveActive; + token = GetToken((Widget) w, XtSessionCheckpoint); + _XtCallConditionalCallbackList((Widget)w, w->session.save_callbacks, + (XtPointer)token, ExamineToken); + XtSessionReturnToken(token); + } +} + +/*ARGSUSED*/ +static void XtCallSaveCallbacks(connection, client_data, save_type, shutdown, + interact, fast) + SmcConn connection; /* unused */ + SmPointer client_data; + int save_type; + Bool shutdown; + int interact; + Bool fast; +{ + SessionShellWidget w = (SessionShellWidget) client_data; + XtSaveYourself save; + XtSaveYourself prev; + + save = XtNew(XtSaveYourselfRec); + save->next = NULL; + save->save_type = save_type; + save->interact_style = interact; + save->shutdown = shutdown; + save->fast = fast; + save->cancel_shutdown = False; + save->phase = 1; + save->interact_dialog_type = SmDialogNormal; + save->request_cancel = save->request_next_phase = False; + save->save_success = True; + save->save_tokens = save->interact_tokens = 0; + + prev = (XtSaveYourself) &w->session.save; + while (prev->next) + prev = prev->next; + prev->next = save; + + if (w->session.checkpoint_state == XtSaveInactive) + CallSaveCallbacks(w); +} + +static void XtInteractPermission(connection, data) + SmcConn connection; + SmPointer data; +{ + Widget w = (Widget) data; + SessionShellWidget sw = (SessionShellWidget) data; + XtCheckpointToken token; + XtCallbackProc callback; + XtPointer client_data; + + + _XtPeekCallback(w, sw->session.interact_callbacks, &callback, + &client_data); + if (callback) { + sw->session.checkpoint_state = XtInteractActive; + token = GetToken(w, XtSessionInteract); + XtRemoveCallback(w, XtNinteractCallback, callback, client_data); + (*callback)(w, client_data, (XtPointer) token); + } else if (! sw->session.save->cancel_shutdown) { + SmcInteractDone(connection, False); + } +} + +/*ARGSUSED*/ +static void XtCallSaveCompleteCallbacks(connection, client_data) + SmcConn connection; + SmPointer client_data; +{ + SessionShellWidget w = (SessionShellWidget) client_data; + + XtCallCallbackList((Widget)w, w->session.save_complete_callbacks, + (XtPointer) NULL); +} + +/*ARGSUSED*/ +static void XtCallNextPhaseCallbacks(connection, client_data) + SmcConn connection; /* unused */ + SmPointer client_data; +{ + SessionShellWidget w = (SessionShellWidget) client_data; + w->session.save->phase = 2; + CallSaveCallbacks(w); +} + +/*ARGSUSED*/ +static void XtCallDieCallbacks(connection, client_data) + SmcConn connection; /* unused */ + SmPointer client_data; +{ + SessionShellWidget w = (SessionShellWidget) client_data; + + StopManagingSession(w, w->session.connection); + XtCallCallbackList((Widget)w, w->session.die_callbacks, + (XtPointer) NULL); +} + +/*ARGSUSED*/ +static void XtCallCancelCallbacks(connection, client_data) + SmcConn connection; /* unused */ + SmPointer client_data; +{ + SessionShellWidget w = (SessionShellWidget) client_data; + Boolean call_interacts = False; + + if (w->session.checkpoint_state != XtSaveInactive) { + w->session.save->cancel_shutdown = True; + call_interacts = (w->session.save->interact_style != + SmInteractStyleNone); + } + + XtCallCallbackList((Widget)w, w->session.cancel_callbacks, + (XtPointer) NULL); + + if (call_interacts) { + w->session.save->interact_style = SmInteractStyleNone; + XtInteractPermission(w->session.connection, (SmPointer) w); + } + + if (w->session.checkpoint_state != XtSaveInactive) { + if (w->session.save->save_tokens == 0 && + w->session.checkpoint_state == XtSaveActive) { + w->session.checkpoint_state = XtSaveInactive; + SmcSaveYourselfDone(w->session.connection, + w->session.save->save_success); + CleanUpSave(w); + } + } +} + +static XtCheckpointToken GetToken(widget, type) + Widget widget; + int type; +{ + SessionShellWidget w = (SessionShellWidget) widget; + XtCheckpointToken token; + XtSaveYourself save = w->session.save; + + if (type == XtSessionCheckpoint) + w->session.save->save_tokens++; + else if (type == XtSessionInteract) + w->session.save->interact_tokens++; + else + return (XtCheckpointToken) NULL; + + token = (XtCheckpointToken) __XtMalloc(sizeof(XtCheckpointTokenRec)); + token->save_type = save->save_type; + token->interact_style = save->interact_style; + token->shutdown = save->shutdown; + token->fast = save->fast; + token->cancel_shutdown = save->cancel_shutdown; + token->phase = save->phase; + token->interact_dialog_type = save->interact_dialog_type; + token->request_cancel = save->request_cancel; + token->request_next_phase = save->request_next_phase; + token->save_success = save->save_success; + token->type = type; + token->widget = widget; + return token; +} + +#if NeedFunctionPrototypes +XtCheckpointToken XtSessionGetToken(Widget widget) +#else +XtCheckpointToken XtSessionGetToken(widget) + Widget widget; +#endif +{ + SessionShellWidget w = (SessionShellWidget) widget; + XtCheckpointToken token = NULL; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + if (w->session.checkpoint_state) + token = GetToken(widget, XtSessionCheckpoint); + + UNLOCK_APP(app); + return token; +} + +static Boolean ExamineToken(call_data) + XtPointer call_data; +{ + XtCheckpointToken token = (XtCheckpointToken) call_data; + SessionShellWidget w = (SessionShellWidget) token->widget; + + if (token->interact_dialog_type == SmDialogError) + w->session.save->interact_dialog_type = SmDialogError; + if (token->request_next_phase) + w->session.save->request_next_phase = True; + if (! token->save_success) + w->session.save->save_success = False; + + token->interact_dialog_type = w->session.save->interact_dialog_type; + token->request_next_phase = w->session.save->request_next_phase; + token->save_success = w->session.save->save_success; + token->cancel_shutdown = w->session.save->cancel_shutdown; + + return True; +} + +#if NeedFunctionPrototypes +void XtSessionReturnToken(XtCheckpointToken token) +#else +void XtSessionReturnToken(token) + XtCheckpointToken token; +#endif +{ + SessionShellWidget w = (SessionShellWidget) token->widget; + Boolean has_some; + Boolean phase_done; + XtCallbackProc callback; + XtPointer client_data; + WIDGET_TO_APPCON((Widget)w); + + LOCK_APP(app); + + has_some = (XtHasCallbacks(token->widget, XtNinteractCallback) + == XtCallbackHasSome); + + (void) ExamineToken((XtPointer) token); + + if (token->type == XtSessionCheckpoint) { + w->session.save->save_tokens--; + if (has_some && w->session.checkpoint_state == XtSaveActive) { + w->session.checkpoint_state = XtInteractPending; + SmcInteractRequest(w->session.connection, + w->session.save->interact_dialog_type, + XtInteractPermission, (SmPointer) w); + } + XtFree((char*) token); + } else { + if (token->request_cancel) + w->session.save->request_cancel = True; + token->request_cancel = w->session.save->request_cancel; + if (has_some) { + _XtPeekCallback((Widget)w, w->session.interact_callbacks, + &callback, &client_data); + XtRemoveCallback((Widget)w, XtNinteractCallback, + callback, client_data); + (*callback)((Widget)w, client_data, (XtPointer)token); + } else { + w->session.save->interact_tokens--; + if (w->session.save->interact_tokens == 0) { + w->session.checkpoint_state = XtSaveActive; + if (! w->session.save->cancel_shutdown) + SmcInteractDone(w->session.connection, + w->session.save->request_cancel); + } + XtFree((char *) token); + } + } + + phase_done = (w->session.save->save_tokens == 0 && + w->session.checkpoint_state == XtSaveActive); + + if (phase_done) { + if (w->session.save->request_next_phase && + w->session.save->phase == 1) { + SmcRequestSaveYourselfPhase2(w->session.connection, + XtCallNextPhaseCallbacks, + (SmPointer)w); + } else { + w->session.checkpoint_state = XtSaveInactive; + SmcSaveYourselfDone(w->session.connection, + w->session.save->save_success); + CleanUpSave(w); + } + } + + UNLOCK_APP(app); +} + +static Boolean IsInArray(str, sarray) + String str; + String *sarray; +{ + if (str == NULL || sarray == NULL) + return False; + for (; *sarray; sarray++) { + if (strcmp(*sarray, str) == 0) + return True; + } + return False; +} + +static String* EditCommand(str, src1, src2) + String str; /* if not NULL, the sm_client_id */ + String *src1; /* first choice */ + String *src2; /* alternate */ +{ + Boolean have; + Boolean want; + int count; + String *sarray; + String *s; + String *new; + + want = (str != NULL); + sarray = (src1 ? src1 : src2); + if (! sarray) return NULL; + have = IsInArray("-xtsessionID", sarray); + if ((want && have) || (!want && !have)) { + if (sarray == src1) + return src1; + else + return NewStringArray(sarray); + } + + count = 0; + for (s = sarray; *s; s++) + count++; + + if (want) { + s = new = (String *) __XtMalloc((Cardinal)(count+3) * sizeof(String*)); + *s = *sarray; s++; sarray++; + *s = "-xtsessionID"; s++; + *s = str; s++; + for (; --count > 0; s++, sarray++) + *s = *sarray; + *s = (String) NULL; + } else { + if (count < 3) + return NewStringArray(sarray); + s = new = (String *) __XtMalloc((Cardinal)(count-1) * sizeof(String*)); + for (; --count >= 0; sarray++) { + if (strcmp(*sarray, "-xtsessionID") == 0) { + sarray++; + count--; + } else { + *s = *sarray; + s++; + } + } + *s = (String) NULL; + } + s = new; + new = NewStringArray(new); + XtFree((char *)s); + return new; +} + diff --git a/src/TMaction.c b/src/TMaction.c new file mode 100644 index 0000000..b185f87 --- /dev/null +++ b/src/TMaction.c @@ -0,0 +1,1068 @@ +/* $Xorg: TMaction.c,v 1.5 2001/02/09 02:03:58 xorgcvs Exp $ */ +/*LINTLIBRARY*/ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* TMaction.c -- maintains the state table of actions for the translation + * manager. + */ + +#include "IntrinsicI.h" +#include "StringDefs.h" + +#if defined(__STDC__) && !defined(NORCONST) +#define RConst const +#else +#define RConst /**/ +#endif + +static String XtNtranslationError = "translationError"; + +typedef struct _CompiledAction{ + XrmQuark signature; + XtActionProc proc; +}CompiledAction, *CompiledActionTable; + + +#define GetClassActions(wc) \ + ((wc->core_class.actions) \ +? (((TMClassCache)wc->core_class.actions)->actions) \ +: NULL) + +static CompiledActionTable CompileActionTable(actions, count, stat, perm) + register struct _XtActionsRec *actions; + register Cardinal count; /* may be 0 */ + Boolean stat; /* if False, copy before compiling in place */ + Boolean perm; /* if False, use XrmStringToQuark */ +{ + register CompiledActionTable cActions; + register int i; + CompiledAction hold; + CompiledActionTable cTableHold; + XrmQuark (*func)(); + + if (!count) + return (CompiledActionTable) NULL; + func = (perm ? XrmPermStringToQuark : XrmStringToQuark); + + if (! stat) { + cTableHold = cActions = (CompiledActionTable) + __XtMalloc(count * sizeof(CompiledAction)); + + for (i=count; --i >= 0; cActions++, actions++) { + cActions->proc = actions->proc; + cActions->signature = (*func)(actions->string); + } + } else { + cTableHold = (CompiledActionTable) actions; + + for (i=count; --i >= 0; actions++) + ((CompiledActionTable) actions)->signature = + (*func)(actions->string); + } + cActions = cTableHold; + + /* Insertion sort. Whatever sort is used, it must be stable. */ + for (i=1; i <= count - 1; i++) { + register int j; + hold = cActions[i]; + j = i; + while (j && cActions[j-1].signature > hold.signature) { + cActions[j] = cActions[j-1]; + j--; + } + cActions[j] = hold; + } + + return cActions; +} + + +typedef struct _ActionListRec *ActionList; +typedef struct _ActionListRec { + ActionList next; + CompiledActionTable table; + TMShortCard count; +} ActionListRec; + +static void ReportUnboundActions(xlations, bindData) + XtTranslations xlations; + TMBindData bindData; +{ + TMSimpleStateTree stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[0]; + Cardinal num_unbound = 0; + Cardinal num_params = 1; + char* message; + char messagebuf[1000]; + String params[1]; + register Cardinal num_chars = 0; + register Cardinal i, j; + XtActionProc *procs; + + for (i=0; i < xlations->numStateTrees; i++) { + if (bindData->simple.isComplex) + procs = TMGetComplexBindEntry(bindData, i)->procs; + else + procs = TMGetSimpleBindEntry(bindData, i)->procs; + + stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i]; + for (j=0; j < stateTree->numQuarks; j++) { + if (procs[j] == NULL) { + String s = XrmQuarkToString(stateTree->quarkTbl[j]); + if (num_unbound != 0) + num_chars += 2; + num_chars += strlen(s); + num_unbound++; + } + } + } + if (num_unbound == 0) + return; + message = XtStackAlloc (num_chars + 1, messagebuf); + if (message != NULL) { + *message = '\0'; + num_unbound = 0; + stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[0]; + for (i=0; i < xlations->numStateTrees; i++) { + if (bindData->simple.isComplex) + procs = TMGetComplexBindEntry(bindData, i)->procs; + else + procs = TMGetSimpleBindEntry(bindData, i)->procs; + + stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i]; + for (j=0; j < stateTree->numQuarks; j++) { + if (procs[j] == NULL) { + String s = XrmQuarkToString(stateTree->quarkTbl[j]); + if (num_unbound != 0) + (void) strcat(message, ", "); + (void) strcat(message, s); + num_unbound++; + } + } + } + message[num_chars] = '\0'; + params[0] = message; + XtWarningMsg(XtNtranslationError,"unboundActions",XtCXtToolkitError, + "Actions not found: %s", + params, &num_params); + XtStackFree (message, messagebuf); + } +} + + +static CompiledAction *SearchActionTable(signature, actionTable, numActions) + XrmQuark signature; + CompiledActionTable actionTable; + Cardinal numActions; +{ + register int i, left, right; + + left = 0; + right = numActions - 1; + while (left <= right) { + i = (left + right) >> 1; + if (signature < actionTable[i].signature) + right = i - 1; + else if (signature > actionTable[i].signature) + left = i + 1; + else { + while (i && actionTable[i - 1].signature == signature) + i--; + return &actionTable[i]; + } + } + return (CompiledAction *) NULL; +} + +static int BindActions(stateTree, procs, compiledActionTable, numActions, ndxP) + TMSimpleStateTree stateTree; + XtActionProc *procs; + CompiledActionTable compiledActionTable; + TMShortCard numActions; + Cardinal *ndxP; +{ + register int unbound = stateTree->numQuarks - *ndxP; + CompiledAction* action; + register Cardinal ndx; + register Boolean savedNdx = False; + + for (ndx = *ndxP; ndx < stateTree->numQuarks; ndx++) { + if (procs[ndx] == NULL) { + /* attempt to bind it */ + XrmQuark q = stateTree->quarkTbl[ndx]; + + action = SearchActionTable(q, compiledActionTable, numActions); + if (action) { + procs[ndx] = action->proc; + unbound--; + } else if (!savedNdx) { + *ndxP= ndx; + savedNdx = True; + } + } else { + /* already bound, leave it alone */ + unbound--; + } + } + return unbound; +} + +typedef struct _TMBindCacheStatusRec{ + unsigned int boundInClass:1; + unsigned int boundInHierarchy:1; + unsigned int boundInContext:1; + unsigned int notFullyBound:1; + unsigned int refCount:28; +}TMBindCacheStatusRec, *TMBindCacheStatus; + +typedef struct _TMBindCacheRec{ + struct _TMBindCacheRec *next; + TMBindCacheStatusRec status; + TMStateTree stateTree; +#ifdef TRACE_TM + WidgetClass widgetClass; +#endif /* TRACE_TM */ + XtActionProc procs[1]; /* variable length */ +}TMBindCacheRec, *TMBindCache; + +typedef struct _TMClassCacheRec { + CompiledActionTable actions; + TMBindCacheRec *bindCache; +}TMClassCacheRec, *TMClassCache; + +#define IsPureClassBind(bc) \ + (bc->status.boundInClass && \ + !(bc->status.boundInHierarchy || \ + bc->status.boundInContext || \ + bc->status.notFullyBound)) + +#define GetClassCache(w) \ + ((TMClassCache)w->core.widget_class->core_class.actions) + + +static int BindProcs(widget, stateTree, procs, bindStatus) + Widget widget; + TMSimpleStateTree stateTree; + XtActionProc *procs; + TMBindCacheStatus bindStatus; +{ + register WidgetClass class; + register ActionList actionList; + int unbound = -1, newUnbound = -1; + Cardinal ndx = 0; + Widget w = widget; + + LOCK_PROCESS; + do { + class = w->core.widget_class; + do { + if (class->core_class.actions != NULL) + unbound = + BindActions(stateTree, + procs, + GetClassActions(class), + class->core_class.num_actions, + &ndx); + class = class->core_class.superclass; + } while (unbound != 0 && class != NULL); + if (unbound < (int)stateTree->numQuarks) + bindStatus->boundInClass = True; + else + bindStatus->boundInClass = False; + if (newUnbound == -1) + newUnbound = unbound; + w = XtParent(w); + } while (unbound != 0 && w != NULL); + + if (newUnbound > unbound) + bindStatus->boundInHierarchy = True; + else + bindStatus->boundInHierarchy = False; + + if (unbound) { + XtAppContext app = XtWidgetToApplicationContext(widget); + newUnbound = unbound; + for (actionList = app->action_table; + unbound != 0 && actionList != NULL; + actionList = actionList->next) { + unbound = BindActions(stateTree, + procs, + actionList->table, + actionList->count, + &ndx); + } + if (newUnbound > unbound) + bindStatus->boundInContext = True; + else + bindStatus->boundInContext = False; + + } + UNLOCK_PROCESS; + return unbound; +} + +static XtActionProc *TryBindCache(widget, stateTree) + Widget widget; + TMStateTree stateTree; +{ + TMClassCache classCache; + + LOCK_PROCESS; + classCache = GetClassCache(widget); + + if (classCache == NULL) + { + WidgetClass wc = XtClass(widget); + + wc->core_class.actions = (XtActionList) + _XtInitializeActionData(NULL, 0, True); + } + else + { + TMBindCache bindCache = + (TMBindCache)(classCache->bindCache); + for (; bindCache; bindCache = bindCache->next) + { + if (IsPureClassBind(bindCache) && + (stateTree == bindCache->stateTree)) + { + bindCache->status.refCount++; + UNLOCK_PROCESS; + return &bindCache->procs[0]; + } + } + } + UNLOCK_PROCESS; + return NULL; +} + + + +/* + * The class record actions field will point to the bind cache header + * after this call is made out of coreClassPartInit. + */ +#if NeedFunctionPrototypes +XtPointer _XtInitializeActionData( + register struct _XtActionsRec *actions, + register Cardinal count, + _XtBoolean inPlace + ) +#else +XtPointer _XtInitializeActionData(actions, count, inPlace) + register struct _XtActionsRec *actions; + register Cardinal count; + Boolean inPlace; +#endif +{ + TMClassCache classCache; + + classCache = XtNew(TMClassCacheRec); + classCache->actions = CompileActionTable(actions, count, inPlace, True); + classCache->bindCache = NULL; + return (XtPointer)classCache; +} + + +#define TM_BIND_CACHE_REALLOC 2 + +static XtActionProc *EnterBindCache(w, stateTree, procs, bindStatus) + Widget w; + TMSimpleStateTree stateTree; + XtActionProc *procs; + TMBindCacheStatus bindStatus; +{ + TMClassCache classCache; + TMBindCache* bindCachePtr; + TMShortCard procsSize; + TMBindCache bindCache; + + LOCK_PROCESS; + classCache = GetClassCache(w); + bindCachePtr = &classCache->bindCache; + procsSize = stateTree->numQuarks * sizeof(XtActionProc); + + for (bindCache = *bindCachePtr; + (*bindCachePtr); + bindCachePtr = &(*bindCachePtr)->next, bindCache = *bindCachePtr) + { + TMBindCacheStatus cacheStatus = &bindCache->status; + + if ((bindStatus->boundInClass == cacheStatus->boundInClass) && + (bindStatus->boundInHierarchy == cacheStatus->boundInHierarchy) && + (bindStatus->boundInContext == cacheStatus->boundInContext) && + (bindCache->stateTree == (TMStateTree)stateTree) && + !XtMemcmp(&bindCache->procs[0], procs, procsSize)) + { + bindCache->status.refCount++; + break; + } + } + if (*bindCachePtr == NULL) + { + *bindCachePtr = + bindCache = (TMBindCache) + __XtMalloc(sizeof(TMBindCacheRec) + + (procsSize - sizeof(XtActionProc))); + bindCache->next = NULL; + bindCache->status = *bindStatus; + bindCache->status.refCount = 1; + bindCache->stateTree = (TMStateTree)stateTree; +#ifdef TRACE_TM + bindCache->widgetClass = XtClass(w); + if (_XtGlobalTM.numBindCache == _XtGlobalTM.bindCacheTblSize) + { + _XtGlobalTM.bindCacheTblSize += 16; + _XtGlobalTM.bindCacheTbl = (TMBindCache *) + XtRealloc((char *)_XtGlobalTM.bindCacheTbl, + ((_XtGlobalTM.bindCacheTblSize) * + sizeof(TMBindCache))); + } + _XtGlobalTM.bindCacheTbl[_XtGlobalTM.numBindCache++] = bindCache; +#endif /* TRACE_TM */ + XtMemmove((XtPointer)&bindCache->procs[0], + (XtPointer)procs, procsSize); + } + UNLOCK_PROCESS; + return &bindCache->procs[0]; +} + +static void RemoveFromBindCache(w,procs) + Widget w; + XtActionProc *procs; +{ + TMClassCache classCache; + TMBindCache* bindCachePtr; + TMBindCache bindCache; + XtAppContext app = XtWidgetToApplicationContext (w); + + LOCK_PROCESS; + classCache = GetClassCache(w); + bindCachePtr = (TMBindCache *)&classCache->bindCache; + + for (bindCache = *bindCachePtr; + *bindCachePtr; + bindCachePtr = &(*bindCachePtr)->next, bindCache = *bindCachePtr) + { + if (&bindCache->procs[0] == procs) + { + if (--bindCache->status.refCount == 0) + { +#ifdef TRACE_TM + TMShortCard j; + Boolean found = False; + TMBindCache *tbl = _XtGlobalTM.bindCacheTbl; + + for (j = 0; j < _XtGlobalTM.numBindCache; j++) { + if (found) + tbl[j-1] = tbl[j]; + if (tbl[j] == bindCache) + found = True; + } + if (!found) + XtWarning("where's the action ??? "); + else + _XtGlobalTM.numBindCache--; +#endif /* TRACE_TM */ + *bindCachePtr = bindCache->next; + bindCache->next = app->free_bindings; + app->free_bindings = bindCache; + } + break; + } + } + UNLOCK_PROCESS; +} + +/* ARGSUSED */ +static void RemoveAccelerators(widget,closure,data) + Widget widget; + XtPointer closure, data; +{ + Widget destination = (Widget)closure; + TMComplexBindProcs bindProcs; + XtTranslations stackXlations[16]; + XtTranslations *xlationsList, destXlations; + TMShortCard i, numXlations = 0; + + if ((destXlations = destination->core.tm.translations) == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + XtNtranslationError,"nullTable",XtCXtToolkitError, + "Can't remove accelerators from NULL table", + (String *)NULL, (Cardinal *)NULL); + return; + } + + xlationsList = (XtTranslations *) + XtStackAlloc((destXlations->numStateTrees * sizeof(XtTranslations)), + stackXlations); + + for (i = 0, bindProcs = TMGetComplexBindEntry(destination->core.tm.proc_table, i); + i < destXlations->numStateTrees; + i++, bindProcs++) { + if (bindProcs->widget == widget) { + /* + * if it's being destroyed don't do all the work + */ + if (destination->core.being_destroyed) { + bindProcs->procs = NULL; + } + else + xlationsList[numXlations] = bindProcs->aXlations; + numXlations++; + } + } + + if (numXlations == 0) + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + XtNtranslationError,"nullTable",XtCXtToolkitError, + "Tried to remove nonexistent accelerators", + (String *)NULL, (Cardinal *)NULL); + else { + if (!destination->core.being_destroyed) + for (i = 0; i < numXlations; i++) + _XtUnmergeTranslations(destination, xlationsList[i]); + } + XtStackFree((char *)xlationsList, stackXlations); +} + +void _XtBindActions(widget, tm) + Widget widget; + XtTM tm; +{ + XtTranslations xlations = tm->translations; + TMSimpleStateTree stateTree; + int globalUnbound = 0; + Cardinal i; + TMBindData bindData = (TMBindData)tm->proc_table; + TMSimpleBindProcs simpleBindProcs; + TMComplexBindProcs complexBindProcs; + XtActionProc *newProcs; + Widget bindWidget; + + if ((xlations == NULL) || widget->core.being_destroyed) + return; + + stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[0]; + + for (i = 0; i < xlations->numStateTrees; i++) + { + stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i]; + if (bindData->simple.isComplex) { + complexBindProcs = TMGetComplexBindEntry(bindData, i); + if (complexBindProcs->widget) { + bindWidget = complexBindProcs->widget; + + if (bindWidget->core.destroy_callbacks != NULL) + _XtAddCallbackOnce((InternalCallbackList *) + &bindWidget->core.destroy_callbacks, + RemoveAccelerators, + (XtPointer)widget); + else + _XtAddCallback((InternalCallbackList *) + &bindWidget->core.destroy_callbacks, + RemoveAccelerators, + (XtPointer)widget); + } + else + bindWidget = widget; + } + else { + simpleBindProcs = TMGetSimpleBindEntry(bindData, i); + bindWidget = widget; + } + if ((newProcs = + TryBindCache(bindWidget,(TMStateTree)stateTree)) == NULL) + { + XtActionProc *procs, stackProcs[256]; + int localUnbound; + TMBindCacheStatusRec bcStatusRec; + + procs = (XtActionProc *) + XtStackAlloc(stateTree->numQuarks * sizeof(XtActionProc), + stackProcs); + XtBZero((XtPointer)procs, + stateTree->numQuarks * sizeof(XtActionProc)); + + localUnbound = BindProcs(bindWidget, + stateTree, + procs, + &bcStatusRec); + + if (localUnbound) + bcStatusRec.notFullyBound = True; + else + bcStatusRec.notFullyBound = False; + + newProcs = + EnterBindCache(bindWidget, + stateTree, + procs, + &bcStatusRec); + XtStackFree((XtPointer)procs, (XtPointer)stackProcs); + globalUnbound += localUnbound; + } + if (bindData->simple.isComplex) + complexBindProcs->procs = newProcs; + else + simpleBindProcs->procs = newProcs; + } + if (globalUnbound) + ReportUnboundActions(xlations, + (TMBindData)tm->proc_table); +} + + +void _XtUnbindActions(widget, xlations, bindData) + Widget widget; + XtTranslations xlations; + TMBindData bindData; +{ + Cardinal i; + Widget bindWidget; + XtActionProc *procs; + + if ((xlations == NULL) || !XtIsRealized(widget)) return; + + for (i = 0; i < xlations->numStateTrees; i++) { + if (bindData->simple.isComplex) { + TMComplexBindProcs complexBindProcs; + + complexBindProcs = TMGetComplexBindEntry(bindData, i); + + if (complexBindProcs->widget) { + /* + * check for this being an accelerator binding whose + * source is gone ( set by RemoveAccelerators) + */ + if (complexBindProcs->procs == NULL) + continue; + + XtRemoveCallback(complexBindProcs->widget, + XtNdestroyCallback, + RemoveAccelerators, + (XtPointer)widget); + bindWidget = complexBindProcs->widget; + } + else + bindWidget = widget; + procs = complexBindProcs->procs; + complexBindProcs->procs = NULL; + } + else { + TMSimpleBindProcs simpleBindProcs; + simpleBindProcs = TMGetSimpleBindEntry(bindData,i); + procs = simpleBindProcs->procs; + simpleBindProcs->procs = NULL; + bindWidget = widget; + } + RemoveFromBindCache(bindWidget, procs); + } +} + +#ifdef notdef +void _XtRemoveBindProcsByIndex(w, bindData, ndx) + Widget w; + TMBindData bindData; + TMShortCard ndx; +{ + TMShortCard i = ndx; + TMBindProcs bindProcs = (TMBindProcs)&bindData->bindTbl[0]; + + RemoveFromBindCache(bindProcs->widget ? bindProcs->widget : w, + bindProcs[i].procs); + + for (; i < bindData->bindTblSize; i++) + bindProcs[i] = bindProcs[i+1]; +} +#endif /* notdef */ + +/* + * used to free all copied action tables, called from DestroyAppContext + */ +void _XtFreeActions(actions) + ActionList actions; +{ + ActionList curr, next; + + for (curr = actions; curr;) { + next = curr->next; + XtFree((char *)curr->table); + XtFree((char *)curr); + curr = next; + } +} + +void XtAddActions(actions, num_actions) + XtActionList actions; + Cardinal num_actions; +{ + XtAppAddActions(_XtDefaultAppContext(), actions, num_actions); +} + +void XtAppAddActions(app, actions, num_actions) + XtAppContext app; + XtActionList actions; + Cardinal num_actions; +{ + register ActionList rec; + + LOCK_APP(app); + rec = XtNew(ActionListRec); + rec->next = app->action_table; + app->action_table = rec; + rec->table = CompileActionTable(actions, num_actions, False, False); + rec->count = num_actions; + UNLOCK_APP(app); +} + +void XtGetActionList(widget_class, actions_return, num_actions_return) + WidgetClass widget_class; + XtActionList* actions_return; + Cardinal* num_actions_return; +{ + XtActionList list; + CompiledActionTable table; + int i; + + *actions_return = NULL; + *num_actions_return = 0; + + LOCK_PROCESS; + if (! widget_class->core_class.class_inited) { + UNLOCK_PROCESS; + return; + } + if (! (widget_class->core_class.class_inited & WidgetClassFlag)) { + UNLOCK_PROCESS; + return; + } + *num_actions_return = widget_class->core_class.num_actions; + if (*num_actions_return) { + list = *actions_return = (XtActionList) + __XtMalloc(*num_actions_return * sizeof(XtActionsRec)); + table = GetClassActions(widget_class); + for (i= (*num_actions_return); --i >= 0; list++, table++) { + list->string = XrmQuarkToString(table->signature); + list->proc = table->proc; + } + } + UNLOCK_PROCESS; +} + +/*********************************************************************** + * + * Pop-up and Grab stuff + * + ***********************************************************************/ + +static Widget _XtFindPopup(widget, name) + Widget widget; + String name; +{ + register Cardinal i; + register XrmQuark q; + register Widget w; + + q = XrmStringToQuark(name); + + for (w=widget; w != NULL; w=w->core.parent) + for (i=0; i<w->core.num_popups; i++) + if (w->core.popup_list[i]->core.xrm_name == q) + return w->core.popup_list[i]; + + return NULL; +} + +void XtMenuPopupAction(widget, event, params, num_params) + Widget widget; + XEvent *event; + String *params; + Cardinal *num_params; +{ + Boolean spring_loaded; + register Widget popup_shell; + XtAppContext app = XtWidgetToApplicationContext(widget); + + LOCK_APP(app); + if (*num_params != 1) { + XtAppWarningMsg(app, + "invalidParameters","xtMenuPopupAction",XtCXtToolkitError, + "MenuPopup wants exactly one argument", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_APP(app); + return; + } + + if (event->type == ButtonPress) + spring_loaded = True; + else if (event->type == KeyPress || event->type == EnterNotify) + spring_loaded = False; + else { + XtAppWarningMsg(app, + "invalidPopup","unsupportedOperation",XtCXtToolkitError, +"Pop-up menu creation is only supported on ButtonPress, KeyPress or EnterNotify events.", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_APP(app); + return; + } + + popup_shell = _XtFindPopup(widget, params[0]); + if (popup_shell == NULL) { + XtAppWarningMsg(app, + "invalidPopup","xtMenuPopup",XtCXtToolkitError, + "Can't find popup widget \"%s\" in XtMenuPopup", + params, num_params); + UNLOCK_APP(app); + return; + } + + if (spring_loaded) _XtPopup(popup_shell, XtGrabExclusive, TRUE); + else _XtPopup(popup_shell, XtGrabNonexclusive, FALSE); + UNLOCK_APP(app); +} + + +/*ARGSUSED*/ +static void _XtMenuPopdownAction(widget, event, params, num_params) + Widget widget; + XEvent *event; + String *params; + Cardinal *num_params; +{ + Widget popup_shell; + + if (*num_params == 0) { + XtPopdown(widget); + } else if (*num_params == 1) { + popup_shell = _XtFindPopup(widget, params[0]); + if (popup_shell == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidPopup","xtMenuPopdown",XtCXtToolkitError, + "Can't find popup widget \"%s\" in XtMenuPopdown", + params, num_params); + return; + } + XtPopdown(popup_shell); + } else { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidParameters","xtMenuPopdown",XtCXtToolkitError, + "XtMenuPopdown called with num_params != 0 or 1", + (String *)NULL, (Cardinal *)NULL); + } +} + +static XtActionsRec RConst tmActions[] = { + {"XtMenuPopup", XtMenuPopupAction}, + {"XtMenuPopdown", _XtMenuPopdownAction}, + {"MenuPopup", XtMenuPopupAction}, /* old & obsolete */ + {"MenuPopdown", _XtMenuPopdownAction}, /* ditto */ +#ifndef NO_MIT_HACKS + {"XtDisplayTranslations", _XtDisplayTranslations}, + {"XtDisplayAccelerators", _XtDisplayAccelerators}, + {"XtDisplayInstalledAccelerators", _XtDisplayInstalledAccelerators}, +#endif +}; + + +void _XtPopupInitialize(app) + XtAppContext app; +{ + register ActionList rec; + + /* + * The _XtGlobalTM.newMatchSemantics flag determines whether + * we support old or new matching + * behavior. This is mainly an issue of whether subsequent lhs will + * get pushed up in the match table if a lhs containing thier initial + * sequence has already been encountered. Currently inited to False; + */ +#ifdef NEW_TM + _XtGlobalTM.newMatchSemantics = True; +#else + _XtGlobalTM.newMatchSemantics = False; +#endif + + rec = XtNew(ActionListRec); + rec->next = app->action_table; + app->action_table = rec; + LOCK_PROCESS; + rec->table = CompileActionTable(tmActions, XtNumber(tmActions), False, + True); + rec->count = XtNumber(tmActions); + UNLOCK_PROCESS; + _XtGrabInitialize(app); +} + + +#if NeedFunctionPrototypes +void XtCallActionProc( + Widget widget, + _Xconst char* action, + XEvent *event, + String *params, + Cardinal num_params + ) +#else +void XtCallActionProc(widget, action, event, params, num_params) + Widget widget; + String action; + XEvent *event; + String *params; + Cardinal num_params; +#endif +{ + CompiledAction* actionP; + XrmQuark q = XrmStringToQuark(action); + Widget w = widget; + XtAppContext app = XtWidgetToApplicationContext(widget); + ActionList actionList; + Cardinal i; + + LOCK_APP(app); + XtCheckSubclass(widget, coreWidgetClass, + "XtCallActionProc first argument is not a subclass of Core"); + LOCK_PROCESS; + do { + WidgetClass class = XtClass(w); + do { + if ((actionP = GetClassActions(class)) != NULL) + for (i = 0; + i < class->core_class.num_actions; + i++, actionP++) { + + if (actionP->signature == q) { + ActionHook hook = app->action_hook_list; + while (hook != NULL) { + (*hook->proc)( widget, + hook->closure, + (String)action, + event, + params, + &num_params + ); + hook= hook->next; + } + (*(actionP->proc)) + (widget, event, params, &num_params); + UNLOCK_PROCESS; + UNLOCK_APP(app); + return; + } + } + class = class->core_class.superclass; + } while (class != NULL); + w = XtParent(w); + } while (w != NULL); + UNLOCK_PROCESS; + + for (actionList = app->action_table; + actionList != NULL; + actionList = actionList->next) { + + for (i = 0, actionP = actionList->table; + i < actionList->count; + i++, actionP++) { + if (actionP->signature == q) { + ActionHook hook = app->action_hook_list; + while (hook != NULL) { + (*hook->proc)( widget, + hook->closure, + (String)action, + event, + params, + &num_params + ); + hook= hook->next; + } + (*(actionP->proc)) + (widget, event, params, &num_params); + UNLOCK_APP(app); + return; + } + } + + } + + { + String params[2]; + Cardinal num_params = 2; + params[0] = (String)action; + params[1] = XtName(widget); + XtAppWarningMsg(app, + "noActionProc", "xtCallActionProc", XtCXtToolkitError, + "No action proc named \"%s\" is registered for widget \"%s\"", + params, &num_params + ); + } + UNLOCK_APP(app); +} + +void _XtDoFreeBindings(app) + XtAppContext app; +{ + TMBindCache bcp; + + while (app->free_bindings) { + bcp = app->free_bindings->next; + XtFree ((char *) app->free_bindings); + app->free_bindings = bcp; + } +} diff --git a/src/TMgrab.c b/src/TMgrab.c new file mode 100644 index 0000000..e2a56e8 --- /dev/null +++ b/src/TMgrab.c @@ -0,0 +1,342 @@ +/* $Xorg: TMgrab.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/*LINTLIBRARY*/ +#include "IntrinsicI.h" + +typedef struct _GrabActionRec { + struct _GrabActionRec* next; + XtActionProc action_proc; + Boolean owner_events; + unsigned int event_mask; + int pointer_mode, keyboard_mode; +} GrabActionRec; + +static GrabActionRec *grabActionList = NULL; + +static void GrabAllCorrectKeys(widget, typeMatch, modMatch, grabP) + Widget widget; + TMTypeMatch typeMatch; + TMModifierMatch modMatch; + GrabActionRec* grabP; +{ + Display *dpy = XtDisplay(widget); + KeyCode *keycodes, *keycodeP; + Cardinal keycount; + Modifiers careOn = 0; + Modifiers careMask = 0; + + if (modMatch->lateModifiers) { + Boolean resolved; + resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers, + &careOn, &careMask); + if (!resolved) return; + } + careOn |= modMatch->modifiers; + careMask |= modMatch->modifierMask; + + XtKeysymToKeycodeList( + dpy, + (KeySym)typeMatch->eventCode, + &keycodes, + &keycount + ); + if (keycount == 0) return; + for (keycodeP = keycodes; keycount--; keycodeP++) { + if (modMatch->standard) { + /* find standard modifiers that produce this keysym */ + KeySym keysym; + int std_mods, least_mod; + Modifiers modifiers_return; + XtTranslateKeycode( dpy, *keycodeP, (Modifiers)0, + &modifiers_return, &keysym ); + if (careOn & modifiers_return) + return; + if (keysym == typeMatch->eventCode) { + XtGrabKey(widget, *keycodeP, careOn, + grabP->owner_events, + grabP->pointer_mode, + grabP->keyboard_mode + ); + /* continue; */ /* grab all modifier combinations */ + } + least_mod = modifiers_return & (~modifiers_return + 1); + for (std_mods = modifiers_return; + std_mods >= least_mod; std_mods--) { + Modifiers dummy; + /* check all useful combinations of modifier bits */ + if (modifiers_return & std_mods && + !(~modifiers_return & std_mods)) { + XtTranslateKeycode( dpy, *keycodeP, + (Modifiers)std_mods, + &dummy, &keysym ); + if (keysym == typeMatch->eventCode) { + XtGrabKey(widget, *keycodeP, + careOn | (Modifiers) std_mods, + grabP->owner_events, + grabP->pointer_mode, + grabP->keyboard_mode + ); + /* break; */ /* grab all modifier combinations */ + } + } + } + } else /* !event->standard */ { + XtGrabKey(widget, *keycodeP, careOn, + grabP->owner_events, + grabP->pointer_mode, + grabP->keyboard_mode + ); + } + } + XtFree((char *)keycodes); +} + +typedef struct { + TMShortCard count; + Widget widget; + GrabActionRec *grabP; +}DoGrabRec; + +static Boolean DoGrab(state, data) + StatePtr state; + XtPointer data; +{ + DoGrabRec *doGrabP = (DoGrabRec *)data; + GrabActionRec* grabP = doGrabP->grabP; + Widget widget = doGrabP->widget; + TMShortCard count = doGrabP->count; + TMShortCard typeIndex = state->typeIndex; + TMShortCard modIndex = state->modIndex; + ActionRec *action; + TMTypeMatch typeMatch; + TMModifierMatch modMatch; + Modifiers careOn = 0; + Modifiers careMask = 0; + Boolean resolved; + + LOCK_PROCESS; + typeMatch = TMGetTypeMatch(typeIndex); + modMatch = TMGetModifierMatch(modIndex); + + for (action = state->actions; action; action = action->next) + if (count == action->idx) break; + if (!action) { + UNLOCK_PROCESS; + return False; + } + + switch (typeMatch->eventType) { + case ButtonPress: + case ButtonRelease: + if (modMatch->lateModifiers) { + resolved = _XtComputeLateBindings(XtDisplay(widget), + modMatch->lateModifiers, + &careOn, &careMask); + if (!resolved) break; + } + careOn |= modMatch->modifiers; + XtGrabButton( + widget, + (unsigned) typeMatch->eventCode, + careOn, + grabP->owner_events, + grabP->event_mask, + grabP->pointer_mode, + grabP->keyboard_mode, + None, + None + ); + break; + + case KeyPress: + case KeyRelease: + GrabAllCorrectKeys(widget, typeMatch, modMatch, grabP); + break; + + case EnterNotify: + break; + + default: + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "invalidPopup","unsupportedOperation",XtCXtToolkitError, + "Pop-up menu creation is only supported on Button, Key or EnterNotify events.", + (String *)NULL, (Cardinal *)NULL); + break; + } + UNLOCK_PROCESS; + return False; +} + +void _XtRegisterGrabs(widget) + Widget widget; +{ + XtTranslations xlations = widget->core.tm.translations; + TMComplexStateTree *stateTreePtr; + unsigned int count; + TMShortCard i; + TMBindData bindData = (TMBindData) widget->core.tm.proc_table; + XtActionProc *procs; + + if (! XtIsRealized(widget) || widget->core.being_destroyed) + return; + + /* walk the widget instance action bindings table looking for */ + /* actions registered as grab actions. */ + /* when you find one, do a grab on the triggering event */ + + if (xlations == NULL) return; + stateTreePtr = (TMComplexStateTree *) xlations->stateTreeTbl; + if (*stateTreePtr == NULL) return; + for (i = 0; i < xlations->numStateTrees; i++, stateTreePtr++) { + if (bindData->simple.isComplex) + procs = TMGetComplexBindEntry(bindData, i)->procs; + else + procs = TMGetSimpleBindEntry(bindData, i)->procs; + for (count=0; count < (*stateTreePtr)->numQuarks; count++) { + GrabActionRec* grabP; + DoGrabRec doGrab; + + LOCK_PROCESS; + for (grabP = grabActionList; grabP != NULL; grabP = grabP->next) { + if (grabP->action_proc == procs[count]) { + /* we've found a "grabber" in the action table. Find the + * states that call this action. Note that if there is + * more than one "grabber" in the action table, we end + * up searching all of the states multiple times. + */ + doGrab.widget = widget; + doGrab.grabP = grabP; + doGrab.count = count; + _XtTraverseStateTree((TMStateTree)*stateTreePtr, + DoGrab, + (XtPointer)&doGrab); + } + } + UNLOCK_PROCESS; + } + } +} + +#if NeedFunctionPrototypes +void XtRegisterGrabAction( + XtActionProc action_proc, + _XtBoolean owner_events, + unsigned int event_mask, + int pointer_mode, + int keyboard_mode + ) +#else +void XtRegisterGrabAction(action_proc, owner_events, event_mask, + pointer_mode, keyboard_mode) + XtActionProc action_proc; + Boolean owner_events; + unsigned int event_mask; + int pointer_mode, keyboard_mode; +#endif +{ + GrabActionRec* actionP; + + LOCK_PROCESS; + for (actionP = grabActionList; actionP != NULL; actionP = actionP->next) { + if (actionP->action_proc == action_proc) break; + } + if (actionP == NULL) { + actionP = XtNew(GrabActionRec); + actionP->action_proc = action_proc; + actionP->next = grabActionList; + grabActionList = actionP; + } +#ifdef DEBUG + else + if ( actionP->owner_events != owner_events + || actionP->event_mask != event_mask + || actionP->pointer_mode != pointer_mode + || actionP->keyboard_mode != keyboard_mode) { + Cardinal n = 0; + XtWarningMsg( + "argsReplaced", "xtRegisterGrabAction", XtCXtToolkitError, + "XtRegisterGrabAction called on same proc with different args", + NULL, &n); + } +#endif /*DEBUG*/ + + actionP->owner_events = owner_events; + actionP->event_mask = event_mask; + actionP->pointer_mode = pointer_mode; + actionP->keyboard_mode = keyboard_mode; + UNLOCK_PROCESS; +} + +/*ARGSUSED*/ +void _XtGrabInitialize(app) + XtAppContext app; +{ + LOCK_PROCESS; + if (grabActionList == NULL) + XtRegisterGrabAction( XtMenuPopupAction, True, + (unsigned)(ButtonPressMask | ButtonReleaseMask), + GrabModeAsync, + GrabModeAsync + ); + UNLOCK_PROCESS; + +} diff --git a/src/TMkey.c b/src/TMkey.c new file mode 100644 index 0000000..92fe81f --- /dev/null +++ b/src/TMkey.c @@ -0,0 +1,744 @@ +/* $Xorg: TMkey.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */ +/*LINTLIBRARY*/ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#define XK_MISCELLANY +#define XK_LATIN1 +#define XK_LATIN2 +#define XK_LATIN3 +#define XK_LATIN4 + +#include "IntrinsicI.h" +#include <X11/keysymdef.h> + +#ifdef __STDC__ +#define Const const +#else +#define Const /**/ +#endif + +#define FLUSHKEYCACHE(ctx) \ + bzero((char *)&ctx->keycache, sizeof(TMKeyCache)) + +/* + * The following array reorders the modifier bits so that the most common ones + * (used by a translator) are in the top-most bits with respect to the size of + * the keycache. The array currently just reverses the bits as a good guess. + * This might be more trouble than it is worth, but it seems to help. + */ + +#define FM(i) i >> (8 - TMKEYCACHELOG2) +static Const unsigned char modmix[256] = { +FM(0x0f), FM(0x8f), FM(0x4f), FM(0xcf), FM(0x2f), FM(0xaf), FM(0x6f), FM(0xef), +FM(0x1f), FM(0x9f), FM(0x5f), FM(0xdf), FM(0x3f), FM(0xbf), FM(0x7f), FM(0xff), +FM(0x07), FM(0x87), FM(0x47), FM(0xc7), FM(0x27), FM(0xa7), FM(0x67), FM(0xe7), +FM(0x17), FM(0x97), FM(0x57), FM(0xd7), FM(0x37), FM(0xb7), FM(0x77), FM(0xf7), +FM(0x0b), FM(0x8b), FM(0x4b), FM(0xcb), FM(0x2b), FM(0xab), FM(0x6b), FM(0xeb), +FM(0x1b), FM(0x9b), FM(0x5b), FM(0xdb), FM(0x3b), FM(0xbb), FM(0x7b), FM(0xfb), +FM(0x03), FM(0x83), FM(0x43), FM(0xc3), FM(0x23), FM(0xa3), FM(0x63), FM(0xe3), +FM(0x13), FM(0x93), FM(0x53), FM(0xd3), FM(0x33), FM(0xb3), FM(0x73), FM(0xf3), +FM(0x0d), FM(0x8d), FM(0x4d), FM(0xcd), FM(0x2d), FM(0xad), FM(0x6d), FM(0xed), +FM(0x1d), FM(0x9d), FM(0x5d), FM(0xdd), FM(0x3d), FM(0xbd), FM(0x7d), FM(0xfd), +FM(0x05), FM(0x85), FM(0x45), FM(0xc5), FM(0x25), FM(0xa5), FM(0x65), FM(0xe5), +FM(0x15), FM(0x95), FM(0x55), FM(0xd5), FM(0x35), FM(0xb5), FM(0x75), FM(0xf5), +FM(0x09), FM(0x89), FM(0x49), FM(0xc9), FM(0x29), FM(0xa9), FM(0x69), FM(0xe9), +FM(0x19), FM(0x99), FM(0x59), FM(0xd9), FM(0x39), FM(0xb9), FM(0x79), FM(0xf9), +FM(0x01), FM(0x81), FM(0x41), FM(0xc1), FM(0x21), FM(0xa1), FM(0x61), FM(0xe1), +FM(0x11), FM(0x91), FM(0x51), FM(0xd1), FM(0x31), FM(0xb1), FM(0x71), FM(0xf1), +FM(0x00), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee), +FM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe), +FM(0x08), FM(0x88), FM(0x48), FM(0xc8), FM(0x28), FM(0xa8), FM(0x68), FM(0xe8), +FM(0x18), FM(0x98), FM(0x58), FM(0xd8), FM(0x38), FM(0xb8), FM(0x78), FM(0xf8), +FM(0x04), FM(0x84), FM(0x44), FM(0xc4), FM(0x24), FM(0xa4), FM(0x64), FM(0xe4), +FM(0x14), FM(0x94), FM(0x54), FM(0xd4), FM(0x34), FM(0xb4), FM(0x74), FM(0xf4), +FM(0x0c), FM(0x8c), FM(0x4c), FM(0xcc), FM(0x2c), FM(0xac), FM(0x6c), FM(0xec), +FM(0x1c), FM(0x9c), FM(0x5c), FM(0xdc), FM(0x3c), FM(0xbc), FM(0x7c), FM(0xfc), +FM(0x02), FM(0x82), FM(0x42), FM(0xc2), FM(0x22), FM(0xa2), FM(0x62), FM(0xe2), +FM(0x12), FM(0x92), FM(0x52), FM(0xd2), FM(0x32), FM(0xb2), FM(0x72), FM(0xf2), +FM(0x0a), FM(0x8a), FM(0x4a), FM(0xca), FM(0x2a), FM(0xaa), FM(0x6a), FM(0xea), +FM(0x1a), FM(0x9a), FM(0x5a), FM(0xda), FM(0x3a), FM(0xba), FM(0x7a), FM(0xfa), +FM(0x06), FM(0x86), FM(0x46), FM(0xc6), FM(0x26), FM(0xa6), FM(0x66), FM(0xe6), +FM(0x16), FM(0x96), FM(0x56), FM(0xd6), FM(0x36), FM(0xb6), FM(0x76), FM(0xf6), +FM(0x0e), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee), +FM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe) +}; +#undef FM + +#define MOD_RETURN(ctx, key) (ctx)->keycache.modifiers_return[key] + +#define TRANSLATE(ctx,pd,dpy,key,mod,mod_ret,sym_ret) \ +{ \ + int _i_ = (((key) - (pd)->min_keycode + modmix[(mod) & 0xff]) & \ + (TMKEYCACHESIZE-1)); \ + if ((key) != 0 && /* Xlib XIM composed input */ \ + (ctx)->keycache.keycode[_i_] == (key) && \ + (ctx)->keycache.modifiers[_i_] == (mod)) { \ + mod_ret = MOD_RETURN(ctx, key); \ + sym_ret = (ctx)->keycache.keysym[_i_]; \ + } else { \ + XtTranslateKeycode(dpy, key, mod, &mod_ret, &sym_ret); \ + (ctx)->keycache.keycode[_i_] = key; \ + (ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \ + (ctx)->keycache.keysym[_i_] = sym_ret; \ + MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \ + } \ +} + +#define UPDATE_CACHE(ctx, pd, key, mod, mod_ret, sym_ret) \ +{ \ + int _i_ = (((key) - (pd)->min_keycode + modmix[(mod) & 0xff]) & \ + (TMKEYCACHESIZE-1)); \ + (ctx)->keycache.keycode[_i_] = key; \ + (ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \ + (ctx)->keycache.keysym[_i_] = sym_ret; \ + MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \ +} + +/* usual number of expected keycodes in XtKeysymToKeycodeList */ +#define KEYCODE_ARRAY_SIZE 10 + +Boolean _XtComputeLateBindings(dpy, lateModifiers, computed, computedMask) + Display *dpy; + LateBindingsPtr lateModifiers; + Modifiers *computed,*computedMask; +{ + int i,j,ref; + ModToKeysymTable* temp; + XtPerDisplay perDisplay; + Boolean found; + KeySym tempKeysym = NoSymbol; + + perDisplay = _XtGetPerDisplay(dpy); + if (perDisplay == NULL) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "displayError","invalidDisplay",XtCXtToolkitError, + "Can't find display structure", + (String *)NULL, (Cardinal *)NULL); + return FALSE; + } + _InitializeKeysymTables(dpy, perDisplay); + for (ref=0; lateModifiers[ref].keysym; ref++) { + found = FALSE; + for (i=0;i<8;i++) { + temp = &(perDisplay->modsToKeysyms[i]); + for (j=0;j<temp->count;j++){ + if (perDisplay->modKeysyms[temp->idx+j] == + lateModifiers[ref].keysym) { + *computedMask = *computedMask | temp->mask; + if (!lateModifiers[ref].knot) + *computed |= temp->mask; + tempKeysym = lateModifiers[ref].keysym; + found = TRUE; break; + } + } + if (found) break; + } + if (!found && !lateModifiers[ref].knot) + if (!lateModifiers[ref].pair && (tempKeysym == NoSymbol)) + return FALSE; + /* if you didn't find the modifier and the modifier must be + asserted then return FALSE. If you didn't find the modifier + and the modifier must be off, then it is OK . Don't + return FALSE if this is the first member of a pair or if + it is the second member of a pair when the first member + was bound to a modifier */ + if (!lateModifiers[ref].pair) tempKeysym = NoSymbol; + } + return TRUE; +} + +void _XtAllocTMContext(pd) + XtPerDisplay pd; +{ + TMKeyContext ctx; + ctx = (TMKeyContext)_XtHeapAlloc(&pd->heap, + sizeof(TMKeyContextRec)); + ctx->event = NULL; + ctx->serial = 0; + ctx->keysym = NoSymbol; + ctx->modifiers = 0; + FLUSHKEYCACHE(ctx); + pd->tm_context = ctx; +} + +static unsigned int num_bits(mask) + unsigned long mask; +{ + register unsigned long y; + + y = (mask >> 1) &033333333333; + y = mask - y - ((y >>1) & 033333333333); + return ((unsigned int) (((y + (y >> 3)) & 030707070707) % 077)); +} + +Boolean _XtMatchUsingDontCareMods(typeMatch, modMatch, eventSeq) + TMTypeMatch typeMatch; + TMModifierMatch modMatch; + TMEventPtr eventSeq; +{ + Modifiers modifiers_return; + KeySym keysym_return; + Modifiers useful_mods; + int i, num_modbits; + Modifiers computed = 0; + Modifiers computedMask = 0; + Boolean resolved = TRUE; + Display *dpy = eventSeq->xev->xany.display; + XtPerDisplay pd; + TMKeyContext tm_context; + + if (modMatch->lateModifiers != NULL) + resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers, + &computed, &computedMask); + if (!resolved) return FALSE; + computed |= modMatch->modifiers; + computedMask |= modMatch->modifierMask; /* gives do-care mask */ + + if ( (computed & computedMask) == + (eventSeq->event.modifiers & computedMask) ) { + + pd = _XtGetPerDisplay(dpy); + tm_context = pd->tm_context; + TRANSLATE(tm_context, pd, dpy, (KeyCode)eventSeq->event.eventCode, + (unsigned)0, modifiers_return, keysym_return); + + if ((keysym_return & typeMatch->eventCodeMask) == typeMatch->eventCode ) { + tm_context->event = eventSeq->xev; + tm_context->serial = eventSeq->xev->xany.serial; + tm_context->keysym = keysym_return; + tm_context->modifiers = (Modifiers)0; + return TRUE; + } + useful_mods = ~computedMask & modifiers_return; + if (useful_mods == 0) return FALSE; + + switch (num_modbits = num_bits(useful_mods)) { + case 1: + case 8: + /* + * one modbit should never happen, in fact the implementation + * of XtTranslateKey and XmTranslateKey guarantee that it + * won't, so don't care if the loop is set up for the case + * when one modbit is set. + * The performance implications of all eight modbits being + * set is horrendous. This isn't a problem with Xt/Xaw based + * applications. We can only hope that Motif's virtual + * modifiers won't result in all eight modbits being set. + */ + for (i = useful_mods; i > 0; i--) { + TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode, + (Modifiers)i, modifiers_return, keysym_return); + if (keysym_return == + (typeMatch->eventCode & typeMatch->eventCodeMask)) { + tm_context->event = eventSeq->xev; + tm_context->serial = eventSeq->xev->xany.serial; + tm_context->keysym = keysym_return; + tm_context->modifiers = (Modifiers)i; + return TRUE; + } + } + break; + default: /* (2..7) */ + { + /* + * Only translate using combinations of the useful modifiers. + * to minimize the chance of invalidating the cache. + */ + static char pows[] = { 0, 1, 3, 7, 15, 31, 63, 127 }; + Modifiers tmod, mod_masks[8]; + int j; + for (tmod = 1, i = 0; tmod <= (Mod5Mask<<1); tmod <<= 1) + if (tmod & useful_mods) mod_masks[i++] = tmod; + for (j = (int) pows[num_modbits]; j > 0; j--) { + tmod = 0; + for (i = 0; i < num_modbits; i++) + if (j & (1<<i)) tmod |= mod_masks[i]; + TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode, + tmod, modifiers_return, keysym_return); + if (keysym_return == + (typeMatch->eventCode & typeMatch->eventCodeMask)) { + tm_context->event = eventSeq->xev; + tm_context->serial = eventSeq->xev->xany.serial; + tm_context->keysym = keysym_return; + tm_context->modifiers = (Modifiers)i; + return TRUE; + } + } + } + break; + } /* switch (num_modbits) */ + } + return FALSE; +} + +void XtConvertCase(dpy,keysym,lower_return,upper_return) + Display *dpy; + KeySym keysym; + KeySym *lower_return, *upper_return; +{ + XtPerDisplay pd; + CaseConverterPtr ptr; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + pd = _XtGetPerDisplay(dpy); + + *lower_return = *upper_return = keysym; + for (ptr=pd->case_cvt; ptr; ptr = ptr->next) + if (ptr->start <= keysym && keysym <= ptr->stop) { + (*ptr->proc)(dpy, keysym, lower_return, upper_return); + return; + } + XConvertCase(keysym, lower_return, upper_return); + UNLOCK_APP(app); +} + +Boolean _XtMatchUsingStandardMods (typeMatch, modMatch, eventSeq) + TMTypeMatch typeMatch; + TMModifierMatch modMatch; + TMEventPtr eventSeq; +{ + Modifiers modifiers_return; + KeySym keysym_return; + Modifiers computed= 0; + Modifiers computedMask = 0; + Boolean resolved = TRUE; + Display *dpy = eventSeq->xev->xany.display; + XtPerDisplay pd = _XtGetPerDisplay(dpy); + TMKeyContext tm_context = pd->tm_context; + Modifiers translateModifiers; + + /* To maximize cache utilization, we mask off nonstandard modifiers + before cache lookup. For a given key translator, standard modifiers + are constant per KeyCode. If a key translator uses no standard + modifiers this implementation will never reference the cache. + */ + + modifiers_return = MOD_RETURN(tm_context, eventSeq->event.eventCode); + if (!modifiers_return) { + XtTranslateKeycode(dpy, (KeyCode)eventSeq->event.eventCode, + eventSeq->event.modifiers, &modifiers_return, + &keysym_return); + translateModifiers = eventSeq->event.modifiers & modifiers_return; + UPDATE_CACHE(tm_context, pd, eventSeq->event.eventCode, + translateModifiers, modifiers_return, keysym_return); + } else { + translateModifiers = eventSeq->event.modifiers & modifiers_return; + TRANSLATE(tm_context, pd, dpy, (KeyCode)eventSeq->event.eventCode, + translateModifiers, modifiers_return, keysym_return); + } + + if ((typeMatch->eventCode & typeMatch->eventCodeMask) == + (keysym_return & typeMatch->eventCodeMask)) { + if (modMatch->lateModifiers != NULL) + resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers, + &computed, &computedMask); + if (!resolved) return FALSE; + computed |= modMatch->modifiers; + computedMask |= modMatch->modifierMask; + + if ((computed & computedMask) == + (eventSeq->event.modifiers & ~modifiers_return & computedMask)) { + tm_context->event = eventSeq->xev; + tm_context->serial = eventSeq->xev->xany.serial; + tm_context->keysym = keysym_return; + tm_context->modifiers = translateModifiers; + return TRUE; + } + } + return FALSE; +} + + +void _XtBuildKeysymTables(dpy,pd) + Display *dpy; + register XtPerDisplay pd; +{ + ModToKeysymTable *table; + int maxCount,i,j,k,tempCount,idx; + KeySym keysym,tempKeysym; + XModifierKeymap* modKeymap; + KeyCode keycode; +#define KeysymTableSize 16 + + FLUSHKEYCACHE(pd->tm_context); + if (pd->keysyms) + XFree( (char *)pd->keysyms ); + pd->keysyms_serial = NextRequest(dpy); + pd->keysyms = XGetKeyboardMapping(dpy, pd->min_keycode, + pd->max_keycode-pd->min_keycode+1, + &pd->keysyms_per_keycode); + if (pd->modKeysyms) + XtFree((char *)pd->modKeysyms); + if (pd->modsToKeysyms) + XtFree((char *)pd->modsToKeysyms); + pd->modKeysyms = (KeySym*)__XtMalloc((Cardinal)KeysymTableSize*sizeof(KeySym)); + maxCount = KeysymTableSize; + tempCount = 0; + + table = (ModToKeysymTable*)__XtMalloc((Cardinal)8*sizeof(ModToKeysymTable)); + pd->modsToKeysyms = table; + + table[0].mask = ShiftMask; + table[1].mask = LockMask; + table[2].mask = ControlMask; + table[3].mask = Mod1Mask; + table[4].mask = Mod2Mask; + table[5].mask = Mod3Mask; + table[6].mask = Mod4Mask; + table[7].mask = Mod5Mask; + tempKeysym = 0; + + modKeymap = XGetModifierMapping(dpy); + for (i=0;i<32;i++) + pd->isModifier[i] = 0; + pd->mode_switch = 0; + pd->num_lock = 0; + for (i=0;i<8;i++) { + table[i].idx = tempCount; + table[i].count = 0; + for (j=0;j<modKeymap->max_keypermod;j++) { + keycode = modKeymap->modifiermap[i*modKeymap->max_keypermod+j]; + if (keycode != 0) { + pd->isModifier[keycode>>3] |= 1 << (keycode & 7); + for (k=0; k<pd->keysyms_per_keycode;k++) { + idx = ((keycode-pd->min_keycode)* + pd->keysyms_per_keycode)+k; + keysym = pd->keysyms[idx]; + if ((keysym == XK_Mode_switch) && (i > 2)) + pd->mode_switch |= 1 << i; + if ((keysym == XK_Num_Lock) && (i > 2)) + pd->num_lock |= 1 << i; + if (keysym != 0 && keysym != tempKeysym ){ + if (tempCount==maxCount) { + maxCount += KeysymTableSize; + pd->modKeysyms = (KeySym*)XtRealloc( + (char*)pd->modKeysyms, + (unsigned) (maxCount*sizeof(KeySym)) ); + } + pd->modKeysyms[tempCount++] = keysym; + table[i].count++; + tempKeysym = keysym; + } + } + } + } + } + pd->lock_meaning = NoSymbol; + for (i = 0; i < table[1].count; i++) { + keysym = pd->modKeysyms[table[1].idx + i]; + if (keysym == XK_Caps_Lock) { + pd->lock_meaning = XK_Caps_Lock; + break; + } else if (keysym == XK_Shift_Lock) { + pd->lock_meaning = XK_Shift_Lock; + } + } + XFreeModifiermap(modKeymap); +} + +#if NeedFunctionPrototypes +void XtTranslateKeycode ( + Display *dpy, + _XtKeyCode keycode, + Modifiers modifiers, + Modifiers *modifiers_return, + KeySym *keysym_return + ) +#else +void XtTranslateKeycode (dpy, keycode, modifiers, + modifiers_return, keysym_return) + + Display *dpy; + KeyCode keycode; + Modifiers modifiers; + Modifiers *modifiers_return; + KeySym *keysym_return; +#endif +{ + XtPerDisplay pd; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + pd = _XtGetPerDisplay(dpy); + _InitializeKeysymTables(dpy, pd); + (*pd->defaultKeycodeTranslator)( + dpy,keycode,modifiers,modifiers_return,keysym_return); + UNLOCK_APP(app); +} + +/* This code should match XTranslateKey (internal, sigh) in Xlib */ +#if NeedFunctionPrototypes +void XtTranslateKey( + register Display *dpy, + _XtKeyCode keycode, + Modifiers modifiers, + Modifiers *modifiers_return, + KeySym *keysym_return + ) +#else +void XtTranslateKey(dpy, keycode, modifiers, + modifiers_return, keysym_return) + register Display *dpy; + KeyCode keycode; + Modifiers modifiers; + Modifiers *modifiers_return; + KeySym *keysym_return; +#endif +#ifndef XKB +{ + XtPerDisplay pd; + int per; + register KeySym *syms; + KeySym sym, lsym, usym; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + pd = _XtGetPerDisplay(dpy); + *modifiers_return = (ShiftMask|LockMask) | pd->mode_switch | pd->num_lock; + if (((int)keycode < pd->min_keycode) || ((int)keycode > pd->max_keycode)) { + *keysym_return = NoSymbol; + UNLOCK_APP(app); + return; + } + per = pd->keysyms_per_keycode; + syms = &pd->keysyms[(keycode - pd->min_keycode) * per]; + while ((per > 2) && (syms[per - 1] == NoSymbol)) + per--; + if ((per > 2) && (modifiers & pd->mode_switch)) { + syms += 2; + per -= 2; + } + if ((modifiers & pd->num_lock) && + (per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) { + if ((modifiers & ShiftMask) || + ((modifiers & LockMask) && (pd->lock_meaning == XK_Shift_Lock))) + *keysym_return = syms[0]; + else + *keysym_return = syms[1]; + } else if (!(modifiers & ShiftMask) && + (!(modifiers & LockMask) || (pd->lock_meaning == NoSymbol))) { + if ((per == 1) || (syms[1] == NoSymbol)) + XtConvertCase(dpy, syms[0], keysym_return, &usym); + else + *keysym_return = syms[0]; + } else if (!(modifiers & LockMask) || + (pd->lock_meaning != XK_Caps_Lock)) { + if ((per == 1) || ((usym = syms[1]) == NoSymbol)) + XtConvertCase(dpy, syms[0], &lsym, &usym); + *keysym_return = usym; + } else { + if ((per == 1) || ((sym = syms[1]) == NoSymbol)) + sym = syms[0]; + XtConvertCase(dpy, sym, &lsym, &usym); + if (!(modifiers & ShiftMask) && (sym != syms[0]) && + ((sym != usym) || (lsym == usym))) + XtConvertCase(dpy, syms[0], &lsym, &usym); + *keysym_return = usym; + } + + if (*keysym_return == XK_VoidSymbol) + *keysym_return = NoSymbol; + UNLOCK_APP(app); +} +#else +{ + XkbLookupKeySym(dpy, keycode, modifiers, modifiers_return, + keysym_return); + return; +} +#endif + +void XtSetKeyTranslator(dpy, translator) + + Display *dpy; + XtKeyProc translator; + +{ + XtPerDisplay pd; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + pd = _XtGetPerDisplay(dpy); + + pd->defaultKeycodeTranslator = translator; + FLUSHKEYCACHE(pd->tm_context); + /* XXX should now redo grabs */ + UNLOCK_APP(app); +} + +void XtRegisterCaseConverter(dpy, proc, start, stop) + Display *dpy; + XtCaseProc proc; + KeySym start; + KeySym stop; +{ + XtPerDisplay pd; + CaseConverterPtr ptr, prev; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + pd = _XtGetPerDisplay(dpy); + + ptr = (CaseConverterPtr) __XtMalloc(sizeof(CaseConverterRec)); + ptr->start = start; + ptr->stop = stop; + ptr->proc = proc; + ptr->next = pd->case_cvt; + pd->case_cvt = ptr; + + /* Remove obsolete case converters from the list */ + prev = ptr; + for (ptr=ptr->next; ptr; ptr=prev->next) { + if (start <= ptr->start && stop >= ptr->stop) { + prev->next = ptr->next; + XtFree((char *)ptr); + } + else prev = ptr; + } + FLUSHKEYCACHE(pd->tm_context); + /* XXX should now redo grabs */ + UNLOCK_APP(app); +} + +KeySym *XtGetKeysymTable(dpy, min_keycode_return, keysyms_per_keycode_return) + Display *dpy; + KeyCode *min_keycode_return; + int *keysyms_per_keycode_return; +{ + XtPerDisplay pd; + KeySym* retval; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + pd = _XtGetPerDisplay(dpy); + _InitializeKeysymTables(dpy, pd); + *min_keycode_return = pd->min_keycode; /* %%% */ + *keysyms_per_keycode_return = pd->keysyms_per_keycode; + retval = pd->keysyms; + UNLOCK_APP(app); + return retval; +} + +void XtKeysymToKeycodeList(dpy, keysym, keycodes_return, keycount_return) + Display *dpy; + KeySym keysym; + KeyCode **keycodes_return; + Cardinal *keycount_return; +{ + XtPerDisplay pd; + unsigned keycode; + int per, match; + register KeySym *syms; + register int i, j; + KeySym lsym, usym; + unsigned maxcodes = 0; + unsigned ncodes = 0; + KeyCode *keycodes, *codeP; + DPY_TO_APPCON(dpy); + + LOCK_APP(app); + pd = _XtGetPerDisplay(dpy); + _InitializeKeysymTables(dpy, pd); + keycodes = NULL; + per = pd->keysyms_per_keycode; + for (syms = pd->keysyms, keycode = (unsigned) pd->min_keycode; + (int)keycode <= pd->max_keycode; + syms += per, keycode++) { + match = 0; + for (j = 0; j < per; j++) { + if (syms[j] == keysym) { + match = 1; + break; + } + } + if (!match) + for (i = 1; i < 5; i += 2) { + if ((per == i) || ((per > i) && (syms[i] == NoSymbol))) { + XtConvertCase(dpy, syms[i-1], &lsym, &usym); + if ((lsym == keysym) || (usym == keysym)) { + match = 1; + break; + } + } + } + if (match) { + if (ncodes == maxcodes) { + KeyCode *old = keycodes; + maxcodes += KEYCODE_ARRAY_SIZE; + keycodes = (KeyCode*)__XtMalloc(maxcodes*sizeof(KeyCode)); + if (ncodes) { + (void) memmove((char *)keycodes, (char *)old, + ncodes*sizeof(KeyCode) ); + XtFree((char *)old); + } + codeP = &keycodes[ncodes]; + } + *codeP++ = (KeyCode) keycode; + ncodes++; + } + } + *keycodes_return = keycodes; + *keycount_return = ncodes; + UNLOCK_APP(app); +} + + diff --git a/src/TMparse.c b/src/TMparse.c new file mode 100644 index 0000000..3ec7de6 --- /dev/null +++ b/src/TMparse.c @@ -0,0 +1,2128 @@ +/* $Xorg: TMparse.c,v 1.6 2001/02/09 02:03:58 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "StringDefs.h" +#include <ctype.h> +#ifndef NOTASCII +#define XK_LATIN1 +#endif +#define XK_MISCELLANY +#include <X11/keysymdef.h> + +#ifdef CACHE_TRANSLATIONS +# ifdef REFCNT_TRANSLATIONS +# define CACHED XtCacheAll | XtCacheRefCount +# else +# define CACHED XtCacheAll +# endif +#else +# define CACHED XtCacheNone +#endif + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +static String XtNtranslationParseError = "translationParseError"; + +typedef int EventType; + +typedef String (*ParseProc)(); /* str, closure, event ,error */ + /* String str; */ + /* Opaque closure; */ + /* EventPtr event; */ + /* Boolean* error */ + +typedef void (*ModifierProc)(); +typedef TMShortCard Value; + +typedef struct _ModifierRec { + char* name; + XrmQuark signature; + ModifierProc modifierParseProc; + Value value; +} ModifierRec, *ModifierKeys; + +typedef struct _EventKey { + char *event; + XrmQuark signature; + EventType eventType; + ParseProc parseDetail; + Opaque closure; +}EventKey, *EventKeys; + +typedef struct { + char *name; + XrmQuark signature; + Value value; +} NameValueRec, *NameValueTable; + +static void ParseModImmed(); +static void ParseModSym(); +static String PanicModeRecovery(); +static String CheckForPoundSign(); +static KeySym StringToKeySym(); +static ModifierRec modifiers[] = { + {"Shift", 0, ParseModImmed,ShiftMask}, + {"Lock", 0, ParseModImmed,LockMask}, + {"Ctrl", 0, ParseModImmed,ControlMask}, + {"Mod1", 0, ParseModImmed,Mod1Mask}, + {"Mod2", 0, ParseModImmed,Mod2Mask}, + {"Mod3", 0, ParseModImmed,Mod3Mask}, + {"Mod4", 0, ParseModImmed,Mod4Mask}, + {"Mod5", 0, ParseModImmed,Mod5Mask}, + {"Meta", 0, ParseModSym, XK_Meta_L}, + {"m", 0, ParseModSym, XK_Meta_L}, + {"h", 0, ParseModSym, XK_Hyper_L}, + {"su", 0, ParseModSym, XK_Super_L}, + {"a", 0, ParseModSym, XK_Alt_L}, + {"Hyper", 0, ParseModSym, XK_Hyper_L}, + {"Super", 0, ParseModSym, XK_Super_L}, + {"Alt", 0, ParseModSym, XK_Alt_L}, + {"Button1", 0, ParseModImmed,Button1Mask}, + {"Button2", 0, ParseModImmed,Button2Mask}, + {"Button3", 0, ParseModImmed,Button3Mask}, + {"Button4", 0, ParseModImmed,Button4Mask}, + {"Button5", 0, ParseModImmed,Button5Mask}, + {"c", 0, ParseModImmed,ControlMask}, + {"s", 0, ParseModImmed,ShiftMask}, + {"l", 0, ParseModImmed,LockMask}, +}; + +static NameValueRec buttonNames[] = { + {"Button1", 0, Button1}, + {"Button2", 0, Button2}, + {"Button3", 0, Button3}, + {"Button4", 0, Button4}, + {"Button5", 0, Button5}, + {NULL, NULLQUARK, 0}, +}; + +static NameValueRec motionDetails[] = { + {"Normal", 0, NotifyNormal}, + {"Hint", 0, NotifyHint}, + {NULL, NULLQUARK, 0}, +}; + +static NameValueRec notifyModes[] = { + {"Normal", 0, NotifyNormal}, + {"Grab", 0, NotifyGrab}, + {"Ungrab", 0, NotifyUngrab}, + {"WhileGrabbed", 0, NotifyWhileGrabbed}, + {NULL, NULLQUARK, 0}, +}; + +#if 0 +static NameValueRec notifyDetail[] = { + {"Ancestor", 0, NotifyAncestor}, + {"Virtual", 0, NotifyVirtual}, + {"Inferior", 0, NotifyInferior}, + {"Nonlinear", 0, NotifyNonlinear}, + {"NonlinearVirtual", 0, NotifyNonlinearVirtual}, + {"Pointer", 0, NotifyPointer}, + {"PointerRoot", 0, NotifyPointerRoot}, + {"DetailNone", 0, NotifyDetailNone}, + {NULL, NULLQUARK, 0}, +}; + +static NameValueRec visibilityNotify[] = { + {"Unobscured", 0, VisibilityUnobscured}, + {"PartiallyObscured", 0, VisibilityPartiallyObscured}, + {"FullyObscured", 0, VisibilityFullyObscured}, + {NULL, NULLQUARK, 0}, +}; + +static NameValueRec circulation[] = { + {"OnTop", 0, PlaceOnTop}, + {"OnBottom", 0, PlaceOnBottom}, + {NULL, NULLQUARK, 0}, +}; + +static NameValueRec propertyChanged[] = { + {"NewValue", 0, PropertyNewValue}, + {"Delete", 0, PropertyDelete}, + {NULL, NULLQUARK, 0}, +}; +#endif /*0*/ + +static NameValueRec mappingNotify[] = { + {"Modifier", 0, MappingModifier}, + {"Keyboard", 0, MappingKeyboard}, + {"Pointer", 0, MappingPointer}, + {NULL, NULLQUARK, 0}, +}; + +static String ParseKeySym(); +static String ParseKeyAndModifiers(); +static String ParseTable(); +static String ParseImmed(); +static String ParseAddModifier(); +static String ParseNone(); +static String ParseAtom(); + +static EventKey events[] = { + +/* Event Name, Quark, Event Type, Detail Parser, Closure */ + +{"KeyPress", NULLQUARK, KeyPress, ParseKeySym, NULL}, +{"Key", NULLQUARK, KeyPress, ParseKeySym, NULL}, +{"KeyDown", NULLQUARK, KeyPress, ParseKeySym, NULL}, +{"Ctrl", NULLQUARK, KeyPress, ParseKeyAndModifiers,(Opaque)ControlMask}, +{"Shift", NULLQUARK, KeyPress, ParseKeyAndModifiers,(Opaque)ShiftMask}, +{"Meta", NULLQUARK, KeyPress, ParseKeyAndModifiers,(Opaque)NULL}, +{"KeyUp", NULLQUARK, KeyRelease, ParseKeySym, NULL}, +{"KeyRelease", NULLQUARK, KeyRelease, ParseKeySym, NULL}, + +{"ButtonPress", NULLQUARK, ButtonPress, ParseTable,(Opaque)buttonNames}, +{"BtnDown", NULLQUARK, ButtonPress, ParseTable,(Opaque)buttonNames}, +{"Btn1Down", NULLQUARK, ButtonPress, ParseImmed,(Opaque)Button1}, +{"Btn2Down", NULLQUARK, ButtonPress, ParseImmed,(Opaque)Button2}, +{"Btn3Down", NULLQUARK, ButtonPress, ParseImmed,(Opaque)Button3}, +{"Btn4Down", NULLQUARK, ButtonPress, ParseImmed,(Opaque)Button4}, +{"Btn5Down", NULLQUARK, ButtonPress, ParseImmed,(Opaque)Button5}, + +/* Event Name, Quark, Event Type, Detail Parser, Closure */ + +{"ButtonRelease", NULLQUARK, ButtonRelease, ParseTable,(Opaque)buttonNames}, +{"BtnUp", NULLQUARK, ButtonRelease, ParseTable,(Opaque)buttonNames}, +{"Btn1Up", NULLQUARK, ButtonRelease, ParseImmed,(Opaque)Button1}, +{"Btn2Up", NULLQUARK, ButtonRelease, ParseImmed,(Opaque)Button2}, +{"Btn3Up", NULLQUARK, ButtonRelease, ParseImmed,(Opaque)Button3}, +{"Btn4Up", NULLQUARK, ButtonRelease, ParseImmed,(Opaque)Button4}, +{"Btn5Up", NULLQUARK, ButtonRelease, ParseImmed,(Opaque)Button5}, + +{"MotionNotify", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, +{"PtrMoved", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, +{"Motion", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, +{"MouseMoved", NULLQUARK, MotionNotify, ParseTable, (Opaque)motionDetails}, +{"BtnMotion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)AnyButtonMask}, +{"Btn1Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button1Mask}, +{"Btn2Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button2Mask}, +{"Btn3Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button3Mask}, +{"Btn4Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button4Mask}, +{"Btn5Motion", NULLQUARK, MotionNotify, ParseAddModifier, (Opaque)Button5Mask}, + +{"EnterNotify", NULLQUARK, EnterNotify, ParseTable,(Opaque)notifyModes}, +{"Enter", NULLQUARK, EnterNotify, ParseTable,(Opaque)notifyModes}, +{"EnterWindow", NULLQUARK, EnterNotify, ParseTable,(Opaque)notifyModes}, + +{"LeaveNotify", NULLQUARK, LeaveNotify, ParseTable,(Opaque)notifyModes}, +{"LeaveWindow", NULLQUARK, LeaveNotify, ParseTable,(Opaque)notifyModes}, +{"Leave", NULLQUARK, LeaveNotify, ParseTable,(Opaque)notifyModes}, + +/* Event Name, Quark, Event Type, Detail Parser, Closure */ + +{"FocusIn", NULLQUARK, FocusIn, ParseTable,(Opaque)notifyModes}, + +{"FocusOut", NULLQUARK, FocusOut, ParseTable,(Opaque)notifyModes}, + +{"KeymapNotify", NULLQUARK, KeymapNotify, ParseNone, NULL}, +{"Keymap", NULLQUARK, KeymapNotify, ParseNone, NULL}, + +{"Expose", NULLQUARK, Expose, ParseNone, NULL}, + +{"GraphicsExpose", NULLQUARK, GraphicsExpose, ParseNone, NULL}, +{"GrExp", NULLQUARK, GraphicsExpose, ParseNone, NULL}, + +{"NoExpose", NULLQUARK, NoExpose, ParseNone, NULL}, +{"NoExp", NULLQUARK, NoExpose, ParseNone, NULL}, + +{"VisibilityNotify",NULLQUARK, VisibilityNotify,ParseNone, NULL}, +{"Visible", NULLQUARK, VisibilityNotify,ParseNone, NULL}, + +{"CreateNotify", NULLQUARK, CreateNotify, ParseNone, NULL}, +{"Create", NULLQUARK, CreateNotify, ParseNone, NULL}, + +/* Event Name, Quark, Event Type, Detail Parser, Closure */ + +{"DestroyNotify", NULLQUARK, DestroyNotify, ParseNone, NULL}, +{"Destroy", NULLQUARK, DestroyNotify, ParseNone, NULL}, + +{"UnmapNotify", NULLQUARK, UnmapNotify, ParseNone, NULL}, +{"Unmap", NULLQUARK, UnmapNotify, ParseNone, NULL}, + +{"MapNotify", NULLQUARK, MapNotify, ParseNone, NULL}, +{"Map", NULLQUARK, MapNotify, ParseNone, NULL}, + +{"MapRequest", NULLQUARK, MapRequest, ParseNone, NULL}, +{"MapReq", NULLQUARK, MapRequest, ParseNone, NULL}, + +{"ReparentNotify", NULLQUARK, ReparentNotify, ParseNone, NULL}, +{"Reparent", NULLQUARK, ReparentNotify, ParseNone, NULL}, + +{"ConfigureNotify", NULLQUARK, ConfigureNotify, ParseNone, NULL}, +{"Configure", NULLQUARK, ConfigureNotify, ParseNone, NULL}, + +{"ConfigureRequest",NULLQUARK, ConfigureRequest,ParseNone, NULL}, +{"ConfigureReq", NULLQUARK, ConfigureRequest,ParseNone, NULL}, + +/* Event Name, Quark, Event Type, Detail Parser, Closure */ + +{"GravityNotify", NULLQUARK, GravityNotify, ParseNone, NULL}, +{"Grav", NULLQUARK, GravityNotify, ParseNone, NULL}, + +{"ResizeRequest", NULLQUARK, ResizeRequest, ParseNone, NULL}, +{"ResReq", NULLQUARK, ResizeRequest, ParseNone, NULL}, + +{"CirculateNotify", NULLQUARK, CirculateNotify, ParseNone, NULL}, +{"Circ", NULLQUARK, CirculateNotify, ParseNone, NULL}, + +{"CirculateRequest",NULLQUARK, CirculateRequest,ParseNone, NULL}, +{"CircReq", NULLQUARK, CirculateRequest,ParseNone, NULL}, + +{"PropertyNotify", NULLQUARK, PropertyNotify, ParseAtom, NULL}, +{"Prop", NULLQUARK, PropertyNotify, ParseAtom, NULL}, + +{"SelectionClear", NULLQUARK, SelectionClear, ParseAtom, NULL}, +{"SelClr", NULLQUARK, SelectionClear, ParseAtom, NULL}, + +{"SelectionRequest",NULLQUARK, SelectionRequest,ParseAtom, NULL}, +{"SelReq", NULLQUARK, SelectionRequest,ParseAtom, NULL}, + +/* Event Name, Quark, Event Type, Detail Parser, Closure */ + +{"SelectionNotify", NULLQUARK, SelectionNotify, ParseAtom, NULL}, +{"Select", NULLQUARK, SelectionNotify, ParseAtom, NULL}, + +{"ColormapNotify", NULLQUARK, ColormapNotify, ParseNone, NULL}, +{"Clrmap", NULLQUARK, ColormapNotify, ParseNone, NULL}, + +{"ClientMessage", NULLQUARK, ClientMessage, ParseAtom, NULL}, +{"Message", NULLQUARK, ClientMessage, ParseAtom, NULL}, + +{"MappingNotify", NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify}, +{"Mapping", NULLQUARK, MappingNotify, ParseTable, (Opaque)mappingNotify}, + +#ifdef DEBUG +# ifdef notdef +{"Timer", NULLQUARK, _XtTimerEventType,ParseNone, NULL}, +# endif /* notdef */ +{"EventTimer", NULLQUARK, _XtEventTimerEventType,ParseNone,NULL}, +#endif /* DEBUG */ + +/* Event Name, Quark, Event Type, Detail Parser, Closure */ + +}; + + +#define ScanFor(str, ch) \ + while ((*(str) != (ch)) && (*(str) != '\0') && (*(str) != '\n')) (str)++ + +#define ScanNumeric(str) while ('0' <= *(str) && *(str) <= '9') (str)++ + +#define ScanAlphanumeric(str) \ + while (('A' <= *(str) && *(str) <= 'Z') || \ + ('a' <= *(str) && *(str) <= 'z') || \ + ('0' <= *(str) && *(str) <= '9')) (str)++ + +#define ScanWhitespace(str) \ + while (*(str) == ' ' || *(str) == '\t') (str)++ + + +static Boolean initialized = FALSE; +static XrmQuark QMeta; +static XrmQuark QCtrl; +static XrmQuark QNone; +static XrmQuark QAny; + +static void FreeEventSeq(eventSeq) + EventSeqPtr eventSeq; +{ + register EventSeqPtr evs = eventSeq; + + while (evs != NULL) { + evs->state = (StatePtr) evs; + if (evs->next != NULL + && evs->next->state == (StatePtr) evs->next) + evs->next = NULL; + evs = evs->next; + } + + evs = eventSeq; + while (evs != NULL) { + register EventPtr event = evs; + evs = evs->next; + if (evs == event) evs = NULL; + XtFree((char *)event); + } +} + +static void CompileNameValueTable(table) + NameValueTable table; +{ + register int i; + + for (i=0; table[i].name; i++) + table[i].signature = XrmPermStringToQuark(table[i].name); +} + +static int OrderEvents(a, b) + EventKey *a, *b; +{ + return ((a->signature < b->signature) ? -1 : 1); +} + +static void Compile_XtEventTable(table, count) + EventKeys table; + Cardinal count; +{ + register int i; + register EventKeys entry = table; + + for (i=count; --i >= 0; entry++) + entry->signature = XrmPermStringToQuark(entry->event); + qsort(table, count, sizeof(EventKey), OrderEvents); +} + +static int OrderModifiers(a, b) + ModifierRec *a, *b; +{ + return ((a->signature < b->signature) ? -1 : 1); +} + +static void Compile_XtModifierTable(table, count) + ModifierKeys table; + Cardinal count; +{ + register int i; + register ModifierKeys entry = table; + + for (i=count; --i >= 0; entry++) + entry->signature = XrmPermStringToQuark(entry->name); + qsort(table, count, sizeof(ModifierRec), OrderModifiers); +} + +static String PanicModeRecovery(str) + String str; +{ + ScanFor(str,'\n'); + if (*str == '\n') str++; + return str; + +} + + +static void Syntax(str0,str1) + String str0,str1; +{ + Cardinal num_params = 2; + String params[2]; + + params[0] = str0; + params[1] = str1; + XtWarningMsg(XtNtranslationParseError,"parseError",XtCXtToolkitError, + "translation table syntax error: %s %s",params,&num_params); +} + + + +static Cardinal LookupTMEventType(eventStr,error) + String eventStr; + Boolean *error; +{ + register int i, left, right; + register XrmQuark signature; + static int previous = 0; + + LOCK_PROCESS; + if ((signature = StringToQuark(eventStr)) == events[previous].signature) { + UNLOCK_PROCESS; + return (Cardinal) previous; + } + + left = 0; + right = XtNumber(events) - 1; + while (left <= right) { + i = (left + right) >> 1; + if (signature < events[i].signature) + right = i - 1; + else if (signature > events[i].signature) + left = i + 1; + else { + previous = i; + UNLOCK_PROCESS; + return (Cardinal) i; + } + } + + Syntax("Unknown event type : ",eventStr); + *error = TRUE; + UNLOCK_PROCESS; + return (Cardinal) i; +} + +static void StoreLateBindings(keysymL,notL,keysymR,notR,lateBindings) + + KeySym keysymL; + Boolean notL; + KeySym keysymR; + Boolean notR; + LateBindingsPtr* lateBindings; +{ + LateBindingsPtr temp; + Boolean pair = FALSE; + unsigned long count,number; + if (lateBindings != NULL){ + temp = *lateBindings; + if (temp != NULL) { + for (count = 0; temp[count].keysym; count++){/*EMPTY*/} + } + else count = 0; + if (! keysymR){ + number = 1;pair = FALSE; + } else{ + number = 2;pair = TRUE; + } + + temp = (LateBindingsPtr)XtRealloc((char *)temp, + (unsigned)((count+number+1) * sizeof(LateBindings)) ); + *lateBindings = temp; + temp[count].knot = notL; + temp[count].pair = pair; + if (count == 0) + temp[count].ref_count = 1; + temp[count++].keysym = keysymL; + if (keysymR){ + temp[count].knot = notR; + temp[count].pair = FALSE; + temp[count].ref_count = 0; + temp[count++].keysym = keysymR; + } + temp[count].knot = temp[count].pair = FALSE; + temp[count].ref_count = 0; + temp[count].keysym = 0; + } +} + +static void _XtParseKeysymMod(name,lateBindings,notFlag,valueP,error) + String name; + LateBindingsPtr* lateBindings; + Boolean notFlag; + Value *valueP; + Boolean *error; +{ + KeySym keySym; + keySym = StringToKeySym(name, error); + *valueP = 0; + if (keySym != NoSymbol) { + StoreLateBindings(keySym,notFlag,(KeySym) NULL,FALSE,lateBindings); + } +} + +static Boolean _XtLookupModifier(signature, lateBindings, notFlag, valueP, + constMask) + XrmQuark signature; + LateBindingsPtr* lateBindings; + Boolean notFlag; + Value *valueP; + Bool constMask; +{ + register int i, left, right; + static int previous = 0; + + LOCK_PROCESS; + if (signature == modifiers[previous].signature) { + if (constMask) *valueP = modifiers[previous].value; + else /* if (modifiers[previous].modifierParseProc) always true */ + (*modifiers[previous].modifierParseProc) + (modifiers[previous].value, lateBindings, notFlag, valueP); + UNLOCK_PROCESS; + return TRUE; + } + + left = 0; + right = XtNumber(modifiers) - 1; + while (left <= right) { + i = (left + right) >> 1; + if (signature < modifiers[i].signature) + right = i - 1; + else if (signature > modifiers[i].signature) + left = i + 1; + else { + previous = i; + if (constMask) *valueP = modifiers[i].value; + else /* if (modifiers[i].modifierParseProc) always true */ + (*modifiers[i].modifierParseProc) + (modifiers[i].value, lateBindings, notFlag, valueP); + UNLOCK_PROCESS; + return TRUE; + } + } + UNLOCK_PROCESS; + return FALSE; +} + + +static String ScanIdent(str) + register String str; +{ + ScanAlphanumeric(str); + while ( + ('A' <= *str && *str <= 'Z') + || ('a' <= *str && *str <= 'z') + || ('0' <= *str && *str <= '9') + || (*str == '-') + || (*str == '_') + || (*str == '$') + ) str++; + return str; +} + +static String FetchModifierToken(str, token_return) + String str; + XrmQuark *token_return; +{ + String start = str; + + if (*str == '$') { + *token_return = QMeta; + str++; + return str; + } + if (*str == '^') { + *token_return = QCtrl; + str++; + return str; + } + str = ScanIdent(str); + if (start != str) { + char modStrbuf[100]; + char* modStr; + + modStr = XtStackAlloc (str - start + 1, modStrbuf); + if (modStr == NULL) _XtAllocError (NULL); + (void) memmove(modStr, start, str-start); + modStr[str-start] = '\0'; + *token_return = XrmStringToQuark(modStr); + XtStackFree (modStr, modStrbuf); + return str; + } + return str; +} + +static String ParseModifiers(str, event,error) + register String str; + EventPtr event; + Boolean* error; +{ + register String start; + Boolean notFlag, exclusive, keysymAsMod; + Value maskBit; + XrmQuark Qmod; + + ScanWhitespace(str); + start = str; + str = FetchModifierToken(str, &Qmod); + exclusive = FALSE; + if (start != str) { + if (Qmod == QNone) { + event->event.modifierMask = ~0; + event->event.modifiers = 0; + ScanWhitespace(str); + return str; + } else if (Qmod == QAny) { /*backward compatability*/ + event->event.modifierMask = 0; + event->event.modifiers = AnyModifier; + ScanWhitespace(str); + return str; + } + str = start; /*if plain modifier, reset to beginning */ + } + else while (*str == '!' || *str == ':') { + if (*str == '!') { + exclusive = TRUE; + str++; + ScanWhitespace(str); + } + if (*str == ':') { + event->event.standard = TRUE; + str++; + ScanWhitespace(str); + } + } + + while (*str != '<') { + if (*str == '~') { + notFlag = TRUE; + str++; + } else + notFlag = FALSE; + if (*str == '@') { + keysymAsMod = TRUE; + str++; + } + else keysymAsMod = FALSE; + start = str; + str = FetchModifierToken(str, &Qmod); + if (start == str) { + Syntax("Modifier or '<' expected",""); + *error = TRUE; + return PanicModeRecovery(str); + } + if (keysymAsMod) { + _XtParseKeysymMod(XrmQuarkToString(Qmod), + &event->event.lateModifiers, + notFlag,&maskBit, error); + if (*error) + return PanicModeRecovery(str); + + } else + if (!_XtLookupModifier(Qmod, &event->event.lateModifiers, + notFlag, &maskBit, FALSE)) { + Syntax("Unknown modifier name: ", XrmQuarkToString(Qmod)); + *error = TRUE; + return PanicModeRecovery(str); + } + event->event.modifierMask |= maskBit; + if (notFlag) event->event.modifiers &= ~maskBit; + else event->event.modifiers |= maskBit; + ScanWhitespace(str); + } + if (exclusive) event->event.modifierMask = ~0; + return str; +} + +static String ParseXtEventType(str, event, tmEventP,error) + register String str; + EventPtr event; + Cardinal *tmEventP; + Boolean* error; +{ + String start = str; + char eventTypeStrbuf[100]; + char* eventTypeStr; + + ScanAlphanumeric(str); + eventTypeStr = XtStackAlloc (str - start + 1, eventTypeStrbuf); + if (eventTypeStr == NULL) _XtAllocError (NULL); + (void) memmove(eventTypeStr, start, str-start); + eventTypeStr[str-start] = '\0'; + *tmEventP = LookupTMEventType(eventTypeStr,error); + XtStackFree (eventTypeStr, eventTypeStrbuf); + if (*error) + return PanicModeRecovery(str); + event->event.eventType = events[*tmEventP].eventType; + return str; +} + +static unsigned long StrToHex(str) + String str; +{ + register char c; + register unsigned long val = 0; + + while ((c = *str)) { + if ('0' <= c && c <= '9') val = val*16+c-'0'; + else if ('a' <= c && c <= 'z') val = val*16+c-'a'+10; + else if ('A' <= c && c <= 'Z') val = val*16+c-'A'+10; + else return 0; + str++; + } + + return val; +} + +static unsigned long StrToOct(str) + String str; +{ + register char c; + register unsigned long val = 0; + + while ((c = *str)) { + if ('0' <= c && c <= '7') val = val*8+c-'0'; else return 0; + str++; + } + + return val; +} + +static unsigned long StrToNum(str) + String str; +{ + register char c; + register unsigned long val = 0; + + if (*str == '0') { + str++; + if (*str == 'x' || *str == 'X') return StrToHex(++str); + else return StrToOct(str); + } + + while ((c = *str)) { + if ('0' <= c && c <= '9') val = val*10+c-'0'; + else return 0; + str++; + } + + return val; +} + +static KeySym StringToKeySym(str, error) + String str; + Boolean *error; +{ + KeySym k; + + if (str == NULL || *str == '\0') return (KeySym) 0; + +#ifndef NOTASCII + /* special case single character ASCII, for speed */ + if (*(str+1) == '\0') { + if (' ' <= *str && *str <= '~') return XK_space + (*str - ' '); + } +#endif + + if ('0' <= *str && *str <= '9') return (KeySym) StrToNum(str); + k = XStringToKeysym(str); + if (k != NoSymbol) return k; + +#ifdef NOTASCII + /* fall-back case to preserve backwards compatibility; no-one + * should be relying upon this! + */ + if (*(str+1) == '\0') return (KeySym) *str; +#endif + + Syntax("Unknown keysym name: ", str); + *error = TRUE; + return NoSymbol; +} +/* ARGSUSED */ +static void ParseModImmed(value, lateBindings, notFlag, valueP) + Value value; + LateBindingsPtr* lateBindings; + Boolean notFlag; + Value* valueP; +{ + *valueP = value; +} + +static void ParseModSym(value, lateBindings, notFlag, valueP) + /* is only valid with keysyms that have an _L and _R in their name; + * and ignores keysym lookup errors (i.e. assumes only valid keysyms) + */ + Value value; + LateBindingsPtr* lateBindings; + Boolean notFlag; + Value* valueP; +{ + register KeySym keysymL = (KeySym)value; + register KeySym keysymR = keysymL + 1; /* valid for supported keysyms */ + StoreLateBindings(keysymL,notFlag,keysymR,notFlag,lateBindings); + *valueP = 0; +} + +#ifdef sparc +/* + * The stupid optimizer in SunOS 4.0.3 and below generates bogus code that + * causes the value of the most recently used variable to be returned instead + * of the value passed in. + */ +static String stupid_optimizer_kludge; +#define BROKEN_OPTIMIZER_HACK(val) stupid_optimizer_kludge = (val) +#else +#define BROKEN_OPTIMIZER_HACK(val) val +#endif + +/* ARGSUSED */ +static String ParseImmed(str, closure, event,error) + register String str; + register Opaque closure; + register EventPtr event; + Boolean* error; +{ + event->event.eventCode = (unsigned long)closure; + event->event.eventCodeMask = (unsigned long)~0L; + + return BROKEN_OPTIMIZER_HACK(str); +} + +/* ARGSUSED */ +static String ParseAddModifier(str, closure, event, error) + register String str; + register Opaque closure; + register EventPtr event; + Boolean* error; +{ + register unsigned long modval = (unsigned long)closure; + event->event.modifiers |= modval; + if (modval != AnyButtonMask) /* AnyButtonMask is don't-care mask */ + event->event.modifierMask |= modval; + + return BROKEN_OPTIMIZER_HACK(str); +} + + +static String ParseKeyAndModifiers(str, closure, event,error) + String str; + Opaque closure; + EventPtr event; + Boolean* error; +{ + str = ParseKeySym(str, closure, event,error); + if ((unsigned long) closure == 0) { + Value metaMask; /* unused */ + (void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE, + &metaMask, FALSE); + } else { + event->event.modifiers |= (unsigned long) closure; + event->event.modifierMask |= (unsigned long) closure; + } + return str; +} + +/*ARGSUSED*/ +static String ParseKeySym(str, closure, event,error) + register String str; + Opaque closure; + EventPtr event; + Boolean* error; +{ + char *start; + char keySymNamebuf[100]; + char* keySymName; + + ScanWhitespace(str); + + if (*str == '\\') { + keySymName = keySymNamebuf; + str++; + keySymName[0] = *str; + if (*str != '\0' && *str != '\n') str++; + keySymName[1] = '\0'; + event->event.eventCode = StringToKeySym(keySymName, error); + event->event.eventCodeMask = ~0L; + } else if (*str == ',' || *str == ':' || + /* allow leftparen to be single char symbol, + * for backwards compatibility + */ + (*str == '(' && *(str+1) >= '0' && *(str+1) <= '9')) { + keySymName = keySymNamebuf; /* just so we can stackfree it later */ + /* no detail */ + event->event.eventCode = 0L; + event->event.eventCodeMask = 0L; + } else { + start = str; + while ( + *str != ',' + && *str != ':' + && *str != ' ' + && *str != '\t' + && *str != '\n' + && (*str != '(' || *(str+1) <= '0' || *(str+1) >= '9') + && *str != '\0') str++; + keySymName = XtStackAlloc (str - start + 1, keySymNamebuf); + (void) memmove(keySymName, start, str-start); + keySymName[str-start] = '\0'; + event->event.eventCode = StringToKeySym(keySymName, error); + event->event.eventCodeMask = ~0L; + } + if (*error) { + if (keySymName[0] == '<') { + /* special case for common error */ + XtWarningMsg(XtNtranslationParseError, "missingComma", + XtCXtToolkitError, + "... possibly due to missing ',' in event sequence.", + (String*)NULL, (Cardinal*)NULL); + } + XtStackFree (keySymName, keySymNamebuf); + return PanicModeRecovery(str); + } + if (event->event.standard) + event->event.matchEvent = _XtMatchUsingStandardMods; + else + event->event.matchEvent = _XtMatchUsingDontCareMods; + + XtStackFree (keySymName, keySymNamebuf); + + return str; +} + +static String ParseTable(str, closure, event,error) + register String str; + Opaque closure; + EventPtr event; + Boolean* error; +{ + register String start = str; + register XrmQuark signature; + NameValueTable table = (NameValueTable) closure; + char tableSymName[100]; + + event->event.eventCode = 0L; + ScanAlphanumeric(str); + if (str == start) {event->event.eventCodeMask = 0L; return str; } + if (str-start >= 99) { + Syntax("Invalid Detail Type (string is too long).", ""); + *error = TRUE; + return str; + } + (void) memmove(tableSymName, start, str-start); + tableSymName[str-start] = '\0'; + signature = StringToQuark(tableSymName); + for (; table->signature != NULLQUARK; table++) + if (table->signature == signature) { + event->event.eventCode = table->value; + event->event.eventCodeMask = ~0L; + return str; + } + + Syntax("Unknown Detail Type: ", tableSymName); + *error = TRUE; + return PanicModeRecovery(str); +} + +/*ARGSUSED*/ +static String ParseNone(str, closure, event,error) + String str; + Opaque closure; + EventPtr event; + Boolean* error; +{ + event->event.eventCode = 0; + event->event.eventCodeMask = 0; + + return BROKEN_OPTIMIZER_HACK(str); +} + +/*ARGSUSED*/ +static String ParseAtom(str, closure, event,error) + String str; + Opaque closure; + EventPtr event; + Boolean* error; +{ + ScanWhitespace(str); + + if (*str == ',' || *str == ':') { + /* no detail */ + event->event.eventCode = 0L; + event->event.eventCodeMask = 0L; + } else { + char *start, atomName[1000]; + start = str; + while ( + *str != ',' + && *str != ':' + && *str != ' ' + && *str != '\t' + && *str != '\n' + && *str != '\0') str++; + if (str-start >= 999) { + Syntax( "Atom name must be less than 1000 characters long.", "" ); + *error = TRUE; + return str; + } + (void) memmove(atomName, start, str-start); + atomName[str-start] = '\0'; + event->event.eventCode = XrmStringToQuark(atomName); + event->event.matchEvent = _XtMatchAtom; + } + return str; +} + +static ModifierMask buttonModifierMasks[] = { + 0, Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask +}; +static String ParseRepeat(); + +static String ParseEvent(str, event, reps, plus, error) + register String str; + EventPtr event; + int* reps; + Boolean* plus; + Boolean* error; +{ + Cardinal tmEvent; + + str = ParseModifiers(str, event,error); + if (*error) return str; + if (*str != '<') { + Syntax("Missing '<' while parsing event type.",""); + *error = TRUE; + return PanicModeRecovery(str); + } + else str++; + str = ParseXtEventType(str, event, &tmEvent,error); + if (*error) return str; + if (*str != '>'){ + Syntax("Missing '>' while parsing event type",""); + *error = TRUE; + return PanicModeRecovery(str); + } + else str++; + if (*str == '(') { + str = ParseRepeat(str, reps, plus, error); + if (*error) return str; + } + str = (*(events[tmEvent].parseDetail))( + str, events[tmEvent].closure, event,error); + if (*error) return str; + +/* gross hack! ||| this kludge is related to the X11 protocol deficiency w.r.t. + * modifiers in grabs. + */ + if ((event->event.eventType == ButtonRelease) + && (event->event.modifiers | event->event.modifierMask) /* any */ + && (event->event.modifiers != AnyModifier)) + { + event->event.modifiers + |= buttonModifierMasks[event->event.eventCode]; + /* the button that is going up will always be in the modifiers... */ + } + + return str; +} + +static String ParseQuotedStringEvent(str, event,error) + register String str; + register EventPtr event; + Boolean *error; +{ + Value metaMask; + char s[2]; + + if (*str=='^') { + str++; + event->event.modifiers = ControlMask; + } else if (*str == '$') { + str++; + (void) _XtLookupModifier(QMeta, &event->event.lateModifiers, FALSE, + &metaMask, FALSE); + } + if (*str == '\\') + str++; + s[0] = *str; + s[1] = '\0'; + if (*str != '\0' && *str != '\n') str++; + event->event.eventType = KeyPress; + event->event.eventCode = StringToKeySym(s, error); + if (*error) return PanicModeRecovery(str); + event->event.eventCodeMask = ~0L; + event->event.matchEvent = _XtMatchUsingStandardMods; + event->event.standard = TRUE; + + return str; +} + + +static EventSeqRec timerEventRec = { + {0, 0, NULL, _XtEventTimerEventType, 0L, 0L, NULL}, + /* (StatePtr) -1 */ NULL, + NULL, + NULL +}; + +static void RepeatDown(eventP, reps, actionsP) + EventPtr *eventP; + int reps; + ActionPtr **actionsP; +{ + EventRec upEventRec; + register EventPtr event, downEvent; + EventPtr upEvent = &upEventRec; + register int i; + + downEvent = event = *eventP; + *upEvent = *downEvent; + upEvent->event.eventType = ((event->event.eventType == ButtonPress) ? + ButtonRelease : KeyRelease); + if ((upEvent->event.eventType == ButtonRelease) + && (upEvent->event.modifiers != AnyModifier) + && (upEvent->event.modifiers | upEvent->event.modifierMask)) + upEvent->event.modifiers + |= buttonModifierMasks[event->event.eventCode]; + + if (event->event.lateModifiers) + event->event.lateModifiers->ref_count += (reps - 1) * 2; + + for (i=1; i<reps; i++) { + + /* up */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *upEvent; + + /* timer */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = timerEventRec; + + /* down */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *downEvent; + + } + + event->next = NULL; + *eventP = event; + *actionsP = &event->actions; +} + +static void RepeatDownPlus(eventP, reps, actionsP) + EventPtr *eventP; + int reps; + ActionPtr **actionsP; +{ + EventRec upEventRec; + register EventPtr event, downEvent, lastDownEvent; + EventPtr upEvent = &upEventRec; + register int i; + + downEvent = event = *eventP; + *upEvent = *downEvent; + upEvent->event.eventType = ((event->event.eventType == ButtonPress) ? + ButtonRelease : KeyRelease); + if ((upEvent->event.eventType == ButtonRelease) + && (upEvent->event.modifiers != AnyModifier) + && (upEvent->event.modifiers | upEvent->event.modifierMask)) + upEvent->event.modifiers + |= buttonModifierMasks[event->event.eventCode]; + + if (event->event.lateModifiers) + event->event.lateModifiers->ref_count += reps * 2 - 1; + + for (i=0; i<reps; i++) { + + if (i > 0) { + /* down */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *downEvent; + } + lastDownEvent = event; + + /* up */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *upEvent; + + /* timer */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = timerEventRec; + + } + + event->next = lastDownEvent; + *eventP = event; + *actionsP = &lastDownEvent->actions; +} + +static void RepeatUp(eventP, reps, actionsP) + EventPtr *eventP; + int reps; + ActionPtr **actionsP; +{ + EventRec upEventRec; + register EventPtr event, downEvent; + EventPtr upEvent = &upEventRec; + register int i; + + /* the event currently sitting in *eventP is an "up" event */ + /* we want to make it a "down" event followed by an "up" event, */ + /* so that sequence matching on the "state" side works correctly. */ + + downEvent = event = *eventP; + *upEvent = *downEvent; + downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ? + ButtonPress : KeyPress); + if ((downEvent->event.eventType == ButtonPress) + && (downEvent->event.modifiers != AnyModifier) + && (downEvent->event.modifiers | downEvent->event.modifierMask)) + downEvent->event.modifiers + &= ~buttonModifierMasks[event->event.eventCode]; + + if (event->event.lateModifiers) + event->event.lateModifiers->ref_count += reps * 2 - 1; + + /* up */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *upEvent; + + for (i=1; i<reps; i++) { + + /* timer */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = timerEventRec; + + /* down */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *downEvent; + + /* up */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *upEvent; + + } + + event->next = NULL; + *eventP = event; + *actionsP = &event->actions; +} + +static void RepeatUpPlus(eventP, reps, actionsP) + EventPtr *eventP; + int reps; + ActionPtr **actionsP; +{ + EventRec upEventRec; + register EventPtr event, downEvent, lastUpEvent; + EventPtr upEvent = &upEventRec; + register int i; + + /* the event currently sitting in *eventP is an "up" event */ + /* we want to make it a "down" event followed by an "up" event, */ + /* so that sequence matching on the "state" side works correctly. */ + + downEvent = event = *eventP; + *upEvent = *downEvent; + downEvent->event.eventType = ((event->event.eventType == ButtonRelease) ? + ButtonPress : KeyPress); + if ((downEvent->event.eventType == ButtonPress) + && (downEvent->event.modifiers != AnyModifier) + && (downEvent->event.modifiers | downEvent->event.modifierMask)) + downEvent->event.modifiers + &= ~buttonModifierMasks[event->event.eventCode]; + + if (event->event.lateModifiers) + event->event.lateModifiers->ref_count += reps * 2; + + for (i=0; i<reps; i++) { + + /* up */ + event->next = XtNew(EventSeqRec); + lastUpEvent = event = event->next; + *event = *upEvent; + + /* timer */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = timerEventRec; + + /* down */ + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *downEvent; + + } + + event->next = lastUpEvent; + *eventP = event; + *actionsP = &lastUpEvent->actions; +} + +static void RepeatOther(eventP, reps, actionsP) + EventPtr *eventP; + int reps; + ActionPtr **actionsP; +{ + register EventPtr event, tempEvent; + register int i; + + tempEvent = event = *eventP; + + if (event->event.lateModifiers) + event->event.lateModifiers->ref_count += reps - 1; + + for (i=1; i<reps; i++) { + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *tempEvent; + } + + *eventP = event; + *actionsP = &event->actions; +} + +static void RepeatOtherPlus(eventP, reps, actionsP) + EventPtr *eventP; + int reps; + ActionPtr **actionsP; +{ + register EventPtr event, tempEvent; + register int i; + + tempEvent = event = *eventP; + + if (event->event.lateModifiers) + event->event.lateModifiers->ref_count += reps - 1; + + for (i=1; i<reps; i++) { + event->next = XtNew(EventSeqRec); + event = event->next; + *event = *tempEvent; + } + + event->next = event; + *eventP = event; + *actionsP = &event->actions; +} + +static void RepeatEvent(eventP, reps, plus, actionsP) + EventPtr *eventP; + int reps; + Boolean plus; + ActionPtr **actionsP; +{ + switch ((*eventP)->event.eventType) { + + case ButtonPress: + case KeyPress: + if (plus) RepeatDownPlus(eventP, reps, actionsP); + else RepeatDown(eventP, reps, actionsP); + break; + + case ButtonRelease: + case KeyRelease: + if (plus) RepeatUpPlus(eventP, reps, actionsP); + else RepeatUp(eventP, reps, actionsP); + break; + + default: + if (plus) RepeatOtherPlus(eventP, reps, actionsP); + else RepeatOther(eventP, reps, actionsP); + } +} + +static String ParseRepeat(str, reps, plus, error) + register String str; + int *reps; + Boolean *plus, *error; +{ + + /*** Parse the repetitions, for double click etc... ***/ + if (*str != '(' || !(isdigit(str[1]) || str[1] == '+' || str[1] == ')')) + return str; + str++; + if (isdigit(*str)) { + String start = str; + char repStr[7]; + int len; + + ScanNumeric(str); + len = (str - start); + if (len < sizeof repStr) { + (void) memmove(repStr, start, len); + repStr[len] = '\0'; + *reps = StrToNum(repStr); + } else { + Syntax("Repeat count too large.", ""); + *error = TRUE; + return str; + } + } + if (*reps == 0) { + Syntax("Missing repeat count.",""); + *error = True; + return str; + } + + if (*str == '+') { + *plus = TRUE; + str++; + } + if (*str == ')') + str++; + else { + Syntax("Missing ')'.",""); + *error = TRUE; + } + + return str; +} + +/*********************************************************************** + * ParseEventSeq + * Parses the left hand side of a translation table production + * up to, and consuming the ":". + * Takes a pointer to a char* (where to start parsing) and returns an + * event seq (in a passed in variable), having updated the String + **********************************************************************/ + +static String ParseEventSeq(str, eventSeqP, actionsP,error) + register String str; + EventSeqPtr *eventSeqP; + ActionPtr **actionsP; + Boolean *error; +{ + EventSeqPtr *nextEvent = eventSeqP; + + *eventSeqP = NULL; + + while ( *str != '\0' && *str != '\n') { + static Event nullEvent = + {0, 0,0L, 0, 0L, 0L,_XtRegularMatch,FALSE}; + EventPtr event; + + ScanWhitespace(str); + + if (*str == '"') { + str++; + while (*str != '"' && *str != '\0' && *str != '\n') { + event = XtNew(EventRec); + event->event = nullEvent; + event->state = /* (StatePtr) -1 */ NULL; + event->next = NULL; + event->actions = NULL; + str = ParseQuotedStringEvent(str, event,error); + if (*error) { + XtWarningMsg(XtNtranslationParseError, "nonLatin1", + XtCXtToolkitError, + "... probably due to non-Latin1 character in quoted string", + (String*)NULL, (Cardinal*)NULL); + return PanicModeRecovery(str); + } + *nextEvent = event; + *actionsP = &event->actions; + nextEvent = &event->next; + } + if (*str != '"') { + Syntax("Missing '\"'.",""); + *error = TRUE; + return PanicModeRecovery(str); + } + else str++; + } else { + int reps = 0; + Boolean plus = FALSE; + + event = XtNew(EventRec); + event->event = nullEvent; + event->state = /* (StatePtr) -1 */ NULL; + event->next = NULL; + event->actions = NULL; + + str = ParseEvent(str, event, &reps, &plus, error); + if (*error) return str; + *nextEvent = event; + *actionsP = &event->actions; + if (reps > 1 || plus) + RepeatEvent(&event, reps, plus, actionsP); + nextEvent = &event->next; + } + ScanWhitespace(str); + if (*str == ':') break; + else { + if (*str != ',') { + Syntax("',' or ':' expected while parsing event sequence.",""); + *error = TRUE; + return PanicModeRecovery(str); + } else str++; + } + } + + if (*str != ':') { + Syntax("Missing ':'after event sequence.",""); + *error = TRUE; + return PanicModeRecovery(str); + } else str++; + + return str; +} + + +static String ParseActionProc(str, actionProcNameP, error) + register String str; + XrmQuark *actionProcNameP; + Boolean *error; +{ + register String start = str; + char procName[200]; + + str = ScanIdent(str); + if (str-start >= 199) { + Syntax("Action procedure name is longer than 199 chars",""); + *error = TRUE; + return str; + } + (void) memmove(procName, start, str-start); + procName[str-start] = '\0'; + *actionProcNameP = XrmStringToQuark( procName ); + return str; +} + + +static String ParseString(str, strP) + register String str; + String *strP; +{ + register String start; + + if (*str == '"') { + register unsigned prev_len, len; + str++; + start = str; + *strP = NULL; + prev_len = 0; + + while (*str != '"' && *str != '\0') { + /* \" produces double quote embedded in a quoted parameter + * \\" produces backslash as last character of a quoted parameter + */ + if (*str == '\\' && + (*(str+1) == '"' || (*(str+1) == '\\' && *(str+2) == '"'))) { + len = prev_len + (str-start+2); + *strP = XtRealloc(*strP, len); + (void) memmove(*strP + prev_len, start, str-start); + prev_len = len-1; + str++; + (*strP)[prev_len-1] = *str; + (*strP)[prev_len] = '\0'; + start = str+1; + } + str++; + } + len = prev_len + (str-start+1); + *strP = XtRealloc(*strP, len); + (void) memmove( *strP + prev_len, start, str-start); + (*strP)[len-1] = '\0'; + if (*str == '"') str++; else + XtWarningMsg(XtNtranslationParseError,"parseString", + XtCXtToolkitError,"Missing '\"'.", + (String *)NULL, (Cardinal *)NULL); + } else { + /* scan non-quoted string, stop on whitespace, ',' or ')' */ + start = str; + while (*str != ' ' + && *str != '\t' + && *str != ',' + && *str != ')' + && *str != '\n' + && *str != '\0') str++; + *strP = __XtMalloc((unsigned)(str-start+1)); + (void) memmove(*strP, start, str-start); + (*strP)[str-start] = '\0'; + } + return str; +} + + +static String ParseParamSeq(str, paramSeqP, paramNumP) + register String str; + String **paramSeqP; + Cardinal *paramNumP; +{ + typedef struct _ParamRec *ParamPtr; + typedef struct _ParamRec { + ParamPtr next; + String param; + } ParamRec; + + ParamPtr params = NULL; + register Cardinal num_params = 0; + register Cardinal i; + + ScanWhitespace(str); + while (*str != ')' && *str != '\0' && *str != '\n') { + String newStr; + str = ParseString(str, &newStr); + if (newStr != NULL) { + ParamPtr temp = (ParamRec*) + ALLOCATE_LOCAL( (unsigned)sizeof(ParamRec) ); + if (temp == NULL) _XtAllocError (NULL); + + num_params++; + temp->next = params; + params = temp; + temp->param = newStr; + ScanWhitespace(str); + if (*str == ',') { + str++; + ScanWhitespace(str); + } + } + } + + if (num_params != 0) { + String *paramP = (String *) + __XtMalloc( (unsigned)(num_params+1) * sizeof(String) ); + *paramSeqP = paramP; + *paramNumP = num_params; + paramP += num_params; /* list is LIFO right now */ + *paramP-- = NULL; + for (i=0; i < num_params; i++) { + ParamPtr next = params->next; + *paramP-- = params->param; + DEALLOCATE_LOCAL( (char *)params ); + params = next; + } + } else { + *paramSeqP = NULL; + *paramNumP = 0; + } + + return str; +} + +static String ParseAction(str, actionP, quarkP, error) + String str; + ActionPtr actionP; + XrmQuark* quarkP; + Boolean* error; +{ + str = ParseActionProc(str, quarkP, error); + if (*error) return str; + + if (*str == '(') { + str++; + str = ParseParamSeq(str, &actionP->params, &actionP->num_params); + } else { + Syntax("Missing '(' while parsing action sequence",""); + *error = TRUE; + return str; + } + if (*str == ')') str++; + else{ + Syntax("Missing ')' while parsing action sequence",""); + *error = TRUE; + return str; + } + return str; +} + + +static String ParseActionSeq(parseTree, str, actionsP, error) + TMParseStateTree parseTree; + String str; + ActionPtr *actionsP; + Boolean *error; +{ + ActionPtr *nextActionP = actionsP; + + *actionsP = NULL; + while (*str != '\0' && *str != '\n') { + register ActionPtr action; + XrmQuark quark; + + action = XtNew(ActionRec); + action->params = NULL; + action->num_params = 0; + action->next = NULL; + + str = ParseAction(str, action, &quark, error); + if (*error) return PanicModeRecovery(str); + + action->idx = _XtGetQuarkIndex(parseTree, quark); + ScanWhitespace(str); + *nextActionP = action; + nextActionP = &action->next; + } + if (*str == '\n') str++; + ScanWhitespace(str); + return str; +} + + +static void ShowProduction(currentProduction) + String currentProduction; +{ + Cardinal num_params = 1; + String params[1]; + int len; + char *eol, *production, productionbuf[500]; + + eol = strchr(currentProduction, '\n'); + if (eol) len = eol - currentProduction; + else len = strlen (currentProduction); + production = XtStackAlloc (len + 1, productionbuf); + if (production == NULL) _XtAllocError (NULL); + (void) memmove(production, currentProduction, len); + production[len] = '\0'; + + params[0] = production; + XtWarningMsg(XtNtranslationParseError, "showLine", XtCXtToolkitError, + "... found while parsing '%s'", params, &num_params); + + XtStackFree (production, productionbuf); +} + +/*********************************************************************** + * ParseTranslationTableProduction + * Parses one line of event bindings. + ***********************************************************************/ + +static String ParseTranslationTableProduction(parseTree, str, error) + TMParseStateTree parseTree; + register String str; + Boolean* error; +{ + EventSeqPtr eventSeq = NULL; + ActionPtr *actionsP; + String production = str; + + str = ParseEventSeq(str, &eventSeq, &actionsP,error); + if (*error == TRUE) { + ShowProduction(production); + FreeEventSeq(eventSeq); + return (str); + } + ScanWhitespace(str); + str = ParseActionSeq(parseTree, str, actionsP, error); + if (*error == TRUE) { + ShowProduction(production); + FreeEventSeq(eventSeq); + return (str); + } + + _XtAddEventSeqToStateTree(eventSeq, parseTree); + FreeEventSeq(eventSeq); + return (str); +} + +static String CheckForPoundSign(str, defaultOp, actualOpRtn) + String str; + _XtTranslateOp defaultOp; + _XtTranslateOp *actualOpRtn; +{ + String start; + char operation[20]; + _XtTranslateOp opType; + + opType = defaultOp; + ScanWhitespace(str); + if (*str == '#') { + int len; + str++; + start = str; + str = ScanIdent(str); + len = MIN(19, str-start); + (void) memmove(operation, start, len); + operation[len] = '\0'; + if (!strcmp(operation,"replace")) + opType = XtTableReplace; + else if (!strcmp(operation,"augment")) + opType = XtTableAugment; + else if (!strcmp(operation,"override")) + opType = XtTableOverride; + ScanWhitespace(str); + if (*str == '\n') { + str++; + ScanWhitespace(str); + } + } + *actualOpRtn = opType; + return str; +} + +static XtTranslations ParseTranslationTable(source, isAccelerator, defaultOp, error) + String source; + Boolean isAccelerator; + _XtTranslateOp defaultOp; + Boolean* error; +{ + XtTranslations xlations; + TMStateTree stateTrees[8]; + TMParseStateTreeRec parseTreeRec, *parseTree = &parseTreeRec; + XrmQuark stackQuarks[200]; + TMBranchHeadRec stackBranchHeads[200]; + StatePtr stackComplexBranchHeads[200]; + _XtTranslateOp actualOp; + + if (source == NULL) + return (XtTranslations)NULL; + + source = CheckForPoundSign(source, defaultOp, &actualOp); + if (isAccelerator && actualOp == XtTableReplace) + actualOp = defaultOp; + + parseTree->isSimple = TRUE; + parseTree->mappingNotifyInterest = FALSE; + parseTree->isAccelerator = isAccelerator; + parseTree->isStackBranchHeads = + parseTree->isStackQuarks = + parseTree->isStackComplexBranchHeads = TRUE; + + parseTree->numQuarks = + parseTree->numBranchHeads = + parseTree->numComplexBranchHeads = 0; + + parseTree->quarkTblSize = + parseTree->branchHeadTblSize = + parseTree->complexBranchHeadTblSize = 200; + + parseTree->quarkTbl = stackQuarks; + parseTree->branchHeadTbl = stackBranchHeads; + parseTree->complexBranchHeadTbl = stackComplexBranchHeads; + + while (source != NULL && *source != '\0') { + source = ParseTranslationTableProduction(parseTree, source, error); + if (*error == TRUE) break; + } + stateTrees[0] = _XtParseTreeToStateTree(parseTree); + + if (!parseTree->isStackQuarks) + XtFree((char *)parseTree->quarkTbl); + if (!parseTree->isStackBranchHeads) + XtFree((char *)parseTree->branchHeadTbl); + if (!parseTree->isStackComplexBranchHeads) + XtFree((char *)parseTree->complexBranchHeadTbl); + + xlations = _XtCreateXlations(stateTrees, 1, NULL, NULL); + xlations->operation = actualOp; + +#ifdef notdef + XtFree(stateTrees); +#endif /* notdef */ + return xlations; +} + +/*** public procedures ***/ + +/*ARGSUSED*/ +Boolean XtCvtStringToAcceleratorTable(dpy, args, num_args, from, to, closure) + Display* dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr from,to; + XtPointer *closure; +{ + String str; + Boolean error = FALSE; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "wrongParameters","cvtStringToAcceleratorTable",XtCXtToolkitError, + "String to AcceleratorTable conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + str = (String)(from->addr); + if (str == NULL) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "badParameters","cvtStringToAcceleratorTable",XtCXtToolkitError, + "String to AcceleratorTable conversion needs string", + (String *)NULL, (Cardinal *)NULL); + return FALSE; + } + if (to->addr != NULL) { + if (to->size < sizeof(XtAccelerators)) { + to->size = sizeof(XtAccelerators); + return FALSE; + } + *(XtAccelerators*)to->addr = + (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, &error); + } + else { + static XtAccelerators staticStateTable; + staticStateTable = + (XtAccelerators) ParseTranslationTable(str, TRUE, XtTableAugment, &error); + to->addr = (XPointer) &staticStateTable; + to->size = sizeof(XtAccelerators); + } + if (error == TRUE) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "parseError","cvtStringToAcceleratorTable",XtCXtToolkitError, + "String to AcceleratorTable conversion encountered errors", + (String *)NULL, (Cardinal *)NULL); + return (error != TRUE); +} + + +/*ARGSUSED*/ +Boolean +XtCvtStringToTranslationTable(dpy, args, num_args, from, to, closure_ret) + Display *dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr from,to; + XtPointer *closure_ret; +{ + String str; + Boolean error = FALSE; + + if (*num_args != 0) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "wrongParameters","cvtStringToTranslationTable",XtCXtToolkitError, + "String to TranslationTable conversion needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + str = (String)(from->addr); + if (str == NULL) { + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "badParameters","cvtStringToTranslation",XtCXtToolkitError, + "String to TranslationTable conversion needs string", + (String *)NULL, (Cardinal *)NULL); + return FALSE; + } + if (to->addr != NULL) { + if (to->size < sizeof(XtTranslations)) { + to->size = sizeof(XtTranslations); + return FALSE; + } + *(XtTranslations*)to->addr = + ParseTranslationTable(str, FALSE, XtTableReplace, &error); + } + else { + static XtTranslations staticStateTable; + staticStateTable = + ParseTranslationTable(str, FALSE, XtTableReplace, &error); + to->addr = (XPointer) &staticStateTable; + to->size = sizeof(XtTranslations); + } + if (error == TRUE) + XtAppWarningMsg(XtDisplayToApplicationContext(dpy), + "parseError","cvtStringToTranslationTable",XtCXtToolkitError, + "String to TranslationTable conversion encountered errors", + (String *)NULL, (Cardinal *)NULL); + return (error != TRUE); +} + + +/* + * Parses a user's or applications translation table + */ +#if NeedFunctionPrototypes +XtAccelerators XtParseAcceleratorTable( + _Xconst char* source + ) +#else +XtAccelerators XtParseAcceleratorTable(source) + String source; +#endif +{ + Boolean error = FALSE; + XtAccelerators ret = + (XtAccelerators) ParseTranslationTable (source, TRUE, XtTableAugment, &error); + if (error == TRUE) + XtWarningMsg ("parseError", "cvtStringToAcceleratorTable", + XtCXtToolkitError, + "String to AcceleratorTable conversion encountered errors", + (String *)NULL, (Cardinal *)NULL); + return ret; +} + +#if NeedFunctionPrototypes +XtTranslations XtParseTranslationTable( + _Xconst char* source + ) +#else +XtTranslations XtParseTranslationTable(source) + String source; +#endif +{ + Boolean error = FALSE; + XtTranslations ret = ParseTranslationTable(source, FALSE, XtTableReplace, &error); + if (error == TRUE) + XtWarningMsg ("parseError", + "cvtStringToTranslationTable", XtCXtToolkitError, + "String to TranslationTable conversion encountered errors", + (String *)NULL, (Cardinal *)NULL); + return ret; +} + +void _XtTranslateInitialize() +{ + LOCK_PROCESS; + if (initialized) { + XtWarningMsg("translationError","xtTranslateInitialize", + XtCXtToolkitError,"Initializing Translation manager twice.", + (String *)NULL, (Cardinal *)NULL); + UNLOCK_PROCESS; + return; + } + + initialized = TRUE; + UNLOCK_PROCESS; + QMeta = XrmPermStringToQuark("Meta"); + QCtrl = XrmPermStringToQuark("Ctrl"); + QNone = XrmPermStringToQuark("None"); + QAny = XrmPermStringToQuark("Any"); + + Compile_XtEventTable( events, XtNumber(events) ); + Compile_XtModifierTable( modifiers, XtNumber(modifiers) ); + CompileNameValueTable( buttonNames ); + CompileNameValueTable( notifyModes ); + CompileNameValueTable( motionDetails ); +#if 0 + CompileNameValueTable( notifyDetail ); + CompileNameValueTable( visibilityNotify ); + CompileNameValueTable( circulation ); + CompileNameValueTable( propertyChanged ); +#endif + CompileNameValueTable( mappingNotify ); +} + +void _XtAddTMConverters(table) + ConverterTable table; +{ + _XtTableAddConverter(table, + _XtQString, + XrmPermStringToQuark(XtRTranslationTable), + XtCvtStringToTranslationTable, (XtConvertArgList) NULL, + (Cardinal)0, True, CACHED, _XtFreeTranslations, True); + _XtTableAddConverter(table, _XtQString, + XrmPermStringToQuark(XtRAcceleratorTable), + XtCvtStringToAcceleratorTable, (XtConvertArgList) NULL, + (Cardinal)0, True, CACHED, _XtFreeTranslations, True); + _XtTableAddConverter(table, + XrmPermStringToQuark( _XtRStateTablePair ), + XrmPermStringToQuark(XtRTranslationTable), + _XtCvtMergeTranslations, (XtConvertArgList) NULL, + (Cardinal)0, True, CACHED, _XtFreeTranslations, True); +} diff --git a/src/TMprint.c b/src/TMprint.c new file mode 100644 index 0000000..24b0d2e --- /dev/null +++ b/src/TMprint.c @@ -0,0 +1,889 @@ +/* $Xorg: TMprint.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/*LINTLIBRARY*/ +#include "IntrinsicI.h" +#include <stdio.h> + +typedef struct _TMStringBufRec{ + String start; + String current; + Cardinal max; +}TMStringBufRec, *TMStringBuf; + + +#define STR_THRESHOLD 25 +#define STR_INCAMOUNT 100 +#define CHECK_STR_OVERFLOW(sb) \ +if (sb->current - sb->start > (int)sb->max - STR_THRESHOLD) \ +{ String old = sb->start; \ + sb->start = XtRealloc(old, (Cardinal)(sb->max += STR_INCAMOUNT)); \ + sb->current = sb->current - old + sb->start; \ +} + +#define ExpandForChars(sb, nchars ) \ + if (sb->current - sb->start > sb->max - STR_THRESHOLD - nchars) { \ + String old = sb->start; \ + sb->start = XtRealloc(old, \ + (Cardinal)(sb->max += STR_INCAMOUNT + nchars)); \ + sb->current = sb->current - old + sb->start; \ + } + +#define ExpandToFit(sb, more) \ +{ \ + int l = strlen(more); \ + ExpandForChars(sb, l); \ + } + +static void PrintModifiers(sb, mask, mod) + TMStringBuf sb; + unsigned long mask, mod; +{ + Boolean notfirst = False; + CHECK_STR_OVERFLOW(sb); + + if (mask == ~0L && mod == 0) { + *sb->current++ = '!'; + *sb->current = '\0'; + return; + } + +#define PRINTMOD(modmask,modstring) \ + if (mask & modmask) { \ + if (! (mod & modmask)) { \ + *sb->current++ = '~'; \ + notfirst = True; \ + } \ + else if (notfirst) \ + *sb->current++ = ' '; \ + else notfirst = True; \ + strcpy(sb->current, modstring); \ + sb->current += strlen(sb->current); \ + } + + PRINTMOD(ShiftMask, "Shift"); + PRINTMOD(ControlMask, "Ctrl"); /* name is not CtrlMask... */ + PRINTMOD(LockMask, "Lock"); + PRINTMOD(Mod1Mask, "Mod1"); + CHECK_STR_OVERFLOW(sb); + PRINTMOD(Mod2Mask, "Mod2"); + PRINTMOD(Mod3Mask, "Mod3"); + PRINTMOD(Mod4Mask, "Mod4"); + PRINTMOD(Mod5Mask, "Mod5"); + CHECK_STR_OVERFLOW(sb); + PRINTMOD(Button1Mask, "Button1"); + PRINTMOD(Button2Mask, "Button2"); + PRINTMOD(Button3Mask, "Button3"); + CHECK_STR_OVERFLOW(sb); + PRINTMOD(Button4Mask, "Button4"); + PRINTMOD(Button5Mask, "Button5"); + +#undef PRINTMOD +} + +static void PrintEventType(sb, event) + TMStringBuf sb; + unsigned long event; +{ + CHECK_STR_OVERFLOW(sb); + switch (event) { +#define PRINTEVENT(event, name) case event: (void) strcpy(sb->current, name); break; + PRINTEVENT(KeyPress, "<KeyPress>") + PRINTEVENT(KeyRelease, "<KeyRelease>") + PRINTEVENT(ButtonPress, "<ButtonPress>") + PRINTEVENT(ButtonRelease, "<ButtonRelease>") + PRINTEVENT(MotionNotify, "<MotionNotify>") + PRINTEVENT(EnterNotify, "<EnterNotify>") + PRINTEVENT(LeaveNotify, "<LeaveNotify>") + PRINTEVENT(FocusIn, "<FocusIn>") + PRINTEVENT(FocusOut, "<FocusOut>") + PRINTEVENT(KeymapNotify, "<KeymapNotify>") + PRINTEVENT(Expose, "<Expose>") + PRINTEVENT(GraphicsExpose, "<GraphicsExpose>") + PRINTEVENT(NoExpose, "<NoExpose>") + PRINTEVENT(VisibilityNotify, "<VisibilityNotify>") + PRINTEVENT(CreateNotify, "<CreateNotify>") + PRINTEVENT(DestroyNotify, "<DestroyNotify>") + PRINTEVENT(UnmapNotify, "<UnmapNotify>") + PRINTEVENT(MapNotify, "<MapNotify>") + PRINTEVENT(MapRequest, "<MapRequest>") + PRINTEVENT(ReparentNotify, "<ReparentNotify>") + PRINTEVENT(ConfigureNotify, "<ConfigureNotify>") + PRINTEVENT(ConfigureRequest, "<ConfigureRequest>") + PRINTEVENT(GravityNotify, "<GravityNotify>") + PRINTEVENT(ResizeRequest, "<ResizeRequest>") + PRINTEVENT(CirculateNotify, "<CirculateNotify>") + PRINTEVENT(CirculateRequest, "<CirculateRequest>") + PRINTEVENT(PropertyNotify, "<PropertyNotify>") + PRINTEVENT(SelectionClear, "<SelectionClear>") + PRINTEVENT(SelectionRequest, "<SelectionRequest>") + PRINTEVENT(SelectionNotify, "<SelectionNotify>") + PRINTEVENT(ColormapNotify, "<ColormapNotify>") + PRINTEVENT(ClientMessage, "<ClientMessage>") + case _XtEventTimerEventType: + (void) strcpy(sb->current,"<EventTimer>"); + break; + default: + (void) sprintf(sb->current, "<0x%x>", (int) event); +#undef PRINTEVENT + } + sb->current += strlen(sb->current); +} + +static void PrintCode(sb, mask, code) + TMStringBuf sb; + unsigned long mask, code; +{ + CHECK_STR_OVERFLOW(sb); + if (mask != 0) { + if (mask != (unsigned long)~0L) + (void) sprintf(sb->current, "0x%lx:0x%lx", mask, code); + else (void) sprintf(sb->current, /*"0x%lx"*/ "%d", code); + sb->current += strlen(sb->current); + } +} + +static void PrintKeysym(sb, keysym) + TMStringBuf sb; + KeySym keysym; +{ + String keysymName; + + if (keysym == 0) return; + + CHECK_STR_OVERFLOW(sb); + keysymName = XKeysymToString(keysym); + if (keysymName == NULL) + PrintCode(sb,(unsigned long)~0L,(unsigned long)keysym); + else { + ExpandToFit(sb, keysymName); + strcpy(sb->current, keysymName); + sb->current += strlen(sb->current); + } +} + +static void PrintAtom(sb, dpy, atom) + TMStringBuf sb; + Display *dpy; + Atom atom; +{ + String atomName; + + if (atom == 0) return; + + atomName = (dpy ? XGetAtomName(dpy, atom) : NULL); + + if (! atomName) + PrintCode(sb,(unsigned long)~0L,(unsigned long)atom); + else { + ExpandToFit( sb, atomName ); + strcpy(sb->current, atomName); + sb->current += strlen(sb->current); + XFree(atomName); + } +} + +static void PrintLateModifiers(sb, lateModifiers) + TMStringBuf sb; + LateBindingsPtr lateModifiers; +{ + for (; lateModifiers->keysym; lateModifiers++) { + CHECK_STR_OVERFLOW(sb); + if (lateModifiers->knot) { + *sb->current++ = '~'; + } else { + *sb->current++ = ' '; + } + strcpy(sb->current, XKeysymToString(lateModifiers->keysym)); + sb->current += strlen(sb->current); + if (lateModifiers->pair) { + *(sb->current -= 2) = '\0'; /* strip "_L" */ + lateModifiers++; /* skip _R keysym */ + } + } +} + +static void PrintEvent(sb, typeMatch, modMatch, dpy) + TMStringBuf sb; + register TMTypeMatch typeMatch; + register TMModifierMatch modMatch; + Display *dpy; +{ + if (modMatch->standard) *sb->current++ = ':'; + + PrintModifiers(sb, modMatch->modifierMask, modMatch->modifiers); + if (modMatch->lateModifiers != NULL) + PrintLateModifiers(sb, modMatch->lateModifiers); + PrintEventType(sb, typeMatch->eventType); + switch (typeMatch->eventType) { + case KeyPress: + case KeyRelease: + PrintKeysym(sb, (KeySym)typeMatch->eventCode); + break; + + case PropertyNotify: + case SelectionClear: + case SelectionRequest: + case SelectionNotify: + case ClientMessage: + PrintAtom(sb, dpy, (Atom)typeMatch->eventCode); + break; + + default: + PrintCode(sb, typeMatch->eventCodeMask, typeMatch->eventCode); + } +} + +static void PrintParams(sb, params, num_params) + TMStringBuf sb; + String *params; + Cardinal num_params; +{ + register Cardinal i; + for (i = 0; i<num_params; i++) { + ExpandToFit( sb, params[i] ); + if (i != 0) { + *sb->current++ = ','; + *sb->current++ = ' '; + } + *sb->current++ = '"'; + strcpy(sb->current, params[i]); + sb->current += strlen(sb->current); + *sb->current++ = '"'; + } + *sb->current = '\0'; +} + +static void PrintActions(sb, actions, quarkTbl, accelWidget) + TMStringBuf sb; + register ActionPtr actions; + XrmQuark *quarkTbl; + Widget accelWidget; +{ + while (actions != NULL) { + String proc; + + *sb->current++ = ' '; + + if (accelWidget) { + /* accelerator */ + String name = XtName(accelWidget); + int nameLen = strlen(name); + ExpandForChars(sb, nameLen ); + XtMemmove(sb->current, name, nameLen ); + sb->current += nameLen; + *sb->current++ = '`'; + } + proc = XrmQuarkToString(quarkTbl[actions->idx]); + ExpandToFit( sb, proc ); + strcpy(sb->current, proc); + sb->current += strlen(proc); + *sb->current++ = '('; + PrintParams(sb, actions->params, actions->num_params); + *sb->current++ = ')'; + actions = actions->next; + } + *sb->current = '\0'; +} + +static Boolean LookAheadForCycleOrMulticlick(state, state_return, countP, + nextLevelP) + register StatePtr state; + StatePtr *state_return; /* state to print, usually startState */ + int *countP; + StatePtr *nextLevelP; +{ + int repeatCount = 0; + StatePtr startState = state; + Boolean isCycle = startState->isCycleEnd; + TMTypeMatch sTypeMatch; + TMModifierMatch sModMatch; + + LOCK_PROCESS; + sTypeMatch = TMGetTypeMatch(startState->typeIndex); + sModMatch = TMGetModifierMatch(startState->modIndex); + + *state_return = startState; + + for (state = state->nextLevel; state != NULL; state = state->nextLevel) { + TMTypeMatch typeMatch = TMGetTypeMatch(state->typeIndex); + TMModifierMatch modMatch = TMGetModifierMatch(state->modIndex); + + /* try to pick up the correct state with actions, to be printed */ + /* This is to accommodate <ButtonUp>(2+), for example */ + if (state->isCycleStart) + *state_return = state; + + if (state->isCycleEnd) { + *countP = repeatCount; + UNLOCK_PROCESS; + return True; + } + if ((startState->typeIndex == state->typeIndex) && + (startState->modIndex == state->modIndex)) { + repeatCount++; + *nextLevelP = state; + } + else if (typeMatch->eventType == _XtEventTimerEventType) + continue; + else /* not same event as starting event and not timer */ { + unsigned int type = sTypeMatch->eventType; + unsigned int t = typeMatch->eventType; + if ( (type == ButtonPress && t != ButtonRelease) + || (type == ButtonRelease && t != ButtonPress) + || (type == KeyPress && t != KeyRelease) + || (type == KeyRelease && t != KeyPress) + || typeMatch->eventCode != sTypeMatch->eventCode + || modMatch->modifiers != sModMatch->modifiers + || modMatch->modifierMask != sModMatch->modifierMask + || modMatch->lateModifiers != sModMatch->lateModifiers + || typeMatch->eventCodeMask != sTypeMatch->eventCodeMask + || typeMatch->matchEvent != sTypeMatch->matchEvent + || modMatch->standard != sModMatch->standard) + /* not inverse of starting event, either */ + break; + } + } + *countP = repeatCount; + UNLOCK_PROCESS; + return isCycle; +} + +static void PrintComplexState(sb, includeRHS, state, stateTree, accelWidget, dpy) + TMStringBuf sb; + Boolean includeRHS; + StatePtr state; + TMStateTree stateTree; + Widget accelWidget; + Display *dpy; +{ + int clickCount = 0; + Boolean cycle; + StatePtr nextLevel = NULL; + StatePtr triggerState = NULL; + + /* print the current state */ + if (! state) return; + LOCK_PROCESS; + cycle = LookAheadForCycleOrMulticlick(state, &triggerState, &clickCount, + &nextLevel); + + PrintEvent(sb, TMGetTypeMatch(triggerState->typeIndex), + TMGetModifierMatch(triggerState->modIndex), dpy); + + if (cycle || clickCount) { + if (clickCount) + sprintf(sb->current, "(%d%s)", clickCount+1, cycle ? "+" : ""); + else + (void) strncpy(sb->current, "(+)", 4); + sb->current += strlen(sb->current); + if (! state->actions && nextLevel) + state = nextLevel; + while (! state->actions && ! state->isCycleEnd) + state = state->nextLevel; /* should be trigger state */ + } + + if (state->actions) { + if (includeRHS) { + CHECK_STR_OVERFLOW(sb); + *sb->current++ = ':'; + PrintActions(sb, + state->actions, + ((TMSimpleStateTree)stateTree)->quarkTbl, + accelWidget); + *sb->current++ = '\n'; + } + } + else { + if (state->nextLevel && !cycle && !clickCount) + *sb->current++ = ','; + else { + /* no actions are attached to this production */ + *sb->current++ = ':'; + *sb->current++ = '\n'; + } + } + *sb->current = '\0'; + + /* print succeeding states */ + if (state->nextLevel && !cycle && !clickCount) + PrintComplexState(sb, includeRHS, state->nextLevel, + stateTree, accelWidget, dpy); + UNLOCK_PROCESS; +} + +typedef struct{ + TMShortCard tIndex; + TMShortCard bIndex; +}PrintRec, *Print; + +static int FindNextMatch(printData, numPrints, xlations, + branchHead, nextLevel, startIndex) + PrintRec *printData; + TMShortCard numPrints; + XtTranslations xlations; + TMBranchHead branchHead; + StatePtr nextLevel; + TMShortCard startIndex; +{ + TMShortCard i; + TMComplexStateTree stateTree; + StatePtr currState, candState; + Boolean noMatch = True; + TMBranchHead prBranchHead; + + for (i = startIndex; noMatch && i < numPrints; i++) { + stateTree = (TMComplexStateTree) + xlations->stateTreeTbl[printData[i].tIndex]; + prBranchHead = + &(stateTree->branchHeadTbl[printData[i].bIndex]); + + if ((prBranchHead->typeIndex == branchHead->typeIndex) && + (prBranchHead->modIndex == branchHead->modIndex)) { + if (prBranchHead->isSimple) { + if (!nextLevel) + return i; + } + else { + currState = TMComplexBranchHead(stateTree, prBranchHead); + currState = currState->nextLevel; + candState = nextLevel; + for (; + ((currState && !currState->isCycleEnd) && + (candState && !candState->isCycleEnd)); + currState = currState->nextLevel, + candState = candState->nextLevel) { + if ((currState->typeIndex != candState->typeIndex) || + (currState->modIndex != candState->modIndex)) + break; + } + if (candState == currState) { + return i; + } + } + } + } + return TM_NO_MATCH; +} + +static void ProcessLaterMatches(printData,xlations,tIndex,bIndex,numPrintsRtn) + PrintRec *printData; + XtTranslations xlations; + TMShortCard tIndex; + int bIndex; + TMShortCard *numPrintsRtn; +{ + TMComplexStateTree stateTree; + int i, j; + TMBranchHead branchHead, matchBranch = NULL; + + for (i = tIndex; i < (int)xlations->numStateTrees; i++) { + stateTree = (TMComplexStateTree)xlations->stateTreeTbl[i]; + if (i == tIndex) { + matchBranch = &stateTree->branchHeadTbl[bIndex]; + j = bIndex+1; + } + else j = 0; + for (branchHead = &stateTree->branchHeadTbl[j]; + j < (int)stateTree->numBranchHeads; + j++, branchHead++) { + if ((branchHead->typeIndex == matchBranch->typeIndex) && + (branchHead->modIndex == matchBranch->modIndex)) { + StatePtr state; + if (!branchHead->isSimple) + state = TMComplexBranchHead(stateTree, branchHead); + else + state = NULL; + if ((!branchHead->isSimple || branchHead->hasActions) && + (FindNextMatch(printData, + *numPrintsRtn, + xlations, + branchHead, + (state ? state->nextLevel : NULL), + 0) == TM_NO_MATCH)) { + printData[*numPrintsRtn].tIndex = i; + printData[*numPrintsRtn].bIndex = j; + (*numPrintsRtn)++; + } + } + } + } +} + +static void ProcessStateTree(printData, xlations, tIndex, numPrintsRtn) + PrintRec *printData; + XtTranslations xlations; + TMShortCard tIndex; + TMShortCard *numPrintsRtn; +{ + TMComplexStateTree stateTree; + int i; + TMBranchHead branchHead; + + stateTree = (TMComplexStateTree)xlations->stateTreeTbl[tIndex]; + + for (i = 0, branchHead = stateTree->branchHeadTbl; + i < (int)stateTree->numBranchHeads; + i++, branchHead++) { + StatePtr state; + if (!branchHead->isSimple) + state = TMComplexBranchHead(stateTree, branchHead); + else + state = NULL; + if (FindNextMatch(printData, *numPrintsRtn, xlations, branchHead, + (state ? state->nextLevel : NULL), 0) + == TM_NO_MATCH) { + if (!branchHead->isSimple || branchHead->hasActions) { + printData[*numPrintsRtn].tIndex = tIndex; + printData[*numPrintsRtn].bIndex = i; + (*numPrintsRtn)++; + } + LOCK_PROCESS; + if (_XtGlobalTM.newMatchSemantics == False) + ProcessLaterMatches(printData, + xlations, + tIndex, + i, + numPrintsRtn); + UNLOCK_PROCESS; + } + } +} + +static void PrintState(sb, tree, branchHead, includeRHS, accelWidget, dpy) + TMStringBuf sb; + TMStateTree tree; + TMBranchHead branchHead; + Boolean includeRHS; + Widget accelWidget; + Display *dpy; +{ + TMComplexStateTree stateTree = (TMComplexStateTree)tree; + LOCK_PROCESS; + if (branchHead->isSimple) { + PrintEvent(sb, + TMGetTypeMatch(branchHead->typeIndex), + TMGetModifierMatch(branchHead->modIndex), + dpy); + if (includeRHS) { + ActionRec actRec; + + CHECK_STR_OVERFLOW(sb); + *sb->current++ = ':'; + actRec.idx = TMBranchMore(branchHead); + actRec.num_params = 0; + actRec.params = NULL; + actRec.next = NULL; + PrintActions(sb, + &actRec, + stateTree->quarkTbl, + accelWidget); + *sb->current++ = '\n'; + } + else + *sb->current++ = ','; +#ifdef TRACE_TM + if (!branchHead->hasActions) + printf(" !! no actions !! "); +#endif + } + else { /* it's a complex branchHead */ + StatePtr state = TMComplexBranchHead(stateTree, branchHead); + PrintComplexState(sb, + includeRHS, + state, + tree, + accelWidget, + (Display *)NULL); + } + *sb->current = '\0'; + UNLOCK_PROCESS; +} + +#if NeedFunctionPrototypes +String _XtPrintXlations( + Widget w, + XtTranslations xlations, + Widget accelWidget, + _XtBoolean includeRHS + ) +#else +String _XtPrintXlations(w, xlations, accelWidget, includeRHS) + Widget w; + XtTranslations xlations; + Widget accelWidget; + Boolean includeRHS; +#endif +{ + register Cardinal i; +#define STACKPRINTSIZE 250 + PrintRec stackPrints[STACKPRINTSIZE]; + PrintRec *prints; + TMStringBufRec sbRec, *sb = &sbRec; + TMShortCard numPrints, maxPrints; +#ifdef TRACE_TM + TMBindData bindData = (TMBindData)w->core.tm.proc_table; + Boolean hasAccel = (accelWidget ? True : False); +#endif /* TRACE_TM */ + if (xlations == NULL) return NULL; + + sb->current = sb->start = __XtMalloc((Cardinal)1000); + sb->max = 1000; + maxPrints = 0; + for (i = 0; i < xlations->numStateTrees; i++) + maxPrints += + ((TMSimpleStateTree)(xlations->stateTreeTbl[i]))->numBranchHeads; + prints = (PrintRec *) + XtStackAlloc(maxPrints * sizeof(PrintRec), stackPrints); + + numPrints = 0; + for (i = 0; i < xlations->numStateTrees; i++) + ProcessStateTree(prints, xlations, i, &numPrints); + + for (i = 0; i < numPrints; i++) { + TMSimpleStateTree stateTree = (TMSimpleStateTree) + xlations->stateTreeTbl[prints[i].tIndex]; + TMBranchHead branchHead = + &stateTree->branchHeadTbl[prints[i].bIndex]; +#ifdef TRACE_TM + TMComplexBindProcs complexBindProcs; + + if (hasAccel == False) { + accelWidget = NULL; + if (bindData->simple.isComplex) { + complexBindProcs = TMGetComplexBindEntry(bindData, 0); + accelWidget = complexBindProcs[prints[i].tIndex].widget; + } + } +#endif /* TRACE_TM */ + PrintState(sb, (TMStateTree)stateTree, branchHead, + includeRHS, accelWidget, XtDisplay(w)); + } + XtStackFree((XtPointer)prints, (XtPointer)stackPrints); + return (sb->start); +} + + +#ifndef NO_MIT_HACKS +/*ARGSUSED*/ +void _XtDisplayTranslations(widget, event, params, num_params) + Widget widget; + XEvent *event; + String *params; + Cardinal *num_params; +{ + String xString; + + xString = _XtPrintXlations(widget, + widget->core.tm.translations, + NULL, + True); + printf("%s\n",xString); + XtFree(xString); +} + +/*ARGSUSED*/ +void _XtDisplayAccelerators(widget, event, params, num_params) + Widget widget; + XEvent *event; + String *params; + Cardinal *num_params; +{ + String xString; + + + xString = _XtPrintXlations(widget, + widget->core.accelerators, + NULL, + True); + printf("%s\n",xString); + XtFree(xString); +} + +/*ARGSUSED*/ +void _XtDisplayInstalledAccelerators(widget, event, params, num_params) + Widget widget; + XEvent *event; + String *params; + Cardinal *num_params; +{ + Widget eventWidget + = XtWindowToWidget(event->xany.display, event->xany.window); + register Cardinal i; + TMStringBufRec sbRec, *sb = &sbRec; + XtTranslations xlations; +#define STACKPRINTSIZE 250 + PrintRec stackPrints[STACKPRINTSIZE]; + PrintRec *prints; + TMShortCard numPrints, maxPrints; + TMBindData bindData = (TMBindData) eventWidget->core.tm.proc_table; + TMComplexBindProcs complexBindProcs; + + if ((eventWidget == NULL) || + ((xlations = eventWidget->core.tm.translations) == NULL) || + (bindData->simple.isComplex == False)) + return; + + sb->current = sb->start = __XtMalloc((Cardinal)1000); + sb->start[0] = '\0'; + sb->max = 1000; + maxPrints = 0; + for (i = 0; i < xlations->numStateTrees; i++) + maxPrints += + ((TMSimpleStateTree)xlations->stateTreeTbl[i])->numBranchHeads; + prints = (PrintRec *) + XtStackAlloc(maxPrints * sizeof(PrintRec), stackPrints); + + numPrints = 0; + + complexBindProcs = TMGetComplexBindEntry(bindData, 0); + for (i = 0; + i < xlations->numStateTrees; + i++, complexBindProcs++) { + if (complexBindProcs->widget) + { + ProcessStateTree(prints, xlations, i, &numPrints); + } + } + for (i = 0; i < numPrints; i++) { + TMSimpleStateTree stateTree = (TMSimpleStateTree) + xlations->stateTreeTbl[prints[i].tIndex]; + TMBranchHead branchHead = + &stateTree->branchHeadTbl[prints[i].bIndex]; + + complexBindProcs = TMGetComplexBindEntry(bindData, 0); + + PrintState(sb, (TMStateTree)stateTree, branchHead, True, + complexBindProcs[prints[i].tIndex].widget, + XtDisplay(widget)); + } + XtStackFree((XtPointer)prints, (XtPointer)stackPrints); + printf("%s\n", sb->start); + XtFree(sb->start); +} +#endif /*NO_MIT_HACKS*/ + +String _XtPrintActions(actions, quarkTbl) + register ActionRec *actions; + XrmQuark *quarkTbl; +{ + TMStringBufRec sbRec, *sb = &sbRec; + + sb->max = 1000; + sb->current = sb->start = __XtMalloc((Cardinal)1000); + PrintActions(sb, + actions, + quarkTbl, + (Widget)NULL); + return sb->start; +} + +String _XtPrintState(stateTree, branchHead) + TMStateTree stateTree; + TMBranchHead branchHead; +{ + TMStringBufRec sbRec, *sb = &sbRec; + + sb->current = sb->start = __XtMalloc((Cardinal)1000); + sb->max = 1000; + PrintState(sb, stateTree, branchHead, + True, (Widget)NULL, (Display *)NULL); + return sb->start; +} + + +String _XtPrintEventSeq(eventSeq, dpy) + register EventSeqPtr eventSeq; + Display *dpy; +{ + TMStringBufRec sbRec, *sb = &sbRec; + TMTypeMatch typeMatch; + TMModifierMatch modMatch; +#define MAXSEQS 100 + EventSeqPtr eventSeqs[MAXSEQS]; + TMShortCard i, j; + Boolean cycle = False; + + sb->current = sb->start = __XtMalloc((Cardinal)1000); + sb->max = 1000; + for (i = 0; + i < MAXSEQS && eventSeq != NULL && !cycle; + eventSeq = eventSeq->next, i++) + { + eventSeqs[i] = eventSeq; + for (j = 0; j < i && !cycle; j++) + if (eventSeqs[j] == eventSeq) + cycle = True; + } + LOCK_PROCESS; + for (j = 0; j < i; j++) { + typeMatch = + TMGetTypeMatch(_XtGetTypeIndex(&eventSeqs[j]->event)); + modMatch = + TMGetModifierMatch(_XtGetModifierIndex(&eventSeqs[j]->event)); + PrintEvent(sb, typeMatch, modMatch, dpy); + if (j < i) + *sb->current++ = ','; + } + UNLOCK_PROCESS; + return sb->start; +} + diff --git a/src/TMstate.c b/src/TMstate.c new file mode 100644 index 0000000..8bfb96e --- /dev/null +++ b/src/TMstate.c @@ -0,0 +1,2340 @@ +/* $Xorg: TMstate.c,v 1.6 2001/02/09 02:03:58 xorgcvs Exp $ */ + +/*********************************************************** +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Digital or Sun not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* + +Copyright 1987, 1988, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +/* TMstate.c -- maintains the state table of actions for the translation + * manager. + */ +/*LINTLIBRARY*/ + +#include "IntrinsicI.h" + +#ifndef TM_NO_MATCH +#define TM_NO_MATCH (-2) +#endif /* TM_NO_MATCH */ + +/* forward definitions */ +static StatePtr NewState(); + + +static String XtNtranslationError = "translationError"; + +TMGlobalRec _XtGlobalTM; /* initialized to zero K&R */ + +#define MatchIncomingEvent(tmEvent, typeMatch, modMatch) \ + (typeMatch->eventType == tmEvent->event.eventType && \ + (typeMatch->matchEvent != NULL) && \ + (*typeMatch->matchEvent)(typeMatch, modMatch, tmEvent)) + + +#define NumStateTrees(xlations) \ + ((translateData->isSimple) ? 1 : (TMComplexXlations(xlations))->numTrees) + +static TMShortCard GetBranchHead(parseTree, typeIndex, modIndex, isDummy) + TMParseStateTree parseTree; + TMShortCard typeIndex; + TMShortCard modIndex; + Boolean isDummy; +{ +#define TM_BRANCH_HEAD_TBL_ALLOC 8 +#define TM_BRANCH_HEAD_TBL_REALLOC 8 + + TMBranchHead branchHead = parseTree->branchHeadTbl; + TMShortCard newSize, i; + + /* + * dummy is used as a place holder for later matching in old-style + * matching behavior. If there's already an entry we don't need + * another dummy. + */ + if (isDummy) { + for (i = 0; i < parseTree->numBranchHeads; i++, branchHead++) { + if ((branchHead->typeIndex == typeIndex) && + (branchHead->modIndex == modIndex)) + return i; + } + } + if (parseTree->numBranchHeads == parseTree->branchHeadTblSize) + { + if (parseTree->branchHeadTblSize == 0) + parseTree->branchHeadTblSize += TM_BRANCH_HEAD_TBL_ALLOC; + else + parseTree->branchHeadTblSize += + TM_BRANCH_HEAD_TBL_REALLOC; + newSize = (parseTree->branchHeadTblSize * sizeof(TMBranchHeadRec)); + if (parseTree->isStackBranchHeads) { + TMBranchHead oldBranchHeadTbl = parseTree->branchHeadTbl; + parseTree->branchHeadTbl = (TMBranchHead) __XtMalloc(newSize); + XtMemmove(parseTree->branchHeadTbl, oldBranchHeadTbl, newSize); + parseTree->isStackBranchHeads = False; + } + else { + parseTree->branchHeadTbl = (TMBranchHead) + XtRealloc((char *)parseTree->branchHeadTbl, + (parseTree->branchHeadTblSize * + sizeof(TMBranchHeadRec))); + } + } +#ifdef TRACE_TM + LOCK_PROCESS; + _XtGlobalTM.numBranchHeads++; + UNLOCK_PROCESS; +#endif /* TRACE_TM */ + branchHead = + &parseTree->branchHeadTbl[parseTree->numBranchHeads++]; + branchHead->typeIndex = typeIndex; + branchHead->modIndex = modIndex; + branchHead->more = 0; + branchHead->isSimple = True; + branchHead->hasActions = False; + branchHead->hasCycles = False; + return parseTree->numBranchHeads-1; +} + +TMShortCard _XtGetQuarkIndex(parseTree, quark) + TMParseStateTree parseTree; + XrmQuark quark; +{ +#define TM_QUARK_TBL_ALLOC 16 +#define TM_QUARK_TBL_REALLOC 16 + TMShortCard i = parseTree->numQuarks; + + for (i=0; i < parseTree->numQuarks; i++) + if (parseTree->quarkTbl[i] == quark) + break; + + if (i == parseTree->numQuarks) + { + if (parseTree->numQuarks == parseTree->quarkTblSize) + { + TMShortCard newSize; + + if (parseTree->quarkTblSize == 0) + parseTree->quarkTblSize += TM_QUARK_TBL_ALLOC; + else + parseTree->quarkTblSize += TM_QUARK_TBL_REALLOC; + newSize = (parseTree->quarkTblSize * sizeof(XrmQuark)); + + if (parseTree->isStackQuarks) { + XrmQuark *oldquarkTbl = parseTree->quarkTbl; + parseTree->quarkTbl = (XrmQuark *) __XtMalloc(newSize); + XtMemmove(parseTree->quarkTbl, oldquarkTbl, newSize); + parseTree->isStackQuarks = False; + } + else { + parseTree->quarkTbl = (XrmQuark *) + XtRealloc((char *)parseTree->quarkTbl, + (parseTree->quarkTblSize * + sizeof(XrmQuark))); + } + } + parseTree->quarkTbl[parseTree->numQuarks++] = quark; + } + return i; +} + +/* + * Get an entry from the parseTrees complex branchHead tbl. If there's none + * there then allocate one + */ +/*ARGSUSED*/ +static TMShortCard GetComplexBranchIndex(parseTree, typeIndex, modIndex) + TMParseStateTree parseTree; + TMShortCard typeIndex; + TMShortCard modIndex; +{ +#define TM_COMPLEXBRANCH_HEAD_TBL_ALLOC 8 +#define TM_COMPLEXBRANCH_HEAD_TBL_REALLOC 4 + + if (parseTree->numComplexBranchHeads == parseTree->complexBranchHeadTblSize) { + TMShortCard newSize; + + if (parseTree->complexBranchHeadTblSize == 0) + parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_ALLOC; + else + parseTree->complexBranchHeadTblSize += TM_COMPLEXBRANCH_HEAD_TBL_REALLOC; + + newSize = (parseTree->complexBranchHeadTblSize * sizeof(StatePtr)); + + if (parseTree->isStackComplexBranchHeads) { + StatePtr *oldcomplexBranchHeadTbl + = parseTree->complexBranchHeadTbl; + parseTree->complexBranchHeadTbl = (StatePtr *) __XtMalloc(newSize); + XtMemmove(parseTree->complexBranchHeadTbl, + oldcomplexBranchHeadTbl, newSize); + parseTree->isStackComplexBranchHeads = False; + } + else { + parseTree->complexBranchHeadTbl = (StatePtr *) + XtRealloc((char *)parseTree->complexBranchHeadTbl, + (parseTree->complexBranchHeadTblSize * + sizeof(StatePtr))); + } + } + parseTree->complexBranchHeadTbl[parseTree->numComplexBranchHeads++] = NULL; + return parseTree->numComplexBranchHeads-1; +} + +TMShortCard _XtGetTypeIndex(event) + Event *event; +{ + TMShortCard i, j = TM_TYPE_SEGMENT_SIZE; + TMShortCard typeIndex = 0; + TMTypeMatch typeMatch; + TMTypeMatch segment; + + LOCK_PROCESS; + for (i = 0; i < _XtGlobalTM.numTypeMatchSegments; i++) { + segment = _XtGlobalTM.typeMatchSegmentTbl[i]; + for (j = 0; + typeIndex < _XtGlobalTM.numTypeMatches && j < TM_TYPE_SEGMENT_SIZE; + j++, typeIndex++) + { + typeMatch = &(segment[j]); + if (event->eventType == typeMatch->eventType && + event->eventCode == typeMatch->eventCode && + event->eventCodeMask == typeMatch->eventCodeMask && + event->matchEvent == typeMatch->matchEvent) { + UNLOCK_PROCESS; + return typeIndex; + } + } + } + + if (j == TM_TYPE_SEGMENT_SIZE) { + if (_XtGlobalTM.numTypeMatchSegments == _XtGlobalTM.typeMatchSegmentTblSize) { + _XtGlobalTM.typeMatchSegmentTblSize += 4; + _XtGlobalTM.typeMatchSegmentTbl = (TMTypeMatch *) + XtRealloc((char *)_XtGlobalTM.typeMatchSegmentTbl, + (_XtGlobalTM.typeMatchSegmentTblSize * sizeof(TMTypeMatch))); + } + _XtGlobalTM.typeMatchSegmentTbl[_XtGlobalTM.numTypeMatchSegments++] = + segment = (TMTypeMatch) + __XtMalloc(TM_TYPE_SEGMENT_SIZE * sizeof(TMTypeMatchRec)); + j = 0; + } + typeMatch = &segment[j]; + typeMatch->eventType = event->eventType; + typeMatch->eventCode = event->eventCode; + typeMatch->eventCodeMask = event->eventCodeMask; + typeMatch->matchEvent = event->matchEvent; + _XtGlobalTM.numTypeMatches++; + UNLOCK_PROCESS; + return typeIndex; +} + +static Boolean CompareLateModifiers(lateBind1P, lateBind2P) + LateBindingsPtr lateBind1P, lateBind2P; +{ + LateBindingsPtr late1P = lateBind1P; + LateBindingsPtr late2P = lateBind2P; + + if (late1P != NULL || late2P != NULL) { + int i = 0; + int j = 0; + if (late1P != NULL) + for (; late1P->keysym != NoSymbol; i++) late1P++; + if (late2P != NULL) + for (; late2P->keysym != NoSymbol; j++) late2P++; + if (i != j) return FALSE; + late1P--; + while (late1P >= lateBind1P) { + Boolean last = True; + for (late2P = lateBind2P + i - 1; + late2P >= lateBind2P; + late2P--) { + if (late1P->keysym == late2P->keysym + && late1P->knot == late2P->knot) { + j--; + if (last) i--; + break; + } + last = False; + } + late1P--; + } + if (j != 0) return FALSE; + } + return TRUE; +} + +TMShortCard _XtGetModifierIndex(event) + Event *event; +{ + TMShortCard i, j = TM_MOD_SEGMENT_SIZE; + TMShortCard modIndex = 0; + TMModifierMatch modMatch; + TMModifierMatch segment; + + LOCK_PROCESS; + for (i = 0; i < _XtGlobalTM.numModMatchSegments; i++) { + segment = _XtGlobalTM.modMatchSegmentTbl[i]; + for (j = 0; + modIndex < _XtGlobalTM.numModMatches && j < TM_MOD_SEGMENT_SIZE; + j++, modIndex++) { + modMatch = &(segment[j]); + if (event->modifiers == modMatch->modifiers && + event->modifierMask == modMatch->modifierMask && + event->standard == modMatch->standard && + ((!event->lateModifiers && !modMatch->lateModifiers) || + CompareLateModifiers(event->lateModifiers, + modMatch->lateModifiers))) { + /* + * if we found a match then we can free the parser's + * late modifiers. If there isn't a match we use the + * parser's copy + */ + if (event->lateModifiers && + --event->lateModifiers->ref_count == 0) { + XtFree((char *)event->lateModifiers); + event->lateModifiers = NULL; + } + UNLOCK_PROCESS; + return modIndex; + } + } + } + + if (j == TM_MOD_SEGMENT_SIZE) { + if (_XtGlobalTM.numModMatchSegments == _XtGlobalTM.modMatchSegmentTblSize) { + _XtGlobalTM.modMatchSegmentTblSize += 4; + _XtGlobalTM.modMatchSegmentTbl = (TMModifierMatch *) + XtRealloc((char *)_XtGlobalTM.modMatchSegmentTbl, + (_XtGlobalTM.modMatchSegmentTblSize * sizeof(TMModifierMatch))); + } + _XtGlobalTM.modMatchSegmentTbl[_XtGlobalTM.numModMatchSegments++] = + segment = (TMModifierMatch) + __XtMalloc(TM_MOD_SEGMENT_SIZE * sizeof(TMModifierMatchRec)); + j = 0; + } + modMatch = &segment[j]; + modMatch->modifiers = event->modifiers;; + modMatch->modifierMask = event->modifierMask; + modMatch->standard = event->standard; + /* + * We use the parser's copy of the late binding array + */ +#ifdef TRACE_TM + if (event->lateModifiers) + _XtGlobalTM.numLateBindings++; +#endif /* TRACE_TM */ + modMatch->lateModifiers = event->lateModifiers; + _XtGlobalTM.numModMatches++; + UNLOCK_PROCESS; + return modIndex; +} + + +/* + * This is called from the SimpleStateHandler to match a stateTree + * entry to the event coming in + */ +static int MatchBranchHead(stateTree, startIndex, event) + TMSimpleStateTree stateTree; + int startIndex; + TMEventPtr event; +{ + TMBranchHead branchHead = &stateTree->branchHeadTbl[startIndex]; + int i; + + LOCK_PROCESS; + for (i = startIndex; + i < (int)stateTree->numBranchHeads; + i++, branchHead++) + { + TMTypeMatch typeMatch; + TMModifierMatch modMatch; + + typeMatch = TMGetTypeMatch(branchHead->typeIndex); + modMatch = TMGetModifierMatch(branchHead->modIndex); + + if (MatchIncomingEvent(event, typeMatch, modMatch)) { + UNLOCK_PROCESS; + return i; + } + } + UNLOCK_PROCESS; + return (TM_NO_MATCH); +} + +Boolean _XtRegularMatch(typeMatch, modMatch, eventSeq) + TMTypeMatch typeMatch; + TMModifierMatch modMatch; + TMEventPtr eventSeq; +{ + Modifiers computed =0; + Modifiers computedMask =0; + Boolean resolved = TRUE; + if (typeMatch->eventCode != (eventSeq->event.eventCode & + typeMatch->eventCodeMask)) return FALSE; + if (modMatch->lateModifiers != NULL) + resolved = _XtComputeLateBindings(eventSeq->xev->xany.display, + modMatch->lateModifiers, + &computed, &computedMask); + if (!resolved) return FALSE; + computed |= modMatch->modifiers; + computedMask |= modMatch->modifierMask; + + return ( (computed & computedMask) == + (eventSeq->event.modifiers & computedMask)); +} + +/*ARGSUSED*/ +Boolean _XtMatchAtom(typeMatch, modMatch, eventSeq) + TMTypeMatch typeMatch; + TMModifierMatch modMatch; + TMEventPtr eventSeq; +{ + Atom atom; + + atom = XInternAtom(eventSeq->xev->xany.display, + XrmQuarkToString(typeMatch->eventCode), + False); + return (atom == eventSeq->event.eventCode); +} + +#define IsOn(vec,idx) ((vec)[(idx)>>3] & (1 << ((idx) & 7))) + +/* + * there are certain cases where you want to ignore the event and stay + * in the same state. + */ +static Boolean Ignore(event) + TMEventPtr event; +{ + Display *dpy; + XtPerDisplay pd; + + if (event->event.eventType == MotionNotify) + return TRUE; + if (!(event->event.eventType == KeyPress || + event->event.eventType == KeyRelease)) + return FALSE; + dpy = event->xev->xany.display; + pd = _XtGetPerDisplay(dpy); + _InitializeKeysymTables(dpy, pd); + return IsOn(pd->isModifier, event->event.eventCode) ? TRUE : FALSE; +} + + +static void XEventToTMEvent(event, tmEvent) + XEvent *event; + TMEventPtr tmEvent; +{ + tmEvent->xev = event; + tmEvent->event.eventCodeMask = 0; + tmEvent->event.modifierMask = 0; + tmEvent->event.eventType = event->type; + tmEvent->event.lateModifiers = NULL; + tmEvent->event.matchEvent = NULL; + tmEvent->event.standard = FALSE; + + switch (event->type) { + + case KeyPress: + case KeyRelease: + tmEvent->event.eventCode = event->xkey.keycode; + tmEvent->event.modifiers = event->xkey.state; + break; + + case ButtonPress: + case ButtonRelease: + tmEvent->event.eventCode = event->xbutton.button; + tmEvent->event.modifiers = event->xbutton.state; + break; + + case MotionNotify: + tmEvent->event.eventCode = event->xmotion.is_hint; + tmEvent->event.modifiers = event->xmotion.state; + break; + + case EnterNotify: + case LeaveNotify: + tmEvent->event.eventCode = event->xcrossing.mode; + tmEvent->event.modifiers = event->xcrossing.state; + break; + + case PropertyNotify: + tmEvent->event.eventCode = event->xproperty.atom; + tmEvent->event.modifiers = 0; + break; + + case SelectionClear: + tmEvent->event.eventCode = event->xselectionclear.selection; + tmEvent->event.modifiers = 0; + break; + + case SelectionRequest: + tmEvent->event.eventCode = event->xselectionrequest.selection; + tmEvent->event.modifiers = 0; + break; + + case SelectionNotify: + tmEvent->event.eventCode = event->xselection.selection; + tmEvent->event.modifiers = 0; + break; + + case ClientMessage: + tmEvent->event.eventCode = event->xclient.message_type; + tmEvent->event.modifiers = 0; + break; + + case MappingNotify: + tmEvent->event.eventCode = event->xmapping.request; + tmEvent->event.modifiers = 0; + break; + + case FocusIn: + case FocusOut: + tmEvent->event.eventCode = event->xfocus.mode; + tmEvent->event.modifiers = 0; + break; + + default: + tmEvent->event.eventCode = 0; + tmEvent->event.modifiers = 0; + break; + } +} + + +static unsigned long GetTime(tm, event) + XtTM tm; + XEvent *event; +{ + switch (event->type) { + + case KeyPress: + case KeyRelease: + return event->xkey.time; + + case ButtonPress: + case ButtonRelease: + return event->xbutton.time; + + default: + return tm->lastEventTime; + + } + +} + +static void HandleActions(w, event, stateTree, accelWidget, procs, actions) + Widget w; + XEvent *event; + TMSimpleStateTree stateTree; + Widget accelWidget; + XtActionProc *procs; + ActionRec *actions; +{ + ActionHook actionHookList; + Widget bindWidget; + + bindWidget = accelWidget ? accelWidget : w; + if (accelWidget && !XtIsSensitive(accelWidget) && + (event->type == KeyPress || event->type == KeyRelease || + event->type == ButtonPress || event->type == ButtonRelease || + event->type == MotionNotify || event->type == EnterNotify || + event->type == LeaveNotify || event->type == FocusIn || + event->type == FocusOut)) + return; + + actionHookList = XtWidgetToApplicationContext(w)->action_hook_list; + + while (actions != NULL) { + /* perform any actions */ + if (procs[actions->idx] != NULL) { + if (actionHookList) { + ActionHook hook; + ActionHook next_hook; + String procName = + XrmQuarkToString(stateTree->quarkTbl[actions->idx] ); + + for (hook = actionHookList; hook != NULL; ) { + /* + * Need to cache hook->next because the following action + * proc may free hook via XtRemoveActionHook making + * hook->next invalid upon return from the action proc. + */ + next_hook = hook->next; + (*hook->proc)(bindWidget, + hook->closure, + procName, + event, + actions->params, + &actions->num_params + ); + hook = next_hook; + } + } + (*(procs[actions->idx])) + (bindWidget, event, + actions->params, &actions->num_params ); + } + actions = actions->next; + } +} + +typedef struct { + unsigned int isCycleStart:1; + unsigned int isCycleEnd:1; + TMShortCard typeIndex; + TMShortCard modIndex; +}MatchPairRec, *MatchPair; + +typedef struct TMContextRec{ + TMShortCard numMatches; + TMShortCard maxMatches; + MatchPair matches; +}TMContextRec, *TMContext; + +static TMContextRec contextCache[2]; + +#define GetContextPtr(tm) ((TMContext *)&(tm->current_state)) + +#define TM_CONTEXT_MATCHES_ALLOC 4 +#define TM_CONTEXT_MATCHES_REALLOC 2 + +static void PushContext(contextPtr, newState) + TMContext *contextPtr; + StatePtr newState; +{ + TMContext context = *contextPtr; + + LOCK_PROCESS; + if (context == NULL) + { + if (contextCache[0].numMatches == 0) + context = &contextCache[0]; + else if (contextCache[1].numMatches == 0) + context = &contextCache[1]; + if (!context) + { + context = XtNew(TMContextRec); + context->matches = NULL; + context->numMatches = + context->maxMatches = 0; + } + } + if (context->numMatches && + context->matches[context->numMatches-1].isCycleEnd) + { + TMShortCard i; + for (i = 0; + i < context->numMatches && + !(context->matches[i].isCycleStart); + i++){}; + if (i < context->numMatches) + context->numMatches = i+1; +#ifdef DEBUG + else + XtWarning("pushing cycle end with no cycle start"); +#endif /* DEBUG */ + } + else + { + if (context->numMatches == context->maxMatches) + { + if (context->maxMatches == 0) + context->maxMatches += TM_CONTEXT_MATCHES_ALLOC; + else + context->maxMatches += TM_CONTEXT_MATCHES_REALLOC; + context->matches = (MatchPairRec *) + XtRealloc((char *)context->matches, + context->maxMatches * sizeof(MatchPairRec)); + } + context->matches[context->numMatches].isCycleStart = newState->isCycleStart; + context->matches[context->numMatches].isCycleEnd = newState->isCycleEnd; + context->matches[context->numMatches].typeIndex = newState->typeIndex; + context->matches[context->numMatches++].modIndex = newState->modIndex; + *contextPtr = context; + } + UNLOCK_PROCESS; +} + +static void FreeContext(contextPtr) + TMContext *contextPtr; +{ + TMContext context = NULL; + + LOCK_PROCESS; + + if (&contextCache[0] == *contextPtr) + context = &contextCache[0]; + else if (&contextCache[1] == *contextPtr) + context = &contextCache[1]; + + if (context) + context->numMatches = 0; + else if (*contextPtr) + { + if ((*contextPtr)->matches) + XtFree ((char *) ((*contextPtr)->matches)); + XtFree((char *)*contextPtr); + } + + *contextPtr = NULL; + UNLOCK_PROCESS; +} + +static int MatchExact(stateTree, startIndex, typeIndex, modIndex) + TMSimpleStateTree stateTree; + int startIndex; + TMShortCard typeIndex, modIndex; +{ + TMBranchHead branchHead = &(stateTree->branchHeadTbl[startIndex]); + int i; + + for (i = startIndex; + i < (int)stateTree->numBranchHeads; + i++, branchHead++) + { + if ((branchHead->typeIndex == typeIndex) && + (branchHead->modIndex == modIndex)) + return i; + } + return (TM_NO_MATCH); +} + + + +static void HandleSimpleState(w, tmRecPtr, curEventPtr) + Widget w; + XtTM tmRecPtr; + TMEventRec *curEventPtr; +{ + XtTranslations xlations = tmRecPtr->translations; + TMSimpleStateTree stateTree; + TMContext *contextPtr = GetContextPtr(tmRecPtr); + TMShortCard i; + ActionRec *actions; + Boolean matchExact = False; + Boolean match = False; + StatePtr complexMatchState = NULL; + int currIndex; + TMShortCard typeIndex, modIndex; + int matchTreeIndex = TM_NO_MATCH; + + LOCK_PROCESS; + stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[0]; + + for (i = 0; + ((!match || !complexMatchState) && (i < xlations->numStateTrees)); + i++){ + stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i]; + currIndex = -1; + /* + * don't process this tree if we're only looking for a + * complexMatchState and there are no complex states + */ + while (!(match && stateTree->isSimple) && + ((!match || !complexMatchState) && (currIndex != TM_NO_MATCH))) { + currIndex++; + if (matchExact) + currIndex = MatchExact(stateTree,currIndex,typeIndex,modIndex); + else + currIndex = MatchBranchHead(stateTree,currIndex,curEventPtr); + if (currIndex != TM_NO_MATCH) { + TMBranchHead branchHead; + StatePtr currState; + + branchHead = &stateTree->branchHeadTbl[currIndex]; + if (branchHead->isSimple) + currState = NULL; + else + currState = ((TMComplexStateTree)stateTree) + ->complexBranchHeadTbl[TMBranchMore(branchHead)]; + + /* + * first check for a complete match + */ + if (!match) { + if (branchHead->hasActions) { + if (branchHead->isSimple) { + static ActionRec dummyAction; + + dummyAction.idx = TMBranchMore(branchHead); + actions = &dummyAction; + } + else + actions = currState->actions; + tmRecPtr->lastEventTime = + GetTime(tmRecPtr, curEventPtr->xev); + FreeContext((TMContext + *)&tmRecPtr->current_state); + match = True; + matchTreeIndex = i; + } + /* + * if it doesn't have actions and + * it's bc mode then it's a potential match node that is + * used to match later sequences. + */ + if (!TMNewMatchSemantics() && !matchExact) { + matchExact = True; + typeIndex = branchHead->typeIndex; + modIndex = branchHead->modIndex; + } + } + /* + * check for it being an event sequence which can be + * a future match + */ + if (!branchHead->isSimple && + !branchHead->hasActions && + !complexMatchState) + complexMatchState = currState; + } + } + } + if (match) + { + TMBindData bindData = (TMBindData) tmRecPtr->proc_table; + XtActionProc *procs; + Widget accelWidget; + + if (bindData->simple.isComplex) { + TMComplexBindProcs bindProcs = + TMGetComplexBindEntry(bindData, matchTreeIndex); + procs = bindProcs->procs; + accelWidget = bindProcs->widget; + } + else { + TMSimpleBindProcs bindProcs = + TMGetSimpleBindEntry(bindData, matchTreeIndex); + procs = bindProcs->procs; + accelWidget = NULL; + } + HandleActions + (w, + curEventPtr->xev, + (TMSimpleStateTree)xlations->stateTreeTbl[matchTreeIndex], + accelWidget, + procs, + actions); + } + if (complexMatchState) + PushContext(contextPtr, complexMatchState); + UNLOCK_PROCESS; +} + +static int MatchComplexBranch(stateTree, startIndex, context, leafStateRtn) + TMComplexStateTree stateTree; + int startIndex; + TMContext context; + StatePtr *leafStateRtn; +{ + TMShortCard i; + + LOCK_PROCESS; + for (i = startIndex; i < stateTree->numComplexBranchHeads; i++) + { + StatePtr candState; + TMShortCard numMatches = context->numMatches; + MatchPair statMatch = context->matches; + + for (candState = stateTree->complexBranchHeadTbl[i]; + numMatches && candState; + numMatches--, statMatch++, candState = candState->nextLevel) + { + if ((statMatch->typeIndex != candState->typeIndex) || + (statMatch->modIndex != candState->modIndex)) + break; + } + if (numMatches == 0) { + *leafStateRtn = candState; + UNLOCK_PROCESS; + return i; + } + } + *leafStateRtn = NULL; + UNLOCK_PROCESS; + return (TM_NO_MATCH); +} + +static StatePtr TryCurrentTree(stateTreePtr, tmRecPtr, curEventPtr) + TMComplexStateTree *stateTreePtr; + XtTM tmRecPtr; + TMEventRec *curEventPtr; +{ + StatePtr candState = NULL, matchState = NULL; + TMContext *contextPtr = GetContextPtr(tmRecPtr); + TMTypeMatch typeMatch; + TMModifierMatch modMatch; + int currIndex = -1; + + /* + * we want the first sequence that both matches and has actions. + * we keep on looking till we find both + */ + LOCK_PROCESS; + while ((currIndex = + MatchComplexBranch(*stateTreePtr, + ++currIndex, + (*contextPtr), + &candState)) + != TM_NO_MATCH) { + if (candState != NULL) { + typeMatch = TMGetTypeMatch(candState->typeIndex); + modMatch = TMGetModifierMatch(candState->modIndex); + + /* does this state's index match? --> done */ + if (MatchIncomingEvent(curEventPtr, typeMatch, modMatch)) + { + if (candState->actions) { + UNLOCK_PROCESS; + return candState; + } + else + matchState = candState; + } + /* is this an event timer? */ + if (typeMatch->eventType == _XtEventTimerEventType) { + StatePtr nextState = candState->nextLevel; + + /* does the succeeding state match? */ + if (nextState != NULL) { + TMTypeMatch nextTypeMatch; + TMModifierMatch nextModMatch; + + nextTypeMatch = TMGetTypeMatch(nextState->typeIndex); + nextModMatch = TMGetModifierMatch(nextState->modIndex); + + /* is it within the timeout? */ + if (MatchIncomingEvent(curEventPtr, + nextTypeMatch, + nextModMatch)) { + XEvent *xev = curEventPtr->xev; + unsigned long time = GetTime(tmRecPtr, xev); + XtPerDisplay pd = _XtGetPerDisplay(xev->xany.display); + unsigned long delta = pd->multi_click_time; + + if ((tmRecPtr->lastEventTime + delta) >= time) { + if (nextState->actions) { + UNLOCK_PROCESS; + return candState; + } + else + matchState = candState; + } + } + } + } + } + } + UNLOCK_PROCESS; + return matchState; +} + +static void HandleComplexState(w, tmRecPtr, curEventPtr) + Widget w; + XtTM tmRecPtr; + TMEventRec *curEventPtr; +{ + XtTranslations xlations = tmRecPtr->translations; + TMContext *contextPtr = GetContextPtr(tmRecPtr); + TMShortCard i, matchTreeIndex; + StatePtr matchState = NULL, candState; + TMComplexStateTree *stateTreePtr = + (TMComplexStateTree *)&xlations->stateTreeTbl[0]; + + LOCK_PROCESS; + for (i = 0; + i < xlations->numStateTrees; + i++, stateTreePtr++) { + /* + * some compilers sign extend Boolean bit fields so test for + * false ||| + */ + if (((*stateTreePtr)->isSimple == False) && + (candState = TryCurrentTree(stateTreePtr, + tmRecPtr, + curEventPtr))) { + if (!matchState || candState->actions) { + matchTreeIndex = i; + matchState = candState; + if (candState->actions) + break; + } + } + } + if (matchState == NULL){ + /* couldn't find it... */ + if (!Ignore(curEventPtr)) + { + FreeContext(contextPtr); + HandleSimpleState(w, tmRecPtr, curEventPtr); + } + } + else { + TMBindData bindData = (TMBindData) tmRecPtr->proc_table; + XtActionProc *procs; + Widget accelWidget; + TMTypeMatch typeMatch; + + typeMatch = TMGetTypeMatch(matchState->typeIndex); + + PushContext(contextPtr, matchState); + if (typeMatch->eventType == _XtEventTimerEventType) { + matchState = matchState->nextLevel; + PushContext(contextPtr, matchState); + } + tmRecPtr->lastEventTime = GetTime (tmRecPtr, curEventPtr->xev); + + if (bindData->simple.isComplex) { + TMComplexBindProcs bindProcs = + TMGetComplexBindEntry(bindData, matchTreeIndex); + procs = bindProcs->procs; + accelWidget = bindProcs->widget; + } + else { + TMSimpleBindProcs bindProcs = + TMGetSimpleBindEntry(bindData, matchTreeIndex); + procs = bindProcs->procs; + accelWidget = NULL; + } + HandleActions(w, + curEventPtr->xev, + (TMSimpleStateTree) + xlations->stateTreeTbl[matchTreeIndex], + accelWidget, + procs, + matchState->actions); + } + UNLOCK_PROCESS; +} + + +void _XtTranslateEvent (w, event) + Widget w; + XEvent * event; +{ + XtTM tmRecPtr = &w->core.tm; + TMEventRec curEvent; + StatePtr current_state = tmRecPtr->current_state; + + XEventToTMEvent (event, &curEvent); + + if (! tmRecPtr->translations) { + XtAppWarningMsg(XtWidgetToApplicationContext(w), + XtNtranslationError,"nullTable",XtCXtToolkitError, + "Can't translate event through NULL table", + (String *)NULL, (Cardinal *)NULL); + return ; + } + if (current_state == NULL) + HandleSimpleState(w, tmRecPtr, &curEvent); + else + HandleComplexState(w, tmRecPtr, &curEvent); +} + + +/*ARGSUSED*/ +static StatePtr NewState(stateTree, typeIndex, modIndex) + TMParseStateTree stateTree; + TMShortCard typeIndex, modIndex; +{ + StatePtr state = XtNew(StateRec); + +#ifdef TRACE_TM + LOCK_PROCESS; + _XtGlobalTM.numComplexStates++; + UNLOCK_PROCESS; +#endif /* TRACE_TM */ + state->typeIndex = typeIndex; + state->modIndex = modIndex; + state->nextLevel = NULL; + state->actions = NULL; + state->isCycleStart = state->isCycleEnd = False; + return state; +} + +/* + * This routine is an iterator for state trees. If the func returns + * true then iteration is over. + */ +void _XtTraverseStateTree(tree, func, data) + TMStateTree tree; + _XtTraversalProc func; + XtPointer data; +{ + TMComplexStateTree stateTree = (TMComplexStateTree)tree; + TMBranchHead currBH; + TMShortCard i; + StateRec dummyStateRec, *dummyState = &dummyStateRec; + ActionRec dummyActionRec, *dummyAction = &dummyActionRec; + Boolean firstSimple = True; + StatePtr currState; + + /* first traverse the complex states */ + if (stateTree->isSimple == False) + for (i = 0; i < stateTree->numComplexBranchHeads; i++) { + currState = stateTree->complexBranchHeadTbl[i]; + for (; currState; currState = currState->nextLevel) { + if (func(currState, data)) + return; + if (currState->isCycleEnd) + break; + } + } + + /* now traverse the simple ones */ + for (i = 0, currBH = stateTree->branchHeadTbl; + i < stateTree->numBranchHeads; + i++, currBH++) + { + if (currBH->isSimple && currBH->hasActions) + { + if (firstSimple) + { + XtBZero((char *) dummyState, sizeof(StateRec)); + XtBZero((char *) dummyAction, sizeof(ActionRec)); + dummyState->actions = dummyAction; + firstSimple = False; + } + dummyState->typeIndex = currBH->typeIndex; + dummyState->modIndex = currBH->modIndex; + dummyAction->idx = currBH->more; + if (func(dummyState, data)) + return; + } + } +} + +static EventMask EventToMask(typeMatch, modMatch) + TMTypeMatch typeMatch; + TMModifierMatch modMatch; +{ + EventMask returnMask; + unsigned long eventType = typeMatch->eventType; + + if (eventType == MotionNotify) { + Modifiers modifierMask = modMatch->modifierMask; + Modifiers tempMask; + + returnMask = 0; + if (modifierMask == 0) { + if (modMatch->modifiers == AnyButtonMask) + return ButtonMotionMask; + else + return PointerMotionMask; + } + tempMask = modifierMask & + (Button1Mask | Button2Mask | Button3Mask + | Button4Mask | Button5Mask); + if (tempMask == 0) + return PointerMotionMask; + if (tempMask & Button1Mask) + returnMask |= Button1MotionMask; + if (tempMask & Button2Mask) + returnMask |= Button2MotionMask; + if (tempMask & Button3Mask) + returnMask |= Button3MotionMask; + if (tempMask & Button4Mask) + returnMask |= Button4MotionMask; + if (tempMask & Button5Mask) + returnMask |= Button5MotionMask; + return returnMask; + } + returnMask = _XtConvertTypeToMask(eventType); + if (returnMask == (StructureNotifyMask|SubstructureNotifyMask)) + returnMask = StructureNotifyMask; + return returnMask; +} + +/*ARGSUSED*/ +static void DispatchMappingNotify(widget, closure, call_data) + Widget widget; /* will be NULL from _RefreshMapping */ + XtPointer closure; /* real Widget */ + XtPointer call_data; /* XEvent* */ +{ + _XtTranslateEvent( (Widget)closure, (XEvent*)call_data); +} + + +/*ARGSUSED*/ +static void RemoveFromMappingCallbacks(widget, closure, call_data) + Widget widget; + XtPointer closure; /* target widget */ + XtPointer call_data; +{ + _XtRemoveCallback( &_XtGetPerDisplay(XtDisplay(widget))->mapping_callbacks, + DispatchMappingNotify, + closure + ); +} + +static Boolean AggregateEventMask(state, data) + StatePtr state; + XtPointer data; +{ + LOCK_PROCESS; + *((EventMask *)data) |= EventToMask(TMGetTypeMatch(state->typeIndex), + TMGetModifierMatch(state->modIndex)); + UNLOCK_PROCESS; + return False; +} + +void _XtInstallTranslations(widget) + Widget widget; +{ + XtTranslations xlations; + Cardinal i; + TMStateTree stateTree; + Boolean mappingNotifyInterest = False; + + xlations = widget->core.tm.translations; + if (xlations == NULL) return; + + /* + * check for somebody stuffing the translations directly into the + * instance structure. We will end up being called again out of + * ComposeTranslations but we *should* have bindings by then + */ + if (widget->core.tm.proc_table == NULL) { + _XtMergeTranslations(widget, NULL, XtTableReplace); + /* + * if we're realized then we'll be called out of + * ComposeTranslations + */ + if (XtIsRealized(widget)) + return; + } + + xlations->eventMask = 0; + for (i = 0; + i < xlations->numStateTrees; + i++) + { + stateTree = xlations->stateTreeTbl[i]; + _XtTraverseStateTree(stateTree, + AggregateEventMask, + (XtPointer)&xlations->eventMask); + mappingNotifyInterest |= stateTree->simple.mappingNotifyInterest; + } + /* double click needs to make sure that you have selected on both + button down and up. */ + + if (xlations->eventMask & ButtonPressMask) + xlations->eventMask |= ButtonReleaseMask; + if (xlations->eventMask & ButtonReleaseMask) + xlations->eventMask |= ButtonPressMask; + + if (mappingNotifyInterest) { + XtPerDisplay pd = _XtGetPerDisplay(XtDisplay(widget)); + if (pd->mapping_callbacks) + _XtAddCallbackOnce(&(pd->mapping_callbacks), + DispatchMappingNotify, + (XtPointer)widget); + else + _XtAddCallback(&(pd->mapping_callbacks), + DispatchMappingNotify, + (XtPointer)widget); + + if (widget->core.destroy_callbacks != NULL) + _XtAddCallbackOnce( (InternalCallbackList *) + &widget->core.destroy_callbacks, + RemoveFromMappingCallbacks, + (XtPointer)widget + ); + else + _XtAddCallback((InternalCallbackList *) + &widget->core.destroy_callbacks, + RemoveFromMappingCallbacks, + (XtPointer)widget + ); + } + _XtBindActions(widget, (XtTM)&widget->core.tm); + _XtRegisterGrabs(widget); +} + +void _XtRemoveTranslations(widget) + Widget widget; +{ + Cardinal i; + TMSimpleStateTree stateTree; + Boolean mappingNotifyInterest = False; + XtTranslations xlations = widget->core.tm.translations; + + if (xlations == NULL) + return; + + for (i = 0; + i < xlations->numStateTrees; + i++) + { + stateTree = (TMSimpleStateTree)xlations->stateTreeTbl[i]; + mappingNotifyInterest |= stateTree->mappingNotifyInterest; + } + if (mappingNotifyInterest) + RemoveFromMappingCallbacks(widget, (XtPointer)widget, NULL); +} + +static void _XtUninstallTranslations(widget) + Widget widget; +{ + XtTranslations xlations = widget->core.tm.translations; + + _XtUnbindActions(widget, + xlations, + (TMBindData)widget->core.tm.proc_table); + _XtRemoveTranslations(widget); + widget->core.tm.translations = NULL; + FreeContext((TMContext *)&widget->core.tm.current_state); +} + +void _XtDestroyTMData(widget) + Widget widget; +{ + TMComplexBindData cBindData; + + _XtUninstallTranslations(widget); + + if ((cBindData = (TMComplexBindData)widget->core.tm.proc_table)) { + if (cBindData->isComplex) { + ATranslations aXlations, nXlations; + + nXlations = (ATranslations) cBindData->accel_context; + while (nXlations){ + aXlations = nXlations; + nXlations = nXlations->next; + XtFree((char *)aXlations); + } + } + XtFree((char *)cBindData); + } +} + +/*** Public procedures ***/ + + +void XtUninstallTranslations(widget) + Widget widget; +{ + EventMask oldMask; + Widget hookobj; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + if (! widget->core.tm.translations) { + UNLOCK_APP(app); + return; + } + oldMask = widget->core.tm.translations->eventMask; + _XtUninstallTranslations(widget); + if (XtIsRealized(widget) && oldMask) + XSelectInput(XtDisplay(widget), XtWindow(widget), + XtBuildEventMask(widget)); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHuninstallTranslations; + call_data.widget = widget; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_APP(app); +} + +#if NeedFunctionPrototypes +XtTranslations _XtCreateXlations( + TMStateTree *stateTrees, + TMShortCard numStateTrees, + XtTranslations first, + XtTranslations second) +#else +XtTranslations _XtCreateXlations(stateTrees, numStateTrees, first, second) + TMStateTree *stateTrees; + TMShortCard numStateTrees; + XtTranslations first, second; +#endif +{ + XtTranslations xlations; + TMShortCard i; + + xlations = (XtTranslations) + __XtMalloc(sizeof(TranslationData) + + (numStateTrees-1) * sizeof(TMStateTree)); +#ifdef TRACE_TM + LOCK_PROCESS; + if (_XtGlobalTM.numTms == _XtGlobalTM.tmTblSize) { + _XtGlobalTM.tmTblSize += 16; + _XtGlobalTM.tmTbl = (XtTranslations *) + XtRealloc((char *)_XtGlobalTM.tmTbl, + _XtGlobalTM.tmTblSize * sizeof(XtTranslations)); + } + _XtGlobalTM.tmTbl[_XtGlobalTM.numTms++] = xlations; + UNLOCK_PROCESS; +#endif /* TRACE_TM */ + + xlations->composers[0] = first; + xlations->composers[1] = second; + xlations->hasBindings = False; + xlations->operation = XtTableReplace; + + for (i = 0;i < numStateTrees; i++) + { + xlations->stateTreeTbl[i] = (TMStateTree) stateTrees[i]; + stateTrees[i]->simple.refCount++; + } + xlations->numStateTrees = numStateTrees; + xlations->eventMask = 0; + return xlations; +} + +TMStateTree _XtParseTreeToStateTree(parseTree) + TMParseStateTree parseTree; +{ + TMSimpleStateTree simpleTree; + unsigned int tableSize; + + if (parseTree->numComplexBranchHeads) { + TMComplexStateTree complexTree; + + complexTree = XtNew(TMComplexStateTreeRec); + complexTree->isSimple = False; + tableSize = parseTree->numComplexBranchHeads * sizeof(StatePtr); + complexTree->complexBranchHeadTbl = (StatePtr *) + __XtMalloc(tableSize); + XtMemmove(complexTree->complexBranchHeadTbl, + parseTree->complexBranchHeadTbl, tableSize); + complexTree->numComplexBranchHeads = + parseTree->numComplexBranchHeads; + simpleTree = (TMSimpleStateTree)complexTree; + } + else { + simpleTree = XtNew(TMSimpleStateTreeRec); + simpleTree->isSimple = True; + } + simpleTree->isAccelerator = parseTree->isAccelerator; + simpleTree->refCount = 0; + simpleTree->mappingNotifyInterest = parseTree->mappingNotifyInterest; + + tableSize = parseTree->numBranchHeads * sizeof(TMBranchHeadRec); + simpleTree->branchHeadTbl = (TMBranchHead) + __XtMalloc(tableSize); + XtMemmove(simpleTree->branchHeadTbl, parseTree->branchHeadTbl, tableSize); + simpleTree->numBranchHeads = parseTree->numBranchHeads; + + tableSize = parseTree->numQuarks * sizeof(XrmQuark); + simpleTree->quarkTbl = (XrmQuark *) __XtMalloc(tableSize); + XtMemmove(simpleTree->quarkTbl, parseTree->quarkTbl, tableSize); + simpleTree->numQuarks = parseTree->numQuarks; + + return (TMStateTree)simpleTree; +} + +static void FreeActions(actions) + ActionPtr actions; +{ + ActionPtr action; + TMShortCard i; + for (action = actions; action;) { + ActionPtr nextAction = action->next; + for (i = action->num_params; i;) { + XtFree( action->params[--i] ); + } + XtFree( (char*)action->params ); + XtFree((char*) action); + action = nextAction; + } +} + +/*ARGSUSED*/ +static void AmbigActions(initialEvent, state, stateTree) + EventSeqPtr initialEvent; + StatePtr *state; + TMParseStateTree stateTree; +{ + String params[3]; + Cardinal numParams = 0; + + params[numParams++] = _XtPrintEventSeq(initialEvent, NULL); + params[numParams++] = _XtPrintActions((*state)->actions, + stateTree->quarkTbl); + XtWarningMsg (XtNtranslationError,"oldActions",XtCXtToolkitError, + "Previous entry was: %s %s", params, &numParams); + XtFree((char *)params[0]); + XtFree((char *)params[1]); + numParams = 0; + params[numParams++] = _XtPrintActions(initialEvent->actions, + stateTree->quarkTbl); + XtWarningMsg (XtNtranslationError,"newActions",XtCXtToolkitError, + "New actions are:%s", params, &numParams); + XtFree((char *)params[0]); + XtWarningMsg (XtNtranslationError,"ambiguousActions", + XtCXtToolkitError, + "Overriding earlier translation manager actions.", + (String *)NULL, (Cardinal *)NULL); + + FreeActions((*state)->actions); + (*state)->actions = NULL; +} + + +void _XtAddEventSeqToStateTree(eventSeq, stateTree) + EventSeqPtr eventSeq; + TMParseStateTree stateTree; +{ + StatePtr *state; + EventSeqPtr initialEvent = eventSeq; + TMBranchHead branchHead; + TMShortCard idx, modIndex, typeIndex; + + if (eventSeq == NULL) return; + + /* note that all states in the event seq passed in start out null */ + /* we fill them in with the matching state as we traverse the list */ + + /* + * We need to free the parser data structures !!! + */ + + typeIndex = _XtGetTypeIndex(&eventSeq->event); + modIndex = _XtGetModifierIndex(&eventSeq->event); + idx = GetBranchHead(stateTree, typeIndex, modIndex, False); + branchHead = &stateTree->branchHeadTbl[idx]; + + /* + * Need to check for pre-existing actions with same lhs ||| + */ + + /* + * Check for optimized case. Don't assume that the eventSeq has actions. + */ + if (!eventSeq->next && + eventSeq->actions && + !eventSeq->actions->next && + !eventSeq->actions->num_params) + { + if (eventSeq->event.eventType == MappingNotify) + stateTree->mappingNotifyInterest = True; + branchHead->hasActions = True; + branchHead->more = eventSeq->actions->idx; + FreeActions(eventSeq->actions); + eventSeq->actions = NULL; + return; + } + + branchHead->isSimple = False; + if (!eventSeq->next) + branchHead->hasActions = True; + branchHead->more = GetComplexBranchIndex(stateTree, typeIndex, modIndex); + state = &stateTree->complexBranchHeadTbl[TMBranchMore(branchHead)]; + + for (;;) { + *state = NewState(stateTree, typeIndex, modIndex); + + if (eventSeq->event.eventType == MappingNotify) + stateTree->mappingNotifyInterest = True; + + /* *state now points at state record matching event */ + eventSeq->state = *state; + + if (eventSeq->actions != NULL) { + if ((*state)->actions != NULL) + AmbigActions(initialEvent, state, stateTree); + (*state)->actions = eventSeq->actions; +#ifdef TRACE_TM + LOCK_PROCESS + _XtGlobalTM.numComplexActions++; + UNLOCK_PROCESS; +#endif /* TRACE_TM */ + } + + if (((eventSeq = eventSeq->next) == NULL) || (eventSeq->state)) + break; + + state = &(*state)->nextLevel; + typeIndex = _XtGetTypeIndex(&eventSeq->event); + modIndex = _XtGetModifierIndex(&eventSeq->event); + LOCK_PROCESS; + if (!TMNewMatchSemantics()) { + /* + * force a potential empty entry into the branch head + * table in order to emulate old matching behavior + */ + (void) GetBranchHead(stateTree, typeIndex, modIndex, True); + } + UNLOCK_PROCESS; + } + + if (eventSeq && eventSeq->state) { + /* we've been here before... must be a cycle in the event seq. */ + branchHead->hasCycles = True; + (*state)->nextLevel = eventSeq->state; + eventSeq->state->isCycleStart = True; + (*state)->isCycleEnd = TRUE; + } +} + + +/* + * Internal Converter for merging. Old and New must both be valid xlations + */ + +/*ARGSUSED*/ +Boolean _XtCvtMergeTranslations(dpy, args, num_args, from, to, closure_ret) + Display *dpy; + XrmValuePtr args; + Cardinal *num_args; + XrmValuePtr from,to; + XtPointer *closure_ret; +{ + XtTranslations first, second, xlations; + TMStateTree *stateTrees, stackStateTrees[16]; + TMShortCard numStateTrees, i; + + if (*num_args != 0) + XtWarningMsg("invalidParameters","mergeTranslations",XtCXtToolkitError, + "MergeTM to TranslationTable needs no extra arguments", + (String *)NULL, (Cardinal *)NULL); + + if (to->addr != NULL && to->size < sizeof(XtTranslations)) { + to->size = sizeof(XtTranslations); + return False; + } + + first = ((TMConvertRec*)from->addr)->old; + second = ((TMConvertRec*)from->addr)->new; + + numStateTrees = first->numStateTrees + second->numStateTrees; + + stateTrees = (TMStateTree *) + XtStackAlloc(numStateTrees * sizeof(TMStateTree), stackStateTrees); + + for (i = 0; i < first->numStateTrees; i++) + stateTrees[i] = first->stateTreeTbl[i]; + for (i = 0; i < second->numStateTrees; i++) + stateTrees[i + first->numStateTrees] = second->stateTreeTbl[i]; + + xlations = _XtCreateXlations(stateTrees, numStateTrees, first, second); + + if (to->addr != NULL) { + *(XtTranslations*)to->addr = xlations; + } + else { + static XtTranslations staticStateTable; + staticStateTable = xlations; + to->addr= (XPointer)&staticStateTable; + to->size = sizeof(XtTranslations); + } + + XtStackFree((XtPointer)stateTrees, (XtPointer)stackStateTrees); + return True; +} + + +static XtTranslations MergeThem(dest, first, second) + Widget dest; + XtTranslations first, second; +{ + XtCacheRef cache_ref; + static XrmQuark from_type = NULLQUARK, to_type; + XrmValue from, to; + TMConvertRec convert_rec; + XtTranslations newTable; + + LOCK_PROCESS; + if (from_type == NULLQUARK) { + from_type = XrmPermStringToQuark(_XtRStateTablePair); + to_type = XrmPermStringToQuark(XtRTranslationTable); + } + UNLOCK_PROCESS; + from.addr = (XPointer)&convert_rec; + from.size = sizeof(TMConvertRec); + to.addr = (XPointer)&newTable; + to.size = sizeof(XtTranslations); + convert_rec.old = first; + convert_rec.new = second; + + LOCK_PROCESS; + if (! _XtConvert(dest, from_type, &from, to_type, &to, &cache_ref)) { + UNLOCK_PROCESS; + return NULL; + } + UNLOCK_PROCESS; + +#ifndef REFCNT_TRANSLATIONS + + if (cache_ref) + XtAddCallback(dest, XtNdestroyCallback, + XtCallbackReleaseCacheRef, (XtPointer)cache_ref); + +#endif + + return newTable; +} + +/* + * Unmerge will recursively traverse the xlation compose tree and + * generate a new xlation that is the result of all instances of + * xlations being removed. It currently doesn't differentiate between + * the potential that an xlation will be both an accelerator and + * normal. This is not supported by the spec anyway. + */ +static XtTranslations UnmergeTranslations(widget, xlations, unmergeXlations, + currIndex, + oldBindings, numOldBindings, + newBindings, numNewBindingsRtn) + Widget widget; + XtTranslations xlations, unmergeXlations; + TMComplexBindProcs oldBindings, newBindings; + TMShortCard currIndex, numOldBindings, *numNewBindingsRtn; + +{ + XtTranslations first, second, result; + + if (!xlations || (xlations == unmergeXlations)) + return NULL; + + if (xlations->composers[0]) { + first = UnmergeTranslations(widget, xlations->composers[0], + unmergeXlations, currIndex, + oldBindings, numOldBindings, + newBindings, numNewBindingsRtn); + } + else + first = NULL; + + if (xlations->composers[1]) { + second = UnmergeTranslations(widget, xlations->composers[1], + unmergeXlations, + currIndex + + xlations->composers[0]->numStateTrees, + oldBindings, numOldBindings, + newBindings, numNewBindingsRtn); + } + else + second = NULL; + + if (first || second) { + if (first && second) { + if ((first != xlations->composers[0]) || + (second != xlations->composers[1])) + result = MergeThem(widget, first, second); + else result = xlations; + } + else { + if (first) + result = first; + else + result = second; + } + } else { /* only update for leaf nodes */ + if (numOldBindings) { + Cardinal i; + for (i = 0; i < xlations->numStateTrees; i++) { + if (xlations->stateTreeTbl[i]->simple.isAccelerator) + newBindings[*numNewBindingsRtn] = + oldBindings[currIndex + i]; + (*numNewBindingsRtn)++; + } + } + result = xlations; + } + return result; +} + +typedef struct { + XtTranslations xlations; + TMComplexBindProcs bindings; +}MergeBindRec, *MergeBind; + +static XtTranslations MergeTranslations(widget, oldXlations, newXlations, + operation, source, oldBindings, + newBindings, numNewRtn) + Widget widget; + XtTranslations oldXlations, newXlations; + _XtTranslateOp operation; + TMComplexBindProcs oldBindings, newBindings; + Widget source; + TMShortCard *numNewRtn; +{ + XtTranslations newTable, xlations; + TMComplexBindProcs bindings; + TMShortCard i, j; + TMStateTree *treePtr; + TMShortCard numNew = *numNewRtn; + MergeBindRec bindPair[2]; + + /* If the new translation has an accelerator context then pull it + * off and pass it and the real xlations in to the caching merge + * routine. + */ + if (newXlations->hasBindings) { + xlations = ((ATranslations) newXlations)->xlations; + bindings = (TMComplexBindProcs) + &((ATranslations) newXlations)->bindTbl[0]; + } + else { + xlations = newXlations; + bindings = NULL; + } + switch(operation) { + case XtTableReplace: + newTable = bindPair[0].xlations = xlations; + bindPair[0].bindings = bindings; + bindPair[1].xlations = NULL; + bindPair[1].bindings = NULL; + break; + case XtTableAugment: + bindPair[0].xlations = oldXlations; + bindPair[0].bindings = oldBindings; + bindPair[1].xlations = xlations; + bindPair[1].bindings = bindings; + newTable = NULL; + break; + case XtTableOverride: + bindPair[0].xlations = xlations; + bindPair[0].bindings = bindings; + bindPair[1].xlations = oldXlations; + bindPair[1].bindings = oldBindings; + newTable = NULL; + break; + } + if (!newTable) + newTable = MergeThem(widget, bindPair[0].xlations, bindPair[1].xlations); + + for (i = 0, numNew = 0; i < 2; i++) { + if (bindPair[i].xlations) + for (j = 0; j < bindPair[i].xlations->numStateTrees; j++, numNew++) { + if (bindPair[i].xlations->stateTreeTbl[j]->simple.isAccelerator) { + if (bindPair[i].bindings) + newBindings[numNew] = bindPair[i].bindings[j]; + else { + newBindings[numNew].widget = source; + newBindings[numNew].aXlations = + bindPair[i].xlations; + } + } + } + } + *numNewRtn = numNew; + treePtr = &newTable->stateTreeTbl[0]; + for (i = 0; i < newTable->numStateTrees; i++, treePtr++) + (*treePtr)->simple.refCount++; + return newTable; +} + +static TMBindData MakeBindData(bindings, numBindings, oldBindData) + TMComplexBindProcs bindings; + TMShortCard numBindings; + TMBindData oldBindData; +{ + TMLongCard bytes; + TMShortCard i; + Boolean isComplex; + TMBindData bindData; + + if (numBindings == 0) + return NULL; + for (i = 0; i < numBindings; i++) + if (bindings[i].widget) + break; + isComplex = (i < numBindings); + if (isComplex) + bytes = (sizeof(TMComplexBindDataRec) + + ((numBindings - 1) * + sizeof(TMComplexBindProcsRec))); + else + bytes = (sizeof(TMSimpleBindDataRec) + + ((numBindings - 1) * + sizeof(TMSimpleBindProcsRec))); + + bindData = (TMBindData) __XtCalloc(sizeof(char), bytes); + bindData->simple.isComplex = isComplex; + if (isComplex) { + TMComplexBindData cBindData = (TMComplexBindData)bindData; + /* + * If there were any accelerator contexts in the old bindData + * then propagate them to the new one. + */ + if (oldBindData && oldBindData->simple.isComplex) + cBindData->accel_context = + ((TMComplexBindData) oldBindData)->accel_context; + XtMemmove((char *)&cBindData->bindTbl[0], (char *)bindings, + numBindings * sizeof(TMComplexBindProcsRec)); + } + return bindData; +} + +/* + * This routine is the central clearinghouse for merging translations + * into a widget. It takes care of preping the action bindings for + * realize time and calling the converter or doing a straight merge if + * the destination is empty. + */ +static Boolean ComposeTranslations(dest, operation, source, newXlations) + Widget dest, source; + _XtTranslateOp operation; + XtTranslations newXlations; +{ + XtTranslations newTable, oldXlations; + XtTranslations accNewXlations; + EventMask oldMask; + TMBindData bindData; + TMComplexBindProcs oldBindings = NULL; + TMShortCard numOldBindings, numNewBindings = 0, numBytes; + TMComplexBindProcsRec stackBindings[16], *newBindings; + + /* + * how should we be handling the refcount decrement for the + * replaced translation table ??? + */ + if (!newXlations) + { + XtAppWarningMsg(XtWidgetToApplicationContext(dest), + XtNtranslationError,"nullTable",XtCXtToolkitError, + "table to (un)merge must not be null", + (String *)NULL, (Cardinal *)NULL); + return False; + } + + accNewXlations = newXlations; + newXlations = ((newXlations->hasBindings) + ? ((ATranslations)newXlations)->xlations + : newXlations); + + if (!(oldXlations = dest->core.tm.translations)) + operation = XtTableReplace; + + /* + * try to avoid generation of duplicate state trees. If the source + * isn't simple (1 state Tree) then it's too much hassle + */ + if (((operation == XtTableAugment) || + (operation == XtTableOverride)) && + (newXlations->numStateTrees == 1)) { + Cardinal i; + for (i = 0; i < oldXlations->numStateTrees; i++) + if (oldXlations->stateTreeTbl[i] == + newXlations->stateTreeTbl[0]) + break; + if (i < oldXlations->numStateTrees) { + if (operation == XtTableAugment) { + /* + * we don't need to do anything since it's already + * there + */ + return True; + } + else {/* operation == XtTableOverride */ + /* + * We'll get rid of the duplicate trees throughout the + * and leave it with a pruned translation table. This + * will only work if the same table has been merged + * into this table (or one of it's composers + */ + _XtUnmergeTranslations(dest, newXlations); + /* + * reset oldXlations so we're back in sync + */ + if (!(oldXlations = dest->core.tm.translations)) + operation = XtTableReplace; + } + } + } + + bindData = (TMBindData) dest->core.tm.proc_table; + if (bindData) { + numOldBindings = (oldXlations ? oldXlations->numStateTrees : 0); + if (bindData->simple.isComplex) + oldBindings = &((TMComplexBindData)bindData)->bindTbl[0]; + else + oldBindings = (TMComplexBindProcs) + (&((TMSimpleBindData)bindData)->bindTbl[0]); + } + + numBytes =(((oldXlations ? oldXlations->numStateTrees : 0) + + newXlations->numStateTrees) * sizeof(TMComplexBindProcsRec)); + newBindings = (TMComplexBindProcs) XtStackAlloc(numBytes, stackBindings); + XtBZero((char *)newBindings, numBytes); + + if (operation == XtTableUnmerge) { + newTable = UnmergeTranslations(dest, + oldXlations, + newXlations, + 0, + oldBindings, numOldBindings, + newBindings, &numNewBindings); +#ifdef DEBUG + /* check for no match for unmerge */ + if (newTable == oldXlations) { + XtWarning("attempt to unmerge invalid table"); + XtStackFree((char *)newBindings, (char *)stackBindings); + return(newTable != NULL); + } +#endif /* DEBUG */ + } + else { + newTable = MergeTranslations(dest, + oldXlations, + accNewXlations, + operation, + source, + oldBindings, + newBindings, + &numNewBindings); + } + if (XtIsRealized(dest)) { + oldMask = 0; + if (oldXlations) + oldMask = oldXlations->eventMask; + _XtUninstallTranslations(dest); + } + + dest->core.tm.proc_table = + (XtActionProc *) MakeBindData(newBindings, numNewBindings, bindData); + + if (bindData) XtFree((char *)bindData); + + dest->core.tm.translations = newTable; + + if (XtIsRealized(dest)) { + EventMask mask = 0; + _XtInstallTranslations(dest); + if (newTable) + mask = newTable->eventMask; + if (mask != oldMask) + XSelectInput(XtDisplay(dest), XtWindow(dest), + XtBuildEventMask(dest)); + } + XtStackFree((XtPointer)newBindings, (XtPointer)stackBindings); + return(newTable != NULL); +} + +/* + * If a GetValues is done on a translation resource that contains + * accelerators we need to return the accelerator context in addition + * to the pure translations. Since this means returning memory that + * the client controlls but we still own, we will track the "headers" + * that we return (via a linked list pointed to from the bindData) and + * free it at destroy time. + */ +XtTranslations _XtGetTranslationValue(w) + Widget w; +{ + XtTM tmRecPtr = (XtTM) &w->core.tm; + ATranslations *aXlationsPtr; + TMComplexBindData cBindData = (TMComplexBindData) tmRecPtr->proc_table; + XtTranslations xlations = tmRecPtr->translations; + + if (!xlations || !cBindData || !cBindData->isComplex) + return xlations; + + /* Walk the list looking to see if we already have generated a + * header for the currently installed translations. If we have, + * just return that header. Otherwise create a new header. + */ + for (aXlationsPtr = (ATranslations *) &cBindData->accel_context; + *aXlationsPtr && (*aXlationsPtr)->xlations != xlations; + aXlationsPtr = &(*aXlationsPtr)->next) + ; + if (*aXlationsPtr) + return (XtTranslations) *aXlationsPtr; + else { + /* create a new aXlations context */ + ATranslations aXlations; + Cardinal numBindings = xlations->numStateTrees; + + (*aXlationsPtr) = aXlations = (ATranslations) + __XtMalloc(sizeof(ATranslationData) + + (numBindings - 1) * sizeof(TMComplexBindProcsRec)); + + aXlations->hasBindings = True; + aXlations->xlations = xlations; + aXlations->next = NULL; + XtMemmove((char *) &aXlations->bindTbl[0], + (char *) &cBindData->bindTbl[0], + numBindings * sizeof(TMComplexBindProcsRec)); + return (XtTranslations) aXlations; + } +} + + +/*ARGSUSED*/ +static void RemoveStateTree(tree) + TMStateTree tree; +{ +#ifdef REFCNT_TRANSLATIONS + TMComplexStateTree stateTree = (TMComplexStateTree)tree; + + if (--stateTree->refCount == 0) { + /* + * should we free/refcount the match recs ? + */ + if (!stateTree->isSimple) { + StatePtr currState, nextState; + TMShortCard i; + for (i = 0; i < stateTree->numComplexBranchHeads; i++) { + currState = + nextState = + stateTree->complexBranchHeadTbl[i]; + for (; nextState;){ + FreeActions(currState->actions); + currState->actions = NULL; + if (!currState->isCycleEnd) + nextState = currState->nextLevel; + else + nextState = NULL; + XtFree( (char*)currState ); + } + } + XtFree((char*)stateTree->complexBranchHeadTbl); + } + XtFree((char*)stateTree->branchHeadTbl); + XtFree((char*)stateTree); + } +#endif /* REFCNT_TRANSLATIONS */ +} + +void _XtRemoveStateTreeByIndex(xlations, i) + XtTranslations xlations; + TMShortCard i; +{ + TMStateTree *stateTrees = xlations->stateTreeTbl; + + RemoveStateTree(stateTrees[i]); + xlations->numStateTrees--; + + for (; i < xlations->numStateTrees; i++) + { + stateTrees[i] = stateTrees[i+1]; + } +} + +/* ARGSUSED */ +void _XtFreeTranslations(app, toVal, closure, args, num_args) + XtAppContext app; + XrmValuePtr toVal; + XtPointer closure; + XrmValuePtr args; + Cardinal *num_args; +{ + XtTranslations xlations; + int i; + + if (*num_args != 0) + XtAppWarningMsg(app, + "invalidParameters","freeTranslations",XtCXtToolkitError, + "Freeing XtTranslations requires no extra arguments", + (String *)NULL, (Cardinal *)NULL); + + xlations = *(XtTranslations*)toVal->addr; + for (i = 0; i < (int)xlations->numStateTrees; i++) + RemoveStateTree(xlations->stateTreeTbl[i]); + XtFree((char *)xlations); +} + +/* The spec is not clear on when actions specified in accelerators are bound; + * Bind them at Realize the same as translations + */ +void XtInstallAccelerators(destination, source) + Widget destination, source; +{ + XtTranslations aXlations; + _XtTranslateOp op; + String buf; + WIDGET_TO_APPCON(destination); + + /* + * test that it was parsed as an accelarator table. Even though + * there doesn't need to be a distinction it makes life easier if + * we honor the spec implication that aXlations is an accelerator + */ + LOCK_APP(app); + LOCK_PROCESS; + if ((!XtIsWidget(source)) || + ((aXlations = source->core.accelerators) == NULL) || + (aXlations->stateTreeTbl[0]->simple.isAccelerator == False)) { + UNLOCK_PROCESS; + UNLOCK_APP(app); + return; + } + + aXlations = source->core.accelerators; + op = aXlations->operation; + + if (ComposeTranslations(destination, op, source, aXlations) && + (XtClass(source)->core_class.display_accelerator != NULL)) { + + buf = _XtPrintXlations(destination, aXlations, source, False); + (*(XtClass(source)->core_class.display_accelerator))(source,buf); + XtFree(buf); + } + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +void XtInstallAllAccelerators(destination,source) + Widget destination,source; +{ + int i; + CompositeWidget cw; + WIDGET_TO_APPCON(destination); + + /* Recurse down normal children */ + LOCK_APP(app); + LOCK_PROCESS; + if (XtIsComposite(source)) { + cw = (CompositeWidget) source; + for (i = 0; i < cw->composite.num_children; i++) { + XtInstallAllAccelerators(destination,cw->composite.children[i]); + } + } + + /* Recurse down popup children */ + if (XtIsWidget(source)) { + for (i = 0; i < source->core.num_popups; i++) { + XtInstallAllAccelerators(destination,source->core.popup_list[i]); + } + } + /* Finally, apply procedure to this widget */ + XtInstallAccelerators(destination,source); + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +#if 0 /* dead code */ +static _XtTranslateOp _XtGetTMOperation(xlations) + XtTranslations xlations; +{ + return ((xlations->hasBindings) + ? ((ATranslations)xlations)->xlations->operation + : xlations->operation); +} +#endif + +void XtAugmentTranslations(widget, new) + Widget widget; + XtTranslations new; +{ + Widget hookobj; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + LOCK_PROCESS; + (void)ComposeTranslations(widget, XtTableAugment, (Widget)NULL, new); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHaugmentTranslations; + call_data.widget = widget; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +void XtOverrideTranslations(widget, new) + Widget widget; + XtTranslations new; +{ + Widget hookobj; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + LOCK_PROCESS; + (void) ComposeTranslations(widget, XtTableOverride, (Widget)NULL, new); + hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); + if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) { + XtChangeHookDataRec call_data; + + call_data.type = XtHoverrideTranslations; + call_data.widget = widget; + XtCallCallbackList(hookobj, + ((HookObject)hookobj)->hooks.changehook_callbacks, + (XtPointer)&call_data); + } + UNLOCK_PROCESS; + UNLOCK_APP(app); +} + +void _XtMergeTranslations(widget, newXlations, op) + Widget widget; + XtTranslations newXlations; + _XtTranslateOp op; +{ + if (!newXlations){ + if (!widget->core.tm.translations) + return; + else { + newXlations = widget->core.tm.translations; + widget->core.tm.translations = NULL; + } + } + (void) ComposeTranslations(widget, + op, + (Widget)NULL, + newXlations); +} + +void _XtUnmergeTranslations(widget, xlations) + Widget widget; + XtTranslations xlations; +{ + ComposeTranslations(widget, XtTableUnmerge, (Widget)NULL, xlations); +} diff --git a/src/Threads.c b/src/Threads.c new file mode 100644 index 0000000..2fca1fb --- /dev/null +++ b/src/Threads.c @@ -0,0 +1,473 @@ +/* $Xorg: Threads.c,v 1.4 2001/02/09 02:03:59 xorgcvs Exp $ */ + +/************************************************************ +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright no- +tice appear in all copies and that both that copyright no- +tice and this permission notice appear in supporting docu- +mentation, and that the name Sun not be used in advertising +or publicity pertaining to distribution of the software +without specific prior written permission. Sun makes no +representations about the suitability of this software for +any purpose. It is provided "as is" without any express or +implied warranty. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +********************************************************/ + +/* + +Copyright 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" + +#ifdef XTHREADS + +#define xmalloc __XtMalloc +#define xfree XtFree +#include <X11/Xthreads.h> + +#ifndef NDEBUG +#define NDEBUG +#endif +#include <assert.h> +#include <stdio.h> + +typedef struct _ThreadStack { + unsigned int size; + int sp; + struct _Tstack { + xthread_t t; + xcondition_t c; + } *st; +} ThreadStack; + +typedef struct _LockRec { + xmutex_t mutex; + int level; + ThreadStack stack; +#ifndef _XMUTEX_NESTS + xthread_t holder; + xcondition_t cond; +#endif +} LockRec; + + +#define STACK_INCR 16 + +static LockPtr process_lock = NULL; + +static void +InitProcessLock() +{ + if(!process_lock) { + process_lock = XtNew(LockRec); + process_lock->mutex = xmutex_malloc(); + xmutex_init(process_lock->mutex); + process_lock->level = 0; +#ifndef _XMUTEX_NESTS + process_lock->cond = xcondition_malloc(); + xcondition_init(process_lock->cond); + xthread_clear_id(process_lock->holder); +#endif + } +} + +static void +ProcessLock() +{ +#ifdef _XMUTEX_NESTS + xmutex_lock(process_lock->mutex); + process_lock->level++; +#else + xthread_t this_thread = xthread_self(); + + xmutex_lock(process_lock->mutex); + + if (!xthread_have_id(process_lock->holder)) { + process_lock->holder = this_thread; + xmutex_unlock(process_lock->mutex); + return; + } + + if (xthread_equal(process_lock->holder,this_thread)) { + process_lock->level++; + xmutex_unlock(process_lock->mutex); + return; + } + + while(xthread_have_id(process_lock->holder)) + xcondition_wait(process_lock->cond, process_lock->mutex); + + process_lock->holder = this_thread; + assert(xthread_equal(process_lock->holder, this_thread)); + xmutex_unlock(process_lock->mutex); +#endif +} + +static void +ProcessUnlock() +{ +#ifdef _XMUTEX_NESTS + process_lock->level--; + xmutex_unlock(process_lock->mutex); +#else + xmutex_lock(process_lock->mutex); + assert(xthread_equal(process_lock->holder, xthread_self())); + if (process_lock->level != 0) { + process_lock->level--; + xmutex_unlock(process_lock->mutex); + return; + } + + xthread_clear_id(process_lock->holder); + xcondition_signal(process_lock->cond); + + xmutex_unlock(process_lock->mutex); +#endif +} + + +static void +#if NeedFunctionPrototypes +AppLock( + XtAppContext app) +#else +AppLock(app) + XtAppContext app; +#endif +{ + LockPtr app_lock = app->lock_info; +#ifdef _XMUTEX_NESTS + xmutex_lock(app_lock->mutex); + app_lock->level++; +#else + xthread_t self = xthread_self(); + xmutex_lock(app_lock->mutex); + if (!xthread_have_id(app_lock->holder)) { + app_lock->holder = self; + assert(xthread_equal(app_lock->holder, self)); + xmutex_unlock(app_lock->mutex); + return; + } + if (xthread_equal(app_lock->holder, self)) { + app_lock->level++; + xmutex_unlock(app_lock->mutex); + return; + } + while(xthread_have_id(app_lock->holder)) { + xcondition_wait(app_lock->cond, app_lock->mutex); + } + app_lock->holder = self; + assert(xthread_equal(app_lock->holder, self)); + xmutex_unlock(app_lock->mutex); +#endif +} + +static void +#if NeedFunctionPrototypes +AppUnlock( + XtAppContext app) +#else +AppUnlock(app) + XtAppContext app; +#endif +{ + LockPtr app_lock = app->lock_info; +#ifdef _XMUTEX_NESTS + app_lock->level--; + xmutex_unlock(app_lock->mutex); +#else + xthread_t self = xthread_self(); + xmutex_lock(app_lock->mutex); + assert(xthread_equal(app_lock->holder, self)); + if (app_lock->level != 0) { + app_lock->level--; + xmutex_unlock(app_lock->mutex); + return; + } + xthread_clear_id(app_lock->holder); + xcondition_signal(app_lock->cond); + xmutex_unlock(app_lock->mutex); +#endif +} + +static void +#if NeedFunctionPrototypes +YieldAppLock( + XtAppContext app, + Boolean* push_thread, + Boolean* pushed_thread, + int* level) +#else +YieldAppLock(app, push_thread, pushed_thread, level) + XtAppContext app; + Boolean* push_thread; + Boolean* pushed_thread; + int* level; +#endif +{ + LockPtr app_lock = app->lock_info; + xthread_t self = xthread_self(); +#ifndef _XMUTEX_NESTS + xmutex_lock(app_lock->mutex); + assert(xthread_equal(app_lock->holder, self)); +#endif + *level = app_lock->level; + if (*push_thread) { + *push_thread = FALSE; + *pushed_thread = TRUE; + + if(app_lock->stack.sp == app_lock->stack.size - 1) { + int ii; + app_lock->stack.st = (struct _Tstack *) + XtRealloc ((char *)app_lock->stack.st, + (app_lock->stack.size + STACK_INCR) * sizeof (struct _Tstack)); + ii = app_lock->stack.size; + app_lock->stack.size += STACK_INCR; + for ( ; ii < app_lock->stack.size; ii++) { + app_lock->stack.st[ii].c = xcondition_malloc(); + xcondition_init(app_lock->stack.st[ii].c); + } + } + app_lock->stack.st[++(app_lock->stack.sp)].t = self; + } +#ifdef _XMUTEX_NESTS + while (app_lock->level > 0) { + app_lock->level--; + xmutex_unlock(app_lock->mutex); + } +#else + xcondition_signal(app_lock->cond); + app_lock->level = 0; + xthread_clear_id(app_lock->holder); + xmutex_unlock(app_lock->mutex); +#endif +} + +static void +#if NeedFunctionPrototypes +RestoreAppLock( + XtAppContext app, + int level, + Boolean* pushed_thread) +#else +RestoreAppLock(app, level, pushed_thread) + XtAppContext app; + int level; + Boolean* pushed_thread; +#endif +{ + LockPtr app_lock = app->lock_info; + xthread_t self = xthread_self(); + xmutex_lock(app_lock->mutex); +#ifdef _XMUTEX_NESTS + app_lock->level++; +#else + while(xthread_have_id(app_lock->holder)) { + xcondition_wait(app_lock->cond, app_lock->mutex); + } +#endif + if (!xthread_equal(app_lock->stack.st[app_lock->stack.sp].t, self)) { + int ii; + for (ii = app_lock->stack.sp - 1; ii >= 0; ii--) { + if (xthread_equal(app_lock->stack.st[ii].t, self)) { + xcondition_wait(app_lock->stack.st[ii].c, app_lock->mutex); + break; + } + } +#ifndef _XMUTEX_NESTS + while(xthread_have_id(app_lock->holder)) { + xcondition_wait(app_lock->cond, app_lock->mutex); + } +#endif + } +#ifdef _XMUTEX_NESTS + while (app_lock->level < level) { + xmutex_lock(app_lock->mutex); + app_lock->level++; + } +#else + app_lock->holder = self; + app_lock->level = level; + assert(xthread_equal(app_lock->holder, self)); +#endif + if (*pushed_thread) { + *pushed_thread = FALSE; + (app_lock->stack.sp)--; + if (app_lock->stack.sp >= 0) { + xcondition_signal (app_lock->stack.st[app_lock->stack.sp].c); + } + } +#ifndef _XMUTEX_NESTS + xmutex_unlock(app_lock->mutex); +#endif +} + +static void +#if NeedFunctionPrototypes +FreeAppLock( + XtAppContext app) +#else +FreeAppLock(app) + XtAppContext app; +#endif +{ + int ii; + LockPtr app_lock = app->lock_info; + + if(app_lock) { + xmutex_clear(app_lock->mutex); + xmutex_free(app_lock->mutex); +#ifndef _XMUTEX_NESTS + xcondition_clear(app_lock->cond); + xcondition_free(app_lock->cond); +#endif + if(app_lock->stack.st != (struct _Tstack *)NULL) { + for (ii = 0; ii < app_lock->stack.size; ii++) { + xcondition_clear(app_lock->stack.st[ii].c); + xcondition_free(app_lock->stack.st[ii].c); + } + XtFree((char *)app_lock->stack.st); + } + XtFree((char *)app_lock); + app->lock_info = NULL; + } +} + +static void +#if NeedFunctionPrototypes +InitAppLock( + XtAppContext app) +#else +InitAppLock(app) + XtAppContext app; +#endif +{ + int ii; + LockPtr app_lock; + + app->lock = AppLock; + app->unlock = AppUnlock; + app->yield_lock = YieldAppLock; + app->restore_lock = RestoreAppLock; + app->free_lock = FreeAppLock; + + app_lock = app->lock_info = XtNew(LockRec); + app_lock->mutex = xmutex_malloc(); + xmutex_init(app_lock->mutex); + app_lock->level = 0; +#ifndef _XMUTEX_NESTS + app_lock->cond = xcondition_malloc(); + xcondition_init(app_lock->cond); + xthread_clear_id(app_lock->holder); +#endif + app_lock->stack.size = STACK_INCR; + app_lock->stack.sp = -1; + app_lock->stack.st = + (struct _Tstack *)__XtMalloc(sizeof(struct _Tstack)*STACK_INCR); + for (ii = 0; ii < STACK_INCR; ii++) { + app_lock->stack.st[ii].c = xcondition_malloc(); + xcondition_init(app_lock->stack.st[ii].c); + } +} + +#endif /* defined(XTHREADS) */ + +#if NeedFunctionPrototypes +void XtAppLock( + XtAppContext app) +#else +void XtAppLock(app) + XtAppContext app; +#endif +{ +#ifdef XTHREADS + if(app->lock) + (*app->lock)(app); +#endif +} + +#if NeedFunctionPrototypes +void XtAppUnlock( + XtAppContext app) +#else +void XtAppUnlock(app) + XtAppContext app; +#endif +{ +#ifdef XTHREADS + if(app->unlock) + (*app->unlock)(app); +#endif +} + +void XtProcessLock() +{ +#ifdef XTHREADS + if(_XtProcessLock) + (*_XtProcessLock)(); +#endif +} + +void XtProcessUnlock() +{ +#ifdef XTHREADS + if(_XtProcessUnlock) + (*_XtProcessUnlock)(); +#endif +} + +Boolean XtToolkitThreadInitialize() +{ +#ifdef XTHREADS + if (_XtProcessLock == NULL) { +#ifdef xthread_init + xthread_init(); +#endif + InitProcessLock(); + _XtProcessLock = ProcessLock; + _XtProcessUnlock = ProcessUnlock; + _XtInitAppLock = InitAppLock; + } + return True; +#else + return False; +#endif +} + diff --git a/src/VarCreate.c b/src/VarCreate.c new file mode 100644 index 0000000..3d9614d --- /dev/null +++ b/src/VarCreate.c @@ -0,0 +1,509 @@ +/* $Xorg: VarCreate.c,v 1.4 2001/02/09 02:03:59 xorgcvs Exp $ */ + +/* + +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright +notice and this permission notice appear in supporting +documentation, and that the name Sun not be used in +advertising or publicity pertaining to distribution of the +software without specific, written prior permission. +Sun makes no representations about the suitability of +this software for any purpose. It is provided "as is" +without express or implied warranty. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +/* + +Copyright 1885, 1986, 1987, 1988, 1989, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "StringDefs.h" +#include "Shell.h" +#include "VarargsI.h" + +#if (defined(SUNSHLIB) || defined(AIXSHLIB)) && defined(SHAREDCODE) +#define XtToolkitInitialize _XtToolkitInitialize +#endif /* (SUNSHLIB || AIXSHLIB) && SHAREDCODE */ + +extern Widget _XtCreateWidget(); +extern Widget _XtAppCreateShell(); +extern Widget _XtCreatePopupShell(); + +static Widget +_XtVaCreateWidget(name, widget_class, parent, var, count) + String name; + WidgetClass widget_class; + Widget parent; + va_list var; + int count; +{ + register Widget widget; + XtTypedArgList typed_args = NULL; + Cardinal num_args; + + _XtVaToTypedArgList(var, count, &typed_args, &num_args); + + widget = _XtCreateWidget(name, widget_class, parent, (ArgList)NULL, + (Cardinal)0, typed_args, num_args); + + if (typed_args != NULL) { + XtFree((XtPointer)typed_args); + } + + return widget; +} + + +#if NeedVarargsPrototypes +Widget +XtVaCreateWidget( + _Xconst char* name, + WidgetClass widget_class, + Widget parent, + ...) +#else +/*VARARGS3*/ +Widget XtVaCreateWidget(name, widget_class, parent, va_alist) + String name; + WidgetClass widget_class; + Widget parent; + va_dcl +#endif +{ + va_list var; + register Widget widget; + int total_count, typed_count; + WIDGET_TO_APPCON(parent); + + LOCK_APP(app); + Va_start(var,parent); + _XtCountVaList(var, &total_count, &typed_count); + va_end(var); + + Va_start(var,parent); + widget = _XtVaCreateWidget(name, widget_class, parent, var, total_count); + va_end(var); + UNLOCK_APP(app); + return widget; +} + + +#if NeedVarargsPrototypes +Widget +XtVaCreateManagedWidget( + _Xconst char* name, + WidgetClass widget_class, + Widget parent, + ...) +#else +/*VARARGS3*/ +Widget XtVaCreateManagedWidget(name, widget_class, parent, va_alist) + String name; + WidgetClass widget_class; + Widget parent; + va_dcl +#endif +{ + va_list var; + register Widget widget; + int total_count, typed_count; + WIDGET_TO_APPCON(parent); + + LOCK_APP(app); + Va_start(var,parent); + _XtCountVaList(var, &total_count, &typed_count); + va_end(var); + + Va_start(var,parent); + widget = _XtVaCreateWidget(name, widget_class, parent, var, total_count); + XtManageChild(widget); + va_end(var); + UNLOCK_APP(app); + return widget; +} + + +#if NeedVarargsPrototypes +Widget +XtVaAppCreateShell( + _Xconst char* name, + _Xconst char* class, + WidgetClass widget_class, + Display* display, + ...) +#else +/*VARARGS4*/ +Widget XtVaAppCreateShell(name, class, widget_class, display, va_alist) + String name; + String class; + WidgetClass widget_class; + Display* display; + va_dcl +#endif +{ + va_list var; + register Widget widget; + XtTypedArgList typed_args = NULL; + Cardinal num_args; + int total_count, typed_count; + DPY_TO_APPCON(display); + + LOCK_APP(app); + Va_start(var,display); + _XtCountVaList(var, &total_count, &typed_count); + va_end(var); + + Va_start(var,display); + + _XtVaToTypedArgList(var, total_count, &typed_args, &num_args); + widget = _XtAppCreateShell(name, class, widget_class, display, + (ArgList)NULL, (Cardinal)0, typed_args, num_args); + if (typed_args != NULL) { + XtFree((XtPointer)typed_args); + } + + va_end(var); + UNLOCK_APP(app); + return widget; +} + + +#if NeedVarargsPrototypes +Widget +XtVaCreatePopupShell( + _Xconst char* name, + WidgetClass widget_class, + Widget parent, + ...) +#else +/*VARARGS3*/ +Widget XtVaCreatePopupShell(name, widget_class, parent, va_alist) + String name; + WidgetClass widget_class; + Widget parent; + va_dcl +#endif +{ + va_list var; + register Widget widget; + XtTypedArgList typed_args = NULL; + Cardinal num_args; + int total_count, typed_count; + WIDGET_TO_APPCON(parent); + + LOCK_APP(app); + Va_start(var,parent); + _XtCountVaList(var, &total_count, &typed_count); + va_end(var); + + Va_start(var,parent); + + _XtVaToTypedArgList(var, total_count, &typed_args, &num_args); + widget = _XtCreatePopupShell(name, widget_class, parent, + (ArgList)NULL, (Cardinal)0, typed_args, num_args); + if (typed_args != NULL) { + XtFree((XtPointer)typed_args); + } + + va_end(var); + UNLOCK_APP(app); + return widget; +} + +#if NeedVarargsPrototypes +void +XtVaSetValues(Widget widget, ...) +#else +/*VARARGS1*/ +void XtVaSetValues(widget, va_alist) + Widget widget; + va_dcl +#endif +{ + va_list var; + ArgList args = NULL; + Cardinal num_args; + int total_count, typed_count; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + Va_start(var,widget); + _XtCountVaList(var, &total_count, &typed_count); + va_end(var); + + Va_start(var,widget); + + _XtVaToArgList(widget, var, total_count, &args, &num_args); + XtSetValues(widget, args, num_args); + _XtFreeArgList(args, total_count, typed_count); + + UNLOCK_APP(app); + va_end(var); +} + + +#if NeedVarargsPrototypes +void +XtVaSetSubvalues(XtPointer base, XtResourceList resources, Cardinal num_resources, ...) +#else +/*VARARGS3*/ +void XtVaSetSubvalues(base, resources, num_resources, va_alist) + XtPointer base; + XtResourceList resources; + Cardinal num_resources; + va_dcl +#endif +{ + va_list var; + ArgList args; + Cardinal num_args; + int total_count, typed_count; + + Va_start(var, num_resources); + _XtCountVaList(var, &total_count, &typed_count); + va_end(var); + + if (typed_count != 0) { + XtWarning("XtVaTypedArg is not valid in XtVaSetSubvalues()\n"); + } + + Va_start(var, num_resources); + _XtVaToArgList((Widget)NULL, var, total_count, &args, &num_args); + + XtSetSubvalues(base, resources, num_resources, args, num_args); + + if (num_args != 0) { + XtFree((XtPointer)args); + } + + va_end(var); +} + +#if NeedVarargsPrototypes +Widget +_XtVaOpenApplication( + XtAppContext *app_context_return, + _Xconst char* application_class, + XrmOptionDescList options, + Cardinal num_options, + int *argc_in_out, + String *argv_in_out, + String *fallback_resources, + WidgetClass widget_class, + va_list var_args) +#else +/*VARARGS8*/ +Widget _XtVaOpenApplication(app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, widget_class, var_args) + XtAppContext *app_context_return; + char *application_class; + XrmOptionDescList options; + Cardinal num_options; + int *argc_in_out; + String *argv_in_out; + String *fallback_resources; + WidgetClass widget_class; + va_list var_args; +#endif +{ + XtAppContext app_con; + Display * dpy; + register int saved_argc = *argc_in_out; + Widget root; + String attr; + int count = 0; + XtTypedArgList typed_args; + + XtToolkitInitialize(); /* cannot be moved into _XtAppInit */ + + dpy = _XtAppInit(&app_con, (String)application_class, options, num_options, + argc_in_out, &argv_in_out, fallback_resources); + + typed_args = (XtTypedArgList) __XtMalloc((unsigned) sizeof(XtTypedArg)); + attr = va_arg (var_args, String); + for(; attr != NULL; attr = va_arg (var_args, String)) { + if (strcmp(attr, XtVaTypedArg) == 0) { + typed_args[count].name = va_arg(var_args, String); + typed_args[count].type = va_arg(var_args, String); + typed_args[count].value = va_arg(var_args, XtArgVal); + typed_args[count].size = va_arg(var_args, int); + } else { + typed_args[count].name = attr; + typed_args[count].type = NULL; + typed_args[count].value = va_arg(var_args, XtArgVal); + typed_args[count].size = 0; + } + count++; + typed_args = (XtTypedArgList) + XtRealloc((char *) typed_args, + (unsigned) (count + 1) * sizeof(XtTypedArg)); + } + typed_args[count].name = NULL; + + va_end (var_args); + + root = + XtVaAppCreateShell( NULL, application_class, + widget_class, dpy, + XtNscreen, (XtArgVal)DefaultScreenOfDisplay(dpy), + XtNargc, (XtArgVal)saved_argc, + XtNargv, (XtArgVal)argv_in_out, + XtVaNestedList, (XtVarArgsList)typed_args, + NULL ); + + if (app_context_return != NULL) + *app_context_return = app_con; + + XtFree((XtPointer)typed_args); + XtFree((XtPointer)argv_in_out); + return(root); +} + +#if NeedVarargsPrototypes +Widget +_XtVaAppInitialize( + XtAppContext *app_context_return, + _Xconst char* application_class, + XrmOptionDescList options, + Cardinal num_options, + int *argc_in_out, + String *argv_in_out, + String *fallback_resources, + va_list var_args) +#else +/*VARARGS7*/ +Widget _XtVaAppInitialize(app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, var_args) + XtAppContext *app_context_return; + char *application_class; + XrmOptionDescList options; + Cardinal num_options; + int *argc_in_out; + String *argv_in_out; + String *fallback_resources; + va_list var_args; +#endif +{ + return _XtVaOpenApplication(app_context_return, application_class, + options, num_options, + argc_in_out, argv_in_out, fallback_resources, + applicationShellWidgetClass, var_args); +} + +#if !((defined(SUNSHLIB) || defined(AIXSHLIB)) && defined(SHAREDCODE)) + +/* + * If not used as a shared library, we still need a front end to + * _XtVaOpenApplication and to _XtVaAppInitialize. + */ + +#if NeedVarargsPrototypes +Widget +XtVaOpenApplication( + XtAppContext *app_context_return, + _Xconst char* application_class, + XrmOptionDescList options, + Cardinal num_options, + int *argc_in_out, + String *argv_in_out, + String *fallback_resources, + WidgetClass widget_class, + ...) +#else +Widget XtVaOpenApplication(app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, widget_class, va_alist) + XtAppContext *app_context_return; + String application_class; + XrmOptionDescList options; + Cardinal num_options; + int *argc_in_out; + String *argv_in_out; + String *fallback_resources; + WidgetClass widget_class; + va_dcl +#endif +{ + va_list var; + + Va_start(var, widget_class); + return _XtVaOpenApplication(app_context_return, (String)application_class, + options, num_options, argc_in_out, argv_in_out, + fallback_resources, widget_class, var); +} + +#if NeedVarargsPrototypes +Widget +XtVaAppInitialize( + XtAppContext *app_context_return, + _Xconst char* application_class, + XrmOptionDescList options, + Cardinal num_options, + int *argc_in_out, + String *argv_in_out, + String *fallback_resources, + ...) +#else +Widget XtVaAppInitialize(app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, va_alist) + XtAppContext *app_context_return; + String application_class; + XrmOptionDescList options; + Cardinal num_options; + int *argc_in_out; + String *argv_in_out; + String *fallback_resources; + va_dcl +#endif +{ + va_list var; + + Va_start(var, fallback_resources); + return _XtVaOpenApplication(app_context_return, (String)application_class, + options, num_options, argc_in_out, argv_in_out, + fallback_resources, + applicationShellWidgetClass, var); +} + +#endif /* !((SUNSHLIB || AIXSHLIB) && SHAREDCODE) */ + diff --git a/src/VarGet.c b/src/VarGet.c new file mode 100644 index 0000000..ef72cad --- /dev/null +++ b/src/VarGet.c @@ -0,0 +1,351 @@ +/* $Xorg: VarGet.c,v 1.4 2001/02/09 02:03:59 xorgcvs Exp $ */ +/* + +Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA. + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright +notice and this permission notice appear in supporting +documentation, and that the name Sun not be used in +advertising or publicity pertaining to distribution of the +software without specific, written prior permission. +Sun makes no representations about the suitability of +this software for any purpose. It is provided "as is" +without express or implied warranty. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +/* + +Copyright 1985, 1986, 1987, 1988, 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "VarargsI.h" +#include "StringDefs.h" + +static String XtNxtGetTypedArg = "xtGetTypedArg"; + +#if NeedVarargsPrototypes +void +XtVaGetSubresources( + Widget widget, + XtPointer base, + _Xconst char* name, + _Xconst char* class, + XtResourceList resources, + Cardinal num_resources, + ...) +#else +/*VARARGS6*/ +void XtVaGetSubresources(widget, base, name, class, resources, num_resources, va_alist) + Widget widget; + XtPointer base; + String name; + String class; + XtResourceList resources; + Cardinal num_resources; + va_dcl +#endif +{ + va_list var; + XtTypedArgList args; + Cardinal num_args; + int total_count, typed_count; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + Va_start(var, num_resources); + _XtCountVaList(var, &total_count, &typed_count); + va_end(var); + + Va_start(var, num_resources); + + _XtVaToTypedArgList(var, total_count, &args, &num_args); + + _XtGetSubresources(widget, base, name, class, resources, num_resources, + NULL, 0, args, num_args); + + if (num_args != 0) { + XtFree((XtPointer)args); + } + + va_end(var); + UNLOCK_APP(app); +} + + +#if NeedVarargsPrototypes +void +XtVaGetApplicationResources(Widget widget, XtPointer base, XtResourceList resources, Cardinal num_resources, ...) +#else +/*VARARGS4*/ +void XtVaGetApplicationResources(widget, base, resources, num_resources, va_alist) + Widget widget; + XtPointer base; + XtResourceList resources; + Cardinal num_resources; + va_dcl +#endif +{ + va_list var; + XtTypedArgList args; + Cardinal num_args; + int total_count, typed_count; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + Va_start(var,num_resources); + _XtCountVaList(var, &total_count, &typed_count); + va_end(var); + + Va_start(var,num_resources); + + _XtVaToTypedArgList(var, total_count, &args, &num_args); + + _XtGetApplicationResources(widget, base, resources, num_resources, + NULL, 0, args, num_args); + + if (num_args != 0) { + XtFree((XtPointer)args); + } + + va_end(var); + UNLOCK_APP(app); +} + + +static void +GetTypedArg(widget, typed_arg, resources, num_resources) + Widget widget; + XtTypedArgList typed_arg; + XtResourceList resources; + Cardinal num_resources; +{ + String from_type = NULL; + Cardinal from_size = 0; + XrmValue from_val, to_val; + register int i; + Arg arg; + XtPointer value; + + /* note we presume that the XtResourceList to be un-compiled */ + + for (i = 0; i < num_resources; i++) { + if (StringToName(typed_arg->name) == StringToName(resources[i].resource_name)) { + from_type = resources[i].resource_type; + from_size = resources[i].resource_size; + break; + } + } + + if (i == num_resources) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "unknownType", XtNxtGetTypedArg, XtCXtToolkitError, + "Unable to find type of resource for conversion", + (String *)NULL, (Cardinal *)NULL); + return; + } + + value = ALLOCATE_LOCAL(from_size); + if (value == NULL) _XtAllocError(NULL); + XtSetArg(arg, typed_arg->name, value); + XtGetValues(widget, &arg, 1); + + from_val.size = from_size; + from_val.addr = (XPointer)value; + to_val.addr = (XPointer)typed_arg->value; + to_val.size = typed_arg->size; + + if (!XtConvertAndStore(widget, from_type, &from_val, + typed_arg->type, &to_val)) { + if (to_val.size > typed_arg->size) { + String params[2]; + Cardinal num_params = 2; + params[0] = typed_arg->type; + params[1] = XtName(widget); + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "insufficientSpace", XtNxtGetTypedArg, XtCXtToolkitError, + "Insufficient space for converted type '%s' in widget '%s'", + params, &num_params); + } + else { + String params[3]; + Cardinal num_params = 3; + params[0] = from_type; + params[1] = typed_arg->type; + params[2] = XtName(widget); + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "conversionFailed", XtNxtGetTypedArg, XtCXtToolkitError, + "Type conversion (%s to %s) failed for widget '%s'", + params, &num_params); + } + } + DEALLOCATE_LOCAL(value); +} + +static int +GetNestedArg(widget, avlist, args, resources, num_resources) + Widget widget; + XtTypedArgList avlist; + ArgList args; + XtResourceList resources; + Cardinal num_resources; +{ + int count = 0; + + for (; avlist->name != NULL; avlist++) { + if (avlist->type != NULL) { + GetTypedArg(widget, avlist, resources, num_resources); + } else if(strcmp(avlist->name, XtVaNestedList) == 0) { + count += GetNestedArg(widget, (XtTypedArgList)avlist->value, + args, resources, num_resources); + } else { + (args+count)->name = avlist->name; + (args+count)->value = avlist->value; + ++count; + } + } + + return(count); +} + +#if NeedVarargsPrototypes +void +XtVaGetValues(Widget widget, ...) +#else +/*VARARGS1*/ +void XtVaGetValues(widget, va_alist) + Widget widget; + va_dcl +#endif +{ + va_list var; + String attr; + ArgList args; + XtTypedArg typed_arg; + XtResourceList resources = (XtResourceList)NULL; + Cardinal num_resources; + int count, total_count, typed_count; + WIDGET_TO_APPCON(widget); + + LOCK_APP(app); + Va_start(var,widget); + + _XtCountVaList(var, &total_count, &typed_count); + + if (total_count != typed_count) { + args = (ArgList)__XtMalloc((unsigned)((total_count - typed_count) + * sizeof(Arg))); + } + else args = NULL; /* for lint; really unused */ + va_end(var); + + Va_start(var,widget); + for(attr = va_arg(var, String), count = 0 ; attr != NULL; + attr = va_arg(var, String)) { + if (strcmp(attr, XtVaTypedArg) == 0) { + typed_arg.name = va_arg(var, String); + typed_arg.type = va_arg(var, String); + typed_arg.value = va_arg(var, XtArgVal); + typed_arg.size = va_arg(var, int); + + if (resources == NULL) { + XtGetResourceList(XtClass(widget), &resources,&num_resources); + } + + GetTypedArg(widget, &typed_arg, resources, num_resources); + } else if (strcmp(attr, XtVaNestedList) == 0) { + if (resources == NULL) { + XtGetResourceList(XtClass(widget),&resources, &num_resources); + } + + count += GetNestedArg(widget, va_arg(var, XtTypedArgList), + (args+count), resources, num_resources); + } else { + args[count].name = attr; + args[count].value = va_arg(var, XtArgVal); + count ++; + } + } + va_end(var); + + if (resources != (XtResourceList)NULL) { + XtFree((XtPointer)resources); + } + + if (total_count != typed_count) { + XtGetValues(widget, args, count); + XtFree((XtPointer)args); + } + UNLOCK_APP(app); +} + +#if NeedVarargsPrototypes +void +XtVaGetSubvalues(XtPointer base,XtResourceList resources, Cardinal num_resources, ...) +#else +/*VARARGS3*/ +void XtVaGetSubvalues(base, resources, num_resources, va_alist) + XtPointer base; + XtResourceList resources; + Cardinal num_resources; + va_dcl +#endif +{ + va_list var; + ArgList args; + Cardinal num_args; + int total_count, typed_count; + + Va_start(var,num_resources); + + _XtCountVaList(var, &total_count, &typed_count); + + if (typed_count != 0) { + XtWarning("XtVaTypedArg is an invalid argument to XtVaGetSubvalues()\n"); + } + va_end(var); + + Va_start(var,num_resources); + _XtVaToArgList((Widget)NULL, var, total_count, &args, &num_args); + va_end(var); + + XtGetSubvalues(base, resources, num_resources, args, num_args); + + if (num_args != 0) { + XtFree((XtPointer)args); + } +} diff --git a/src/Varargs.c b/src/Varargs.c new file mode 100644 index 0000000..e2a0f45 --- /dev/null +++ b/src/Varargs.c @@ -0,0 +1,565 @@ +/* $Xorg: Varargs.c,v 1.4 2001/02/09 02:03:59 xorgcvs Exp $ */ + +/* + +Copyright 1985, 1986, 1987, 1988, 1989, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#include "IntrinsicI.h" +#include "VarargsI.h" +#include "StringDefs.h" + +static String XtNxtConvertVarToArgList = "xtConvertVarToArgList"; + +/* + * Given a nested list, _XtCountNestedList() returns counts of the + * total number of attribute-value pairs and the count of those + * attributes that are typed. The list is counted recursively. + */ +static void +_XtCountNestedList(avlist, total_count, typed_count) + XtTypedArgList avlist; + int *total_count; + int *typed_count; +{ + for (; avlist->name != NULL; avlist++) { + if (strcmp(avlist->name, XtVaNestedList) == 0) { + _XtCountNestedList((XtTypedArgList)avlist->value, total_count, + typed_count); + } else { + if (avlist->type != NULL) { + ++(*typed_count); + } + ++(*total_count); + } + } +} + + +/* + * Given a variable length attribute-value list, _XtCountVaList() + * returns counts of the total number of attribute-value pairs, + * and the count of the number of those attributes that are typed. + * The list is counted recursively. + */ +#if NeedFunctionPrototypes +void +_XtCountVaList(va_list var, int* total_count, int* typed_count) +#else +void +_XtCountVaList(var, total_count, typed_count) + va_list var; + int *total_count; + int *typed_count; +#endif +{ + String attr; + + *total_count = 0; + *typed_count = 0; + + for(attr = va_arg(var, String) ; attr != NULL; + attr = va_arg(var, String)) { + if (strcmp(attr, XtVaTypedArg) == 0) { + va_arg(var, String); + va_arg(var, String); + va_arg(var, XtArgVal); + va_arg(var, int); + ++(*total_count); + ++(*typed_count); + } else if (strcmp(attr, XtVaNestedList) == 0) { + _XtCountNestedList(va_arg(var, XtTypedArgList), total_count, + typed_count); + } else { + va_arg(var, XtArgVal); + ++(*total_count); + } + } +} + + +/* + * Given a variable length attribute-value list, XtVaCreateArgsList() + * constructs an attribute-value list of type XtTypedArgList and + * returns the list. + */ +#if NeedVarargsPrototypes +XtVarArgsList +XtVaCreateArgsList(XtPointer unused, ...) +#else +/*ARGSUSED*/ +/*VARARGS1*/ +XtVarArgsList XtVaCreateArgsList(unused, va_alist) + XtPointer unused; + va_dcl +#endif +{ + va_list var; + XtTypedArgList avlist; + int count = 0; + String attr; + + /* + * Count the number of attribute-value pairs in the list. + * Note: The count is required only to allocate enough space to store + * the list. Therefore nested lists are not counted recursively. + */ + Va_start(var,unused); + for(attr = va_arg(var, String) ; attr != NULL; + attr = va_arg(var, String)) { + ++count; + if (strcmp(attr, XtVaTypedArg) == 0) { + va_arg(var, String); + va_arg(var, String); + va_arg(var, XtArgVal); + va_arg(var, int); + } else { + va_arg(var, XtArgVal); + } + } + va_end(var); + + Va_start(var,unused); + avlist = _XtVaCreateTypedArgList(var, count); + va_end(var); + return (XtVarArgsList)avlist; +} + + +#if NeedFunctionPrototypes +XtTypedArgList _XtVaCreateTypedArgList(va_list var, register int count) +#else +XtTypedArgList _XtVaCreateTypedArgList(var, count) + va_list var; + register int count; +#endif +{ + String attr; + XtTypedArgList avlist; + + avlist = (XtTypedArgList) + __XtCalloc((int)count + 1, (unsigned)sizeof(XtTypedArg)); + + for(attr = va_arg(var, String), count = 0; attr != NULL; + attr = va_arg(var, String)) { + if (strcmp(attr, XtVaTypedArg) == 0) { + avlist[count].name = va_arg(var, String); + avlist[count].type = va_arg(var, String); + avlist[count].value = va_arg(var, XtArgVal); + avlist[count].size = va_arg(var, int); + } else { + avlist[count].name = attr; + avlist[count].type = NULL; + avlist[count].value = va_arg(var, XtArgVal); + } + ++count; + } + avlist[count].name = NULL; + + return avlist; +} + + +/* + * TypedArgToArg() invokes a resource converter to convert the + * passed typed arg into a name/value pair and stores the name/value + * pair in the passed Arg structure. If memory is allocated for the + * converted value, the address is returned in the value field of + * memory_return; otherwise that field is NULL. The function returns + * 1 if the conversion succeeded and 0 if the conversion failed. + */ +static int +TypedArgToArg(widget, typed_arg, arg_return, resources, num_resources, + memory_return) + Widget widget; + XtTypedArgList typed_arg; + ArgList arg_return; + XtResourceList resources; + Cardinal num_resources; + ArgList memory_return; +{ + String to_type = NULL; + XrmValue from_val, to_val; + + + if (widget == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "nullWidget", XtNxtConvertVarToArgList, XtCXtToolkitError, + "XtVaTypedArg conversion needs non-NULL widget handle", + (String *)NULL, (Cardinal *)NULL); + return(0); + } + + /* again we assume that the XtResourceList is un-compiled */ + + for (; num_resources--; resources++) + if (strcmp(typed_arg->name, resources->resource_name) == 0) { + to_type = resources->resource_type; + break; + } + + if (to_type == NULL) { + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "unknownType", XtNxtConvertVarToArgList, XtCXtToolkitError, + "Unable to find type of resource for conversion", + (String *)NULL, (Cardinal *)NULL); + return(0); + } + + to_val.addr = NULL; + from_val.size = typed_arg->size; + if ((strcmp(typed_arg->type, XtRString) == 0) || + (typed_arg->size > sizeof(XtArgVal))) { + from_val.addr = (XPointer)typed_arg->value; + } else { + from_val.addr = (XPointer)&typed_arg->value; + } + + LOCK_PROCESS; + XtConvertAndStore(widget, typed_arg->type, &from_val, to_type, &to_val); + + if (to_val.addr == NULL) { + UNLOCK_PROCESS; + XtAppWarningMsg(XtWidgetToApplicationContext(widget), + "conversionFailed", XtNxtConvertVarToArgList, XtCXtToolkitError, + "Type conversion failed", (String *)NULL, (Cardinal *)NULL); + return(0); + } + + arg_return->name = typed_arg->name; + memory_return->value = (XtArgVal) NULL; + + if (strcmp(to_type, XtRString) == 0) { + arg_return->value = (XtArgVal) to_val.addr; + } + else { + if (to_val.size == sizeof(long)) + arg_return->value = (XtArgVal) *(long *)to_val.addr; + else if (to_val.size == sizeof(short)) + arg_return->value = (XtArgVal) *(short *)to_val.addr; + else if (to_val.size == sizeof(char)) + arg_return->value = (XtArgVal) *(char *)to_val.addr; + else if (to_val.size == sizeof(XtArgVal)) + arg_return->value = *(XtArgVal *)to_val.addr; + else if (to_val.size > sizeof(XtArgVal)) { + arg_return->value = (XtArgVal) __XtMalloc(to_val.size); + memory_return->value = (XtArgVal) + memcpy((void *)arg_return->value, to_val.addr, to_val.size); + } + } + UNLOCK_PROCESS; + + return(1); +} + + +/* + * NestedArgtoArg() converts the passed nested list into + * an ArgList/count. + */ +static int +NestedArgtoArg(widget, avlist, args, resources, num_resources, + memory_return) + Widget widget; + XtTypedArgList avlist; + ArgList args; + XtResourceList resources; + Cardinal num_resources; + ArgList memory_return; +{ + int count = 0; + + for (; avlist->name != NULL; avlist++) { + if (avlist->type != NULL) { + /* If widget is NULL, the typed arg is ignored */ + if (widget != NULL) { + /* this is a typed arg */ + count += TypedArgToArg(widget, avlist, (args+count), + resources, num_resources, + (memory_return+count)); + } + } else if (strcmp(avlist->name, XtVaNestedList) == 0) { + count += NestedArgtoArg(widget, (XtTypedArgList)avlist->value, + (args+count), resources, num_resources, + (memory_return+count)); + } else { + (args+count)->name = avlist->name; + (args+count)->value = avlist->value; + ++count; + } + } + + return(count); +} + +/* + * Free memory allocated through _XtVaToArgList. The actual args array + * size is expected to be total_count * 2, where total_count is the number + * of elements needed for resource representations. The lower half of the + * array contains pairs of resource names and values as usual. For each + * element [n] in the lower half of the array, the value field of the + * corresponding element [n + total_count] in the upper half of the array + * has been pressed into service in order to note whether the resource value + * is a pointer to memory that was allocated in TypedArgToArg. In the + * upper half, if the value field is not NULL, it contains the address of + * memory which should now be freed. That memory could have been allocated + * only as a result of the conversion of typed arguments. Therefore, if + * there were no typed arguments in the original varargs, there is no need + * to examine the upper half of the array. In the choice of data structure + * to make this representation, priority was given to the wish to retrofit + * the release of memory around the existing signature of _XtVaToArgList. + */ +#if NeedFunctionPrototypes +void +_XtFreeArgList( + ArgList args, /* as returned by _XtVaToArgList */ + int total_count, /* argument count returned by _XtCountVaList */ + int typed_count) /* typed arg count returned by _XtCountVaList */ +#else +void +_XtFreeArgList(args, total_count, typed_count) + ArgList args; + int total_count; + int typed_count; +#endif +{ + ArgList p; + + if (args) { + if (typed_count) + for (p = args + total_count; total_count--; ++p) { + if (p->value) XtFree((char *)p->value); + } + XtFree((char *)args); + } +} + + +static void GetResources(); + + +/* + * Given a variable argument list, _XtVaToArgList() returns the + * equivalent ArgList and count. _XtVaToArgList() handles nested + * lists and typed arguments. If typed arguments are present, the + * ArgList should be freed with _XtFreeArgList. + */ +#if NeedFunctionPrototypes +void +_XtVaToArgList( + Widget widget, + va_list var, + int max_count, + ArgList *args_return, + Cardinal *num_args_return) +#else +void +_XtVaToArgList(widget, var, max_count, args_return, num_args_return) + Widget widget; + va_list var; + int max_count; + ArgList *args_return; + Cardinal *num_args_return; +#endif +{ + String attr; + int count; + ArgList args = (ArgList)NULL; + XtTypedArg typed_arg; + XtResourceList resources = (XtResourceList)NULL; + Cardinal num_resources; + Boolean fetched_resource_list = False; + + if (max_count == 0) { + *num_args_return = 0; + *args_return = (ArgList)NULL; + return; + } + + args = (ArgList)__XtMalloc((unsigned)(max_count * 2 * sizeof(Arg))); + for (count = max_count * 2; --count >= 0; ) + args[count].value = (XtArgVal) NULL; + count = 0; + + for(attr = va_arg(var, String) ; attr != NULL; + attr = va_arg(var, String)) { + if (strcmp(attr, XtVaTypedArg) == 0) { + typed_arg.name = va_arg(var, String); + typed_arg.type = va_arg(var, String); + typed_arg.value = va_arg(var, XtArgVal); + typed_arg.size = va_arg(var, int); + + /* if widget is NULL, typed args are ignored */ + if (widget != NULL) { + if (!fetched_resource_list) { + GetResources(widget, &resources, &num_resources); + fetched_resource_list = True; + } + count += TypedArgToArg(widget, &typed_arg, &args[count], + resources, num_resources, + &args[max_count + count]); + } + } else if (strcmp(attr, XtVaNestedList) == 0) { + if (widget != NULL) { + if (!fetched_resource_list) { + GetResources(widget, &resources, &num_resources); + fetched_resource_list = True; + } + } + + count += NestedArgtoArg(widget, va_arg(var, XtTypedArgList), + &args[count], resources, num_resources, + &args[max_count + count]); + } else { + args[count].name = attr; + args[count].value = va_arg(var, XtArgVal); + count ++; + } + } + + if (resources != NULL) + XtFree((XtPointer)resources); + + *num_args_return = (Cardinal)count; + *args_return = (ArgList)args; +} + +/* Function Name: GetResources + * Description: Retreives the normal and constraint resources + * for this widget. + * Arguments: widget - the widget. + * RETURNED res_list - the list of resource for this widget + * RETURNED number - the number of resources in the above list. + * Returns: none + */ + +static void +GetResources(widget, res_list, number) +Widget widget; +XtResourceList * res_list; +Cardinal * number; +{ + Widget parent = XtParent(widget); + + XtInitializeWidgetClass(XtClass(widget)); + XtGetResourceList(XtClass(widget), res_list, number); + + if (!XtIsShell(widget) && parent && XtIsConstraint(parent)) { + XtResourceList res, constraint, cons_top; + Cardinal num_constraint, temp; + + XtGetConstraintResourceList(XtClass(parent), &constraint, + &num_constraint); + + cons_top = constraint; + *res_list = (XtResourceList) XtRealloc((char*)*res_list, + ((*number + num_constraint) * + sizeof(XtResource))); + + for (temp= num_constraint, res= *res_list + *number; temp != 0; temp--) + *res++ = *constraint++; + + *number += num_constraint; + XtFree( (XtPointer) cons_top); + } +} + +static int NestedArgtoTypedArg(args, avlist) + XtTypedArgList args; + XtTypedArgList avlist; +{ + int count = 0; + + for (; avlist->name != NULL; avlist++) { + if (avlist->type != NULL) { + (args+count)->name = avlist->name; + (args+count)->type = avlist->type; + (args+count)->size = avlist->size; + (args+count)->value = avlist->value; + ++count; + } else if(strcmp(avlist->name, XtVaNestedList) == 0) { + count += NestedArgtoTypedArg((args+count), + (XtTypedArgList)avlist->value); + } else { + (args+count)->name = avlist->name; + (args+count)->type = NULL; + (args+count)->value = avlist->value; + ++count; + } + } + return(count); +} + + +/* + * Given a variable argument list, _XtVaToTypedArgList() returns + * the equivalent TypedArgList. _XtVaToTypedArgList() handles nested + * lists. + * Note: _XtVaToTypedArgList() does not do type conversions. + */ +#if NeedFunctionPrototypes +void +_XtVaToTypedArgList( + va_list var, + int max_count, + XtTypedArgList *args_return, + Cardinal *num_args_return) +#else +void +_XtVaToTypedArgList(var, max_count, args_return, num_args_return) + va_list var; + int max_count; + XtTypedArgList *args_return; + Cardinal *num_args_return; +#endif +{ + XtTypedArgList args = NULL; + String attr; + int count; + + args = (XtTypedArgList) + __XtMalloc((unsigned)(max_count * sizeof(XtTypedArg))); + + for(attr = va_arg(var, String), count = 0 ; attr != NULL; + attr = va_arg(var, String)) { + if (strcmp(attr, XtVaTypedArg) == 0) { + args[count].name = va_arg(var, String); + args[count].type = va_arg(var, String); + args[count].value = va_arg(var, XtArgVal); + args[count].size = va_arg(var, int); + ++count; + } else if (strcmp(attr, XtVaNestedList) == 0) { + count += NestedArgtoTypedArg(&args[count], + va_arg(var, XtTypedArgList)); + } else { + args[count].name = attr; + args[count].type = NULL; + args[count].value = va_arg(var, XtArgVal); + ++count; + } + } + + *args_return = args; + *num_args_return = count; +} diff --git a/src/Vendor.c b/src/Vendor.c new file mode 100644 index 0000000..4123ddc --- /dev/null +++ b/src/Vendor.c @@ -0,0 +1,118 @@ +/* $Xorg: Vendor.c,v 1.4 2001/02/09 02:03:59 xorgcvs Exp $ */ + +/*********************************************************** + +Copyright 1987, 1988, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* Make sure all wm properties can make it out of the resource manager */ + +#include "IntrinsicI.h" +#include "StringDefs.h" +#include "Shell.h" +#include "ShellP.h" +#include "Vendor.h" +#include "VendorP.h" +#include <stdio.h> + +/*************************************************************************** + * + * Vendor shell class record + * + ***************************************************************************/ + +externaldef(vendorshellclassrec) VendorShellClassRec vendorShellClassRec = { + { + /* superclass */ (WidgetClass) &wmShellClassRec, + /* class_name */ "VendorShell", + /* size */ sizeof(VendorShellRec), + /* Class Initializer */ NULL, + /* class_part_initialize*/ NULL, + /* Class init'ed ? */ FALSE, + /* initialize */ NULL, + /* initialize_notify */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ NULL, + /* resource_count */ 0, + /* xrm_class */ NULLQUARK, + /* compress_motion */ FALSE, + /* compress_exposure */ TRUE, + /* compress_enterleave*/ FALSE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ XtInheritResize, + /* expose */ NULL, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* intrinsics version */ XtVersion, + /* callback offsets */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ NULL, + /* extension */ NULL + },{ + /* geometry_manager */ XtInheritGeometryManager, + /* change_managed */ XtInheritChangeManaged, + /* insert_child */ XtInheritInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + },{ + /* extension */ NULL + } +}; + +#if !defined(AIXSHLIB) || !defined(SHAREDCODE) +externaldef(vendorshellwidgetclass) WidgetClass vendorShellWidgetClass = + (WidgetClass) (&vendorShellClassRec); +#endif diff --git a/src/sharedlib.c b/src/sharedlib.c new file mode 100644 index 0000000..55d79c6 --- /dev/null +++ b/src/sharedlib.c @@ -0,0 +1,302 @@ +/* $Xorg: sharedlib.c,v 1.4 2001/02/09 02:03:59 xorgcvs Exp $ */ + +/* + +Copyright 1989, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + +*/ + +#if (defined(SUNSHLIB) || defined(AIXSHLIB)) && !defined(SHAREDCODE) +#include "IntrinsicI.h" +#include "VarargsI.h" +#include "ShellP.h" +#include "VendorP.h" + + +#ifdef AIXSHLIB +WidgetClass vendorShellWidgetClass = (WidgetClass) &vendorShellClassRec; + +static void _XtVendorInitialize() +{ + transientShellWidgetClass->core_class.superclass = + (WidgetClass) &vendorShellClassRec; + topLevelShellWidgetClass->core_class.superclass = + (WidgetClass) &vendorShellClassRec; +} + +#define VENDORINIT _XtVendorInitialize(); + +#else + +#define VENDORINIT /* as nothing */ + +#endif + +#ifdef SUNSHLIB +/* + * _XtInherit needs to be statically linked since it is compared against as + * well as called. + */ +void _XtInherit() +{ + extern void __XtInherit(); + __XtInherit(); +} +#endif + +/* + * The following routine will be called by every toolkit + * application, forcing this file to be statically linked. + * + * Note: XtInitialize, XtAppInitialize, and XtOpenApplication + * call XtToolkitInitialize. + */ + +void XtToolkitInitialize() +{ + extern void _XtToolkitInitialize(); + VENDORINIT + _XtToolkitInitialize(); +} + +#if NeedFunctionPrototypes +Widget +XtInitialize( +_Xconst char* name, +_Xconst char* classname, +XrmOptionDescRec *options, +Cardinal num_options, +int *argc, +String *argv +) +#else +Widget +XtInitialize(name, classname, options, num_options, argc, argv) +String name, classname; +XrmOptionDescRec *options; +Cardinal num_options; +String *argv; +int *argc; +#endif +{ + extern Widget _XtInitialize(); + VENDORINIT + return _XtInitialize (name, classname, options, num_options, argc, argv); +} + +#if NeedFunctionPrototypes +Widget +XtAppInitialize( +XtAppContext * app_context_return, +_Xconst char* application_class, +XrmOptionDescRec *options, +Cardinal num_options, +int *argc_in_out, +String *argv_in_out, +String *fallback_resources, +ArgList args_in, +Cardinal num_args_in +) +#else +Widget +XtAppInitialize(app_context_return, application_class, options, num_options, + argc_in_out, argv_in_out, fallback_resources, + args_in, num_args_in) +XtAppContext * app_context_return; +String application_class; +XrmOptionDescRec *options; +Cardinal num_options, num_args_in; +int *argc_in_out; +String *argv_in_out, * fallback_resources; +ArgList args_in; +#endif +{ + extern Widget _XtAppInitialize(); + VENDORINIT + return _XtAppInitialize (app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, args_in, num_args_in); +} + +#if NeedVarargsPrototypes +Widget +XtVaAppInitialize( + XtAppContext *app_context_return, + _Xconst char* application_class, + XrmOptionDescList options, + Cardinal num_options, + int *argc_in_out, + String *argv_in_out, + String *fallback_resources, + ...) +#else +Widget XtVaAppInitialize(app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, va_alist) + XtAppContext *app_context_return; + String application_class; + XrmOptionDescList options; + Cardinal num_options; + int *argc_in_out; + String *argv_in_out; + String *fallback_resources; + va_dcl +#endif +{ + va_list var; + extern Widget _XtVaAppInitialize(); + + VENDORINIT + Va_start(var, fallback_resources); + return _XtVaAppInitialize(app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, var); +} + +#if NeedFunctionPrototypes +Widget +XtOpenApplication( +XtAppContext * app_context_return, +_Xconst char* application_class, +XrmOptionDescRec *options, +Cardinal num_options, +int *argc_in_out, +String *argv_in_out, +String *fallback_resources, +WidgetClass widget_class, +ArgList args_in, +Cardinal num_args_in +) +#else +Widget +XtOpenApplication(app_context_return, application_class, options, num_options, + argc_in_out, argv_in_out, fallback_resources, + widget_class, args_in, num_args_in) +XtAppContext * app_context_return; +String application_class; +XrmOptionDescRec *options; +Cardinal num_options, num_args_in; +int *argc_in_out; +String *argv_in_out, * fallback_resources; +WidgetClass widget_class; +ArgList args_in; +#endif +{ + extern Widget _XtOpenApplication(); + VENDORINIT + return _XtOpenApplication (app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, widget_class, + args_in, num_args_in); +} + +#if NeedVarargsPrototypes +Widget +XtVaOpenApplication( + XtAppContext *app_context_return, + _Xconst char* application_class, + XrmOptionDescList options, + Cardinal num_options, + int *argc_in_out, + String *argv_in_out, + String *fallback_resources, + WidgetClass widget_class, + ...) +#else +Widget XtVaOpenApplication(app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, widget_class, va_alist) + XtAppContext *app_context_return; + String application_class; + XrmOptionDescList options; + Cardinal num_options; + int *argc_in_out; + String *argv_in_out; + String *fallback_resources; + WidgetClass widget_class; + va_dcl +#endif +{ + va_list var; + extern Widget _XtVaOpenApplication(); + + VENDORINIT + Va_start(var, widget_class); + return _XtVaOpenApplication(app_context_return, application_class, options, + num_options, argc_in_out, argv_in_out, + fallback_resources, widget_class, var); +} + +#else + +#ifndef lint +static int dummy; /* avoid warning from ranlib */ +#endif + +#endif /* SUNSHLIB or AIXSHLIB */ + +#if defined(SUNSHLIB) && !defined(SHAREDCODE) + +int _XtInheritTranslations = 0; + +extern CompositeClassRec compositeClassRec; +WidgetClass compositeWidgetClass = (WidgetClass) &compositeClassRec; + +extern ConstraintClassRec constraintClassRec; +WidgetClass constraintWidgetClass = (WidgetClass) &constraintClassRec; + +extern WidgetClassRec widgetClassRec; +WidgetClass widgetClass = &widgetClassRec; +WidgetClass coreWidgetClass = &widgetClassRec; + +extern ObjectClassRec objectClassRec; +WidgetClass objectClass = (WidgetClass)&objectClassRec; + +extern RectObjClassRec rectObjClassRec; +WidgetClass rectObjClass = (WidgetClass)&rectObjClassRec; + +extern ShellClassRec shellClassRec; +WidgetClass shellWidgetClass = (WidgetClass) &shellClassRec; + +extern OverrideShellClassRec overrideShellClassRec; +WidgetClass overrideShellWidgetClass = (WidgetClass) &overrideShellClassRec; + +extern WMShellClassRec wmShellClassRec; +WidgetClass wmShellWidgetClass = (WidgetClass) &wmShellClassRec; + +extern TransientShellClassRec transientShellClassRec; +WidgetClass transientShellWidgetClass = (WidgetClass) &transientShellClassRec; + +extern TopLevelShellClassRec topLevelShellClassRec; +WidgetClass topLevelShellWidgetClass = (WidgetClass) &topLevelShellClassRec; + +extern ApplicationShellClassRec applicationShellClassRec; +WidgetClass applicationShellWidgetClass = (WidgetClass) &applicationShellClassRec; + +extern SessionShellClassRec sessionShellClassRec; +WidgetClass sessionShellWidgetClass = (WidgetClass) &sessionShellClassRec; + +extern HookObjClassRec hookObjClassRec; +WidgetClass hookObjectClass = (WidgetClass) &hookObjClassRec; + +#endif /* SUNSHLIB */ |