3 Copyright 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
28 * Author: Chris D. Peterson, Dave Sternlicht, MIT X Consortium
34 #include <X11/IntrinsicP.h> /* To get into the composite and core widget
36 #include <X11/ObjectP.h> /* For XtIs<Classname> macros. */
37 #include <X11/StringDefs.h> /* for XtRString. */
38 #include <X11/ShellP.h> /* for Application Shell Widget class. */
40 #include <X11/Xatom.h>
41 #include <X11/Xos.h> /* for strcpy declaration */
42 #include <X11/Xfuncs.h>
43 #include <X11/Xmu/EditresP.h>
45 #include <X11/Xmu/CharSet.h>
46 #include <X11/Xmu/SysUtil.h>
51 #define _XEditResPutBool _XEditResPut8
52 #define _XEditResPutResourceType _XEditResPut8
63 typedef struct _SetValuesEvent {
64 EditresCommand type; /* first field must be type */
66 unsigned short num_entries; /* number of set values requests */
70 unsigned short value_len;
73 typedef struct _SVErrorInfo {
74 SetValuesEvent *event;
75 ProtocolStream *stream;
76 unsigned short *count;
80 typedef struct _GetValuesEvent {
81 EditresCommand type; /* first field must be type */
83 unsigned short num_entries; /* number of get values requests */
87 typedef struct _FindChildEvent {
88 EditresCommand type; /* first field must be type */
93 typedef struct _GenericGetEvent {
94 EditresCommand type; /* first field must be type */
96 unsigned short num_entries; /* number of set values requests */
97 } GenericGetEvent, GetResEvent, GetGeomEvent;
100 * Common to all events
102 typedef struct _AnyEvent {
103 EditresCommand type; /* first field must be type */
110 typedef union _EditresEvent {
112 SetValuesEvent set_values_event;
113 GetResEvent get_resources_event;
114 GetGeomEvent get_geometry_event;
115 FindChildEvent find_child_event;
118 typedef struct _Globals {
120 SVErrorInfo error_info;
121 ProtocolStream stream;
122 ProtocolStream *command_stream; /* command stream */
123 #if defined(LONG64) || defined(WORD64)
124 unsigned long base_address;
128 #define CURRENT_PROTOCOL_VERSION 5L
130 #define streq(a,b) (strcmp((a), (b)) == 0)
135 static Widget _FindChild(Widget, int, int);
136 static void _XEditresGetStringValues(Widget, Arg*, int);
137 static XtPointer BuildReturnPacket(ResIdent, EditResError, ProtocolStream*);
138 static void CommandDone(Widget, Atom*, Atom*);
139 static Boolean ConvertReturnCommand(Widget, Atom*, Atom*, Atom*, XtPointer*,
140 unsigned long*, int*);
141 static Boolean CvtStringToBlock(Display*, XrmValue*, Cardinal*,
142 XrmValue*, XrmValue*, XtPointer*);
143 static EditresEvent *BuildEvent(Widget, Atom, XtPointer, ResIdent,
145 static _Xconst char *DoFindChild(Widget, EditresEvent*, ProtocolStream*);
146 static _Xconst char *DoGetGeometry(Widget, EditresEvent*, ProtocolStream*);
147 static _Xconst char *DoGetResources(Widget, EditresEvent*, ProtocolStream*);
148 static _Xconst char *DoSetValues(Widget, EditresEvent*, ProtocolStream*);
149 static void DumpChildren(Widget, ProtocolStream*, unsigned short*);
150 static _Xconst char *DumpValues(Widget, EditresEvent*, ProtocolStream*);
151 static _Xconst char *DumpWidgets(Widget, EditresEvent*, ProtocolStream*);
152 static void ExecuteCommand(Widget, Atom, ResIdent, EditresEvent*);
153 static void ExecuteGetGeometry(Widget, ProtocolStream*);
154 static void ExecuteGetResources(Widget w, ProtocolStream *stream);
155 static void ExecuteSetValues(Widget, SetValuesEvent*, WidgetInfo*,
156 ProtocolStream*, unsigned short*);
157 static void FreeEvent(EditresEvent*);
158 static void GetCommand(Widget w, XtPointer, Atom*, Atom*, XtPointer,
159 unsigned long*, int*);
160 static void HandleToolkitErrors(String, String, String, String,
162 static void InsertWidget(ProtocolStream*, Widget);
163 static Bool IsChild(Widget, Widget, Widget);
164 static Bool isApplicationShell(Widget);
165 static void LoadResources(Widget);
166 static Bool PositionInChild(Widget, int, int);
167 static int qcmp_widget_list(register _Xconst void*, register _Xconst void*);
168 static void SendCommand(Widget, Atom, ResIdent, EditResError,
170 static void SendFailure(Widget, Atom, ResIdent, _Xconst char*);
171 static _Xconst char *VerifyWidget(Widget, WidgetInfo*);
176 void _XEditResCheckMessages(Widget, XtPointer, XEvent*, Boolean*);
181 static Atom res_editor_command, res_editor_protocol, client_value;
182 static Globals globals;
184 /************************************************************
185 * Resource Editor Communication Code
186 ************************************************************/
189 * _XEditResCheckMessages
193 * event - The X Event that triggered this handler
197 * This callback routine is set on all shell widgets, and checks to
198 * see if a client message event has come from the resource editor.
202 _XEditResCheckMessages(Widget w, XtPointer data, XEvent *event, Boolean *cont)
206 static Boolean first_time = False;
207 static Atom res_editor, res_comm;
210 if (event->type == ClientMessage)
212 XClientMessageEvent * c_event = (XClientMessageEvent *)event;
218 static _Xconst char *names[] = {
219 EDITRES_NAME, EDITRES_COMMAND_ATOM,
220 EDITRES_PROTOCOL_ATOM, EDITRES_CLIENT_VALUE
224 XInternAtoms(dpy, (char **) names, 4, False, atoms);
225 res_editor = atoms[0];
226 res_editor_command = atoms[1];
227 res_editor_protocol = atoms[2];
228 /* Used in later procedures */
229 client_value = atoms[3];
233 if ((c_event->message_type != res_editor)
234 || (c_event->format != EDITRES_SEND_EVENT_FORMAT))
237 time = c_event->data.l[0];
238 res_comm = c_event->data.l[1];
239 ident = (ResIdent) c_event->data.l[2];
240 if (c_event->data.l[3] != CURRENT_PROTOCOL_VERSION)
242 _XEditResResetStream(&globals.stream);
243 _XEditResPut8(&globals.stream,
244 (unsigned int) CURRENT_PROTOCOL_VERSION);
245 SendCommand(w, res_comm, ident, ProtocolMismatch, &globals.stream);
249 XtGetSelectionValue(w, res_comm, res_editor_command,
250 GetCommand, (XtPointer)(long)ident, time);
259 * w - widget to own selection, in case of error
260 * sel - selection to send error message beck in
261 * data - the data for the request
262 * ident - the id number we are looking for
263 * length - length of request
266 * Takes the info out the protocol stream an constructs
267 * the proper event structure.
272 #if defined(ERROR_MESSAGE)
275 #define ERROR_MESSAGE "Client: Improperly formatted protocol request"
276 static EditresEvent *
277 BuildEvent(Widget w, Atom sel, XtPointer data, ResIdent ident,
278 unsigned long length)
281 ProtocolStream alloc_stream, *stream;
283 register unsigned int i;
285 stream = &alloc_stream;
286 stream->current = stream->top = (unsigned char *)data;
287 stream->size = HEADER_SIZE; /* size of header */
290 * Retrieve the Header
292 if (length < HEADER_SIZE)
294 SendFailure(w, sel, ident, ERROR_MESSAGE);
298 (void)_XEditResGet8(stream, &temp);
299 if (temp != ident) /* Id's don't match, ignore request */
302 event = (EditresEvent *)XtCalloc(sizeof(EditresEvent), 1);
304 (void)_XEditResGet8(stream, &temp);
305 event->any_event.type = (EditresCommand)temp;
306 (void)_XEditResGet32(stream, &stream->size);
307 stream->top = stream->current; /* reset stream to top of value */
310 * Now retrieve the data segment
312 switch(event->any_event.type)
315 break; /* no additional info */
318 SetValuesEvent *sv_event = (SetValuesEvent *)event;
320 if (!(_XEditResGetString8(stream, &sv_event->name)
321 && _XEditResGetString8(stream, &sv_event->res_type)))
325 * Since we need the value length, we have to pull the
328 if (!_XEditResGet16(stream, &sv_event->value_len))
331 sv_event->value = XtMalloc(sizeof(char) * (sv_event->value_len + 1));
333 for (i = 0; i < sv_event->value_len; i++)
334 if (!_XEditResGet8(stream, (unsigned char *)sv_event->value + i))
337 ((char*)sv_event->value)[i] = '\0';
339 if (!_XEditResGet16(stream, &sv_event->num_entries))
342 sv_event->widgets = (WidgetInfo *)
343 XtCalloc(sizeof(WidgetInfo), sv_event->num_entries);
345 for (i = 0; i < sv_event->num_entries; i++)
346 if (!_XEditResGetWidgetInfo(stream, sv_event->widgets + i))
352 FindChildEvent *find_event = (FindChildEvent *)event;
354 find_event->widgets = (WidgetInfo *)XtCalloc(sizeof(WidgetInfo), 1);
356 if (!(_XEditResGetWidgetInfo(stream, find_event->widgets)
357 && _XEditResGetSigned16(stream, &find_event->x)
358 && _XEditResGetSigned16(stream, &find_event->y)))
365 GenericGetEvent *get_event = (GenericGetEvent *)event;
367 if (!_XEditResGet16(stream, &get_event->num_entries))
370 get_event->widgets = (WidgetInfo *)
371 XtCalloc(sizeof(WidgetInfo), get_event->num_entries);
373 for (i = 0; i < get_event->num_entries; i++)
374 if (!_XEditResGetWidgetInfo(stream, get_event->widgets + i))
380 GetValuesEvent *gv_event = (GetValuesEvent *)event;
382 _XEditResGetString8(stream, &gv_event->name);
383 _XEditResGet16(stream, &gv_event->num_entries);
384 gv_event->widgets = (WidgetInfo *)
385 XtCalloc(sizeof(WidgetInfo), gv_event->num_entries);
386 _XEditResGetWidgetInfo(stream, gv_event->widgets);
393 XmuSnprintf(buf, sizeof(buf),
394 "Unknown Protocol request %d.", event->any_event.type);
395 SendFailure(w, sel, ident, buf);
404 SendFailure(w, sel, ident, ERROR_MESSAGE);
414 * event - event to free
417 * Frees the event structure and any other pieces in it that need freeing.
420 FreeEvent(EditresEvent *event)
422 if (event->any_event.widgets != NULL)
424 XtFree((char *)event->any_event.widgets->ids);
425 XtFree((char *)event->any_event.widgets);
428 if (event->any_event.type == SetValues)
430 XtFree(event->set_values_event.name);
431 XtFree(event->set_values_event.res_type);
434 XtFree((char *)event);
442 * (See Xt XtConvertSelectionProc)
443 * data - contains the ident number for the command
446 * Gets the Command out of the selection asserted by the resource manager.
450 GetCommand(Widget w, XtPointer data, Atom *selection, Atom *type,
451 XtPointer value, unsigned long *length, int *format)
453 ResIdent ident = (ResIdent)(long)data;
456 if (*type != res_editor_protocol || *format != EDITRES_FORMAT)
459 if ((event = BuildEvent(w, *selection, value, ident, *length)) != NULL)
461 ExecuteCommand(w, *selection, ident, event);
472 * command - the command to execute
473 * value - the associated with the command
476 * Executes a command string received from the resource editor.
480 ExecuteCommand(Widget w, Atom sel, ResIdent ident, EditresEvent *event)
482 _Xconst char *(*func)(Widget, EditresEvent*, ProtocolStream*);
485 if (globals.block == BlockAll)
487 SendFailure(w, sel, ident,
488 "This client has blocked all Editres commands.");
491 else if (globals.block == BlockSetValues
492 && event->any_event.type == SetValues)
494 SendFailure(w, sel, ident,
495 "This client has blocked all SetValues requests.");
499 switch(event->any_event.type)
502 #if defined(LONG64) || defined(WORD64)
503 globals.base_address = (unsigned long)w & 0xFFFFFFFF00000000;
514 func = DoGetGeometry;
517 func = DoGetResources;
526 XmuSnprintf(buf, sizeof(buf),
527 "Unknown Protocol request %d.",event->any_event.type);
528 SendFailure(w, sel, ident, buf);
533 _XEditResResetStream(&globals.stream);
534 if ((str = (*func)(w, event, &globals.stream)) == NULL)
535 SendCommand(w, sel, ident, PartialSuccess, &globals.stream);
537 SendFailure(w, sel, ident, str);
542 * ConvertReturnCommand
545 * w - the widget that owns the selection
546 * selection - selection to convert
547 * target - target type for this selection
548 * type_ret - type of the selection
549 * value_ret - selection value
550 * length_ret - lenght of this selection
551 * format_ret - the format the selection is in
554 * Converts a selection
557 * True if conversion was sucessful
561 ConvertReturnCommand(Widget w, Atom *selection, Atom *target, Atom *type_ret,
562 XtPointer *value_ret, unsigned long *length_ret,
566 * I assume the intrinsics give me the correct selection back
568 if ((*target != client_value))
571 *type_ret = res_editor_protocol;
572 *value_ret = (XtPointer)globals.command_stream->real_top;
573 *length_ret = globals.command_stream->size + HEADER_SIZE;
574 *format_ret = EDITRES_FORMAT;
589 * done with the selection
593 CommandDone(Widget widget, Atom *selection, Atom *target)
595 /* Keep the toolkit from automaticaly freeing the selection value */
603 * w - widget to own the selection
604 * sel - selection to assert
606 * str - error message
609 * Sends a failure message
612 SendFailure(Widget w, Atom sel, ResIdent ident, _Xconst char *str)
614 _XEditResResetStream(&globals.stream);
615 _XEditResPutString8(&globals.stream, str);
616 SendCommand(w, sel, ident, Failure, &globals.stream);
625 * command - command code
626 * stream - protocol stream
628 * Builds a return packet, given the data to send
634 BuildReturnPacket(ResIdent ident, EditResError error, ProtocolStream *stream)
636 long old_alloc, old_size;
637 unsigned char *old_current;
640 * We have cleverly keep enough space at the top of the header
641 * for the return protocol stream, so all we have to do is
645 * Fool the insert routines into putting the header in the right
646 * place while being damn sure not to realloc (that would be very bad.)
648 old_current = stream->current;
649 old_alloc = stream->alloc;
650 old_size = stream->size;
652 stream->current = stream->real_top;
653 stream->alloc = stream->size + (2 * HEADER_SIZE);
655 _XEditResPut8(stream, ident);
656 _XEditResPut8(stream, (unsigned char)error);
657 _XEditResPut32(stream, old_size);
659 stream->alloc = old_alloc;
660 stream->current = old_current;
661 stream->size = old_size;
663 return ((XtPointer)stream->real_top);
670 * w - widget to own the selection
671 * sel - selection to assert
673 * command - command code
674 * stream - protocol stream
677 * Builds a return command line
680 SendCommand(Widget w, Atom sel, ResIdent ident, EditResError error,
681 ProtocolStream *stream)
683 BuildReturnPacket(ident, error, stream);
684 globals.command_stream = stream;
687 * I REALLY want to own the selection. Since this was not triggered
688 * by a user action, and I am the only one using this atom it is safe to
691 XtOwnSelection(w, sel, CurrentTime, ConvertReturnCommand, NULL, CommandDone);
694 /************************************************************
695 * Generic Utility Functions
696 ************************************************************/
698 qcmp_widget_list(register _Xconst void *left, register _Xconst void *right)
700 return (char *)*(Widget **)left - (char *)*(Widget **)right;
708 * parent - parent widget
709 * children - list of children
710 * normal - return normal children
711 * popup - return popup children
712 * extra - return extra children
715 * Retuns all children (popup, normal and otherwise) of this widget
721 FindChildren(Widget parent, Widget **children, Bool normal, Bool popup,
724 CompositeWidget cw = (CompositeWidget)parent;
725 Cardinal i, num_children, current = 0;
726 Widget *extra_widgets = NULL;
727 Cardinal num_extra = 0;
731 if (XtIsWidget(parent) && popup)
732 num_children += parent->core.num_popups;
734 if (XtIsComposite(parent) && normal)
735 num_children += cw->composite.num_children;
737 if (XtIsWidget(parent) && extra)
739 XtResourceList norm_list, cons_list;
740 Cardinal num_norm, num_cons;
744 XtGetResourceList(XtClass(parent), &norm_list, &num_norm);
746 if (XtParent(parent) != NULL)
747 XtGetConstraintResourceList(XtClass(XtParent(parent)),
748 &cons_list, &num_cons);
752 extra_widgets = (Widget *)XtMalloc(sizeof(Widget));
753 for (i = 0; i < num_norm; i++)
754 if (strcmp(norm_list[i].resource_type, XtRWidget) == 0)
757 XtSetArg(args[0], norm_list[i].resource_name, &widget);
758 XtGetValues(parent, args, 1);
759 if (widget && XtParent(widget) == parent)
762 extra_widgets = (Widget *) XtRealloc(
763 (char *)extra_widgets, num_extra * sizeof(Widget));
764 extra_widgets[num_extra - 1] = widget;
767 for (i = 0; i < num_cons; i++)
768 if (strcmp(cons_list[i].resource_type, XtRWidget) == 0)
771 XtSetArg(args[0], cons_list[i].resource_name, &widget);
772 XtGetValues(parent, args, 1);
773 if (widget && XtParent(widget) == parent)
776 extra_widgets = (Widget *) XtRealloc(
777 (char *)extra_widgets, num_extra * sizeof(Widget));
778 extra_widgets[num_extra - 1] = widget;
782 XtFree((char *)norm_list);
784 XtFree((char *)cons_list);
787 if ((num_children + num_extra) == 0)
793 *children = (Widget *)XtMalloc(sizeof(Widget) * (num_children + num_extra));
795 if (XtIsComposite(parent) && normal)
796 for (i = 0; i < cw->composite.num_children; i++, current++)
797 (*children)[current] = cw->composite.children[i];
799 if (XtIsWidget(parent) && popup)
800 for (i = 0; i < parent->core.num_popups; i++, current++)
801 (*children)[current] = parent->core.popup_list[i];
806 Cardinal j, old_num_extra = num_extra;
808 qsort(extra_widgets, num_extra, sizeof(Widget), qcmp_widget_list);
809 for (i = 0; i < num_extra - 1; i++)
810 while (i < num_extra - 1 &&
811 extra_widgets[i] == extra_widgets[i + 1])
813 memmove(&extra_widgets[i], &extra_widgets[i + 1],
814 (num_extra - i) * sizeof(Widget));
818 for (i = 0; i < num_children; i++)
819 for (j = 0; j < num_extra; j++)
820 if ((*children)[i] == extra_widgets[j])
822 if ((j + 1) < num_extra)
823 memmove(&extra_widgets[j], &extra_widgets[j + 1],
824 (num_extra - j) * sizeof(Widget));
828 if (old_num_extra != num_extra)
829 *children = (Widget *)XtRealloc((char *)*children, sizeof(Widget)
830 * (num_children + num_extra));
833 memcpy(&(*children)[num_children], extra_widgets,
834 sizeof(Widget) * num_extra);
837 XtFree((char *)extra_widgets);
838 if (num_children + num_extra == 0)
840 XtFree((char *)*children);
844 return (num_children + num_extra);
852 * top - top of the tree
853 * parent - parent widget
854 * child - child widget
857 * Check to see of child is a child of parent
860 IsChild(Widget top, Widget parent, Widget child)
866 return (top == child);
868 num_children = FindChildren(parent, &children, True, True, True);
870 for (i = 0; i < num_children; i++)
871 if (children[i] == child)
873 XtFree((char *)children);
877 XtFree((char *)children);
886 * w - any widget in the tree
887 * info - info about the widget to verify
890 * Makes sure all the widgets still exist
892 static _Xconst char *
893 VerifyWidget(Widget w, WidgetInfo *info)
897 register Widget parent;
898 register unsigned long *child;
900 for (top = w; XtParent(top) != NULL; top = XtParent(top))
909 if (!IsChild(top, parent, (Widget) *child))
910 return ("This widget no longer exists in the client.");
912 if (++count == info->num_widgets)
915 parent = (Widget)*child++;
918 info->real_widget = (Widget)*child;
923 /************************************************************
924 * Code to Perform SetValues operations
925 ************************************************************/
931 * w - a widget in the tree
932 * event - event that caused this action
933 * stream - protocol stream to add
936 * Performs the setvalues requested
941 static _Xconst char *
942 DoSetValues(Widget w, EditresEvent *event, ProtocolStream *stream)
946 unsigned short count = 0;
947 SetValuesEvent *sv_event = (SetValuesEvent *)event;
949 _XEditResPut16(stream, count); /* insert 0, will be overwritten later */
951 for (i = 0; i < sv_event->num_entries; i++)
953 if ((str = VerifyWidget(w, &sv_event->widgets[i])) != NULL)
955 _XEditResPutWidgetInfo(stream, &sv_event->widgets[i]);
956 _XEditResPutString8(stream, str);
960 ExecuteSetValues(sv_event->widgets[i].real_widget,
961 sv_event, sv_event->widgets + i, stream, &count);
965 * Overwrite the first 2 bytes with the real count.
967 *(stream->top) = count >> XER_NBBY;
968 *(stream->top + 1) = count;
975 * HandleToolkitErrors
978 * name - name of the error
979 * type - type of the error
980 * class - class of the error
981 * msg - the default message
982 * params - the extra parameters for this message
985 * Description: Handles X Toolkit Errors.
989 HandleToolkitErrors(String name, String type, String class, String msg,
990 String *params, Cardinal *num_params)
992 SVErrorInfo *info = &globals.error_info;
995 if (streq(name, "unknownType"))
996 XmuSnprintf(buf, sizeof(buf),
997 "The `%s' resource is not used by this widget.",
999 else if (streq(name, "noColormap"))
1000 XmuSnprintf(buf, sizeof(buf), msg, params[0]);
1001 else if (streq(name, "conversionFailed") || streq(name, "conversionError"))
1003 if (streq((String)info->event->value, XtRString))
1004 XmuSnprintf(buf, sizeof(buf),
1005 "Could not convert the string '%s' for the `%s' "
1006 "resource.", (String)info->event->value,
1009 XmuSnprintf(buf, sizeof(buf),
1010 "Could not convert the `%s' resource.",
1014 XmuSnprintf(buf, sizeof(buf),
1015 "Name: %s, Type: %s, Class: %s, Msg: %s",
1016 name, type, class, msg);
1019 * Insert this info into the protocol stream, and update the count
1022 _XEditResPutWidgetInfo(info->stream, info->entry);
1023 _XEditResPutString8(info->stream, buf);
1031 * w - widget to perform the set_values on
1032 * sv_event - set values event
1033 * sv_info - set_value info
1036 * Performs a setvalues for a given command
1039 ExecuteSetValues(Widget w, SetValuesEvent *sv_event, WidgetInfo *entry,
1040 ProtocolStream *stream, unsigned short *count)
1042 XtErrorMsgHandler old;
1043 SVErrorInfo *info = &globals.error_info;
1045 info->event = sv_event; /* No data can be passed to */
1046 info->stream = stream; /* an error handler, so we */
1047 info->count = count; /* have to use a global */
1048 info->entry = entry;
1050 old = XtAppSetWarningMsgHandler(XtWidgetToApplicationContext(w),
1051 HandleToolkitErrors);
1053 XtVaSetValues(w, XtVaTypedArg,
1054 sv_event->name, sv_event->res_type,
1055 sv_event->value, sv_event->value_len,
1058 (void)XtAppSetWarningMsgHandler(XtWidgetToApplicationContext(w), old);
1061 /************************************************************
1062 * Code for Creating and dumping widget tree.
1063 ************************************************************/
1068 * w - a widget in the tree
1069 * event - event that caused this action
1070 * stream - protocol stream to add
1073 * Given a widget it builds a protocol packet containing the entire
1079 #define TOOLKIT_TYPE ("Xt")
1081 static _Xconst char *
1082 DumpWidgets(Widget w, EditresEvent *event, ProtocolStream *stream)
1084 unsigned short count = 0;
1086 /* Find Tree's root */
1087 for (; XtParent(w) != NULL; w = XtParent(w))
1091 * hold space for count, overwritten later
1093 _XEditResPut16(stream, (unsigned int)0);
1095 DumpChildren(w, stream, &count);
1098 * write out toolkit type
1100 _XEditResPutString8(stream, TOOLKIT_TYPE);
1103 * Overwrite the first 2 bytes with the real count
1105 *(stream->top) = count >> XER_NBBY;
1106 *(stream->top + 1) = count;
1116 * w - widget to dump
1117 * stream - stream to dump to
1118 * count - number of dumps we have performed
1121 * Adds a child's name to the list.
1123 /* This is a trick/kludge. To make shared libraries happier (linking
1124 * against Xmu but not linking against Xt, and apparently even work
1125 * as we desire on SVR4, we need to avoid an explicit data reference
1126 * to applicationShellWidgetClass. XtIsTopLevelShell is known
1127 * (implementation dependent assumption!) to use a bit flag. So we
1128 * go that far. Then, we test whether it is an applicationShellWidget
1129 * class by looking for an explicit class name. Seems pretty safe.
1132 isApplicationShell(Widget w)
1134 register WidgetClass c;
1136 if (!XtIsTopLevelShell(w))
1138 for (c = XtClass(w); c; c = c->core_class.superclass)
1139 if (strcmp(c->core_class.class_name, "ApplicationShell") == 0)
1146 DumpChildren(Widget w, ProtocolStream *stream, unsigned short *count)
1148 int i, num_children;
1150 unsigned long window;
1155 InsertWidget(stream, w); /* Insert the widget into the stream */
1157 _XEditResPutString8(stream, XtName(w)); /* Insert name */
1159 if (isApplicationShell(w))
1160 c_class = ((ApplicationShellWidget)w)->application.class;
1162 c_class = XtClass(w)->core_class.class_name;
1164 _XEditResPutString8(stream, c_class); /* Insert class */
1167 if (XtIsRealized(w))
1168 window = XtWindow(w);
1170 window = EDITRES_IS_UNREALIZED;
1172 window = EDITRES_IS_OBJECT;
1174 _XEditResPut32(stream, window); /* Insert window id */
1177 * Find children and recurse
1179 num_children = FindChildren(w, &children, True, True, True);
1180 for (i = 0; i < num_children; i++)
1181 DumpChildren(children[i], stream, count);
1183 XtFree((char *)children);
1186 /************************************************************
1187 * Code for getting the geometry of widgets
1188 ************************************************************/
1194 * w - widget in the tree
1195 * event - event that caused this action
1196 * stream - protocol stream to add
1199 * Retrieves the Geometry of each specified widget.
1204 static _Xconst char *
1205 DoGetGeometry(Widget w, EditresEvent *event, ProtocolStream *stream)
1209 GetGeomEvent *geom_event = (GetGeomEvent *)event;
1211 _XEditResPut16(stream, geom_event->num_entries);
1213 for (i = 0; i < geom_event->num_entries; i++)
1216 * Send out the widget id
1218 _XEditResPutWidgetInfo(stream, &geom_event->widgets[i]);
1220 if ((str = VerifyWidget(w, &geom_event->widgets[i])) != NULL)
1222 _XEditResPutBool(stream, True); /* an error occured */
1223 _XEditResPutString8(stream, str); /* set message */
1226 ExecuteGetGeometry(geom_event->widgets[i].real_widget, stream);
1234 * ExecuteGetGeometry
1237 * w - widget to get geometry
1238 * stream - stream to append to
1241 * Gets the geometry for each widget specified.
1244 * True if no error occured.
1247 ExecuteGetGeometry(Widget w, ProtocolStream *stream)
1250 Boolean mapped_when_man;
1251 Dimension width, height, border_width;
1253 Cardinal num_args = 0;
1256 if (!XtIsRectObj(w) || (XtIsWidget(w) && !XtIsRealized(w)))
1258 _XEditResPutBool(stream, False); /* no error */
1259 _XEditResPutBool(stream, False); /* not visable */
1260 for (i = 0; i < 5; i++) /* fill in extra space with 0's */
1261 _XEditResPut16(stream, 0);
1265 XtSetArg(args[num_args], XtNwidth, &width); num_args++;
1266 XtSetArg(args[num_args], XtNheight, &height); num_args++;
1267 XtSetArg(args[num_args], XtNborderWidth, &border_width); num_args++;
1268 XtSetArg(args[num_args], XtNmappedWhenManaged, &mapped_when_man);
1270 XtGetValues(w, args, num_args);
1272 if (!(XtIsManaged(w) && mapped_when_man) && XtIsWidget(w))
1274 XWindowAttributes attrs;
1277 * The toolkit does not maintain mapping state, we have
1278 * to go to the server
1280 if (XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attrs) != 0)
1282 if (attrs.map_state != IsViewable)
1284 _XEditResPutBool(stream, False); /* no error */
1285 _XEditResPutBool(stream, False); /* not visable */
1286 for (i = 0; i < 5; i++) /* fill in extra space with 0's */
1287 _XEditResPut16(stream, 0);
1293 _XEditResPut8(stream, True); /* Error occured. */
1294 _XEditResPutString8(stream, "XGetWindowAttributes failed.");
1299 XtTranslateCoords(w, -((int) border_width), -((int) border_width), &x, &y);
1301 _XEditResPutBool(stream, False); /* no error */
1302 _XEditResPutBool(stream, True); /* Visable */
1303 _XEditResPut16(stream, x);
1304 _XEditResPut16(stream, y);
1305 _XEditResPut16(stream, width);
1306 _XEditResPut16(stream, height);
1307 _XEditResPut16(stream, border_width);
1310 /************************************************************
1311 * Code for executing FindChild
1312 ************************************************************/
1318 * child - child widget to check
1319 * x - location of point to check in the parent's coord space
1323 * Returns true if this location is in the child.
1326 PositionInChild(Widget child, int x, int y)
1330 Dimension width, height, border_width;
1331 Position child_x, child_y;
1332 Boolean mapped_when_managed;
1334 if (!XtIsRectObj(child)) /* we must at least be a rect obj */
1338 XtSetArg(args[num], XtNmappedWhenManaged, &mapped_when_managed); num++;
1339 XtSetArg(args[num], XtNwidth, &width); num++;
1340 XtSetArg(args[num], XtNheight, &height); num++;
1341 XtSetArg(args[num], XtNx, &child_x); num++;
1342 XtSetArg(args[num], XtNy, &child_y); num++;
1343 XtSetArg(args[num], XtNborderWidth, &border_width); num++;
1344 XtGetValues(child, args, num);
1347 * The only way we will know of the widget is mapped is to see if
1348 * mapped when managed is True and this is a managed child. Otherwise
1349 * we will have to ask the server if this window is mapped
1351 if (XtIsWidget(child) && !(mapped_when_managed && XtIsManaged(child)))
1353 XWindowAttributes attrs;
1355 if (XGetWindowAttributes(XtDisplay(child), XtWindow(child), &attrs)
1356 && attrs.map_state != IsViewable)
1360 return ((x >= child_x)
1361 && (x <= (child_x + (Position)width + 2 * (Position)border_width))
1363 && (y <= (child_y + (Position)height + 2 * (Position)border_width)));
1371 * parent - widget that is known to contain the point specified
1372 * x - point in coordinates relative to the widget specified
1376 * Finds the child that actually contains the point shown.
1379 _FindChild(Widget parent, int x, int y)
1382 int i = FindChildren(parent, &children, True, False, True);
1388 if (PositionInChild(children[i], x, y))
1390 Widget child = children[i];
1392 XtFree((char *)children);
1393 return (_FindChild(child, x - child->core.x, y - child->core.y));
1397 XtFree((char *)children);
1407 * w - widget in the tree
1408 * event - event that caused this action
1409 * stream - protocol stream to add
1411 * Finds the child that contains the location specified.
1414 * An allocated error message if something went horribly wrong and
1415 * no set values were performed, else NULL.
1417 static _Xconst char *
1418 DoFindChild(Widget w, EditresEvent *event, ProtocolStream *stream)
1421 Widget parent, child;
1422 Position parent_x, parent_y;
1423 FindChildEvent *find_event = (FindChildEvent *)event;
1425 if ((str = VerifyWidget(w, find_event->widgets)) != NULL)
1428 parent = find_event->widgets->real_widget;
1430 XtTranslateCoords(parent, (Position) 0, (Position) 0,
1431 &parent_x, &parent_y);
1433 child = _FindChild(parent, find_event->x - (int) parent_x,
1434 find_event->y - (int) parent_y);
1436 InsertWidget(stream, child);
1441 /************************************************************
1442 * Procedures for performing GetResources
1443 ************************************************************/
1449 * w - widget in the tree
1450 * event - event that caused this action
1451 * stream - protocol stream to add
1454 * Gets the Resources associated with the widgets passed.
1459 static _Xconst char *
1460 DoGetResources(Widget w, EditresEvent *event, ProtocolStream *stream)
1464 GetResEvent *res_event = (GetResEvent *)event;
1466 _XEditResPut16(stream, res_event->num_entries); /* number of replys */
1468 for (i = 0; i < res_event->num_entries; i++)
1471 * Send out the widget id
1473 _XEditResPutWidgetInfo(stream, &res_event->widgets[i]);
1474 if ((str = VerifyWidget(w, &res_event->widgets[i])) != NULL)
1476 _XEditResPutBool(stream, True); /* an error occured */
1477 _XEditResPutString8(stream, str); /* set message */
1481 _XEditResPutBool(stream, False); /* no error occured */
1482 ExecuteGetResources(res_event->widgets[i].real_widget, stream);
1490 * ExecuteGetResources
1493 * w - widget to get resources on
1494 * stream - protocol stream
1497 * Gets the resources for any individual widget
1500 ExecuteGetResources(Widget w, ProtocolStream *stream)
1502 XtResourceList norm_list, cons_list;
1503 Cardinal num_norm, num_cons;
1504 register Cardinal i;
1507 * Get Normal Resources
1509 XtGetResourceList(XtClass(w), &norm_list, &num_norm);
1511 if (XtParent(w) != NULL)
1512 XtGetConstraintResourceList(XtClass(XtParent(w)), &cons_list,&num_cons);
1516 _XEditResPut16(stream, num_norm + num_cons); /* how many resources */
1519 * Insert all the normal resources
1521 for (i = 0; i < num_norm; i++)
1523 _XEditResPutResourceType(stream, NormalResource);
1524 _XEditResPutString8(stream, norm_list[i].resource_name);
1525 _XEditResPutString8(stream, norm_list[i].resource_class);
1526 _XEditResPutString8(stream, norm_list[i].resource_type);
1528 XtFree((char *)norm_list);
1531 * Insert all the constraint resources
1535 for (i = 0; i < num_cons; i++)
1537 _XEditResPutResourceType(stream, ConstraintResource);
1538 _XEditResPutString8(stream, cons_list[i].resource_name);
1539 _XEditResPutString8(stream, cons_list[i].resource_class);
1540 _XEditResPutString8(stream, cons_list[i].resource_type);
1542 XtFree((char *)cons_list);
1551 * event - event that caused this action
1552 * stream - protocol stream to add
1555 * Returns resource values to the resource editor.
1561 static _Xconst char *
1562 DumpValues(Widget w, EditresEvent* event, ProtocolStream* stream)
1566 _Xconst _XtString res_value = NULL;
1567 GetValuesEvent *gv_event = (GetValuesEvent *)event;
1569 /* put the count in the stream */
1570 _XEditResPut16(stream, (unsigned int)1);
1573 * Get the resource of the widget asked for by the
1574 * resource editor and insert it into the stream
1576 XtSetArg(warg[0], gv_event->name, &res_value);
1578 if ((str = VerifyWidget(w, &gv_event->widgets[0])) != NULL)
1579 _XEditResPutString8(stream, str);
1582 _XEditresGetStringValues(gv_event->widgets[0].real_widget, warg, 1);
1584 res_value = "NoValue";
1585 _XEditResPutString8(stream, res_value);
1591 /************************************************************
1592 * Code for inserting values into the protocol stream
1593 ************************************************************/
1599 * stream - protocol stream
1600 * w - widget to insert
1603 * Inserts the full parent hierarchy of this widget into the protocol
1604 * stream as a widget list.
1607 InsertWidget(ProtocolStream *stream, Widget w)
1610 unsigned long *widget_list;
1611 register int i, num_widgets;
1613 for (temp = w, i = 0; temp != NULL; temp = XtParent(temp), i++)
1617 widget_list = (unsigned long *)XtMalloc(sizeof(unsigned long) * num_widgets);
1620 * Put the widgets into the list
1621 * make sure that they are inserted in the list from parent -> child
1623 for (i--, temp = w; temp != NULL; temp = XtParent(temp), i--)
1624 widget_list[i] = (unsigned long)temp;
1626 _XEditResPut16(stream, num_widgets); /* insert number of widgets */
1627 for (i = 0; i < num_widgets; i++) /* insert Widgets themselves */
1628 _XEditResPut32(stream, widget_list[i]);
1630 XtFree((char *)widget_list);
1633 /************************************************************
1634 * All of the following routines are public
1635 ************************************************************/
1638 * _XEditResPutString8
1641 * stream - stream to insert string into
1642 * str - string to insert
1645 * Inserts a string into the protocol stream.
1648 _XEditResPutString8(ProtocolStream *stream, _Xconst char *str)
1650 int i, len = strlen(str);
1652 _XEditResPut16(stream, len);
1653 for (i = 0; i < len; i++, str++)
1654 _XEditResPut8(stream, *str);
1662 * stream - stream to insert string into
1663 * value - value to insert
1666 * Inserts an 8 bit integer into the protocol stream.
1669 _XEditResPut8(ProtocolStream *stream, unsigned int value)
1673 if (stream->size >= stream->alloc)
1675 stream->alloc += 100;
1676 stream->real_top = (unsigned char *)
1677 XtRealloc((char *)stream->real_top, stream->alloc + HEADER_SIZE);
1678 stream->top = stream->real_top + HEADER_SIZE;
1679 stream->current = stream->top + stream->size;
1682 temp = (unsigned char) (value & BYTE_MASK);
1683 *((stream->current)++) = temp;
1692 * stream - stream to insert string into
1693 * value - value to insert
1696 * Inserts a 16 bit integer into the protocol stream.
1699 _XEditResPut16(ProtocolStream *stream, unsigned int value)
1701 _XEditResPut8(stream, (value >> XER_NBBY) & BYTE_MASK);
1702 _XEditResPut8(stream, value & BYTE_MASK);
1710 * stream - stream to insert string into
1711 * value - value to insert
1714 * Inserts a 32 bit integer into the protocol stream.
1717 _XEditResPut32(ProtocolStream *stream, unsigned long value)
1721 for (i = 3; i >= 0; i--)
1722 _XEditResPut8(stream, (value >> (XER_NBBY * i)) & BYTE_MASK);
1727 * _XEditResPutWidgetInfo
1730 * stream - stream to insert widget info into
1731 * info - info to insert
1734 * Inserts the widget info into the protocol stream.
1737 _XEditResPutWidgetInfo(ProtocolStream *stream, WidgetInfo *info)
1741 _XEditResPut16(stream, info->num_widgets);
1742 for (i = 0; i < info->num_widgets; i++)
1743 _XEditResPut32(stream, info->ids[i]);
1746 /************************************************************
1747 * Code for retrieving values from the protocol stream
1748 ************************************************************/
1751 * _XEditResResetStream
1754 * stream - stream to reset
1757 * Resets the protocol stream.
1760 _XEditResResetStream(ProtocolStream *stream)
1762 stream->current = stream->top;
1764 if (stream->real_top == NULL)
1766 stream->real_top = (unsigned char *)
1767 XtRealloc((char *)stream->real_top, stream->alloc + HEADER_SIZE);
1768 stream->top = stream->real_top + HEADER_SIZE;
1769 stream->current = stream->top + stream->size;
1774 * NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
1776 * The only modified field if the "current" field
1778 * The only fields that must be set correctly are the "current", "top"
1779 * and "size" fields.
1786 * stream - protocol stream
1787 * value - a pointer to value to return
1790 * Retrieves an unsigned 8 bit value from the protocol stream.
1796 _XEditResGet8(ProtocolStream *stream, unsigned char *value)
1798 if (stream->size < (unsigned long)(stream->current - stream->top))
1801 *value = *((stream->current)++);
1810 * stream - protocol stream
1811 * value - pointer to return value
1814 * Retrieves an unsigned 16 bit value from the protocol stream.
1820 _XEditResGet16(ProtocolStream *stream, unsigned short *value)
1822 unsigned char temp1, temp2;
1824 if (!(_XEditResGet8(stream, &temp1) && _XEditResGet8(stream, &temp2)))
1827 *value = ((unsigned short)temp1 << XER_NBBY) + (unsigned short)temp2;
1833 * _XEditResGetSigned16
1836 * stream - protocol stream
1837 * value - pointer to return value
1840 * Retrieves an signed 16 bit value from the protocol stream.
1846 _XEditResGetSigned16(ProtocolStream *stream, short *value)
1848 unsigned char temp1, temp2;
1850 if (!(_XEditResGet8(stream, &temp1) && _XEditResGet8(stream, &temp2)))
1853 if (temp1 & (1 << (XER_NBBY - 1))) /* If the sign bit is active */
1855 *value = -1; /* store all 1's */
1856 *value &= (temp1 << XER_NBBY); /* Now and in the MSB */
1857 *value &= temp2; /* and LSB */
1860 *value = ((unsigned short)temp1 << XER_NBBY) + (unsigned short)temp2;
1870 * stream - protocol stream
1871 * value - pointer to return value
1874 * Retrieves an unsigned 32 bit value from the protocol stream.
1880 _XEditResGet32(ProtocolStream *stream, unsigned long *value)
1882 unsigned short temp1, temp2;
1884 if (!(_XEditResGet16(stream, &temp1) && _XEditResGet16(stream, &temp2)))
1887 *value = ((unsigned short)temp1 << (XER_NBBY * 2)) + (unsigned short)temp2;
1892 * _XEditResGetString8
1895 * stream - protocol stream
1896 * str - string to retrieve
1899 * Retrieves an 8 bit string value from the protocol stream.
1902 * True if retrieval was successful
1905 _XEditResGetString8(ProtocolStream *stream, char **str)
1908 register unsigned i;
1910 if (!_XEditResGet16(stream, &len))
1913 *str = XtMalloc(sizeof(char) * (len + 1));
1915 for (i = 0; i < len; i++)
1917 if (!_XEditResGet8(stream, (unsigned char *)*str + i))
1931 * _XEditResGetWidgetInfo
1934 * stream - protocol stream
1935 * info - widget info struct to store into
1938 * Retrieves the list of widgets that follow and stores them in the
1939 * widget info structure provided.
1942 * True if retrieval was successful
1945 _XEditResGetWidgetInfo(ProtocolStream *stream, WidgetInfo *info)
1949 if (!_XEditResGet16(stream, &info->num_widgets))
1952 info->ids = (unsigned long *)XtMalloc(sizeof(long) * info->num_widgets);
1954 for (i = 0; i < info->num_widgets; i++)
1956 if (!_XEditResGet32(stream, info->ids + i))
1958 XtFree((char *)info->ids);
1962 #if defined(LONG64) || defined(WORD64)
1963 info->ids[i] |= globals.base_address;
1969 /************************************************************
1970 * Code for Loading the EditresBlock resource
1971 ************************************************************/
1980 * from_val - value to convert
1981 * to_val - where to store
1982 * converter_data - unused
1985 * Converts a string to an editres block value.
1988 * True if conversion was sucessful
1992 CvtStringToBlock(Display *dpy, XrmValue *args, Cardinal *num_args,
1993 XrmValue *from_val, XrmValue *to_val,
1994 XtPointer *converter_data)
1997 static EditresBlock block;
1999 XmuNCopyISOLatin1Lowered(ptr, from_val->addr, sizeof(ptr));
2001 if (streq(ptr, "none"))
2003 else if (streq(ptr, "setvalues"))
2004 block = BlockSetValues;
2005 else if (streq(ptr, "all"))
2009 Cardinal num_params = 1;
2012 params[0] = from_val->addr;
2013 XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
2014 "CvtStringToBlock", "unknownValue", "EditresError",
2015 "Could not convert string \"%s\" to EditresBlock.",
2016 params, &num_params);
2020 if (to_val->addr != NULL)
2022 if (to_val->size < sizeof(EditresBlock))
2024 to_val->size = sizeof(EditresBlock);
2027 *(EditresBlock *)(to_val->addr) = block;
2030 to_val->addr = (XtPointer)block;
2032 to_val->size = sizeof(EditresBlock);
2036 #define XtREditresBlock "EditresBlock"
2042 * w - any widget in the tree
2045 * Loads a global resource the determines of this application should
2046 * allow Editres requests.
2049 LoadResources(Widget w)
2051 static XtResource resources[] = {
2052 {"editresBlock", "EditresBlock", XtREditresBlock, sizeof(EditresBlock),
2053 XtOffsetOf(Globals, block), XtRImmediate, (XtPointer)BlockNone}
2056 for (; XtParent(w) != NULL; w = XtParent(w))
2059 XtAppSetTypeConverter(XtWidgetToApplicationContext(w),
2060 XtRString, XtREditresBlock, CvtStringToBlock,
2061 NULL, 0, XtCacheAll, NULL);
2063 XtGetApplicationResources(w, (XtPointer)&globals, resources,
2064 XtNumber(resources), NULL, 0);
2069 * _XEditresGetStringValues
2073 * warg - where to store result
2078 _XEditresGetStringValues(Widget w, Arg *warg, int numargs)
2080 static char buffer[32];
2081 XtResourceList res_list;
2083 XtResource *res = NULL;
2091 * Look for the resource
2093 XtGetResourceList(XtClass(w), &res_list, &num_res);
2094 for (i = 0; i < num_res; i++)
2095 if (strcmp(res_list[i].resource_name, warg->name) == 0)
2101 if (res == NULL && XtParent(w) != NULL)
2103 XtFree((char *)res_list);
2104 XtGetConstraintResourceList(XtClass(XtParent(w)), &res_list, &num_res);
2105 for (i = 0; i < num_res; i++)
2106 if (strcmp(res_list[i].resource_name, warg->name) == 0)
2115 /* Couldn't find resource */
2117 XtFree((char *)res_list);
2118 *(XtPointer *)warg->value = NULL;
2122 /* try to get the value in the proper size */
2123 switch (res->resource_size)
2133 XtSetArg(args[0], res->resource_name, &v1);
2134 XtGetValues(w, args, 1);
2138 XtSetArg(args[0], res->resource_name, &v2);
2139 XtGetValues(w, args, 1);
2143 XtSetArg(args[0], res->resource_name, &v4);
2144 XtGetValues(w, args, 1);
2149 XtSetArg(args[0], res->resource_name, &v8);
2150 XtGetValues(w, args, 1);
2155 fprintf(stderr, "_XEditresGetStringValues: bad size %d\n",
2156 res->resource_size);
2157 string = "bad size";
2158 *(char **)(warg->value) = string;
2159 XtFree((char *)res_list);
2164 * If the resource is already String, no conversion needed
2166 if (strcmp(XtRString, res->resource_type) == 0)
2171 string = (char *)value;
2175 from.size = res->resource_size;
2176 from.addr = (XPointer)&value;
2180 if (XtConvertAndStore(w,res->resource_type, &from, XtRString, &to))
2186 * Conversion failed, fall back to representing it as integer
2188 switch (res->resource_size)
2191 XmuSnprintf(buffer, sizeof(buffer), "%d", (int)(value & 0xff));
2194 XmuSnprintf(buffer, sizeof(buffer), "%d", (int)(value & 0xffff));
2197 XmuSnprintf(buffer, sizeof(buffer), "0x%08x", (int)value);
2201 XmuSnprintf(buffer, sizeof(buffer), "0x%016lx", value);
2211 *(char **)(warg->value) = string;
2212 XtFree((char *)res_list);