/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $TOG: MotifUI.C /main/8 1998/08/03 08:59:09 mgreess $ */ /* * * (c) Copyright 1993, 1994 Hewlett-Packard Company * * (c) Copyright 1993, 1994 International Business Machines Corp. * * (c) Copyright 1993, 1994 Sun Microsystems, Inc. * * (c) Copyright 1993, 1994 Novell, Inc. * */ #include "MotifUI.h" #include "Menu.h" #include "Dialog.h" #include "Icon.h" #include #include #include #include #include #ifdef NO_CDE #include "xpm.h" #include #else #include
#include
#endif #include
#include #include #include #include PixmapLookupList MotifUI::pixmap_table = NULL; XtAppContext MotifUI::appContext = NULL; XmFontList MotifUI::userFont = NULL; Display * MotifUI::display = NULL; Widget MotifUI::topLevel; Window MotifUI::root; Font MotifUI::font; Pixel MotifUI::black; Pixel MotifUI::white; int MotifUI::shadowThickness; int MotifUI::depth; int MotifUI::bMenuButton; int MotifUI::n_pixmaps = 0; PointerCursor MotifUI::pointer_style = LEFT_SLANTED_ARROW_CURSOR; MotifUI::MotifUI(MotifUI *parent, const char *name, const char *category, const char *widgetName) : BaseUI(parent, name, category) { _w = NULL; if (widgetName) _widgetName = STRDUP(widgetName); else _widgetName = STRDUP(name); } MotifUI::~MotifUI() { if (_w) XtRemoveCallback(_w, XmNdestroyCallback, &MotifUI::WidgetDestroyCB, (XtPointer) this); delete _widgetName; } void MotifUI::ThreadCB(MotifThread *_thread, BaseUI *obj, ThreadCallback cb) { (*cb)(obj, _thread->output, _thread->status); delete _thread; } void MotifUI::Thread(const char *cmd, ThreadCallback cb, int buf_len) { new MotifThread(this, cmd, &(MotifUI::ThreadCB), cb, buf_len); } void MotifUI::Thread(int pid, int fd, ThreadCallback cb, int buf_len) { new MotifThread(this, pid, fd, &(MotifUI::ThreadCB), cb, buf_len); } void MotifUI::Thread(int socket, ThreadCallback cb, int buf_len) { new MotifThread(this, socket, &(MotifUI::ThreadCB), cb, buf_len); } void MotifUI::SetFocus() { DoSetFocus(_w); } void MotifUI::DoSetFocus(Widget w) { XmProcessTraversal(w, XmTRAVERSE_CURRENT); } boolean MotifUI::DoIsVisible() { boolean rc = true; if (_w) { if (UIClass() == APPLICATION) { if (XtIsRealized(_w)) { XWindowAttributes attributes; XGetWindowAttributes(display, XtWindow(_w), &attributes); if (attributes.map_state == IsUnmapped) rc = false; } } else if (XmGetVisibility(_w) == XmVISIBILITY_FULLY_OBSCURED) rc = false; } return rc; } void MotifUI::DoMakeVisible() { Widget sw = XtParent(_w); if (sw && !XmIsScrolledWindow(sw)) sw = XtParent(sw); if (sw && !XmIsScrolledWindow(sw)) sw = XtParent(sw); if (sw && XmIsScrolledWindow(sw) && !XmIsMainWindow(sw)) XmScrollVisible(sw, _w, 0, 0); } void MotifUI::DoContextualHelp() { Widget context_widget, shell; #ifdef NO_CDE XEvent event; static Cursor cursor = (Cursor) NULL; if (cursor == (Cursor) NULL) cursor = XCreateFontCursor(display, XC_question_arrow); #endif BaseUI *window = this; while (window->UIClass() != MAIN_WINDOW) window = window->Parent(); shell = ((MotifUI *)window)->_w; #ifdef NO_CDE context_widget = XmTrackingEvent(shell, cursor, False, &event); if (event.type == KeyPress || event.type == KeyRelease) { int offset; KeySym keySym; // Look for ESC key press and stop if we get one if (event.xkey.state & ShiftMask) offset = 1; else offset = 0; keySym = XLookupKeysym((XKeyEvent *)&event, offset); if (keySym == XK_Escape) return; } if (context_widget != NULL) { #else int returnVal = DtHelpReturnSelectedWidgetId(shell, 0, &context_widget); if (returnVal == DtHELP_SELECT_VALID) { #endif XmAnyCallbackStruct cb; cb.reason = XmCR_HELP; #ifdef NO_CDE cb.event = &event; #endif while (context_widget != NULL) { // If there is no help at this widget, back track to find help if (XtHasCallbacks(context_widget, XmNhelpCallback) == XtCallbackHasSome) { XtCallCallbacks(context_widget, XmNhelpCallback, &cb); break; } else context_widget = XtParent(context_widget); } } } void MotifUI::WidgetHelpCB(Widget, XtPointer clientData, XtPointer) { MotifUI * obj = (MotifUI *) clientData; obj->HandleHelpRequest(); } void MotifUI::WidgetDestroyCB(Widget, XtPointer clientData, XtPointer) { MotifUI * obj = (MotifUI *) clientData; obj->WidgetDestroyed(); } void MotifUI::WidgetDestroyed() { _w = NULL; delete _widgetName; } void MotifUI::DoRefresh() { if (_w) XmUpdateDisplay(_w); } void MotifUI::DoToFront() { if (_w) { if (XtIsShell(XtParent(_w))) XRaiseWindow(display, XtWindow(XtParent(_w))); else XRaiseWindow(display, XtWindow(_w)); } } void MotifUI::InstallDestroyCB() { if (_w) XtAddCallback(_w, XmNdestroyCallback, &MotifUI::WidgetDestroyCB, (XtPointer) this); } void MotifUI::InstallHelpCB() { if (!_w) return; if (UIClass() == MENU && UISubClass() != POPUP_MENU) XtAddCallback(((Menu*)this)->GetCascade(), XmNhelpCallback, &MotifUI::WidgetHelpCB, (XtPointer) this); else XtAddCallback(_w, XmNhelpCallback, &MotifUI::WidgetHelpCB, (XtPointer) this); } boolean MotifUI::SetSelected(boolean flag) { if (!_w) return false; if (GuiIsIcon(_w)) XtVaSetValues(_w, GuiNselected, flag, NULL); else if (XmIsToggleButton(_w)) XmToggleButtonSetState(_w, flag, False); return true; } boolean MotifUI::SetName(char *name) { if (!InnerWidget()) return false; XmString xm_string = StringCreate(name); XtVaSetValues(InnerWidget(), XmNlabelString, xm_string, NULL); StringFree(xm_string); return true; } boolean MotifUI::SetActivity(boolean flag) { if (!_w) return false; if (GuiIsIcon(_w)) XtVaSetValues(_w, GuiNactive, flag, NULL); else XtSetSensitive(_w, flag); return true; } boolean MotifUI::SetVisiblity(boolean flag) { if (!_w) return false; if (flag) XtManageChild(_w); else XtUnmanageChild(_w); return true; } void MotifUI::GetResources(const XtResourceList resources, const int numResources) { if (_w && resources) XtGetSubresources(XtParent(_w), (XtPointer) this, _widgetName, className(), resources, numResources, NULL, 0); } void MotifUI::SetDefaultResources(const Widget, const String *resources) { XrmDatabase rdb = NULL; int i; rdb = XrmGetStringDatabase(""); i = 0; while (resources[i]) { char *buf = new char[1000]; sprintf(buf, "%s%s", _name, resources[i]); XrmPutLineResource(&rdb, buf); i++; delete [] buf; } if (rdb) { XrmMergeDatabases(XtDatabase(display), &rdb); XrmSetDatabase(display, rdb); } } void MotifUI::NotifyDelete(BaseUI *obj) { MotifUI *p = (MotifUI *) obj; if (p->_w) { XtRemoveCallback(_w, XmNdestroyCallback, &MotifUI::WidgetDestroyCB, (XtPointer) this); XtDestroyWidget(p->_w); p->_w = NULL; } } void MotifUI::Width(int width) { XtVaSetValues(this->BaseWidget(), XmNwidth, width, NULL); } int MotifUI::Width() { Dimension w; XtVaGetValues(this->BaseWidget(), XmNwidth, &w, NULL); return (int) w; } void MotifUI::Height(int height) { XtVaSetValues(this->BaseWidget(), XmNheight, height, NULL); } int MotifUI::Height() { Dimension h; XtVaGetValues(this->BaseWidget(), XmNheight, &h, NULL); return (int) h; } void MotifUI::WidthHeight(int width, int height) { XtVaSetValues(this->BaseWidget(), XmNwidth, width, XmNheight, height, NULL); } void MotifUI::WidthHeight(int *width, int *height) { Dimension w, h; XtVaGetValues(this->BaseWidget(), XmNwidth, &w, XmNheight, &h, NULL); *width = (int) w; *height = (int) h; } void MotifUI::AttachAll(int offset) { XtVaSetValues(this->BaseWidget(), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, NULL); XtVaSetValues(this->BaseWidget(), XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, offset, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, offset, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, offset, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, offset, NULL); } void MotifUI::AttachTop(int offset) { XtVaSetValues(this->BaseWidget(), XmNtopAttachment, XmATTACH_NONE, NULL); XtVaSetValues(this->BaseWidget(), XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, offset, NULL); } void MotifUI::AttachBottom(int offset) { XtVaSetValues(this->BaseWidget(), XmNbottomAttachment, XmATTACH_NONE, NULL); XtVaSetValues(this->BaseWidget(), XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, offset, NULL); } void MotifUI::AttachLeft(int offset) { XtVaSetValues(this->BaseWidget(), XmNleftAttachment, XmATTACH_NONE, NULL); XtVaSetValues(this->BaseWidget(), XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, offset, NULL); } void MotifUI::AttachRight(int offset) { XtVaSetValues(this->BaseWidget(), XmNrightAttachment, XmATTACH_NONE, NULL); XtVaSetValues(this->BaseWidget(), XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, offset, NULL); } void MotifUI::AttachTop(BaseUI *obj, int offset, boolean opposite) { XtVaSetValues(this->BaseWidget(), XmNtopAttachment, XmATTACH_NONE, NULL); if (obj) { Widget w = ((MotifUI *)obj)->BaseWidget(); int attachment; if (opposite) attachment = XmATTACH_OPPOSITE_WIDGET; else attachment = XmATTACH_WIDGET; XtVaSetValues(this->BaseWidget(), XmNtopAttachment, attachment, XmNtopWidget, w, XmNtopOffset, offset, NULL); } } void MotifUI::AttachBottom(BaseUI *obj, int offset, boolean opposite) { XtVaSetValues(this->BaseWidget(), XmNbottomAttachment, XmATTACH_NONE, NULL); if (obj) { Widget w = ((MotifUI *)obj)->BaseWidget(); int attachment; if (opposite) attachment = XmATTACH_OPPOSITE_WIDGET; else attachment = XmATTACH_WIDGET; XtVaSetValues(this->BaseWidget(), XmNbottomAttachment, attachment, XmNbottomWidget, w, XmNbottomOffset, offset, NULL); } } void MotifUI::AttachLeft(BaseUI *obj, int offset, boolean opposite) { XtVaSetValues(this->BaseWidget(), XmNleftAttachment, XmATTACH_NONE, NULL); if (obj) { int attachment; if (opposite) attachment = XmATTACH_OPPOSITE_WIDGET; else attachment = XmATTACH_WIDGET; Widget w = ((MotifUI *)obj)->BaseWidget(); XtVaSetValues(this->BaseWidget(), XmNleftAttachment, attachment, XmNleftWidget, w, XmNleftOffset, offset, NULL); } } void MotifUI::AttachRight(BaseUI *obj, int offset, boolean opposite) { XtVaSetValues(this->BaseWidget(), XmNrightAttachment, XmATTACH_NONE, NULL); if (obj) { Widget w = ((MotifUI *)obj)->BaseWidget(); int attachment; if (opposite) attachment = XmATTACH_OPPOSITE_WIDGET; else attachment = XmATTACH_WIDGET; XtVaSetValues(this->BaseWidget(), XmNrightAttachment, attachment, XmNrightWidget, w, XmNrightOffset, offset, NULL); } } void MotifUI::StringWidthHeight(const char *string, int *width, int *height) { Dimension w, h; XmString xm_string = StringCreate((char *)string); XmStringExtent(userFont, xm_string, &w, &h); *width = w; *height = h; StringFree(xm_string); } int MotifUI::StringWidth(const char *string) { int dummy; int width; StringWidthHeight(string, &width, &dummy); return width; } int MotifUI::StringHeight(const char *string) { int dummy; int height; StringWidthHeight(string, &dummy, &height); return height; } boolean MotifUI::SetOrder(int new_position) { if (XmIsRowColumn(((MotifUI *)Parent())->InnerWidget())) XtVaSetValues(BaseWidget(), XmNpositionIndex, new_position, NULL); return true; } void MotifUI::Dump(boolean verbose, int level) { if (verbose) { BaseUI::Dump(true, level); int i; for (i = -2; i < level; i++) printf(" "); printf("BaseWidget : %08lx\n", _w); } else BaseUI::Dump(false, level); } // Time out stuff typedef struct { TimeOutCallback fp; BaseUI *obj; void *callback_data; } TimeOutCallbackData; static void ObjectTimeProc(XtPointer callback_data, XtIntervalId * /*id*/) { TimeOutCallbackData *data = (TimeOutCallbackData *) callback_data; (*data->fp)(data->obj, data->callback_data); delete data; data = NULL; } void MotifUI::SetAddTimeOut(TimeOutCallback timeoutCB, void *callback_data, long interval) { if (!_w) return; TimeOutCallbackData * data = new TimeOutCallbackData; data->fp = timeoutCB; data->obj = this; data->callback_data = callback_data; XtAppAddTimeOut(appContext, (unsigned long) interval, ObjectTimeProc, data); } void MotifUI::FillBackground(Widget widget, Pixmap pixmap, Pixmap mask) { static Pixmap temp = 0L; static GC gc = 0L; static unsigned int old_width = 0, old_height = 0, old_depth = 0; unsigned int width, height, junk, dep; Window root; XGCValues xgc; XGetGeometry(display, pixmap, &root, (int *) &junk, (int *) &junk, &width, &height, &junk, &dep); if (temp && (old_width < width || old_height < height || old_depth != dep)) { // Free resources XFreeGC(display, gc); XFreePixmap(display, temp); temp = 0L; gc = 0L; } old_width = width; old_height = height; old_depth = dep; if (dep == 1 && UIClass() == MAIN_WINDOW) XtVaGetValues(widget, XmNforeground, &xgc.foreground, NULL); else XtVaGetValues(widget, XmNbackground, &xgc.foreground, NULL); if (!temp) { temp = XCreatePixmap(display, RootWindowOfScreen(XtScreen(widget)), width, height, dep); xgc.function = GXcopy; gc = XCreateGC(display, pixmap, GCForeground|GCFunction, &xgc); } else XSetForeground(display, gc, xgc.foreground); XFillRectangle(display, temp, gc, 0, 0, width, height); if (mask != XmUNSPECIFIED_PIXMAP) XSetClipMask(display, gc, mask); else XSetClipMask(display, gc, None); XCopyArea(display, pixmap, temp, gc, 0, 0, width, height, 0, 0); XSetClipMask(display, gc, None); XCopyArea(display, temp, pixmap, gc, 0, 0, width, height, 0, 0); } // Pixmap caching utility void MotifUI::GetPixmaps(Widget w, char *name, Pixmap *pixmap, Pixmap *mask) { // Try to find pixmap in cache PixmapLookupList pixmaps = pixmap_table; int i; for (i = 0; i < n_pixmaps; i++, pixmaps++) if (!strcmp((**pixmaps).name, name)) { *pixmap = (**pixmaps).pixmap; if (mask) *mask = (**pixmaps).mask; return; } Pixmap _mask; char *s; SubstitutionRec subs[1]; char *bmPath; char *PIXMAP_DIR = "/usr/dt/appconfig/icons/%L/%B:" "/usr/dt/appconfig/icons/C/%B:" "/usr/include/X11/bitmaps/%B"; if (*name == '/') s = name; else { #ifdef NO_CDE if ((s = getenv("XBMLANGPATH")) && *s) #else if ((s = getenv("XMICONSEARCHPATH")) && *s) #endif { bmPath = new char [strlen(s) + strlen(PIXMAP_DIR) + 2]; sprintf(bmPath, "%s:%s", PIXMAP_DIR, s); } else bmPath = PIXMAP_DIR; subs[0].match = 'B'; subs[0].substitution = name; s = XtFindFile(bmPath, subs, XtNumber(subs), NULL); if (bmPath != PIXMAP_DIR) delete [] bmPath; } struct stat statbuf; if (!s || stat(s, &statbuf) < 0) { *pixmap = XmUNSPECIFIED_PIXMAP; if (mask) *mask = XmUNSPECIFIED_PIXMAP; return; } int len = strlen(s); if (!strcmp(s + len - 3, ".pm")) { XpmAttributes attributes; memset((char *)&attributes, 0, sizeof(XpmAttributes)); #ifdef NO_CDE XpmReadFileToPixmap(display, root, s, pixmap, &_mask, &attributes); #else _DtXpmReadFileToPixmap(display, root, s, pixmap, &_mask, &attributes); #endif if (_mask) FillBackground(w, *pixmap, _mask); #ifdef NO_CDE XpmFreeAttributes(&attributes); #else _DtXpmFreeAttributes(&attributes); #endif } else { if (UIClass() == MAIN_WINDOW) *pixmap = XmGetPixmapByDepth(XtScreen(w), s, white, black, depth); else *pixmap = XmGetPixmapByDepth(XtScreen(w), s, black, white, depth); char *s1 = new char [len + 3]; strcpy(s1, s); strcpy(s1 + len - 3, "_m.bm"); if (stat(s1, &statbuf) < 0) _mask = XmUNSPECIFIED_PIXMAP; else { _mask = XmGetPixmapByDepth(XtScreen(w), s1, white, black, 1); FillBackground(w, *pixmap, _mask); } delete [] s1; } if (mask) *mask = _mask; if (s != name) XtFree(s); // Add pixmap to table if (!(n_pixmaps % 8)) { pixmaps = new PixmapLookup [n_pixmaps + 8]; for (i = 0; i < n_pixmaps; i++) pixmaps[i] = pixmap_table[i]; for (i = n_pixmaps; i < n_pixmaps + 8; i++) pixmaps[i] = new PixmapLookupStruct; delete []pixmap_table; pixmap_table = pixmaps; } pixmap_table[n_pixmaps]->name = strdup(name); pixmap_table[n_pixmaps]->pixmap = *pixmap; pixmap_table[n_pixmaps]->mask = _mask; n_pixmaps++; } PointerCursor MotifUI::PointerShape() { return pointer_style; } void MotifUI::PointerShape(PointerCursor style) { static Cursor left = (Cursor) 0L; static Cursor right = (Cursor) 0L; static Cursor watch = (Cursor) 0L; static Cursor hour_glass = (Cursor) 0L; static Cursor ibeam = (Cursor) 0L; static Cursor cross_hair = (Cursor) 0L; if (!_w) return; Cursor cursor; switch (pointer_style = style) { case LEFT_SLANTED_ARROW_CURSOR: if (!left) left = XCreateFontCursor(display, XC_left_ptr); cursor = left; break; case RIGHT_SLANTED_ARROW_CURSOR: if (!right) right = XCreateFontCursor(display, XC_right_ptr); cursor = right; break; case WATCH_CURSOR: if (!watch) watch = XCreateFontCursor(display, XC_watch); cursor = watch; break; case HOUR_GLASS_CURSOR: if (!hour_glass) hour_glass = _DtGetHourGlassCursor(display); cursor = hour_glass; break; case IBEAM_CURSOR: if (!ibeam) ibeam = XCreateFontCursor(display, XC_xterm); cursor = ibeam; break; case CROSS_HAIRS_CURSOR: if (!cross_hair) cross_hair = XCreateFontCursor(display, XC_crosshair); cursor = cross_hair; break; default: cursor = None; break; } if (XtIsRealized(_w)) XDefineCursor(display, XtWindow(_w), cursor); } static int G_width; static void VerbosePass1(Widget w, int level) { int i; if (level == 0) G_width = 0; int new_width = (level * 3) + strlen(XrmQuarkToString(w->core.xrm_name)) + strlen(w->core.widget_class->core_class.class_name) + 3; if (new_width > G_width) G_width = new_width; if (XtIsWidget(w)) for (i = 0; i < w->core.num_popups; i++) VerbosePass1(w->core.popup_list[i], level + 1); if (XtIsComposite(w)) { CompositeWidget cw = (CompositeWidget) w; for (i = 0; i < cw->composite.num_children; i++) VerbosePass1(cw->composite.children[i], level + 1); } } void MotifUI::DumpWidget(Widget w, boolean verbose, int level) { int i; for (i = 0; i < level; i++) printf(" "); printf("%s : %s", XrmQuarkToString(w->core.xrm_name), w->core.widget_class->core_class.class_name); if (verbose) { int n = (level * 3) + strlen(XrmQuarkToString(w->core.xrm_name)) + strlen(w->core.widget_class->core_class.class_name) + 3; for ( ; n < G_width; n++) printf(" "); if (XtIsManaged(w)) printf(" Managed "); else printf(" Unmanaged"); if (XtIsSensitive(w)) printf(" Sensitive "); else printf(" Insensitive"); if (XtIsRealized(w)) printf(" Realized "); else printf(" Unrealized"); if (w->core.visible) printf(" Visible\n"); else printf(" Invisible\n"); } else printf("\n"); } void MotifUI::DumpWidgets(Widget w, boolean verbose, int level) { DumpWidget(w, verbose, level); int i; if (XtIsWidget(w)) { for (i = 0; i < w->core.num_popups; i++) DumpWidgets(w->core.popup_list[i], verbose, level + 1); } if (XtIsComposite(w)) { CompositeWidget cw = (CompositeWidget) w; for (i = 0; i < cw->composite.num_children; i++) DumpWidgets(cw->composite.children[i], verbose, level + 1); } } void MotifUI::DumpUIHierarchy(boolean verbose, int level) { if (verbose) VerbosePass1(_w, 0); DumpWidgets(_w, verbose, level); }