1 /*************************************<+>*************************************
2 *****************************************************************************
8 ** Description: Code/Definitions for Button widget meta class.
10 ****************************************************************************
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
15 ** Permission to use, copy, modify, and distribute this software
16 ** and its documentation for any purpose and without fee is hereby
17 ** granted, provided that the above copyright notice appear in all
18 ** copies and that both that copyright notice and this permission
19 ** notice appear in supporting documentation, and that the names of
20 ** Hewlett-Packard or M.I.T. not be used in advertising or publicity
21 ** pertaining to distribution of the software without specific, written
24 *****************************************************************************
25 *************************************<+>************************************/
29 * Include files & Static Routine Definitions
35 #include <X11/StringDefs.h>
36 #include <X11/IntrinsicP.h>
37 #include <X11/Intrinsic.h>
38 #include <X11/Xatom.h>
42 static Boolean
SetValues();
43 static void ButtonDestroy();
46 /*************************************<->*************************************
49 * Description: resource list for class: Button
52 * Provides default resource settings for instances of this class.
53 * To get full set of default settings, examine resouce list of super
54 * classes of this class.
56 *************************************<->***********************************/
58 static XtResource resources
[] =
62 XtNfont
, XtCFont
, XtRFontStruct
, sizeof(XFontStruct
*),
63 XtOffset (XwButtonWidget
, button
.font
), XtRString
, "Fixed"
67 XtNlabel
, XtCLabel
, XtRString
, sizeof (caddr_t
),
68 XtOffset (XwButtonWidget
, button
.label
), XtRString
, NULL
72 XtNlabelLocation
, XtCLabelLocation
, XtRLabelLocation
, sizeof(int),
73 XtOffset (XwButtonWidget
, button
.label_location
), XtRString
, "right"
77 XtNvSpace
, XtCVSpace
, XtRDimension
, sizeof(Dimension
),
78 XtOffset (XwButtonWidget
, button
.internal_height
), XtRString
, "2"
82 XtNhSpace
, XtCHSpace
, XtRDimension
, sizeof(Dimension
),
83 XtOffset (XwButtonWidget
, button
.internal_width
), XtRString
, "2"
87 XtNset
, XtCSet
, XtRBoolean
, sizeof (Boolean
),
88 XtOffset (XwButtonWidget
, button
.set
), XtRString
, "False"
92 XtNsensitiveTile
, XtCSensitiveTile
, XtRTileType
, sizeof (int),
93 XtOffset(XwButtonWidget
, button
.sensitive_tile
),
94 XtRString
, "foreground"
98 XtNborderWidth
, XtCBorderWidth
, XtRDimension
, sizeof(Dimension
),
99 XtOffset(XwButtonWidget
,core
.border_width
), XtRString
, "0"
106 /*************************************<->*************************************
109 * Description: global class record for instances of class: Button
112 * Defines default field settings for this class record. Note that
113 * while Button needs a special type converter, it doesn't need to
114 * register that converter since Primitive takes care of registering
115 * all of the converters for the X Widgets library and Button is a
116 * subclass of Primitive.
118 *************************************<->***********************************/
120 XwButtonClassRec XwbuttonClassRec
=
123 (WidgetClass
) &XwprimitiveClassRec
, /* superclass */
124 "XwButton", /* class_name */
125 sizeof(XwButtonRec
), /* widget_size */
126 NULL
, /* class_initialize */
127 NULL
, /* class part initialize */
128 FALSE
, /* class_inited */
129 _XwInitializeButton
, /* initialize */
130 NULL
, /* initialize hook */
134 resources
, /* resources */
135 XtNumber(resources
), /* num_resources */
136 NULLQUARK
, /* xrm_class */
137 TRUE
, /* compress_motion */
138 TRUE
, /* compress_exposure */
139 TRUE
, /* compress_enterleave */
140 FALSE
, /* visible_interest */
141 ButtonDestroy
, /* destroy */
144 SetValues
, /* set_values */
145 NULL
, /* set_values_hook */
146 XtInheritSetValuesAlmost
, /* set_values_almost */
147 NULL
, /* get_values_hook */
148 NULL
, /* accept_focus */
149 XtVersion
, /* toolkit version */
150 NULL
, /* PRIVATE callback */
152 NULL
, /* query_geometry */
153 /* display_accelerator */ XtInheritDisplayAccelerator
,
157 /* Inherit procedures for handling traversal and selection */
159 (XtWidgetProc
) XtInheritBorderHighlight
,
160 (XtWidgetProc
) XtInheritBorderUnhighlight
,
161 (XwEventProc
) XtInheritSelectProc
,
162 (XwEventProc
) XtInheritReleaseProc
,
163 (XwEventProc
) XtInheritToggleProc
,
167 0, /* Button class part - unused */
171 WidgetClass XwbuttonWidgetClass
= (WidgetClass
) &XwbuttonClassRec
;
175 /*************************************<->*************************************
181 * Free up the space taken by the button's label and free up the
182 * button's graphic contexts.
187 * bw = button (or subclass of button) to be destroyed.
189 *************************************<->***********************************/
190 static void ButtonDestroy (bw
)
193 if (bw
->button
.label
)
194 XtFree (bw
->button
.label
);
195 XtDestroyGC (bw
->button
.normal_GC
);
196 XtDestroyGC (bw
->button
.inverse_GC
);
199 /*************************************<->*************************************
201 * SetValues(current, request, new, last)
205 * This is the set values procedure for the button class.
210 * current = original widget;
211 * request = copy of current (?);
212 * new = copy of request which reflects changes made to it by
213 * set values procedures of its superclasses;
214 * last = TRUE if this is the last set values procedure to be called.
222 *************************************<->***********************************/
224 static Boolean
SetValues(current
, request
, new)
225 Widget current
, request
, new;
227 XwButtonWidget curcbox
= (XwButtonWidget
) current
;
228 XwButtonWidget newcbox
= (XwButtonWidget
) new;
229 Boolean flag
= FALSE
; /* our return value */
236 /************************************************************
237 * If the button setting has been changed then set flag so that
238 * button will be redisplayed. NOTE THAT IF THE APPLICATION
239 * WANTS THE CALLBACKS ASSOCIATED WITH THE BUTTON TO BE INVOKED
240 * IT WILL HAVE TO DIRECTLY CALL XTCALLCALLBACKS.
241 ************************************************************/
242 if (curcbox
->button
.set
!= newcbox
->button
.set
) flag
= TRUE
;
245 /************************************************************
246 * If the font has been changed then we need to
247 * recompute the text width and height. We'll also have
248 * to change other things, see below...
249 ************************************************************/
250 if (curcbox
->button
.font
!= newcbox
->button
.font
)
252 _XwSetTextWidthAndHeight(newcbox
);
257 /**************************************************************
258 * If a new label has been provided then we'll need to copy it
259 * into our data space.
260 * Free up any space previously allocated for the label name.
261 * NOTE: We allow them to specify a NULL label.
262 ***************************************************************/
263 if (curcbox
->button
.label
!= newcbox
->button
.label
)
265 /* Set label length, height and width */
266 _XwSetTextWidthAndHeight(newcbox
);
268 if (newcbox
->button
.label
)
269 newcbox
->button
.label
= strcpy(
270 XtMalloc((unsigned) newcbox
->button
.label_len
+ 1),
271 newcbox
->button
.label
);
273 if (curcbox
->button
.label
)
274 XtFree ((char *) curcbox
->button
.label
);
280 /**********************************************************************
281 * If the label location flag has changed set the redisplay flag TRUE
282 * and check that it has a valid setting. If its invalid, then issue
284 ********************************************************************/
285 if (curcbox
->button
.label_location
!= newcbox
->button
.label_location
)
288 if ((newcbox
->button
.label_location
!= XwLEFT
) &&
289 (newcbox
->button
.label_location
!= XwRIGHT
) &&
290 (newcbox
->button
.label_location
!= XwCENTER
))
292 XtWarning("SetValues: Invalid Label Location Setting.");
293 newcbox
->button
.label_location
=
294 curcbox
->button
.label_location
;
298 /*********************************************************************
299 * If the sensitive tile has changed, validate it. Then, if the
300 * foreground or background or font or sensitive tile has changed
301 * then recompute/get a new (In)sensitive GC.
302 ********************************************************************/
303 if (newcbox
->button
.sensitive_tile
!= XwFOREGROUND
)
305 newcbox
->button
.sensitive_tile
= curcbox
->button
.sensitive_tile
;
306 XtWarning("SetValues: Invalid sensitive tile setting.");
309 if (curcbox
->primitive
.foreground
!= newcbox
->primitive
.foreground
||
310 curcbox
->core
.background_pixel
!= newcbox
->core
.background_pixel
)
312 /* GET ALL NEW GC's */
313 GCflag
= NewNormal
| NewInverse
;
316 if (curcbox
->button
.font
->fid
!= newcbox
->button
.font
->fid
)
318 /* GET NEW GC's FOR normal & inverse */
319 GCflag
= NewNormal
| NewInverse
;
322 if ((curcbox
->button
.sensitive_tile
!= newcbox
->button
.sensitive_tile
) &&
323 (! newcbox
->core
.sensitive
|| ! newcbox
->core
.ancestor_sensitive
))
325 /* GET NEW normal GC */
329 if ((newcbox
->core
.sensitive
!= curcbox
->core
.sensitive
) &&
330 ((newcbox
->core
.sensitive
&& newcbox
->core
.ancestor_sensitive
) ||
331 (!newcbox
->core
.sensitive
&& curcbox
->core
.ancestor_sensitive
)))
333 /* GET NEW normal GC */
336 else if (newcbox
->core
.sensitive
&&
337 (curcbox
->core
.ancestor_sensitive
!= newcbox
->core
.ancestor_sensitive
))
339 /* GET NEW normal GC */
345 if (GCflag
& NewNormal
)
347 XtDestroyGC(curcbox
->button
.normal_GC
);
348 _XwGetNormalGC(newcbox
);
351 if (GCflag
& NewInverse
)
353 XtDestroyGC(curcbox
->button
.inverse_GC
);
354 _XwGetInverseGC(newcbox
);
359 /********************************************************************
360 * NOTE THAT SUBCLASSES OF BUTTON WILL HAVE TO CHECK FOR CHANGES IN
361 * internal_width, internal_height AND DETERMINE WHAT SHOULD BE DONE.
362 * WE'RE JUST BEING GOOD CITIZENS HERE AND FLAGING THAT IT WILL HAVE
363 * TO BE REDISPLAYED BECAUSE OF THE CHANGE.
364 *********************************************************************/
365 if ((curcbox
->button
.internal_width
366 != newcbox
->button
.internal_width
) ||
367 (curcbox
->button
.internal_height
368 != newcbox
->button
.internal_height
)) flag
= TRUE
;
376 /*************************************<->*************************************
378 * void _XwSetTextWidthAndHeight (aButton)
382 * Calculate width and height of displayed text in pixels.
383 * Sets the following fields in the button portion of a button
392 * aButton = XwButtonWidget
396 * XwStrlen() [a macro: #define XwStrlen(s) ((s) ? strlen(s) : 0) ]
398 *************************************<->***********************************/
400 void _XwSetTextWidthAndHeight(aButton
)
401 XwButtonWidget aButton
;
403 register XFontStruct
*fs
= aButton
->button
.font
;
405 aButton
->button
.label_height
=
406 fs
->max_bounds
.ascent
+ fs
->max_bounds
.descent
;
408 if (aButton
->button
.label
)
410 aButton
->button
.label_len
= XwStrlen(aButton
->button
.label
);
412 aButton
->button
.label_width
= XTextWidth(
413 fs
, aButton
->button
.label
,
414 (int) aButton
->button
.label_len
);
418 aButton
->button
.label_len
= 0;
419 aButton
->button
.label_width
= 0;
423 /*************************************<->*************************************
425 * void _XwGetNormalGC(aButton)
426 * XwButtonWidget aButton;
430 * Uses the widget specific foreground to generate the "normal"
431 * graphic context. Note that this is a XToolkit sharable GC.
432 * Creates the needed GC and sets ptr. in instance record.
436 * aButton = widget instance.
444 *************************************<->***********************************/
446 void _XwGetNormalGC(aButton
)
447 XwButtonWidget aButton
;
451 values
.foreground
= aButton
->primitive
.foreground
;
452 values
.background
= aButton
->core
.background_pixel
;
453 values
.font
= aButton
->button
.font
->fid
;
455 values
.line_width
= 1;
456 aButton
->button
.normal_GC
= XtGetGC((Widget
)aButton
,
457 (unsigned) GCForeground
|
458 (unsigned) GCBackground
|
464 /*************************************<->*************************************
466 * void _XwGetInverseGC(aButton)
467 * XwButtonWidget aButton;
474 * aButton = widget instance.
482 *************************************<->***********************************/
484 void _XwGetInverseGC(aButton
)
485 XwButtonWidget aButton
;
488 values
.foreground
= aButton
->core
.background_pixel
;
489 values
.background
= aButton
->primitive
.foreground
;
490 values
.font
= aButton
->button
.font
->fid
;
491 values
.line_width
= 1;
493 aButton
->button
.inverse_GC
= XtGetGC((Widget
)aButton
,
494 (unsigned) GCForeground
| (unsigned) GCBackground
|
495 GCLineWidth
| GCFont
, &values
);
498 /*************************************<->*************************************
500 * _XwInitializeButton (request, new)
504 * This is the button instance initialize procedure. Make sure
505 * that the button has a label, compute its height and width fields;
506 * set the appropriate graphic contexts.
510 * request = original instance record;
512 * new = instance record with modifications induced by
513 * other initialize routines, changes are made to this
516 * args = argument list specified in XtCreateWidget;
518 * num_args = argument count;
526 *************************************<->***********************************/
528 void _XwInitializeButton (request
, new)
532 XwButtonWidget aButton
= (XwButtonWidget
) new;
535 * NOTE: we don't allow a NULL string for our button label.
536 * If we do find a NULL at initialize time then we will use the
537 * button name. The rationale for this is that this allows someone
538 * to change the button label in the .Xdefaults file, whereas if
539 * the application programmer hardwired the name into an arg list
540 * it would be impossible to change. However, if you really want
541 * a NULL string, do a SetValues and change the label to NULL.
543 * We need to malloc space for this string and copy it to our
544 * space. The toolkit simply copies the pointer to the string.
546 if (aButton
->button
.label
== NULL
) aButton
->button
.label
=
549 aButton
->button
.label
= strcpy( XtMalloc((unsigned)
550 (XwStrlen(aButton
->button
.label
)+1)),
551 aButton
->button
.label
);
555 * make sure that sensitive_tile is valid
557 if (aButton
->button
.sensitive_tile
!= XwFOREGROUND
)
559 aButton
->button
.sensitive_tile
= XwFOREGROUND
;
560 XtWarning("Initialize: Invalid sensitive tile setting.");
564 _XwGetInverseGC(aButton
);
565 _XwGetNormalGC(aButton
);
567 _XwSetTextWidthAndHeight(aButton
);
569 aButton
->primitive
.display_sensitive
= FALSE
;
570 aButton
->primitive
.highlighted
= FALSE
;
573 } /* _XwInitializeButton */
576 /*************************************<->*************************************
582 * This is a generalize routine used by both subclasses of Primitive
583 * and Manager. It sets bit gravity to NW for managers and to Forget
584 * for others, but for Buttons is sets it according to the setting of
589 * w = widget to be realized.
591 * valueMask = contains event mask for this window/widget.
593 * attributes = window attributes for this window/widget.
601 *************************************<->***********************************/
603 void _XwRealize(w
, p_valueMask
, attributes
)
606 XSetWindowAttributes
*attributes
;
608 Mask valueMask
= *p_valueMask
;
609 valueMask
|= CWBitGravity
;
611 if (XtIsSubclass(w
, XwprimitiveWidgetClass
)) {
612 register XwPrimitiveWidget pw
= (XwPrimitiveWidget
) w
;
613 if (pw
->primitive
.cursor
!= None
) valueMask
|= CWCursor
;
614 attributes
->cursor
= pw
->primitive
.cursor
;
617 if (XtIsSubclass(w
, XwmanagerWidgetClass
))
618 attributes
->bit_gravity
= NorthWestGravity
;
620 if (w
->core
.widget_class
!= XwbuttonWidgetClass
)
621 attributes
->bit_gravity
= ForgetGravity
;
623 switch (((XwButtonWidget
)w
)->button
.label_location
)
626 attributes
->bit_gravity
= EastGravity
; break;
628 attributes
->bit_gravity
= WestGravity
; break;
630 attributes
->bit_gravity
= CenterGravity
; break;
633 XtCreateWindow(w
, InputOutput
, (Visual
*)CopyFromParent
,
634 valueMask
, attributes
);
636 _XwRegisterName(w
); /* hang widget name as property on window */
641 /*************************************<->*************************************
647 * A resize event has been generated. Recompute location of button
650 * USED BY CHECKBOX AND PUSHBUTTON CLASSES.
654 * w = widget to be resized.
662 *************************************<->***********************************/
665 void _XwResizeButton(w
)
668 register XwButtonWidget aButton
= (XwButtonWidget
) w
;
669 int direction
= aButton
->button
.label_location
;
674 aButton
->button
.label_x
= ((int)aButton
->core
.width
+ 1 -
675 (int)aButton
->button
.label_width
) / 2;
679 aButton
->button
.label_x
= (int)aButton
->core
.width
-
680 (int)aButton
->button
.internal_width
-
681 aButton
->primitive
.highlight_thickness
-
682 (int)aButton
->button
.label_width
;
686 aButton
->button
.label_x
= aButton
->button
.internal_width
+
687 aButton
->primitive
.highlight_thickness
;
690 aButton
->button
.label_y
=
691 (((int)aButton
->core
.height
- (int)aButton
->button
.label_height
) >> 1)
692 + aButton
->button
.font
->max_bounds
.ascent
;
697 /*************************************<->*************************************
699 * ProcedureName (parameters)
703 * This procedure is used to store the name of the widget as a
704 * property on the widget's window. The property name is the
705 * string "XW_NAME". Note that we do not malloc space for the
706 * widget's name, we merely use the pointer to this string which
707 * is already in core.name. This shouldn't be a problem since
708 * the name will remain as long as the widget exists.
710 * We only want to do this one time, thus the hokey method of
711 * initializing a static boolean which prevents us from registering
712 * this atom more than once on the server.
714 * If possible, we should put this together with other functions done
715 * once. Also, WILL THIS BE A PROBLEM WHEN THE TOOLKIT ALLOWS MORE
716 * THAN ONE DISPLAY TO BE OPENED?????
720 * w = widget being created.
728 *************************************<->***********************************/
730 static Atom widget_name
;
731 static Boolean first
=True
;
733 void _XwRegisterName(w
)
738 widget_name
= XInternAtom (XtDisplay(w
), "XW_NAME", False
);
741 XChangeProperty (XtDisplay(w
), XtWindow(w
), widget_name
, XA_STRING
, 8,
742 PropModeReplace
, w
->core
.name
,
743 XwStrlen(w
->core
.name
)+1);
747 /*************************************<->*************************************
749 * _XwRecomputeSize(current, new)
753 * Used during SetValues for PButton and Toggle.
754 * If the font has changed OR the label has changed OR
755 * the internal spacing has changed OR the highlight
756 * thickness has changed AND the recompute flag is TRUE
757 * (in the new widget) return TRUE, else return FALSE.
762 * current = current version of widget
763 * new = new version of widget
767 * TRUE if resize is needed and okay, FALSE otherwise.
769 *************************************<->***********************************/
770 Boolean
_XwRecomputeSize(current
, new)
771 XwButtonWidget current
, new;
773 if (((new->button
.font
!= current
->button
.font
) ||
774 (new->button
.label
!= current
->button
.label
) ||
775 (new->primitive
.highlight_thickness
!=
776 current
->primitive
.highlight_thickness
) ||
777 (new->button
.internal_height
!= current
->button
.internal_height
) ||
778 (new->button
.internal_width
!= current
->button
.internal_width
)) &&
779 (new->primitive
.recompute_size
== TRUE
))