Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wbutton.c
1
2 #include "WINGsP.h"
3
4 typedef struct W_Button {
5         W_Class widgetClass;
6         WMView *view;
7
8         char *caption;
9
10         char *altCaption;
11
12         WMFont *font;
13
14         WMColor *textColor;
15         WMColor *altTextColor;
16         WMColor *disTextColor;
17
18         W_Pixmap *image;
19         W_Pixmap *altImage;
20
21         W_Pixmap *dimage;
22
23         void *clientData;
24         WMAction *action;
25
26         int tag;
27
28         int groupIndex;
29
30         float periodicDelay;
31         float periodicInterval;
32
33         WMHandlerID *timer;     /* for continuous mode */
34
35         struct {
36                 WMButtonType type:4;
37                 WMImagePosition imagePosition:4;
38                 WMAlignment alignment:2;
39
40                 unsigned int selected:1;
41
42                 unsigned int enabled:1;
43
44                 unsigned int dimsWhenDisabled:1;
45
46                 unsigned int bordered:1;
47
48                 unsigned int springLoaded:1;
49
50                 unsigned int pushIn:1;  /* change relief while pushed */
51
52                 unsigned int pushLight:1;       /* highlight while pushed */
53
54                 unsigned int pushChange:1;      /* change caption while pushed */
55
56                 unsigned int stateLight:1;      /* state indicated by highlight */
57
58                 unsigned int stateChange:1;     /* state indicated by caption change */
59
60                 unsigned int statePush:1;       /* state indicated by relief */
61
62                 unsigned int continuous:1;      /* continually perform action */
63
64                 unsigned int prevSelected:1;
65
66                 unsigned int pushed:1;
67
68                 unsigned int wasPushed:1;
69
70                 unsigned int redrawPending:1;
71
72                 unsigned int addedObserver:1;
73         } flags;
74 } Button;
75
76 #define DEFAULT_BUTTON_WIDTH    60
77 #define DEFAULT_BUTTON_HEIGHT   24
78 #define DEFAULT_BUTTON_ALIGNMENT        WACenter
79 #define DEFAULT_BUTTON_IS_BORDERED      True
80
81 #define DEFAULT_RADIO_WIDTH     100
82 #define DEFAULT_RADIO_HEIGHT    20
83 #define DEFAULT_RADIO_ALIGNMENT WALeft
84 #define DEFAULT_RADIO_IMAGE_POSITION    WIPLeft
85 #define DEFAULT_RADIO_TEXT      "Radio"
86
87 #define DEFAULT_SWITCH_WIDTH    100
88 #define DEFAULT_SWITCH_HEIGHT   20
89 #define DEFAULT_SWITCH_ALIGNMENT        WALeft
90 #define DEFAULT_SWITCH_IMAGE_POSITION   WIPLeft
91 #define DEFAULT_SWITCH_TEXT     "Switch"
92
93 static void destroyButton(Button * bPtr);
94 static void paintButton(Button * bPtr);
95
96 static void handleEvents(XEvent * event, void *data);
97 static void handleActionEvents(XEvent * event, void *data);
98
99 static char *WMPushedRadioNotification = "WMPushedRadioNotification";
100
101 #define NFONT(b) (b)->view->screen->normalFont
102
103 WMButton *WMCreateCustomButton(WMWidget * parent, int behaviourMask)
104 {
105         Button *bPtr;
106
107         bPtr = wmalloc(sizeof(Button));
108         memset(bPtr, 0, sizeof(Button));
109
110         bPtr->widgetClass = WC_Button;
111
112         bPtr->view = W_CreateView(W_VIEW(parent));
113         if (!bPtr->view) {
114                 wfree(bPtr);
115                 return NULL;
116         }
117         bPtr->view->self = bPtr;
118
119         bPtr->flags.type = 0;
120
121         bPtr->flags.springLoaded = (behaviourMask & WBBSpringLoadedMask) != 0;
122         bPtr->flags.pushIn = (behaviourMask & WBBPushInMask) != 0;
123         bPtr->flags.pushChange = (behaviourMask & WBBPushChangeMask) != 0;
124         bPtr->flags.pushLight = (behaviourMask & WBBPushLightMask) != 0;
125         bPtr->flags.stateLight = (behaviourMask & WBBStateLightMask) != 0;
126         bPtr->flags.stateChange = (behaviourMask & WBBStateChangeMask) != 0;
127         bPtr->flags.statePush = (behaviourMask & WBBStatePushMask) != 0;
128
129         W_ResizeView(bPtr->view, DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT);
130         bPtr->flags.alignment = DEFAULT_BUTTON_ALIGNMENT;
131         bPtr->flags.bordered = DEFAULT_BUTTON_IS_BORDERED;
132
133         bPtr->flags.enabled = 1;
134         bPtr->flags.dimsWhenDisabled = 1;
135
136         WMCreateEventHandler(bPtr->view, ExposureMask | StructureNotifyMask, handleEvents, bPtr);
137
138         WMCreateEventHandler(bPtr->view, ButtonPressMask | ButtonReleaseMask
139                              | EnterWindowMask | LeaveWindowMask, handleActionEvents, bPtr);
140
141         W_ResizeView(bPtr->view, DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT);
142         bPtr->flags.alignment = DEFAULT_BUTTON_ALIGNMENT;
143         bPtr->flags.bordered = DEFAULT_BUTTON_IS_BORDERED;
144
145         return bPtr;
146 }
147
148 WMButton *WMCreateButton(WMWidget * parent, WMButtonType type)
149 {
150         W_Screen *scrPtr = W_VIEW(parent)->screen;
151         Button *bPtr;
152
153         switch (type) {
154         case WBTMomentaryPush:
155                 bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | WBBPushInMask | WBBPushLightMask);
156                 break;
157
158         case WBTMomentaryChange:
159                 bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | WBBPushChangeMask);
160                 break;
161
162         case WBTPushOnPushOff:
163                 bPtr = WMCreateCustomButton(parent, WBBPushInMask | WBBStatePushMask | WBBStateLightMask);
164                 break;
165
166         case WBTToggle:
167                 bPtr = WMCreateCustomButton(parent, WBBPushInMask | WBBStateChangeMask | WBBStatePushMask);
168                 break;
169
170         case WBTOnOff:
171                 bPtr = WMCreateCustomButton(parent, WBBStateLightMask);
172                 break;
173
174         case WBTSwitch:
175                 bPtr = WMCreateCustomButton(parent, WBBStateChangeMask);
176                 bPtr->flags.bordered = 0;
177                 bPtr->image = WMRetainPixmap(scrPtr->checkButtonImageOff);
178                 bPtr->altImage = WMRetainPixmap(scrPtr->checkButtonImageOn);
179                 break;
180
181         case WBTRadio:
182                 bPtr = WMCreateCustomButton(parent, WBBStateChangeMask);
183                 bPtr->flags.bordered = 0;
184                 bPtr->image = WMRetainPixmap(scrPtr->radioButtonImageOff);
185                 bPtr->altImage = WMRetainPixmap(scrPtr->radioButtonImageOn);
186                 break;
187
188         default:
189         case WBTMomentaryLight:
190                 bPtr = WMCreateCustomButton(parent, WBBSpringLoadedMask | WBBPushLightMask);
191                 bPtr->flags.bordered = 1;
192                 break;
193         }
194
195         bPtr->flags.type = type;
196
197         if (type == WBTRadio) {
198                 W_ResizeView(bPtr->view, DEFAULT_RADIO_WIDTH, DEFAULT_RADIO_HEIGHT);
199                 WMSetButtonText(bPtr, DEFAULT_RADIO_TEXT);
200                 bPtr->flags.alignment = DEFAULT_RADIO_ALIGNMENT;
201                 bPtr->flags.imagePosition = DEFAULT_RADIO_IMAGE_POSITION;
202         } else if (type == WBTSwitch) {
203                 W_ResizeView(bPtr->view, DEFAULT_SWITCH_WIDTH, DEFAULT_SWITCH_HEIGHT);
204                 WMSetButtonText(bPtr, DEFAULT_SWITCH_TEXT);
205                 bPtr->flags.alignment = DEFAULT_SWITCH_ALIGNMENT;
206                 bPtr->flags.imagePosition = DEFAULT_SWITCH_IMAGE_POSITION;
207         }
208
209         return bPtr;
210 }
211
212 static void updateDisabledMask(WMButton * bPtr)
213 {
214         WMScreen *scr = WMWidgetScreen(bPtr);
215         Display *dpy = scr->display;
216
217         if (bPtr->image) {
218                 XGCValues gcv;
219
220                 if (bPtr->dimage->mask) {
221                         XFreePixmap(dpy, bPtr->dimage->mask);
222                         bPtr->dimage->mask = None;
223                 }
224
225                 if (bPtr->flags.dimsWhenDisabled) {
226                         bPtr->dimage->mask = XCreatePixmap(dpy, scr->stipple,
227                                                            bPtr->dimage->width, bPtr->dimage->height, 1);
228
229                         XSetForeground(dpy, scr->monoGC, 0);
230                         XFillRectangle(dpy, bPtr->dimage->mask, scr->monoGC, 0, 0,
231                                        bPtr->dimage->width, bPtr->dimage->height);
232
233                         gcv.foreground = 1;
234                         gcv.background = 0;
235                         gcv.stipple = scr->stipple;
236                         gcv.fill_style = FillStippled;
237                         gcv.clip_mask = bPtr->image->mask;
238                         gcv.clip_x_origin = 0;
239                         gcv.clip_y_origin = 0;
240
241                         XChangeGC(dpy, scr->monoGC, GCForeground | GCBackground | GCStipple
242                                   | GCFillStyle | GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
243
244                         XFillRectangle(dpy, bPtr->dimage->mask, scr->monoGC, 0, 0,
245                                        bPtr->dimage->width, bPtr->dimage->height);
246
247                         gcv.fill_style = FillSolid;
248                         gcv.clip_mask = None;
249                         XChangeGC(dpy, scr->monoGC, GCFillStyle | GCClipMask, &gcv);
250                 }
251         }
252 }
253
254 void WMSetButtonImageDefault(WMButton * bPtr)
255 {
256         WMSetButtonImage(bPtr, WMWidgetScreen(bPtr)->buttonArrow);
257         WMSetButtonAltImage(bPtr, WMWidgetScreen(bPtr)->pushedButtonArrow);
258 }
259
260 void WMSetButtonImage(WMButton * bPtr, WMPixmap * image)
261 {
262         if (bPtr->image != NULL)
263                 WMReleasePixmap(bPtr->image);
264         bPtr->image = WMRetainPixmap(image);
265
266         if (bPtr->dimage) {
267                 bPtr->dimage->pixmap = None;
268                 WMReleasePixmap(bPtr->dimage);
269                 bPtr->dimage = NULL;
270         }
271
272         if (image) {
273                 bPtr->dimage = WMCreatePixmapFromXPixmaps(WMWidgetScreen(bPtr),
274                                                           image->pixmap, None,
275                                                           image->width, image->height, image->depth);
276                 updateDisabledMask(bPtr);
277         }
278
279         if (bPtr->view->flags.realized) {
280                 paintButton(bPtr);
281         }
282 }
283
284 void WMSetButtonAltImage(WMButton * bPtr, WMPixmap * image)
285 {
286         if (bPtr->altImage != NULL)
287                 WMReleasePixmap(bPtr->altImage);
288         bPtr->altImage = WMRetainPixmap(image);
289
290         if (bPtr->view->flags.realized) {
291                 paintButton(bPtr);
292         }
293 }
294
295 void WMSetButtonImagePosition(WMButton * bPtr, WMImagePosition position)
296 {
297         bPtr->flags.imagePosition = position;
298
299         if (bPtr->view->flags.realized) {
300                 paintButton(bPtr);
301         }
302 }
303
304 void WMSetButtonTextAlignment(WMButton * bPtr, WMAlignment alignment)
305 {
306         bPtr->flags.alignment = alignment;
307
308         if (bPtr->view->flags.realized) {
309                 paintButton(bPtr);
310         }
311 }
312
313 void WMSetButtonText(WMButton * bPtr, char *text)
314 {
315         if (bPtr->caption)
316                 wfree(bPtr->caption);
317
318         if (text != NULL) {
319                 bPtr->caption = wstrdup(text);
320         } else {
321                 bPtr->caption = NULL;
322         }
323
324         if (bPtr->view->flags.realized) {
325                 paintButton(bPtr);
326         }
327 }
328
329 void WMSetButtonAltText(WMButton * bPtr, char *text)
330 {
331         if (bPtr->altCaption)
332                 wfree(bPtr->altCaption);
333
334         if (text != NULL) {
335                 bPtr->altCaption = wstrdup(text);
336         } else {
337                 bPtr->altCaption = NULL;
338         }
339
340         if (bPtr->view->flags.realized) {
341                 paintButton(bPtr);
342         }
343 }
344
345 void WMSetButtonTextColor(WMButton * bPtr, WMColor * color)
346 {
347         if (bPtr->textColor)
348                 WMReleaseColor(bPtr->textColor);
349
350         bPtr->textColor = WMRetainColor(color);
351 }
352
353 void WMSetButtonAltTextColor(WMButton * bPtr, WMColor * color)
354 {
355         if (bPtr->altTextColor)
356                 WMReleaseColor(bPtr->altTextColor);
357
358         bPtr->altTextColor = WMRetainColor(color);
359 }
360
361 void WMSetButtonDisabledTextColor(WMButton * bPtr, WMColor * color)
362 {
363         if (bPtr->disTextColor)
364                 WMReleaseColor(bPtr->disTextColor);
365
366         bPtr->disTextColor = WMRetainColor(color);
367 }
368
369 void WMSetButtonSelected(WMButton * bPtr, int isSelected)
370 {
371         bPtr->flags.selected = isSelected ? 1 : 0;
372
373         if (bPtr->view->flags.realized) {
374                 paintButton(bPtr);
375         }
376         if (bPtr->groupIndex > 0)
377                 WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL);
378 }
379
380 int WMGetButtonSelected(WMButton * bPtr)
381 {
382         CHECK_CLASS(bPtr, WC_Button);
383
384         return bPtr->flags.selected;
385 }
386
387 void WMSetButtonBordered(WMButton * bPtr, int isBordered)
388 {
389         bPtr->flags.bordered = isBordered;
390
391         if (bPtr->view->flags.realized) {
392                 paintButton(bPtr);
393         }
394 }
395
396 void WMSetButtonFont(WMButton * bPtr, WMFont * font)
397 {
398         if (bPtr->font)
399                 WMReleaseFont(bPtr->font);
400
401         bPtr->font = WMRetainFont(font);
402 }
403
404 void WMSetButtonEnabled(WMButton * bPtr, Bool flag)
405 {
406         bPtr->flags.enabled = ((flag == 0) ? 0 : 1);
407
408         if (bPtr->view->flags.mapped) {
409                 paintButton(bPtr);
410         }
411 }
412
413 int WMGetButtonEnabled(WMButton * bPtr)
414 {
415         CHECK_CLASS(bPtr, WC_Button);
416
417         return bPtr->flags.enabled;
418 }
419
420 void WMSetButtonImageDimsWhenDisabled(WMButton * bPtr, Bool flag)
421 {
422         bPtr->flags.dimsWhenDisabled = ((flag == 0) ? 0 : 1);
423
424         updateDisabledMask(bPtr);
425 }
426
427 void WMSetButtonTag(WMButton * bPtr, int tag)
428 {
429         bPtr->tag = tag;
430 }
431
432 void WMPerformButtonClick(WMButton * bPtr)
433 {
434         CHECK_CLASS(bPtr, WC_Button);
435
436         if (!bPtr->flags.enabled)
437                 return;
438
439         bPtr->flags.pushed = 1;
440         bPtr->flags.selected = 1;
441
442         if (bPtr->view->flags.mapped) {
443                 paintButton(bPtr);
444                 XFlush(WMScreenDisplay(WMWidgetScreen(bPtr)));
445                 wusleep(20000);
446         }
447
448         bPtr->flags.pushed = 0;
449
450         if (bPtr->groupIndex > 0) {
451                 WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL);
452         }
453
454         if (bPtr->action)
455                 (*bPtr->action) (bPtr, bPtr->clientData);
456
457         if (bPtr->view->flags.mapped)
458                 paintButton(bPtr);
459 }
460
461 void WMSetButtonAction(WMButton * bPtr, WMAction * action, void *clientData)
462 {
463         CHECK_CLASS(bPtr, WC_Button);
464
465         bPtr->action = action;
466
467         bPtr->clientData = clientData;
468 }
469
470 static void radioPushObserver(void *observerData, WMNotification * notification)
471 {
472         WMButton *bPtr = (WMButton *) observerData;
473         WMButton *pushedButton = (WMButton *) WMGetNotificationObject(notification);
474
475         if (bPtr != pushedButton && pushedButton->groupIndex == bPtr->groupIndex && bPtr->groupIndex != 0) {
476                 if (bPtr->flags.selected) {
477                         bPtr->flags.selected = 0;
478                         paintButton(bPtr);
479                 }
480         }
481 }
482
483 void WMGroupButtons(WMButton * bPtr, WMButton * newMember)
484 {
485         static int tagIndex = 0;
486
487         CHECK_CLASS(bPtr, WC_Button);
488         CHECK_CLASS(newMember, WC_Button);
489
490         if (!bPtr->flags.addedObserver) {
491                 WMAddNotificationObserver(radioPushObserver, bPtr, WMPushedRadioNotification, NULL);
492                 bPtr->flags.addedObserver = 1;
493         }
494         if (!newMember->flags.addedObserver) {
495                 WMAddNotificationObserver(radioPushObserver, newMember, WMPushedRadioNotification, NULL);
496                 newMember->flags.addedObserver = 1;
497         }
498
499         if (bPtr->groupIndex == 0) {
500                 bPtr->groupIndex = ++tagIndex;
501         }
502         newMember->groupIndex = bPtr->groupIndex;
503 }
504
505 void WMSetButtonContinuous(WMButton * bPtr, Bool flag)
506 {
507         bPtr->flags.continuous = ((flag == 0) ? 0 : 1);
508         if (bPtr->timer) {
509                 WMDeleteTimerHandler(bPtr->timer);
510                 bPtr->timer = NULL;
511         }
512 }
513
514 void WMSetButtonPeriodicDelay(WMButton * bPtr, float delay, float interval)
515 {
516         bPtr->periodicInterval = interval;
517         bPtr->periodicDelay = delay;
518 }
519
520 static void paintButton(Button * bPtr)
521 {
522         W_Screen *scrPtr = bPtr->view->screen;
523         WMReliefType relief;
524         int offset;
525         char *caption;
526         WMPixmap *image;
527         WMColor *textColor;
528         WMColor *backColor;
529
530         backColor = NULL;
531         caption = bPtr->caption;
532
533         if (bPtr->flags.enabled) {
534                 textColor = (bPtr->textColor != NULL ? bPtr->textColor : scrPtr->black);
535         } else {
536                 textColor = (bPtr->disTextColor != NULL ? bPtr->disTextColor : scrPtr->darkGray);
537         }
538
539         if (bPtr->flags.enabled || !bPtr->dimage)
540                 image = bPtr->image;
541         else
542                 image = bPtr->dimage;
543         offset = 0;
544         if (bPtr->flags.bordered)
545                 relief = WRRaised;
546         else
547                 relief = WRFlat;
548
549         if (bPtr->flags.selected) {
550                 if (bPtr->flags.stateLight) {
551                         backColor = scrPtr->white;
552                         textColor = scrPtr->black;
553                 }
554
555                 if (bPtr->flags.stateChange) {
556                         if (bPtr->altCaption)
557                                 caption = bPtr->altCaption;
558                         if (bPtr->altImage)
559                                 image = bPtr->altImage;
560                         if (bPtr->altTextColor)
561                                 textColor = bPtr->altTextColor;
562                 }
563
564                 if (bPtr->flags.statePush && bPtr->flags.bordered) {
565                         relief = WRSunken;
566                         offset = 1;
567                 }
568         }
569
570         if (bPtr->flags.pushed) {
571                 if (bPtr->flags.pushIn) {
572                         relief = WRPushed;
573                         offset = 1;
574                 }
575                 if (bPtr->flags.pushLight) {
576                         backColor = scrPtr->white;
577                         textColor = scrPtr->black;
578                 }
579
580                 if (bPtr->flags.pushChange) {
581                         if (bPtr->altCaption)
582                                 caption = bPtr->altCaption;
583                         if (bPtr->altImage)
584                                 image = bPtr->altImage;
585                         if (bPtr->altTextColor)
586                                 textColor = bPtr->altTextColor;
587                 }
588         }
589
590         W_PaintTextAndImage(bPtr->view, True, textColor,
591                             (bPtr->font != NULL ? bPtr->font : scrPtr->normalFont),
592                             relief, caption, bPtr->flags.alignment, image,
593                             bPtr->flags.imagePosition, backColor, offset);
594 }
595
596 static void handleEvents(XEvent * event, void *data)
597 {
598         Button *bPtr = (Button *) data;
599
600         CHECK_CLASS(data, WC_Button);
601
602         switch (event->type) {
603         case Expose:
604                 if (event->xexpose.count != 0)
605                         break;
606                 paintButton(bPtr);
607                 break;
608
609         case DestroyNotify:
610                 destroyButton(bPtr);
611                 break;
612         }
613 }
614
615 static void autoRepeat(void *data)
616 {
617         Button *bPtr = (Button *) data;
618
619         if (bPtr->action && bPtr->flags.pushed)
620                 (*bPtr->action) (bPtr, bPtr->clientData);
621
622         bPtr->timer = WMAddTimerHandler((int)(bPtr->periodicInterval * 1000), autoRepeat, bPtr);
623 }
624
625 static void handleActionEvents(XEvent * event, void *data)
626 {
627         Button *bPtr = (Button *) data;
628         int doclick = 0, dopaint = 0;
629
630         CHECK_CLASS(data, WC_Button);
631
632         if (!bPtr->flags.enabled)
633                 return;
634
635         switch (event->type) {
636         case EnterNotify:
637                 if (bPtr->groupIndex == 0) {
638                         bPtr->flags.pushed = bPtr->flags.wasPushed;
639                         if (bPtr->flags.pushed) {
640                                 bPtr->flags.selected = !bPtr->flags.prevSelected;
641                                 dopaint = 1;
642                         }
643                 }
644                 break;
645
646         case LeaveNotify:
647                 if (bPtr->groupIndex == 0) {
648                         bPtr->flags.wasPushed = bPtr->flags.pushed;
649                         if (bPtr->flags.pushed) {
650                                 bPtr->flags.selected = bPtr->flags.prevSelected;
651                                 dopaint = 1;
652                         }
653                         bPtr->flags.pushed = 0;
654                 }
655                 break;
656
657         case ButtonPress:
658                 if (event->xbutton.button == Button1) {
659                         bPtr->flags.prevSelected = bPtr->flags.selected;
660                         bPtr->flags.wasPushed = 0;
661                         bPtr->flags.pushed = 1;
662                         if (bPtr->groupIndex > 0) {
663                                 bPtr->flags.selected = 1;
664                                 dopaint = 1;
665                                 break;
666                         }
667                         bPtr->flags.selected = !bPtr->flags.selected;
668                         dopaint = 1;
669
670                         if (bPtr->flags.continuous && !bPtr->timer) {
671                                 bPtr->timer = WMAddTimerHandler((int)(bPtr->periodicDelay * 1000),
672                                                                 autoRepeat, bPtr);
673                         }
674                 }
675                 break;
676
677         case ButtonRelease:
678                 if (event->xbutton.button == Button1) {
679                         if (bPtr->flags.pushed) {
680                                 if (bPtr->groupIndex == 0 || (bPtr->flags.selected && bPtr->groupIndex > 0))
681                                         doclick = 1;
682                                 dopaint = 1;
683                                 if (bPtr->flags.springLoaded) {
684                                         bPtr->flags.selected = bPtr->flags.prevSelected;
685                                 }
686                         }
687                         bPtr->flags.pushed = 0;
688                 }
689                 if (bPtr->timer) {
690                         WMDeleteTimerHandler(bPtr->timer);
691                         bPtr->timer = NULL;
692                 }
693                 break;
694         }
695
696         if (dopaint)
697                 paintButton(bPtr);
698
699         if (doclick) {
700                 if (bPtr->flags.selected && bPtr->groupIndex > 0) {
701                         WMPostNotificationName(WMPushedRadioNotification, bPtr, NULL);
702                 }
703
704                 if (bPtr->action)
705                         (*bPtr->action) (bPtr, bPtr->clientData);
706         }
707 }
708
709 static void destroyButton(Button * bPtr)
710 {
711         if (bPtr->flags.addedObserver) {
712                 WMRemoveNotificationObserver(bPtr);
713         }
714
715         if (bPtr->timer)
716                 WMDeleteTimerHandler(bPtr->timer);
717
718         if (bPtr->font)
719                 WMReleaseFont(bPtr->font);
720
721         if (bPtr->caption)
722                 wfree(bPtr->caption);
723
724         if (bPtr->altCaption)
725                 wfree(bPtr->altCaption);
726
727         if (bPtr->textColor)
728                 WMReleaseColor(bPtr->textColor);
729
730         if (bPtr->altTextColor)
731                 WMReleaseColor(bPtr->altTextColor);
732
733         if (bPtr->disTextColor)
734                 WMReleaseColor(bPtr->disTextColor);
735
736         if (bPtr->image)
737                 WMReleasePixmap(bPtr->image);
738
739         if (bPtr->dimage) {
740                 /* yuck.. kluge */
741                 bPtr->dimage->pixmap = None;
742
743                 WMReleasePixmap(bPtr->dimage);
744         }
745         if (bPtr->altImage)
746                 WMReleasePixmap(bPtr->altImage);
747
748         wfree(bPtr);
749 }