Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtprintinfo / libUI / MotifUI / MotifUI.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: MotifUI.C /main/8 1998/08/03 08:59:09 mgreess $ */
24 /*                                                                      *
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30
31 #include "MotifUI.h"
32 #include "Menu.h"
33 #include "Dialog.h"
34 #include "Icon.h"
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <sys/stat.h>
38
39 #include <X11/cursorfont.h>
40 #include <X11/IntrinsicP.h>
41
42 #ifdef NO_CDE
43 #include "xpm.h"
44 #include <X11/keysym.h>
45 #else
46 #include <Dt/xpm.h>
47 #include <Dt/Help.h>
48 #endif
49
50 #include <Xm/ToggleB.h>
51 #include <Xm/RowColumn.h>
52 #include <Xm/ScrolledW.h>
53 #include <Xm/MainW.h>
54
55 PixmapLookupList MotifUI::pixmap_table = NULL;
56 XtAppContext     MotifUI::appContext = NULL;
57 XmFontList       MotifUI::userFont = NULL;
58 Display *        MotifUI::display = NULL;
59 Widget           MotifUI::topLevel;
60 Window           MotifUI::root;
61 Font             MotifUI::font;
62 Pixel            MotifUI::black;
63 Pixel            MotifUI::white;
64 int              MotifUI::shadowThickness;
65 int              MotifUI::depth;
66 int              MotifUI::bMenuButton;
67 int              MotifUI::n_pixmaps = 0;
68 PointerCursor    MotifUI::pointer_style = LEFT_SLANTED_ARROW_CURSOR;
69
70
71 MotifUI::MotifUI(MotifUI *parent, 
72                  const char *name,
73                  const char *category,
74                  const char *widgetName)
75         : BaseUI(parent, name, category)
76 {
77    _w = NULL;
78    if (widgetName)
79       _widgetName = STRDUP(widgetName);
80    else
81       _widgetName = STRDUP(name);
82 }
83
84 MotifUI::~MotifUI()
85 {
86    if (_w)
87       XtRemoveCallback(_w, XmNdestroyCallback, &MotifUI::WidgetDestroyCB, 
88                        (XtPointer) this);
89    delete _widgetName;
90 }
91
92 void MotifUI::ThreadCB(MotifThread *_thread, BaseUI *obj, ThreadCallback cb)
93 {
94    (*cb)(obj, _thread->output, _thread->status);
95    delete _thread;
96 }
97
98 void MotifUI::Thread(const char *cmd, ThreadCallback cb, int buf_len)
99
100 {
101    new MotifThread(this, cmd, &(MotifUI::ThreadCB), cb, buf_len);
102 }
103
104 void MotifUI::Thread(int pid, int fd, ThreadCallback cb, int buf_len)
105 {
106    new MotifThread(this, pid, fd, &(MotifUI::ThreadCB), cb, buf_len);
107 }
108
109 void MotifUI::Thread(int socket, ThreadCallback cb, int buf_len)
110 {
111    new MotifThread(this, socket, &(MotifUI::ThreadCB), cb, buf_len);
112 }
113
114 void MotifUI::SetFocus()
115 {
116    DoSetFocus(_w);
117 }
118
119 void MotifUI::DoSetFocus(Widget w)
120 {
121    XmProcessTraversal(w, XmTRAVERSE_CURRENT);
122 }
123
124 boolean MotifUI::DoIsVisible()
125 {
126    boolean rc = true;
127    if (_w)
128     {
129       if (UIClass() == APPLICATION)
130        {
131          if (XtIsRealized(_w))
132           {
133             XWindowAttributes attributes;
134             XGetWindowAttributes(display, XtWindow(_w), &attributes);
135             if (attributes.map_state == IsUnmapped)
136                rc = false;
137           }
138        }
139       else if (XmGetVisibility(_w) == XmVISIBILITY_FULLY_OBSCURED)
140          rc = false;
141     }
142    return rc;
143 }
144
145 void MotifUI::DoMakeVisible()
146 {
147    Widget sw = XtParent(_w);
148    if (sw && !XmIsScrolledWindow(sw))
149       sw = XtParent(sw);
150    if (sw && !XmIsScrolledWindow(sw))
151       sw = XtParent(sw);
152    if (sw && XmIsScrolledWindow(sw) && !XmIsMainWindow(sw))
153       XmScrollVisible(sw, _w, 0, 0);
154 }
155
156 void MotifUI::DoContextualHelp()
157 {
158    Widget context_widget, shell;
159 #ifdef NO_CDE
160    XEvent event;
161    static Cursor cursor = (Cursor) NULL;
162
163    if (cursor == (Cursor) NULL)
164       cursor =  XCreateFontCursor(display, XC_question_arrow);
165 #endif
166
167    BaseUI *window = this;
168    while (window->UIClass() != MAIN_WINDOW)
169       window = window->Parent();
170    shell = ((MotifUI *)window)->_w;
171 #ifdef NO_CDE
172    context_widget = XmTrackingEvent(shell, cursor, False, &event);
173
174    if (event.type == KeyPress || event.type == KeyRelease)
175     {
176       int offset;
177       KeySym keySym;
178
179       // Look for ESC key press and stop if we get one 
180       if (event.xkey.state & ShiftMask)
181          offset = 1;
182       else
183          offset = 0;
184
185       keySym = XLookupKeysym((XKeyEvent *)&event, offset);
186       if (keySym == XK_Escape)
187          return;
188     }
189
190    if (context_widget != NULL)
191     {
192 #else
193    int returnVal = DtHelpReturnSelectedWidgetId(shell, NULL, &context_widget);
194    if (returnVal == DtHELP_SELECT_VALID)
195     {
196 #endif
197       XmAnyCallbackStruct cb;
198
199       cb.reason = XmCR_HELP;
200 #ifdef NO_CDE
201       cb.event = &event;
202 #endif
203       while (context_widget != NULL)
204        {
205          // If there is no help at this widget, back track to find help 
206          if (XtHasCallbacks(context_widget, XmNhelpCallback) ==
207                             XtCallbackHasSome)
208           {
209             XtCallCallbacks(context_widget, XmNhelpCallback, &cb);
210             break;
211           }
212          else
213             context_widget = XtParent(context_widget);
214        }
215     }
216 }
217
218 void MotifUI::WidgetHelpCB(Widget,
219                            XtPointer clientData,
220                            XtPointer)
221 {
222    MotifUI * obj = (MotifUI *) clientData;
223
224    obj->HandleHelpRequest();
225 }
226
227 void MotifUI::WidgetDestroyCB(Widget,
228                               XtPointer clientData,
229                               XtPointer)
230 {
231    MotifUI * obj = (MotifUI *) clientData;
232
233    obj->WidgetDestroyed();
234 }
235
236 void MotifUI::WidgetDestroyed()
237 {
238    _w = NULL;
239    delete _widgetName;
240 }
241
242 void MotifUI::DoRefresh()
243 {
244    if (_w)
245       XmUpdateDisplay(_w);
246 }
247
248 void MotifUI::DoToFront()
249 {
250    if (_w)
251     {
252       if (XtIsShell(XtParent(_w)))
253          XRaiseWindow(display, XtWindow(XtParent(_w)));
254       else
255          XRaiseWindow(display, XtWindow(_w));
256     }
257 }
258
259 void MotifUI::InstallDestroyCB()
260 {
261    if (_w)
262       XtAddCallback(_w, XmNdestroyCallback, &MotifUI::WidgetDestroyCB, 
263                     (XtPointer) this);
264 }
265
266 void MotifUI::InstallHelpCB()
267 {
268    if (!_w)
269       return;
270
271    if (UIClass() == MENU && UISubClass() != POPUP_MENU)
272       XtAddCallback(((Menu*)this)->GetCascade(), XmNhelpCallback,
273                     &MotifUI::WidgetHelpCB, (XtPointer) this);
274    else
275       XtAddCallback(_w, XmNhelpCallback, &MotifUI::WidgetHelpCB, 
276                     (XtPointer) this);
277 }
278
279 boolean MotifUI::SetSelected(boolean flag)
280 {
281    if (!_w)
282       return false;
283
284    if (GuiIsIcon(_w))
285       XtVaSetValues(_w, GuiNselected, flag, NULL);
286    else if (XmIsToggleButton(_w))
287       XmToggleButtonSetState(_w, flag, False);
288
289    return true;
290 }
291
292 boolean MotifUI::SetName(char *name)
293 {
294    if (!InnerWidget())
295       return false;
296
297    XmString xm_string = StringCreate(name);
298    XtVaSetValues(InnerWidget(), XmNlabelString, xm_string, NULL);
299    StringFree(xm_string);
300
301    return true;
302 }
303
304 boolean MotifUI::SetActivity(boolean flag)
305 {
306    if (!_w)
307       return false;
308
309    if (GuiIsIcon(_w))
310       XtVaSetValues(_w, GuiNactive, flag, NULL);
311    else
312       XtSetSensitive(_w, flag);
313
314    return true;
315 }
316
317 boolean MotifUI::SetVisiblity(boolean flag)
318 {
319    if (!_w)
320       return false;
321
322    if (flag)
323       XtManageChild(_w);
324    else
325       XtUnmanageChild(_w);
326
327    return true;
328 }
329
330 void MotifUI::GetResources(const XtResourceList resources, 
331                            const int numResources)
332 {
333    if (_w && resources)
334       XtGetSubresources(XtParent(_w), (XtPointer) this, _widgetName,
335                         className(), resources, numResources, NULL, 0);
336 }
337
338 void MotifUI::SetDefaultResources(const Widget,
339                                   const String *resources)
340 {
341    XrmDatabase rdb = NULL;
342    int         i;
343
344    rdb = XrmGetStringDatabase("");
345
346    i = 0;
347    while (resources[i])
348     {
349       char *buf = new char[1000];
350
351       sprintf(buf, "%s%s", _name, resources[i]);
352       XrmPutLineResource(&rdb, buf);
353       i++;
354
355       delete [] buf;
356     }
357    if (rdb)
358     {
359       XrmMergeDatabases(XtDatabase(display), &rdb);
360       XrmSetDatabase(display, rdb);
361     }
362 }
363
364 void MotifUI::NotifyDelete(BaseUI *obj)
365 {
366    MotifUI *p = (MotifUI *) obj;
367    if (p->_w)
368     {
369       XtRemoveCallback(_w, XmNdestroyCallback, &MotifUI::WidgetDestroyCB, 
370                        (XtPointer) this);
371       XtDestroyWidget(p->_w);
372       p->_w = NULL;
373     }
374 }
375
376 void MotifUI::Width(int width)
377 {
378    XtVaSetValues(this->BaseWidget(), XmNwidth, width, NULL);
379 }
380
381 int MotifUI::Width()
382 {
383    Dimension w;
384    XtVaGetValues(this->BaseWidget(), XmNwidth, &w, NULL);
385    return (int) w;
386 }
387
388 void MotifUI::Height(int height)
389 {
390    XtVaSetValues(this->BaseWidget(), XmNheight, height, NULL);
391 }
392
393 int MotifUI::Height()
394 {
395    Dimension h;
396    XtVaGetValues(this->BaseWidget(), XmNheight, &h, NULL);
397    return (int) h;
398 }
399
400 void MotifUI::WidthHeight(int width, int height)
401 {
402    XtVaSetValues(this->BaseWidget(), XmNwidth, width, XmNheight, height, NULL);
403 }
404
405 void MotifUI::WidthHeight(int *width, int *height)
406 {
407    Dimension w, h;
408
409    XtVaGetValues(this->BaseWidget(), XmNwidth, &w, XmNheight, &h, NULL);
410    *width = (int) w;
411    *height = (int) h;
412 }
413
414 void MotifUI::AttachAll(int offset)
415 {
416    XtVaSetValues(this->BaseWidget(),
417                  XmNtopAttachment, XmATTACH_NONE,
418                  XmNbottomAttachment, XmATTACH_NONE,
419                  XmNleftAttachment, XmATTACH_NONE,
420                  XmNrightAttachment, XmATTACH_NONE,
421                  NULL);
422    XtVaSetValues(this->BaseWidget(),
423                  XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, offset,
424                  XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, offset,
425                  XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, offset,
426                  XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, offset,
427                  NULL);
428 }
429
430 void MotifUI::AttachTop(int offset)
431 {
432    XtVaSetValues(this->BaseWidget(), XmNtopAttachment, XmATTACH_NONE, NULL);
433    XtVaSetValues(this->BaseWidget(), XmNtopAttachment, XmATTACH_FORM,
434                  XmNtopOffset, offset, NULL);
435 }
436
437 void MotifUI::AttachBottom(int offset)
438 {
439    XtVaSetValues(this->BaseWidget(), XmNbottomAttachment, XmATTACH_NONE, NULL);
440    XtVaSetValues(this->BaseWidget(), XmNbottomAttachment, XmATTACH_FORM,
441                  XmNbottomOffset, offset, NULL);
442 }
443
444 void MotifUI::AttachLeft(int offset)
445 {
446    XtVaSetValues(this->BaseWidget(), XmNleftAttachment, XmATTACH_NONE, NULL);
447    XtVaSetValues(this->BaseWidget(), XmNleftAttachment, XmATTACH_FORM,
448                  XmNleftOffset, offset, NULL);
449 }
450
451 void MotifUI::AttachRight(int offset)
452 {
453    XtVaSetValues(this->BaseWidget(), XmNrightAttachment, XmATTACH_NONE, NULL);
454    XtVaSetValues(this->BaseWidget(), XmNrightAttachment, XmATTACH_FORM,
455                  XmNrightOffset, offset, NULL);
456 }
457
458 void MotifUI::AttachTop(BaseUI *obj, int offset, boolean opposite)
459 {
460    XtVaSetValues(this->BaseWidget(), XmNtopAttachment, XmATTACH_NONE, NULL);
461    if (obj)
462     {
463       Widget w = ((MotifUI *)obj)->BaseWidget();
464       int attachment;
465       if (opposite)
466          attachment = XmATTACH_OPPOSITE_WIDGET;
467       else
468          attachment = XmATTACH_WIDGET;
469
470       XtVaSetValues(this->BaseWidget(), XmNtopAttachment, attachment,
471                     XmNtopWidget, w, XmNtopOffset, offset, NULL);
472     }
473 }
474
475 void MotifUI::AttachBottom(BaseUI *obj, int offset, boolean opposite)
476 {
477    XtVaSetValues(this->BaseWidget(), XmNbottomAttachment, XmATTACH_NONE, NULL);
478    if (obj)
479     {
480       Widget w = ((MotifUI *)obj)->BaseWidget();
481       int attachment;
482       if (opposite)
483          attachment = XmATTACH_OPPOSITE_WIDGET;
484       else
485          attachment = XmATTACH_WIDGET;
486
487       XtVaSetValues(this->BaseWidget(), XmNbottomAttachment, attachment,
488                     XmNbottomWidget, w, XmNbottomOffset, offset, NULL);
489     }
490 }
491
492 void MotifUI::AttachLeft(BaseUI *obj, int offset, boolean opposite)
493 {
494    XtVaSetValues(this->BaseWidget(), XmNleftAttachment, XmATTACH_NONE, NULL);
495    if (obj)
496     {
497       int attachment;
498       if (opposite)
499          attachment = XmATTACH_OPPOSITE_WIDGET;
500       else
501          attachment = XmATTACH_WIDGET;
502       Widget w = ((MotifUI *)obj)->BaseWidget();
503       XtVaSetValues(this->BaseWidget(), XmNleftAttachment, attachment,
504                     XmNleftWidget, w, XmNleftOffset, offset, NULL);
505     }
506 }
507
508 void MotifUI::AttachRight(BaseUI *obj, int offset, boolean opposite)
509 {
510    XtVaSetValues(this->BaseWidget(), XmNrightAttachment, XmATTACH_NONE, NULL);
511    if (obj)
512     {
513       Widget w = ((MotifUI *)obj)->BaseWidget();
514       int attachment;
515       if (opposite)
516          attachment = XmATTACH_OPPOSITE_WIDGET;
517       else
518          attachment = XmATTACH_WIDGET;
519
520       XtVaSetValues(this->BaseWidget(), XmNrightAttachment, attachment,
521                     XmNrightWidget, w, XmNrightOffset, offset, NULL);
522     }
523 }
524
525 void MotifUI::StringWidthHeight(const char *string, int *width, int *height)
526 {
527    Dimension w, h;
528
529    XmString xm_string = StringCreate((char *)string);
530    XmStringExtent(userFont, xm_string, &w, &h);
531    *width = w;
532    *height = h;
533    StringFree(xm_string);
534 }
535
536 int MotifUI::StringWidth(const char *string)
537 {
538    int dummy;
539    int width;
540    StringWidthHeight(string, &width, &dummy);
541    return width;
542 }
543
544 int MotifUI::StringHeight(const char *string)
545 {
546    int dummy;
547    int height;
548    StringWidthHeight(string, &dummy, &height);
549    return height;
550 }
551
552 boolean MotifUI::SetOrder(int new_position)
553 {
554    if (XmIsRowColumn(((MotifUI *)Parent())->InnerWidget()))
555        XtVaSetValues(BaseWidget(), XmNpositionIndex, new_position, NULL);
556    return true;
557 }
558
559 void MotifUI::Dump(boolean verbose, 
560                    int level)
561 {
562    if (verbose)
563     {
564       BaseUI::Dump(true, level);
565
566       int i;
567       for (i = -2; i < level; i++) printf("   ");
568       printf("BaseWidget : %08lx\n", _w);
569     }
570    else
571       BaseUI::Dump(false, level);
572 }
573
574 // Time out stuff
575
576 typedef struct
577 {
578    TimeOutCallback fp;
579    BaseUI *obj;
580    void *callback_data;
581 } TimeOutCallbackData;
582
583 static void
584 ObjectTimeProc(XtPointer callback_data, XtIntervalId * /*id*/)
585 {
586    TimeOutCallbackData *data = (TimeOutCallbackData *) callback_data;
587    (*data->fp)(data->obj, data->callback_data);
588    delete data;
589    data = NULL;
590 }
591
592 void MotifUI::SetAddTimeOut(TimeOutCallback timeoutCB,
593                             void *callback_data,
594                             long interval)
595 {
596    if (!_w)
597       return;
598
599    TimeOutCallbackData * data = new TimeOutCallbackData;
600    data->fp = timeoutCB;
601    data->obj = this;
602    data->callback_data = callback_data;
603    XtAppAddTimeOut(appContext, (unsigned long) interval, ObjectTimeProc, data);
604 }
605
606 void MotifUI::FillBackground(Widget widget, Pixmap pixmap, Pixmap mask)
607 {
608    static Pixmap temp = 0L;
609    static GC gc = 0L;
610    static unsigned int old_width = 0, old_height = 0, old_depth = 0;
611    unsigned int width, height, junk, dep;
612    Window root;
613    XGCValues xgc;
614
615    XGetGeometry(display, pixmap, &root, (int *) &junk,
616                 (int *) &junk, &width, &height, &junk, &dep);
617    if (temp &&
618        (old_width < width || old_height < height || old_depth != dep))
619     {
620       // Free resources
621       XFreeGC(display, gc);
622       XFreePixmap(display, temp);
623       temp = 0L;
624       gc = 0L;
625     }
626
627    old_width = width;
628    old_height = height;
629    old_depth = dep;
630    if (dep == 1 && UIClass() == MAIN_WINDOW)
631       XtVaGetValues(widget, XmNforeground, &xgc.foreground, NULL);
632    else
633       XtVaGetValues(widget, XmNbackground, &xgc.foreground, NULL);
634    if (!temp)
635     {
636       temp = XCreatePixmap(display, RootWindowOfScreen(XtScreen(widget)),
637                            width, height, dep);
638       xgc.function = GXcopy;
639       gc = XCreateGC(display, pixmap, GCForeground|GCFunction, &xgc);
640     }
641    else
642       XSetForeground(display, gc, xgc.foreground);
643
644    XFillRectangle(display, temp, gc, 0, 0, width, height);
645    if (mask != XmUNSPECIFIED_PIXMAP)
646       XSetClipMask(display, gc, mask);
647    else
648       XSetClipMask(display, gc, None);
649    XCopyArea(display, pixmap, temp, gc, 0, 0, width, height, 0, 0);
650    XSetClipMask(display, gc, None);
651    XCopyArea(display, temp, pixmap, gc, 0, 0, width, height, 0, 0);
652 }
653
654 // Pixmap caching utility
655 void MotifUI::GetPixmaps(Widget w,
656                          char *name,
657                          Pixmap *pixmap,
658                          Pixmap *mask)
659 {
660    // Try to find pixmap in cache
661    PixmapLookupList pixmaps = pixmap_table;
662    int i;
663    for (i = 0; i < n_pixmaps; i++, pixmaps++)
664       if (!strcmp((**pixmaps).name, name))
665        {
666          *pixmap = (**pixmaps).pixmap;
667          if (mask)
668             *mask = (**pixmaps).mask;
669          return;
670        }
671
672    Pixmap _mask;
673    char *s;
674    SubstitutionRec subs[1];
675    char *bmPath;
676    char *PIXMAP_DIR = "/usr/dt/appconfig/icons/%L/%B:"
677                       "/usr/dt/appconfig/icons/C/%B:"
678                       "/usr/include/X11/bitmaps/%B";
679
680    if (*name == '/')
681      s = name;
682    else
683     {
684 #ifdef NO_CDE
685       if ((s = getenv("XBMLANGPATH")) && *s)
686 #else
687       if ((s = getenv("XMICONSEARCHPATH")) && *s)
688 #endif
689        {
690          bmPath = new char [strlen(s) + strlen(PIXMAP_DIR) + 2];
691          sprintf(bmPath, "%s:%s", PIXMAP_DIR, s);
692        }
693       else
694          bmPath = PIXMAP_DIR;
695       subs[0].match = 'B';
696       subs[0].substitution = name;
697       s = XtFindFile(bmPath, subs, XtNumber(subs), NULL);
698       if (bmPath != PIXMAP_DIR)
699          delete [] bmPath;
700     }
701
702    struct stat statbuf;
703    if (!s || stat(s, &statbuf) < 0)
704     {
705       *pixmap = XmUNSPECIFIED_PIXMAP;
706       if (mask)
707          *mask = XmUNSPECIFIED_PIXMAP;
708       return;
709     }
710
711    int len = strlen(s);
712    if (!strcmp(s + len - 3, ".pm"))
713     {
714       XpmAttributes attributes;
715       memset((char *)&attributes, 0, sizeof(XpmAttributes));
716 #ifdef NO_CDE
717       XpmReadFileToPixmap(display, root, s, pixmap, &_mask, &attributes);
718 #else
719       _DtXpmReadFileToPixmap(display, root, s, pixmap, &_mask, &attributes);
720 #endif
721
722       if (_mask)
723          FillBackground(w, *pixmap, _mask);
724 #ifdef NO_CDE
725       XpmFreeAttributes(&attributes);
726 #else
727       _DtXpmFreeAttributes(&attributes);
728 #endif
729     }
730    else
731     {
732       if (UIClass() == MAIN_WINDOW)
733          *pixmap = XmGetPixmapByDepth(XtScreen(w), s, white, black, depth);
734       else
735          *pixmap = XmGetPixmapByDepth(XtScreen(w), s, black, white, depth);
736       char *s1 = new char [len + 3];
737       strcpy(s1, s);
738       strcpy(s1 + len - 3, "_m.bm");
739       if (stat(s1, &statbuf) < 0)
740          _mask = XmUNSPECIFIED_PIXMAP;
741       else
742        {
743          _mask = XmGetPixmapByDepth(XtScreen(w), s1, white, black, 1);
744          FillBackground(w, *pixmap, _mask);
745        }
746       delete [] s1;
747     }
748    if (mask)
749       *mask = _mask;
750    if (s != name)
751       XtFree(s);
752
753    // Add pixmap to table
754    if (!(n_pixmaps % 8))
755     {
756       pixmaps = new PixmapLookup [n_pixmaps + 8];
757       for (i = 0; i < n_pixmaps; i++)
758          pixmaps[i] = pixmap_table[i];
759       for (i = n_pixmaps; i < n_pixmaps + 8; i++)
760          pixmaps[i] = new PixmapLookupStruct;
761       delete []pixmap_table;
762       pixmap_table = pixmaps;
763     }
764    pixmap_table[n_pixmaps]->name = strdup(name);
765    pixmap_table[n_pixmaps]->pixmap = *pixmap;
766    pixmap_table[n_pixmaps]->mask = _mask;
767    n_pixmaps++;
768 }
769
770 // Cursor Shape support
771
772 #define time32_width 32
773 #define time32_height 32
774 #define time32_x_hot 15
775 #define time32_y_hot 15
776 static unsigned char time32_bits[] = {
777    0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
778    0x8c, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
779    0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x32,
780    0x8c, 0x00, 0x00, 0x31, 0x0c, 0x7f, 0xfe, 0x30, 0x0c, 0xfe, 0x7f, 0x30,
781    0x0c, 0xfc, 0x3f, 0x30, 0x0c, 0xf8, 0x1f, 0x30, 0x0c, 0xe0, 0x07, 0x30,
782    0x0c, 0x80, 0x01, 0x30, 0x0c, 0x80, 0x01, 0x30, 0x0c, 0x60, 0x06, 0x30,
783    0x0c, 0x18, 0x18, 0x30, 0x0c, 0x04, 0x20, 0x30, 0x0c, 0x02, 0x40, 0x30,
784    0x0c, 0x01, 0x80, 0x30, 0x8c, 0x00, 0x00, 0x31, 0x4c, 0x80, 0x01, 0x32,
785    0x4c, 0xc0, 0x03, 0x32, 0x4c, 0xf0, 0x1f, 0x32, 0x4c, 0xff, 0xff, 0x32,
786    0xcc, 0xff, 0xff, 0x33, 0x8c, 0xff, 0xff, 0x31, 0xfe, 0xff, 0xff, 0x7f,
787    0xfe, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00};
788
789 #define time32m_width 32
790 #define time32m_height 32
791 static unsigned char time32m_bits[] = {
792    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
793    0xcf, 0x00, 0x00, 0xf3, 0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76,
794    0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76, 0x6e, 0x00, 0x00, 0x76,
795    0xce, 0x00, 0x00, 0x73, 0x8e, 0x7f, 0xfe, 0x71, 0x0e, 0xff, 0xff, 0x70,
796    0x0e, 0xfe, 0x7f, 0x70, 0x0e, 0xfc, 0x3f, 0x70, 0x0e, 0xf8, 0x1f, 0x70,
797    0x0e, 0xe0, 0x07, 0x70, 0x0e, 0xe0, 0x07, 0x70, 0x0e, 0x78, 0x1e, 0x70,
798    0x0e, 0x1c, 0x38, 0x70, 0x0e, 0x06, 0x60, 0x70, 0x0e, 0x03, 0xc0, 0x70,
799    0x8e, 0x01, 0x80, 0x71, 0xce, 0x00, 0x00, 0x73, 0x6e, 0x80, 0x01, 0x76,
800    0x6e, 0xc0, 0x03, 0x76, 0x6e, 0xf0, 0x1f, 0x76, 0x6e, 0xff, 0xff, 0x76,
801    0xee, 0xff, 0xff, 0x77, 0xcf, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff,
802    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
803
804 #define time16_x_hot 7
805 #define time16_y_hot 7
806 #define time16_width 16
807 #define time16_height 16
808 static unsigned char time16_bits[] = {
809    0x00, 0x00, 0xfe, 0x7f, 0x14, 0x28, 0x14, 0x28, 0x14, 0x28, 0x24, 0x24,
810    0x44, 0x22, 0x84, 0x21, 0x84, 0x21, 0x44, 0x22, 0x24, 0x24, 0x14, 0x28,
811    0x94, 0x29, 0xd4, 0x2b, 0xfe, 0x7f, 0x00, 0x00};
812
813 #define time16m_width 16
814 #define time16m_height 16
815 static unsigned char time16m_bits[] = {
816    0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
817    0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
818    0xfe, 0x7f, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff};
819
820 Cursor MotifUI::InitHourGlassCursor()
821 {
822     unsigned int width;
823     unsigned int height;
824     unsigned int xHotspot;
825     unsigned int yHotspot;
826     Pixmap       pixmap;
827     Pixmap       maskPixmap;
828     XColor       xcolors[2];
829     char *       bits;
830     char *       maskBits;
831     Cursor       cursor = None;
832
833     if (XQueryBestCursor(display, root, 32, 32, &width, &height))
834       {
835         if ((width >= 32) && (height >= 32))
836           {
837             width = time32_width;
838             height = time32_height;
839             bits = (char *)time32_bits;
840             maskBits = (char *)time32m_bits;
841             xHotspot = time32_x_hot;
842             yHotspot = time32_y_hot;
843           }
844         else
845           {
846             width = time16_width;
847             height = time16_height;
848             bits = (char *)time16_bits;
849             maskBits = (char *)time16m_bits;
850             xHotspot = time16_x_hot;
851             yHotspot = time16_y_hot;
852           }
853
854         pixmap = XCreateBitmapFromData(display, root, bits, width, height);
855
856         maskPixmap = XCreateBitmapFromData(display, root, maskBits,
857                                            width, height);
858         xcolors[0].pixel = black;
859         xcolors[1].pixel = white;
860
861         XQueryColors(display, 
862             DefaultColormapOfScreen(DefaultScreenOfDisplay (display)),
863             xcolors, 2);
864         cursor = XCreatePixmapCursor(display, pixmap, maskPixmap,
865             &(xcolors[0]), &(xcolors[1]), xHotspot, yHotspot);
866         XFreePixmap(display, pixmap);
867         XFreePixmap(display, maskPixmap);
868       }
869     return cursor;
870 }
871
872 PointerCursor MotifUI::PointerShape()
873 {
874    return pointer_style;
875 }
876
877 void MotifUI::PointerShape(PointerCursor style)
878 {
879    static Cursor left = (Cursor) 0L;
880    static Cursor right = (Cursor) 0L;
881    static Cursor watch = (Cursor) 0L;
882    static Cursor hour_glass = (Cursor) 0L;
883    static Cursor ibeam = (Cursor) 0L;
884    static Cursor cross_hair = (Cursor) 0L;
885
886    if (!_w)
887       return;
888
889    Cursor cursor;
890    switch (pointer_style = style)
891    {
892    case LEFT_SLANTED_ARROW_CURSOR: 
893       if (!left)
894          left = XCreateFontCursor(display, XC_left_ptr);
895       cursor = left;
896       break;
897    case RIGHT_SLANTED_ARROW_CURSOR:
898       if (!right)
899          right = XCreateFontCursor(display, XC_right_ptr);
900       cursor = right;
901       break;
902    case WATCH_CURSOR:
903       if (!watch)
904          watch = XCreateFontCursor(display, XC_watch);
905       cursor = watch;
906       break;
907    case HOUR_GLASS_CURSOR:
908       if (!hour_glass)
909          hour_glass = InitHourGlassCursor();
910       cursor = hour_glass;
911       break;
912    case IBEAM_CURSOR:
913       if (!ibeam)
914          ibeam = XCreateFontCursor(display, XC_xterm);
915       cursor = ibeam;
916       break;
917    case CROSS_HAIRS_CURSOR:
918       if (!cross_hair)
919          cross_hair = XCreateFontCursor(display, XC_crosshair);
920       cursor = cross_hair;
921       break;
922    default: cursor = None; break;
923    }
924
925    if (XtIsRealized(_w))
926       XDefineCursor(display, XtWindow(_w), cursor);
927 }
928
929 static int G_width;
930
931 static void VerbosePass1(Widget w, int level)
932 {
933    int i;
934    if (level == 0)
935       G_width = 0;
936    int new_width = (level * 3) + strlen(XrmQuarkToString(w->core.xrm_name)) +
937                    strlen(w->core.widget_class->core_class.class_name) + 3;
938    if (new_width > G_width)
939       G_width = new_width;
940    if (XtIsWidget(w))
941       for (i = 0; i < w->core.num_popups; i++)
942          VerbosePass1(w->core.popup_list[i], level + 1);
943    if (XtIsComposite(w))
944     {
945       CompositeWidget cw = (CompositeWidget) w;
946       for (i = 0; i < cw->composite.num_children; i++)
947          VerbosePass1(cw->composite.children[i], level + 1);
948     }
949 }
950
951 void MotifUI::DumpWidget(Widget w, boolean verbose, int level)
952 {
953    int i;
954
955    for (i = 0; i < level; i++)
956       printf("   ");
957    printf("%s : %s", XrmQuarkToString(w->core.xrm_name),
958           w->core.widget_class->core_class.class_name);
959    if (verbose)
960     {
961       int n = (level * 3) + strlen(XrmQuarkToString(w->core.xrm_name)) +
962               strlen(w->core.widget_class->core_class.class_name) + 3;
963       for ( ; n < G_width; n++)
964          printf(" ");
965       if (XtIsManaged(w))
966          printf(" Managed  ");
967       else
968          printf(" Unmanaged");
969       if (XtIsSensitive(w))
970          printf(" Sensitive  ");
971       else
972          printf(" Insensitive");
973       if (XtIsRealized(w))
974          printf(" Realized  ");
975       else
976          printf(" Unrealized");
977       if (w->core.visible)
978          printf("  Visible\n");
979       else
980          printf("  Invisible\n");
981     }
982    else
983       printf("\n");
984 }
985
986 void MotifUI::DumpWidgets(Widget w, boolean verbose, int level)
987 {
988    DumpWidget(w, verbose, level);
989
990    int i;
991    if (XtIsWidget(w))
992     {
993       for (i = 0; i < w->core.num_popups; i++)
994          DumpWidgets(w->core.popup_list[i], verbose, level + 1);
995     }
996    if (XtIsComposite(w))
997     {
998       CompositeWidget cw = (CompositeWidget) w;
999       for (i = 0; i < cw->composite.num_children; i++)
1000          DumpWidgets(cw->composite.children[i], verbose, level + 1);
1001     }
1002 }
1003
1004 void MotifUI::DumpUIHierarchy(boolean verbose, int level)
1005 {
1006    if (verbose)
1007       VerbosePass1(_w, 0);
1008    DumpWidgets(_w, verbose, level);
1009 }