/* * 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 librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * $XConsortium: lib_funcs.c /main/3 1995/11/06 18:07:31 rswiston $ * * @(#)lib_funcs.c 1.9 11 Apr 1994 cde_app_builder/src/abmf * * RESTRICTED CONFIDENTIAL INFORMATION: * * The information in this document is subject to special * restrictions in a confidential disclosure agreement between * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this * document outside HP, IBM, Sun, USL, SCO, or Univel without * Sun's specific written approval. This document and all copies * and derivative works thereof must be returned or destroyed at * Sun's request. * * Copyright 1993 Sun Microsystems, Inc. All rights reserved. * */ /* * lib_funcs.c * * This file contains the "library" functions that get put into * a generated application. This file is converted into strings * that are included in the abmf executable. This file is NOT * linked into abmf. * * The comment preceding each function is preserved in the final * version (in the generated code). */ /**************************************************************************** * * END TEST CODE * * This code exists so that this file may be compiled to test its * syntactic correctness. None of this gets pulled in into dtcodegen. */ #undef _POSIX_SOURCE /* tooltalk headers won't compile with this set */ #include #include #include #include #include #include #include #include #include #include #include #include #include
#include
#include
#include
#include
/* doesn't exist in CDE, but OK for testing */ /* * File: dtb_utils.h * CDE Application Builder General Utility Functions * * This file was generated from project dtbuilder by dtcodegen * * ** DO NOT MODIFY BY HAND - ALL MODIFICATIONS WILL BE LOST ** * */ #ifndef _DTB_UTILS_H_ #define _DTB_UTILS_H_ #include #include /* * Function type for client session save callback */ typedef Boolean (*DtbClientSessionSaveCB) ( Widget, char *, char ***, int * ); /* * Function type for Application-defined ToolTalk Message callbacks */ typedef Boolean (*DtbTTMsgHandlerCB) ( Tt_message msg, void *calldata ); /* * Function type for client session restore callback */ typedef Boolean (*DtbClientSessionRestoreCB) ( Widget, char * ); typedef struct { char *help_text; char *help_volume; char *help_locationID; } DtbObjectHelpDataRec, *DtbObjectHelpData; /* * Returns answer value for modal MessageBox */ typedef enum { DTB_ANSWER_NONE, DTB_ANSWER_ACTION1, DTB_ANSWER_ACTION2, DTB_ANSWER_ACTION3, DTB_ANSWER_CANCEL, DTB_ANSWER_HELP } DTB_MODAL_ANSWER; /* * Values for MessageBox default button */ typedef enum { DTB_ACTION1_BUTTON, DTB_ACTION2_BUTTON, DTB_ACTION3_BUTTON, DTB_CANCEL_BUTTON, DTB_NONE } DTB_BUTTON; /* * Types/ways of centering an object */ typedef enum { DTB_CENTER_NONE, DTB_CENTER_POSITION_VERT, DTB_CENTER_POSITION_HORIZ, DTB_CENTER_POSITION_BOTH } DTB_CENTERING_TYPES; /* * Structure to store values for Messages */ typedef struct { unsigned char type; String title; String message; String action1_label; XtCallbackProc action1_callback; String action2_label; XtCallbackProc action2_callback; String action3_label; XtCallbackProc action3_callback; Boolean cancel_button; XtCallbackProc cancel_callback; Boolean help_button; DTB_BUTTON default_button; } DtbMessageDataRec, *DtbMessageData; /* * Application Builder utility functions */ int dtb_cvt_file_to_pixmap( String fileName, Widget widget, Pixmap *pixmapReturnPtr ); int dtb_set_label_pixmaps( Widget widget, Pixmap labelPixmap, Pixmap labelInsensitivePixmap ); int dtb_set_label_from_bitmap_data( Widget widget, int width, int height, unsigned char *bitmapData ); Boolean dtb_file_has_extension( String fileName, String extension ); int dtb_cvt_filebase_to_pixmap( Widget widget, String fileBase, String extension, Pixmap *pixmap_ptr ); int dtb_cvt_image_file_to_pixmap( Widget widget, String fileName, Pixmap *pixmap ); int dtb_set_label_from_image_file( Widget widget, String fileName ); unsigned long dtb_cvt_resource_from_string( Widget parent, String res_type, unsigned int size_of_type, String res_str_value, unsigned long error_value ); Pixmap dtb_create_greyed_pixmap( Widget widget, Pixmap pixmap ); void dtb_save_toplevel_widget( Widget toplevel ); Widget dtb_get_toplevel_widget(); void dtb_remove_sash_focus( Widget panedwindow ); void dtb_save_command( char *command ); char * dtb_get_command(); void dtb_help_dispatch( Widget widget, XtPointer clientData, XtPointer callData ); void dtb_help_back_hdlr( Widget widget, XtPointer clientData, XtPointer callData ); void dtb_more_help_dispatch( Widget widget, XtPointer clientData, XtPointer callData ); void dtb_do_onitem_help(); void dtb_show_help_volume_info( char *volume_name, char *location_id ); Widget dtb_create_message_dlg( Widget parent, DtbMessageData mbr, String override_msg ); static void destroyCB( Widget widget, XtPointer client_data, XtPointer call_data ); Widget dtb_MessageBoxGetActionButton( Widget msg_dlg, DTB_BUTTON which_btn ); void dtb_show_message( Widget parent, DtbMessageData mbr, String override_msg, DtbObjectHelpData override_help ); DTB_MODAL_ANSWER dtb_show_modal_message( Widget parent, DtbMessageData mbr, String override_msg, DtbObjectHelpData override_help, Widget *modal_dlg_pane_out_ptr ); static void modal_dlgCB( Widget widget, XtPointer client_data, XtPointer call_data ); void dtb_children_center( Widget form, DTB_CENTERING_TYPES type ); void dtb_children_uncenter( Widget form, DTB_CENTERING_TYPES type ); void dtb_center( Widget form_child, DTB_CENTERING_TYPES type ); void dtb_uncenter( Widget form_child, DTB_CENTERING_TYPES type ); void dtb_session_save( Widget widget, XtPointer clientData, XtPointer callData ); DtbClientSessionSaveCB dtb_get_client_session_saveCB(); void dtb_set_client_session_saveCB( DtbClientSessionSaveCB session_saveCB ); void dtb_session_restore( Widget widget, char *session_file ); void dtb_set_client_session_restoreCB( DtbClientSessionRestoreCB session_restoreCB ); DtbClientSessionRestoreCB dtb_get_client_session_restoreCB(); void dtb_set_tt_msg_quitCB( DtbTTMsgHandlerCB msg_quitCB ); void dtb_set_tt_msg_do_commandCB( DtbTTMsgHandlerCB msg_do_commandCB ); void dtb_set_tt_msg_get_statusCB( DtbTTMsgHandlerCB msg_get_statusCB ); void dtb_set_tt_msg_pause_resumeCB( DtbTTMsgHandlerCB msg_pause_resumeCB ); Tt_message dtb_tt_contractCB( Tt_message msg, void *client_data, Tt_message contract ); void dtb_tt_close(); #define dtb_cvt_string_to_pixel(parent, str) \ ((Pixel)dtb_cvt_resource_from_string( \ (parent), XtRPixel, sizeof(Pixel), (str), 0)) #endif /* _DTB_UTILS_H_ */ #ifndef min #define min(a,b) ((a) < (b)? (a):(b)) #endif /* * Static functions used for dynamic centering of objects */ static void center_widget( Widget form_child, DTB_CENTERING_TYPES type ); static void uncenter_widget( Widget form_child, DTB_CENTERING_TYPES type ); static void centering_handler( Widget widget, XtPointer client_data, XEvent *event, Boolean *cont_dispatch ); /* * Private functions for determining the directory the executable was * loaded from. */ static char *dtb_get_exe_dir(void); static int determine_exe_dir( char *argv0, char *buf, int bufSize ); static int determine_exe_dir_from_argv( char *argv0, char *buf, int bufSize ); static int determine_exe_dir_from_path( char *argv0, char *buf, int bufSize ); static Boolean path_is_executable( char *path, uid_t euid, gid_t egid ); static void get_widest_label( WidgetList list, int count, Widget *child_widget, Dimension *label_width ); static Position get_offset_from_ancestor( Widget ancestor, Widget w ); static void get_widest_value( WidgetList list, int count, Widget *child_widget, Dimension *value_width ); static void get_widget_rect( Widget widget, XRectangle *rect ); static void get_greatest_size( Widget *list, int count, int *width, int *height, Widget *tallest, Widget *widest ); static void get_group_cell_size( Widget parent, DtbGroupInfo *group_info, int *cell_width, int *cell_height ); static void get_group_row_col( Widget parent, DtbGroupInfo *group_info, int *rows, int *cols ); /* * Variable for storing client session save callback */ static DtbClientSessionSaveCB dtb_client_session_saveCB = NULL; /* * Variable for storing client session restore callback */ static DtbClientSessionRestoreCB dtb_client_session_restoreCB = NULL; /* * Variable for storing top level widget */ static Widget dtb_project_toplevel_widget = (Widget)NULL; /* * Variable for storing command used to invoke application */ static char *dtb_save_command_str = (char *)NULL; /* * Directory binary for this process was loaded from. */ static char *dtb_exe_dir = (char *)NULL; /* * END TEST CODE * ****************************************************************************/ /**************************************************************************** **************************************************************************** ***** ***** ***** LIBRARY FUNCTIONS BEGIN ***** ***** ***** **************************************************************************** ****************************************************************************/ /* * Create/load a Pixmap given an XPM or Bitmap files * NOTE: this allocates a server Pixmap; it is the responsibility * of the caller to free the Pixmap */ int dtb_cvt_file_to_pixmap( String fileName, Widget widget, Pixmap *pixmapReturnPtr ) { #define pixmapReturn (*pixmapReturnPtr) Pixmap pixmap = NULL; Screen *screen = NULL; Pixel fgPixel = 0; Pixel bgPixel = 0; char image_path[MAXPATHLEN+1]; Boolean pixmap_found = False; /* * Get default values */ screen = XtScreenOfObject(widget); fgPixel = WhitePixelOfScreen(screen); bgPixel = BlackPixelOfScreen(screen); /* * Get proper colors for widget */ XtVaGetValues(widget, XmNforeground, &fgPixel, XmNbackground, &bgPixel, NULL); /* * In CDE, XmGetPixmap handles .xpm files, as well. */ if (!pixmap_found) { pixmap = XmGetPixmap(screen, fileName, fgPixel, bgPixel); } pixmap_found = ((pixmap != NULL) && (pixmap != XmUNSPECIFIED_PIXMAP)); if (!pixmap_found) { sprintf(image_path, "%s/%s", dtb_get_exe_dir(), fileName); pixmap = XmGetPixmap(screen, image_path, fgPixel, bgPixel); } pixmap_found = ((pixmap != NULL) && (pixmap != XmUNSPECIFIED_PIXMAP)); if (!pixmap_found) { sprintf(image_path, "%s/bitmaps/%s", dtb_get_exe_dir(), fileName); pixmap = XmGetPixmap(screen, image_path, fgPixel, bgPixel); } pixmap_found = ((pixmap != NULL) && (pixmap != XmUNSPECIFIED_PIXMAP)); if (!pixmap_found) { return -1; } pixmapReturn = pixmap; pixmapReturn = pixmap; return 0; #undef pixmapReturn } /* * For a given pixmap, create a 50% greyed version. Most likely this will * be used where the source pixmap is the labelPixmap for a widget and an * insensitivePixmap is needed so the widget will look right when it is * "not sensitive" ("greyed out" or "inactive"). * * NOTE: This routine creates a Pixmap, which is an X server resource. The * created pixmap must be freed by the caller when it is no longer * needed. */ Pixmap dtb_create_greyed_pixmap( Widget widget, Pixmap pixmap ) { Display *dpy; Window root; Pixmap insensitive_pixmap; Pixel background; unsigned int width, height, depth, bw; int x,y; XGCValues gcv; XtGCMask gcm; GC gc; dpy = XtDisplayOfObject(widget); if(pixmap == XmUNSPECIFIED_PIXMAP || pixmap == (Pixmap)NULL) { return((Pixmap)NULL); } XtVaGetValues(widget, XmNbackground, &background, NULL); /* Get width/height of source pixmap */ if (!XGetGeometry(dpy,pixmap,&root,&x,&y,&width,&height,&bw,&depth)) { return((Pixmap)NULL); } gcv.foreground = background; gcv.fill_style = FillStippled; gcv.stipple = XmGetPixmapByDepth(XtScreenOfObject(widget), "50_foreground", 1, 0, 1); gcm = GCForeground | GCFillStyle | GCStipple; gc = XtGetGC(widget, gcm, &gcv); /* Create insensitive pixmap */ insensitive_pixmap = XCreatePixmap(dpy, pixmap, width, height, depth); XCopyArea(dpy, pixmap, insensitive_pixmap, gc, 0, 0, width, height, 0, 0); XFillRectangle(dpy, insensitive_pixmap, gc, 0, 0, width, height); XtReleaseGC(widget, gc); return(insensitive_pixmap); } /* * Sets the label and insensitive label pixmaps of the widget. * * If either (or both) pixmap is NULL, it is ignored. */ int dtb_set_label_pixmaps( Widget widget, Pixmap labelPixmap, Pixmap labelInsensitivePixmap ) { if ( (widget == NULL) || ((labelPixmap == NULL) && (labelInsensitivePixmap == NULL)) ) { return -1; } /* * Set the approriate resources. */ XtVaSetValues(widget, XmNlabelType, XmPIXMAP, NULL); if (labelPixmap != NULL) { XtVaSetValues(widget, XmNlabelPixmap, labelPixmap, NULL); } if (labelInsensitivePixmap != NULL) { XtVaSetValues(widget, XmNlabelInsensitivePixmap, labelInsensitivePixmap, NULL); } return 0; } /* * Returns True if the fileName has the extension */ Boolean dtb_file_has_extension( String fileName, String extension ) { Boolean hasExt = False; if (extension == NULL) { hasExt = ( (fileName == NULL) || (strlen(fileName) == 0) ); } else { if (fileName == NULL) hasExt = False; else { char *dotPtr= strrchr(fileName, '.'); if (dotPtr == NULL) hasExt= False; else if (strcmp(dotPtr+1, extension) == 0) hasExt = True; } } return hasExt; } /* * Appends the extension to fileBase and attempts to load in * the Pixmap */ int dtb_cvt_filebase_to_pixmap( Widget widget, String fileBase, String extension, Pixmap *pixmap_ptr ) { char fileName[512]; int rc = 0; strcpy(fileName, fileBase); strcat(fileName, extension); rc = dtb_cvt_file_to_pixmap(fileName, widget, pixmap_ptr); return rc; } int dtb_cvt_image_file_to_pixmap( Widget widget, String fileName, Pixmap *pixmap ) { int rc = 0; /* return code */ Pixmap tmpPixmap = NULL; int depth; if (dtb_file_has_extension(fileName, "pm") || dtb_file_has_extension(fileName, "xpm") || dtb_file_has_extension(fileName, "bm") || dtb_file_has_extension(fileName, "xbm")) { /* If explicit filename requested, use it directly */ rc = dtb_cvt_file_to_pixmap(fileName, widget, &tmpPixmap); } else /* Append extensions to locate best graphic match */ { XtVaGetValues(XtIsSubclass(widget, xmGadgetClass)? XtParent(widget) : widget, XmNdepth, &depth, NULL); if (depth > 1) /* Look for Color Graphics First */ { rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".pm", &tmpPixmap); if (rc < 0) rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".xpm", &tmpPixmap); if (rc < 0) rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".bm", &tmpPixmap); if (rc < 0) rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".xbm", &tmpPixmap); } else /* Look for Monochrome First */ { rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".bm", &tmpPixmap); if (rc < 0) rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".xbm", &tmpPixmap); if (rc < 0) rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".pm", &tmpPixmap); if (rc < 0) rc = dtb_cvt_filebase_to_pixmap(widget, fileName, ".xpm", &tmpPixmap); } } if (rc < 0) { *pixmap = NULL; return rc; } *pixmap = tmpPixmap; return 0; } /* * Sets the XmNlabel from the image file (either xbitmap or xpixmap format). * * returns negative on error. */ int dtb_set_label_from_image_file( Widget widget, String fileName ) { int rc = 0; /* return code */ Pixmap labelPixmap = NULL; Pixmap insensitivePixmap = NULL; int depth; rc = dtb_cvt_image_file_to_pixmap(widget, fileName, &labelPixmap); if (rc < 0) { return rc; } insensitivePixmap = dtb_create_greyed_pixmap(widget,labelPixmap); rc = dtb_set_label_pixmaps(widget, labelPixmap, insensitivePixmap); if (rc < 0) { return rc; } return 0; } /* * Sets both the sensitive and insensitve pixmaps */ int dtb_set_label_from_bitmap_data( Widget widget, int width, int height, unsigned char *bitmapData ) { Display *display = NULL; Screen *screen = NULL; Drawable window = NULL; long bgPixel = 0; long fgPixel = 0; unsigned int depth = 0; Pixmap labelPixmap = NULL; if ( (widget == NULL) || (width < 1) || (height < 1) || (bitmapData == NULL) ) { return -1; } /* * Get a whole slew of information X needs */ { Pixel widgetBg = 0; Pixel widgetFg = 0; int widgetDepth = 0; display = XtDisplay(widget); screen = XtScreen(widget); window = XtWindow(widget); if (window == NULL) { /* Widget has not been realized, yet */ window = RootWindowOfScreen(screen); } XtVaGetValues(XtIsSubclass(widget, xmGadgetClass)? XtParent(widget) : widget, XmNbackground, &widgetBg, XmNforeground, &widgetFg, XmNdepth, &widgetDepth, NULL); bgPixel = widgetBg; fgPixel = widgetFg; depth = widgetDepth; } /* * Create the pixmap */ labelPixmap = XCreatePixmapFromBitmapData( display, window, (char *) bitmapData, width, height, fgPixel, bgPixel, depth); if (labelPixmap == NULL) { return -1; } dtb_set_label_pixmaps(widget, labelPixmap, NULL); return 0; } /* * Sets both the sensitive and insensitve pixmaps */ int dtb_set_label_from_xpm_data( Widget widget, char *xpmData[] ) { int status = 0; Display *display = NULL; Screen *screen = NULL; Drawable window = NULL; Pixmap labelPixmap = NULL; if ( (widget == NULL) || (xpmData == NULL) ) { return -1; } display = XtDisplay(widget); screen = XtScreen(widget); window = XtWindow(widget); if (window == NULL) { /* Widget has not been realized, yet */ window = RootWindowOfScreen(screen); } status = _DtXpmCreatePixmapFromData( display, window, xpmData, &labelPixmap, (Pixmap *)NULL, (XpmAttributes *)NULL); if (status != XpmSuccess) return -1; dtb_set_label_pixmaps(widget, labelPixmap, NULL); return 0; } unsigned long dtb_cvt_resource_from_string( Widget parent, String res_type, unsigned int size_of_type, String res_str_value, unsigned long error_value ) { unsigned long cvt_value_return = error_value; unsigned char cvt_value1 = 0; unsigned short cvt_value2 = 0; unsigned int cvt_value3 = 0; unsigned long cvt_value4 = 0; XtPointer cvt_value_ptr = NULL; int which_cvt_value = -1; XrmValue source; XrmValue dest; if (size_of_type > sizeof(cvt_value_return)) { /* Type we are converting to is too large */ return cvt_value_return; } /* * Get a data object of the appropriate size */ if (size_of_type == sizeof(cvt_value1)) { which_cvt_value = 1; cvt_value_ptr = (XtPointer)&cvt_value1; } else if (size_of_type == sizeof(cvt_value2)) { which_cvt_value = 2; cvt_value_ptr = (XtPointer)&cvt_value2; } else if (size_of_type == sizeof(cvt_value3)) { which_cvt_value = 3; cvt_value_ptr = (XtPointer)&cvt_value3; } else if (size_of_type == sizeof(cvt_value4)) { which_cvt_value = 4; cvt_value_ptr = (XtPointer)&cvt_value4; } else { return cvt_value_return; } /* * Actually do the conversion */ source.size = strlen(res_str_value) + 1; source.addr = res_str_value; dest.size = size_of_type; dest.addr = (char *)cvt_value_ptr; if (XtConvertAndStore(parent, XtRString, &source, res_type, &dest) != 0) { switch (which_cvt_value) { case 1: cvt_value_return = (unsigned long)cvt_value1; break; case 2: cvt_value_return = (unsigned long)cvt_value2; break; case 3: cvt_value_return = (unsigned long)cvt_value3; break; case 4: cvt_value_return = (unsigned long)cvt_value4; break; } } return cvt_value_return; } /* ** Routines to save and access the toplevel widget for an application. ** This is useful in dtb_ convenience functions, and also probably by ** developers in routines they provide in their _stubs.c files. ** static Widget dtb_project_toplevel_widget = (Widget) NULL; */ void dtb_save_toplevel_widget( Widget toplevel ) { dtb_project_toplevel_widget = toplevel; } Widget dtb_get_toplevel_widget() { return(dtb_project_toplevel_widget); } /* ** Function to turn off traversal on the invisible sash within a ** PanedWindow. This is primarily used for the PanedWindow within ** a Custom Dialog object. */ void dtb_remove_sash_focus( Widget widget ) { WidgetList children; int numChildren, i; if (widget == NULL || !XtIsSubclass(widget, xmPanedWindowWidgetClass)) return; XtVaGetValues(widget, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); for(i = 0; i < numChildren; i++) if (XtIsSubclass(children[i], xmSashWidgetClass)) XtVaSetValues(children[i], XmNtraversalOn, False, NULL); } /* ** Routines to save and access the command used to invoke the application. */ void dtb_save_command( char *argv0 ) { char exe_dir[MAXPATHLEN+1]; dtb_save_command_str = argv0; /* * Save the path to the executable */ if (determine_exe_dir(argv0, exe_dir, MAXPATHLEN+1) >= 0) { dtb_exe_dir = (char *)malloc(strlen(exe_dir)+1); if (dtb_exe_dir != NULL) { strcpy(dtb_exe_dir, exe_dir); } } } char * dtb_get_command() { return(dtb_save_command_str); } /* ** Generic callback function to be attached as XmNhelpCallback and ** provide support for on-object and Help-key help. The help text to ** be displayed is provided via a specialized data structure passed in ** as client data. */ void dtb_help_dispatch( Widget widget, XtPointer clientData, XtPointer callData ) { DtbObjectHelpData help_data = (DtbObjectHelpData)clientData; int i; Arg wargs[10]; char buffer[100]; Widget back_button; static Widget Quick_help_dialog = (Widget)NULL; static Widget MoreButton; /* ** In order to save the more-help info (help volume & location ID) as part ** of the quick help dialog's backtrack mechanism, we have to splice the ** volume & ID strings together and save them as the help volume field. ** If there isn't supplemental help information, we save a null string. ** ** Checking the status of the more-help info also lets us decide whether ** the "More..." button should be enabled on the dialog. */ if( help_data->help_volume ==0 || *(help_data->help_volume) == NULL || help_data->help_locationID ==0 || *(help_data->help_locationID)== NULL){ buffer[0] = '\0'; } else { sprintf(buffer,"%s/%s",help_data->help_volume,help_data->help_locationID); } /* ** If this is our first time to post help, create the proper dialog and ** set its attributes to suit the current object. If not, then just ** update the attributes. ** ** (You have to be careful about gratuitous SetValues on the dialog because ** its internal stack mechanism takes repeated settings as separate items ** and updates the stack for each.) */ if(Quick_help_dialog == (Widget)NULL) { /* Create shared help dialog */ i = 0; XtSetArg(wargs[i],XmNtitle, "Application Help"); i++; XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_DYNAMIC_STRING); i++; XtSetArg(wargs[i],DtNstringData,help_data->help_text); i++; XtSetArg(wargs[i],DtNhelpVolume,buffer); i++; Quick_help_dialog = DtCreateHelpQuickDialog(dtb_get_toplevel_widget(), "Help",wargs,i); /* ** Fetch out the Dialog's More button child and hook the 'more help' ** handler to its activateCallback. Set it's current status to ** indicate whether this object has supplemental help data. */ MoreButton = DtHelpQuickDialogGetChild(Quick_help_dialog, DtHELP_QUICK_MORE_BUTTON); XtManageChild(MoreButton); XtAddCallback(MoreButton,XmNactivateCallback,dtb_more_help_dispatch, (XtPointer)Quick_help_dialog); if(buffer[0] == '\0') XtSetSensitive(MoreButton,False); /* ** Fetch out the Dialog's Backtrack button child & hook a callback ** that will control button sensitivity based on the presence of more ** help data. */ back_button = DtHelpQuickDialogGetChild(Quick_help_dialog, DtHELP_QUICK_BACK_BUTTON); XtAddCallback(back_button,XmNactivateCallback,dtb_help_back_hdlr, (XtPointer)Quick_help_dialog); } /* Otherwise the dialog already exists so we just set the attributes. */ else { /* ** If we have supplemental help info, enable the more button. ** Also save this info for later use in the backtrack handler. */ if(buffer[0] == '\0') { XtSetSensitive(MoreButton,False); } else { XtSetSensitive(MoreButton,True); } XtVaSetValues(Quick_help_dialog, DtNhelpType, DtHELP_TYPE_DYNAMIC_STRING, DtNhelpVolume,buffer, DtNstringData,help_data->help_text, NULL); } /* Now display the help dialog */ XtManageChild(Quick_help_dialog); } /* ** Callback that is added to the QuickHelpDialog widget's "Backtrack" button ** and is used to control the "More.." button. At each step in the backtrack, ** this routine checks to see if there is help volume & location info stored ** in the dialog's helpVolume resource. If so, then the "More..." button is ** enabled. If not, then it is disabled. */ void dtb_help_back_hdlr( Widget widget, XtPointer clientData, XtPointer callData ) { String buffer, text, vol, loc; char *cp; Widget more_button; Widget help_dialog = (Widget)clientData; /* Fetch the saved volume/locationID information from the dialog widget */ XtVaGetValues(help_dialog, DtNhelpVolume,&buffer, DtNstringData,&text, NULL); /* Get a handle to the "More..." button */ more_button = DtHelpQuickDialogGetChild(help_dialog, DtHELP_QUICK_MORE_BUTTON); /* ** Parse the combined volume/locationID string. Disable the "More..." ** button if there isn't any help info, and enable it if there is. */ if( buffer == 0 || (*buffer == NULL) || (cp=strrchr(buffer,'/')) == (char *)NULL) { XtSetSensitive(more_button,False); } else { XtSetSensitive(more_button,True); } } /* ** This callback is invoked when the user presses "More..." on the ** QuickHelpDialog. It figures out whether a help volume entry is associated ** with the displayed help text, and if so it brings up a GeneralHelpDialog ** to display the appropriate help volume information. */ void dtb_more_help_dispatch( Widget widget, XtPointer clientData, XtPointer callData ) { int i; Arg wargs[10]; String buffer, vol, loc; char *cp; static Widget GeneralHelpDialog = (Widget) NULL; Widget help_dialog = (Widget)clientData; Widget more_button; /* Fetch the saved volume/locationID information from the dialog widget */ XtVaGetValues(help_dialog, DtNhelpVolume,&buffer, NULL); /* ** Parse the combined volume/locationID string. If that fails there ** must be no data, so don't bother displaying the GeneralHelpDialog. ** (We shouldn't be in this callback routine if that happens, though...) */ if( (cp=strrchr(buffer,'/')) != (char *)NULL) { *cp++ = 0; vol = buffer; loc = cp; } if(GeneralHelpDialog == (Widget)NULL) { /* Create General Help Dialog */ i = 0; XtSetArg(wargs[i],XmNtitle, "Application Help"); i++; XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_TOPIC); i++; XtSetArg(wargs[i],DtNhelpVolume, vol); i++; XtSetArg(wargs[i],DtNlocationId,loc); i++; GeneralHelpDialog = DtCreateHelpDialog(dtb_get_toplevel_widget(), "GeneralHelp",wargs,i); } else { i = 0; XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_TOPIC); i++; XtSetArg(wargs[i],DtNhelpVolume,vol); i++; XtSetArg(wargs[i],DtNlocationId,loc); i++; XtSetValues(GeneralHelpDialog,wargs,i); } /* Now take down the quick help dialog and display the full help one */ XtManageChild(GeneralHelpDialog); XtUnmanageChild(help_dialog); } /* ** Utility function used to provide support for on-item help. ** It is typically invoked via a callback on the "On Item" item in the ** main menubar's "Help" menu. */ void dtb_do_onitem_help() { Widget target; /* Call the DtHelp routine that supports interactive on-item help. */ if(DtHelpReturnSelectedWidgetId(dtb_get_toplevel_widget(), (Cursor)NULL,&target) != DtHELP_SELECT_VALID) return; /* ** Starting at the target widget, wander up the widget tree looking ** for one that has an XmNhelpCallback, and call the first one we ** find. */ while(target != (Widget)NULL) { if( XtHasCallbacks(target,XmNhelpCallback) == XtCallbackHasSome) { XtCallCallbacks(target,XmNhelpCallback,(XtPointer)NULL); return; } else { target = XtParent(target); } } return; } /* ** Utility function called to display help volume information. ** It needs the name of the help volume and the location ID (both as ** strings) so it can configure the full help dialog widget properly. */ int dtb_show_help_volume_info( char *volume_name, char *location_id ) { int i; Arg wargs[10]; static Widget GeneralHelpDialog = (Widget) NULL; if(GeneralHelpDialog == (Widget)NULL) { /* Create General Help Dialog */ i = 0; XtSetArg(wargs[i],XmNtitle, "Application Help"); i++; XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_TOPIC); i++; XtSetArg(wargs[i],DtNhelpVolume, volume_name); i++; XtSetArg(wargs[i],DtNlocationId,location_id); i++; GeneralHelpDialog = DtCreateHelpDialog(dtb_get_toplevel_widget(), "GeneralHelp",wargs,i); } else { i = 0; XtSetArg(wargs[i],DtNhelpType, DtHELP_TYPE_TOPIC); i++; XtSetArg(wargs[i],DtNhelpVolume,volume_name); i++; XtSetArg(wargs[i],DtNlocationId,location_id); i++; XtSetValues(GeneralHelpDialog,wargs,i); } /* Now display the full help dialog */ XtManageChild(GeneralHelpDialog); return(0); } /* * dtb_session_save() * Callback that is called when the application (top level * widget of application) gets a WM_SAVE_YOURSELF ClientMessage * This callback will call the client/application's session * save callback. */ void dtb_session_save( Widget widget, XtPointer clientData, XtPointer callData ) { int new_argc, client_argc = 0, new_argc_counter, i; char **new_argv, **client_argv = NULL, *session_file_path, *session_file_name, *app_name = NULL; Boolean status = False; DtbClientSessionSaveCB session_saveCB; /* * Return if no widget passed in. */ if (!widget) return; /* * Get session file path/name to store application's state */ if (DtSessionSavePath(widget, &session_file_path, &session_file_name) == False) return; /* * Get client session save callback */ session_saveCB = dtb_get_client_session_saveCB(); /* * Call client session save callback */ if (session_saveCB) /* * client_argv and client_argc are the variables that * will contain any extra command line options * that need to be used when invoking the application * to bring it to the current state. */ status = session_saveCB(widget, session_file_path, &client_argv, &client_argc); /* * Generate the reinvoking command and add it as the property value */ /* * Fetch command used to invoke application */ app_name = dtb_get_command(); /* * new_argc and new_argc are the variables used to reconstruct * the command to re-invoke the application */ /* * Start new_argc with: * 1 for argv[0], normally the application * client_argc any extra command line options as * returned from client session save * callback */ new_argc = 1 + client_argc; /* * If the status returned from session save callback is 'True', * the session file was actually used. This means we need to * add: * -session * to the command saved, which is 2 more strings. */ if (status) new_argc += 2; /* * Allocate vector */ new_argv = (char **)XtMalloc((sizeof(char **) * new_argc)); /* * Set new_argv[0] to be the application name */ new_argc_counter = 0; new_argv[new_argc_counter] = app_name; new_argc_counter++; /* * Proceed to copy every command line option from * client_argv. Skip -session, if found. */ for (i=0; i < client_argc;) { if (strcmp(client_argv[i], "-session")) { new_argv[new_argc_counter] = client_argv[i]; new_argc_counter++; } else { /* * Skip "-session" * The next increment below will skip the session file. */ ++i; } ++i; } /* * If session file used, add * -session */ if (status) { new_argv[new_argc_counter] = "-session"; new_argc_counter++; new_argv[new_argc_counter] = session_file_name; } else { /* * otherwise, destroy session file */ (void)unlink(session_file_path); } /* * Set WM_COMMAND property with vector constructed */ XSetCommand(XtDisplay(widget), XtWindow(widget), new_argv, new_argc); /* * Free argument vector */ XtFree ((char *)new_argv); /* * CDE Sessioning API states that the path/name * strings have to be free'd by the application. */ XtFree ((char *)session_file_path); XtFree ((char *)session_file_name); } /* * dtb_get_client_session_saveCB() */ DtbClientSessionSaveCB dtb_get_client_session_saveCB() { return(dtb_client_session_saveCB); } /* * dtb_set_client_session_saveCB() */ void dtb_set_client_session_saveCB( DtbClientSessionSaveCB session_saveCB ) { dtb_client_session_saveCB = session_saveCB; } /* * dtb_session_restore() * Callback that is called during session restore (application * startup). It is called only if the application was invoked * with: * -session * It calls the client session restore callback. */ void dtb_session_restore( Widget widget, char *session_file ) { DtbClientSessionRestoreCB session_restoreCB; char *session_file_path; Boolean status; /* * If parameters are NULL, return. */ if (!widget || !session_file) return; /* * Get path of session file to read */ if (DtSessionRestorePath(widget, &session_file_path, session_file) == False) return; /* * Get client session restore callback */ session_restoreCB = dtb_get_client_session_restoreCB(); /* * Call client session restore callback */ if (session_restoreCB) status = session_restoreCB(widget, session_file_path); /* * CDE Sessioning API states that the path * string has to be free'd by the application. */ if (!session_file_path) XtFree((char *)session_file_path); } /* * dtb_set_client_session_restoreCB() */ void dtb_set_client_session_restoreCB( DtbClientSessionRestoreCB session_restoreCB ) { dtb_client_session_restoreCB = session_restoreCB; } /* * dtb_get_client_session_restoreCB() */ DtbClientSessionRestoreCB dtb_get_client_session_restoreCB() { return(dtb_client_session_restoreCB); } /* * Create a Message Dialog. */ Widget dtb_create_message_dlg( Widget parent, DtbMessageData mbr, XmString override_msg, DtbObjectHelpData override_help ) { Widget msg_dlg = (Widget) NULL; Widget shell = (Widget) NULL; Widget button = (Widget) NULL; Widget action_button = (Widget) NULL; unsigned char default_btn = XmDIALOG_NONE; Arg arg[12]; int n = 0; /* The dialog should be parented off of a Shell, * so walk up the tree to find the parent's shell * ancestor... */ shell = parent; while(!XtIsSubclass(shell, shellWidgetClass)) shell = XtParent(shell); msg_dlg = XmCreateMessageDialog(shell,"dtb_msg_dlg", NULL, 0); if (!mbr->cancel_button) { button = XmMessageBoxGetChild(msg_dlg, XmDIALOG_CANCEL_BUTTON); XtUnmanageChild(button); } if (!mbr->help_button) { button = XmMessageBoxGetChild(msg_dlg, XmDIALOG_HELP_BUTTON); XtUnmanageChild(button); } if (mbr->action1_label == (XmString) NULL) { button = XmMessageBoxGetChild(msg_dlg, XmDIALOG_OK_BUTTON); XtUnmanageChild(button); } else { XtSetArg(arg[n], XmNokLabelString, mbr->action1_label); n++; } /* Create an extra button for the MessageBox */ if (mbr->action2_label != (XmString) NULL) { button = XtVaCreateManagedWidget("action2_button", xmPushButtonWidgetClass, msg_dlg, XmNlabelString, mbr->action2_label, XmNuserData, DTB_ACTION2_BUTTON, NULL); } /* Create an extra button for the MessageBox */ if (mbr->action3_label != (XmString) NULL) { button = XtVaCreateManagedWidget("action3_button", xmPushButtonWidgetClass, msg_dlg, XmNlabelString, mbr->action3_label, XmNuserData, DTB_ACTION3_BUTTON, NULL); } XtSetArg(arg[n], XmNdialogType, mbr->type); n++; XtSetValues(msg_dlg, arg, n); if (override_msg != (XmString) NULL) { XtVaSetValues(msg_dlg, XmNmessageString, override_msg, NULL); } else if (mbr->message != (XmString) NULL) { XtVaSetValues(msg_dlg, XmNmessageString, mbr->message, NULL); } if (mbr->title != (XmString) NULL) { XtVaSetValues(msg_dlg, XmNdialogTitle, mbr->title, NULL); } else { XmString null_str; null_str = XmStringCreateLocalized(" "); XtVaSetValues(msg_dlg, XmNdialogTitle, null_str, NULL); XmStringFree(null_str); } switch (mbr->default_button) { case DTB_ACTION1_BUTTON: default_btn = XmDIALOG_OK_BUTTON; break; case DTB_ACTION2_BUTTON: case DTB_ACTION3_BUTTON: case DTB_NONE: default_btn = XmDIALOG_NONE; break; case DTB_CANCEL_BUTTON: default_btn = XmDIALOG_CANCEL_BUTTON; break; default: break; } XtVaSetValues(msg_dlg, XmNdefaultButtonType, default_btn, NULL); if (mbr->default_button == DTB_ACTION2_BUTTON) { action_button = dtb_MessageBoxGetActionButton(msg_dlg, DTB_ACTION2_BUTTON); } else if (mbr->default_button == DTB_ACTION3_BUTTON) { action_button = dtb_MessageBoxGetActionButton(msg_dlg, DTB_ACTION3_BUTTON); } if (action_button != (Widget) NULL) { XtVaSetValues(action_button, XmNdefaultButtonShadowThickness, 2, XmNshowAsDefault, True, NULL); XtVaSetValues(msg_dlg, XmNdefaultButton, action_button, NULL); } XtAddCallback(XtParent(msg_dlg), XtNpopdownCallback, destroyCB, (XtPointer) override_help); return(msg_dlg); } /* * popdownCallback for MessageBox. */ static void destroyCB( Widget widget, XtPointer client_data, XtPointer call_data ) { DtbObjectHelpData help_data = (DtbObjectHelpData)client_data; if (help_data != (DtbObjectHelpData) NULL) { if (help_data->help_text) XtFree((char *)help_data->help_text); if (help_data->help_volume) XtFree((char *)help_data->help_volume); if (help_data->help_locationID) XtFree((char *)help_data->help_locationID); XtFree((char *)help_data); } XtDestroyWidget(widget); } /* * Get handle to Action2 button. */ Widget dtb_MessageBoxGetActionButton( Widget msg_dlg, DTB_BUTTON which_btn ) { int i, numChildren = 0; WidgetList children = NULL; Widget action_button = NULL; int button = -1; Boolean Found = False; XtVaGetValues(msg_dlg, XmNnumChildren, &numChildren, XmNchildren, &children, NULL); for (i = 0; i < numChildren && !Found; i++) { XtVaGetValues(children[i], XmNuserData, &button, NULL); if (which_btn == (DTB_BUTTON) button) { Found = True; action_button = children[i]; } } return (action_button); } /* * Use this routine to post a non-modal message. It should * be used to post Information and Working messages. */ void dtb_show_message( Widget parent, DtbMessageData mbr, XmString override_msg, DtbObjectHelpData override_help ) { DtbObjectHelpData help_data_copy = (DtbObjectHelpData)NULL; Widget msg_dlg = (Widget) NULL, action_btn = (Widget) NULL; if (override_help != (DtbObjectHelpData) NULL) { help_data_copy = (DtbObjectHelpData)XtMalloc(sizeof(DtbObjectHelpDataRec)); help_data_copy->help_text = override_help->help_text ? XtNewString(override_help->help_text) : NULL; help_data_copy->help_volume = override_help->help_volume ? XtNewString(override_help->help_volume) : NULL; help_data_copy->help_locationID = override_help->help_locationID ? XtNewString(override_help->help_locationID) : NULL; } msg_dlg = dtb_create_message_dlg(parent, mbr, override_msg, help_data_copy); if (msg_dlg == (Widget) NULL) return; /* Add Callbacks if necessary */ if (mbr->action1_callback != (XtCallbackProc) NULL) XtAddCallback(msg_dlg, XmNokCallback, mbr->action1_callback, NULL); if (mbr->cancel_callback != (XtCallbackProc) NULL) XtAddCallback(msg_dlg, XmNcancelCallback, mbr->cancel_callback, NULL); if (mbr->action2_callback != (XtCallbackProc) NULL) { action_btn = dtb_MessageBoxGetActionButton(msg_dlg, DTB_ACTION2_BUTTON); if (action_btn != NULL) XtAddCallback(action_btn, XmNactivateCallback, mbr->action2_callback, NULL); } if (mbr->action3_callback != (XtCallbackProc) NULL) { action_btn = dtb_MessageBoxGetActionButton(msg_dlg, DTB_ACTION3_BUTTON); if (action_btn != NULL) XtAddCallback(action_btn, XmNactivateCallback, mbr->action3_callback, NULL); } if (mbr->help_button) { if (help_data_copy != (DtbObjectHelpData) NULL) { XtAddCallback(msg_dlg, XmNhelpCallback, dtb_help_dispatch, (XtPointer) help_data_copy); } else if (mbr->help_data.help_text != (char *) NULL) { XtAddCallback(msg_dlg, XmNhelpCallback, dtb_help_dispatch, (XtPointer) &(mbr->help_data)); } } XtManageChild(msg_dlg); XRaiseWindow(XtDisplay(msg_dlg), XtWindow(XtParent(msg_dlg))); } /* * Use this routine to post a modal message. * It should be used to post Error, Question, and Warning messages. * It returns the information on which button was pressed. A switch * statement can then be done to process the answer. */ DTB_MODAL_ANSWER dtb_show_modal_message( Widget parent, DtbMessageData mbr, XmString override_msg, DtbObjectHelpData override_help, Widget *modal_dlg_pane_out_ptr ) { XtAppContext app; Widget modal_dlg_pane = (Widget) NULL; Widget action2_button = (Widget) NULL; Widget action3_button = (Widget) NULL; DtbObjectHelpData help_data_copy = (DtbObjectHelpData)NULL; DTB_MODAL_ANSWER answer = DTB_ANSWER_NONE; XtCallbackRec ok_callback[] = { {(XtCallbackProc)modal_dlgCB, (XtPointer) DTB_ANSWER_ACTION1}, {(XtCallbackProc) NULL, (XtPointer) NULL} }; XtCallbackRec cancel_callback[] = { {(XtCallbackProc)modal_dlgCB, (XtPointer) DTB_ANSWER_CANCEL}, {(XtCallbackProc) NULL, (XtPointer) NULL} }; if (override_help != (DtbObjectHelpData) NULL) { help_data_copy = (DtbObjectHelpData)XtMalloc(sizeof(DtbObjectHelpDataRec)); help_data_copy->help_text = override_help->help_text ? XtNewString(override_help->help_text) : NULL; help_data_copy->help_volume = override_help->help_volume ? XtNewString(override_help->help_volume) : NULL; help_data_copy->help_locationID = override_help->help_locationID ? XtNewString(override_help->help_locationID) : NULL; } modal_dlg_pane = dtb_create_message_dlg(parent, mbr, override_msg, help_data_copy); if (modal_dlg_pane == (Widget) NULL) return (answer); XtVaSetValues(modal_dlg_pane, XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL, XmNokCallback, &ok_callback, XmNcancelCallback, &cancel_callback, XmNuserData, &answer, NULL); action2_button = dtb_MessageBoxGetActionButton(modal_dlg_pane, DTB_ACTION2_BUTTON); if (action2_button != (Widget) NULL) { XtVaSetValues(action2_button, XmNuserData, (XtPointer) &answer, NULL); XtAddCallback(action2_button, XmNactivateCallback, modal_dlgCB, (XtPointer) DTB_ANSWER_ACTION2); } action3_button = dtb_MessageBoxGetActionButton(modal_dlg_pane, DTB_ACTION3_BUTTON); if (action3_button != (Widget) NULL) { XtVaSetValues(action3_button, XmNuserData, (XtPointer) &answer, NULL); XtAddCallback(action3_button, XmNactivateCallback, modal_dlgCB, (XtPointer) DTB_ANSWER_ACTION3); } if (mbr->help_button) { if (help_data_copy != (DtbObjectHelpData) NULL) { XtAddCallback(modal_dlg_pane, XmNhelpCallback, dtb_help_dispatch, (XtPointer) help_data_copy); } else if (mbr->help_data.help_text != (char *) NULL) { XtAddCallback(modal_dlg_pane, XmNhelpCallback, dtb_help_dispatch, (XtPointer) &(mbr->help_data)); } } /* Popup Modal MessageDialog and wait for answer */ XtManageChild(modal_dlg_pane); XRaiseWindow(XtDisplay(modal_dlg_pane), XtWindow(XtParent(modal_dlg_pane))); app = XtDisplayToApplicationContext(XtDisplay(modal_dlg_pane)); while (answer == DTB_ANSWER_NONE) XtAppProcessEvent(app, XtIMAll); if (modal_dlg_pane_out_ptr != NULL) { (*modal_dlg_pane_out_ptr) = modal_dlg_pane; } return(answer); } /* * This is the activateCallback for the MessageBox buttons. * It returns the button which was pressed. */ static void modal_dlgCB( Widget widget, XtPointer client_data, XtPointer call_data ) { DTB_MODAL_ANSWER op = (DTB_MODAL_ANSWER) client_data; DTB_MODAL_ANSWER *answerp = (DTB_MODAL_ANSWER) NULL; XtVaGetValues(widget, XmNuserData, &answerp, NULL); /* Will cause Modal dialog to return */ *answerp = op; } /* * This function will center all the passed form's children. * The type of centering depends on what 'type' is. */ void dtb_children_center( Widget form, DTB_CENTERING_TYPES type ) { WidgetList children_list; int i, num_children; if (!form || (type == DTB_CENTER_NONE)) return; /* * Get children list */ XtVaGetValues(form, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); /* * Center all children */ for (i=0; i < num_children; ++i) { dtb_center(children_list[i], type); } } /* * This function 'uncenters' the children of the passed * form widget. */ void dtb_children_uncenter( Widget form, DTB_CENTERING_TYPES type ) { WidgetList children_list; int i; int num_children; if (!form || (type == DTB_CENTER_NONE)) return; /* * Get children list */ XtVaGetValues(form, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); /* * Center all children */ for (i=0; i < num_children; ++i) { dtb_uncenter(children_list[i], type); } } /* * This function centers the passed widget. * This is done by setting the proper offsets. * Dynamic centering is accomplished by attaching an event handler * which detect resizes and recomputes and sets the appropriate offset. */ void dtb_center( Widget form_child, DTB_CENTERING_TYPES type ) { if (!form_child || (type == DTB_CENTER_NONE)) return; center_widget(form_child, type); XtAddEventHandler(form_child, StructureNotifyMask, False, centering_handler, (XtPointer)type); } /* * This function 'uncenters' the passed widget. * This involves resetting the attachment offsets * and removing the resize event handler. */ void dtb_uncenter( Widget form_child, DTB_CENTERING_TYPES type ) { if (!form_child || (type == DTB_CENTER_NONE)) return; uncenter_widget(form_child, type); XtRemoveEventHandler(form_child, StructureNotifyMask, False, centering_handler, (XtPointer)type); } /* * This function centers the passed widget. * This is done by making the appropriate offset equal * to the negative half of it's width/height (depending * on whether horizontal or vertical centering was chosen. */ static void center_widget( Widget form_child, DTB_CENTERING_TYPES type ) { Widget parent; Dimension width = 0, height = 0; int center_offset; unsigned char left_attach = XmATTACH_NONE, top_attach = XmATTACH_NONE; if (!form_child || !XtIsManaged(form_child) || !XtIsRealized(form_child)) return; parent = XtParent(form_child); if (!parent || !XtIsSubclass(parent, xmFormWidgetClass)) return; XtVaGetValues(form_child, XmNwidth, &width, XmNheight, &height, XmNleftAttachment, &left_attach, XmNtopAttachment, &top_attach, NULL); switch (type) { case DTB_CENTER_POSITION_VERT: if (left_attach != XmATTACH_POSITION) return; center_offset = -(width/2); XtVaSetValues(form_child, XmNleftOffset, center_offset, NULL); break; case DTB_CENTER_POSITION_HORIZ: if (top_attach != XmATTACH_POSITION) return; center_offset = -(height/2); XtVaSetValues(form_child, XmNtopOffset, center_offset, NULL); break; case DTB_CENTER_POSITION_BOTH: { int left_offset, top_offset; if ((left_attach != XmATTACH_POSITION) && (top_attach != XmATTACH_POSITION)) return; left_offset = -(width/2); top_offset = -(height/2); XtVaSetValues(form_child, XmNleftOffset, left_offset, XmNtopOffset, top_offset, NULL); } break; } } /* * This function 'uncenters' the passed widget. * It merely resets the offsets of the top/left attachments to 0. */ static void uncenter_widget( Widget form_child, DTB_CENTERING_TYPES type ) { Widget parent; unsigned char left_attach = XmATTACH_NONE, top_attach = XmATTACH_NONE; if (!form_child || !XtIsManaged(form_child) || !XtIsRealized(form_child)) return; parent = XtParent(form_child); if (!parent || !XtIsSubclass(parent, xmFormWidgetClass)) return; XtVaGetValues(form_child, XmNleftAttachment, &left_attach, XmNtopAttachment, &top_attach, NULL); switch (type) { case DTB_CENTER_POSITION_VERT: if (left_attach != XmATTACH_POSITION) return; XtVaSetValues(form_child, XmNleftOffset, 0, NULL); break; case DTB_CENTER_POSITION_HORIZ: if (top_attach != XmATTACH_POSITION) return; XtVaSetValues(form_child, XmNtopOffset, 0, NULL); break; case DTB_CENTER_POSITION_BOTH: if ((left_attach != XmATTACH_POSITION) && (top_attach != XmATTACH_POSITION)) return; XtVaSetValues(form_child, XmNleftOffset, 0, XmNtopOffset, 0, NULL); break; } } /* * Event handler to center a widget * The type of centering needed is passed in as client_data */ static void centering_handler( Widget widget, XtPointer client_data, XEvent *event, Boolean *cont_dispatch ) { XConfigureEvent *xcon = &event->xconfigure; Widget resized_child; DTB_CENTERING_TYPES type = (DTB_CENTERING_TYPES)client_data; if ((event->type != ConfigureNotify) && (event->type != MapNotify)) return; resized_child = XtWindowToWidget(XtDisplay(widget), xcon->window); if (!resized_child) return; center_widget(resized_child, type); } /* * Given a widget, return it's label widget. */ static Widget get_label_widget( Widget widget ) { WidgetList children_list; Widget label_widget = NULL; int i, num_children = 0; char *subobj_name = NULL, *label_name = NULL; char *underscore_ptr = NULL; if (XtIsSubclass(widget, xmLabelWidgetClass)) { return(widget); } subobj_name = XtName(widget); label_name = (char *)XtMalloc(1 + strlen(subobj_name) + strlen("_label") + 5); label_name[0] = '*'; strcpy(label_name+1, subobj_name); if ((underscore_ptr = strrchr(label_name, '_')) != NULL) { strcpy(underscore_ptr, "_label"); label_widget = XtNameToWidget(widget, label_name); } if (label_widget == NULL) { strcpy(label_name+1, subobj_name); strcat(label_name, "_label"); label_widget = XtNameToWidget(widget, label_name); } XtFree((char *)label_name); if (label_widget) return(label_widget); /* * How to look for 1st child of group object ?? * How do we know if 'widget' is a group object ?? * For now, just check if it is a form */ if (XtIsSubclass(widget, xmFormWidgetClass) || XtIsSubclass(widget, xmFrameWidgetClass)) XtVaGetValues(widget, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children > 0) return(get_label_widget(children_list[0])); return (NULL); } static Position get_offset_from_ancestor( Widget ancestor, Widget w ) { Widget cur = w; Widget cur_parent = NULL; Position offset = 0; if (!ancestor || !w || (w == ancestor)) return (0); XtVaGetValues(cur, XmNx, &offset, NULL); cur_parent = XtParent(cur); while (cur_parent != ancestor) { Position tmp_offset = 0; cur = cur_parent; XtVaGetValues(cur, XmNx, &tmp_offset, NULL); offset += tmp_offset; cur_parent = XtParent(cur); } return (offset); } static Dimension get_label_width( Widget widget ) { WidgetList children_list; Widget lbl_widget = NULL; Dimension lbl_width = 0; lbl_widget = get_label_widget(widget); if (lbl_widget) { Position offset = 0; XtVaGetValues(lbl_widget, XmNwidth, &lbl_width, NULL); offset = get_offset_from_ancestor(widget, lbl_widget); lbl_width += (Dimension)offset; } return (lbl_width); } static void get_widest_label( WidgetList list, int count, Widget *child_widget, Dimension *label_width ) { Widget cur_widest = NULL; Dimension cur_width = 0; int i; for (i = 0; i < count; ++i) { Dimension tmp; tmp = get_label_width(list[i]); if (tmp > cur_width) { cur_width = tmp; cur_widest = list[i]; } } *child_widget = cur_widest; *label_width = cur_width; } static void get_widest_value( WidgetList list, int count, Widget *child_widget, Dimension *value_width ) { Widget cur_widest = NULL; Dimension cur_width = 0; int i; for (i = 0; i < count; ++i) { Dimension tmp, label_width, obj_width = 0; label_width = get_label_width(list[i]); XtVaGetValues(list[i], XmNwidth, &obj_width, NULL); tmp = obj_width - label_width; if (tmp > cur_width) { cur_width = tmp; cur_widest = list[i]; } } *child_widget = cur_widest; *value_width = cur_width; } static void get_widget_rect( Widget widget, XRectangle *rect ) { if (!rect) return; XtVaGetValues(widget, XtNwidth, (XtArgVal)&(rect->width), XtNheight, (XtArgVal)&(rect->height), XtNx, (XtArgVal)&(rect->x), XtNy, (XtArgVal)&(rect->y), NULL); } static void get_greatest_size( Widget *list, int count, int *width, int *height, Widget *tallest, Widget *widest ) { XRectangle w_rect; int i; int previous_width, previous_height; if (!list || (count < 0)) return; get_widget_rect(list[0], &w_rect); *width = w_rect.width; previous_width = *width; *height = w_rect.height; previous_height = *height; if (tallest != NULL) *tallest = list[0]; if (widest != NULL) *widest = list[0]; for (i=0; i < count; i++) { get_widget_rect(list[i], &w_rect); *width = max((int) w_rect.width, (int) *width); if (widest != NULL && *width > previous_width) *widest = list[i]; *height = max((int) w_rect.height, (int)*height); if (tallest != NULL && *height > previous_height) *tallest = list[i]; } } static void get_group_cell_size( Widget parent, DtbGroupInfo *group_info, int *cell_width, int *cell_height ) { WidgetList children_list = NULL; int i, num_children = 0; /* * Get children list */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); get_greatest_size(children_list, num_children, cell_width, cell_height, (Widget *)NULL, (Widget *)NULL); } static void get_group_row_col( Widget parent, DtbGroupInfo *group_info, int *rows, int *cols ) { WidgetList children_list = NULL; int num_rows, num_cols, num_children; if (!parent || !group_info) { *rows = *cols = -1; return; } /* * Get children list */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); num_rows = group_info->num_rows; num_cols = group_info->num_cols; if ((num_rows <= 0) && (num_cols <= 0)) { *rows = *cols = -1; return; } if (num_cols <= 0) num_cols = (num_children/num_rows) + ((num_children % num_rows) ? 1 : 0); if (num_rows <= 0) num_rows = (num_children/num_cols) + ((num_children % num_cols) ? 1 : 0); *rows = num_rows; *cols = num_cols; } static Widget get_group_child( Widget parent, DtbGroupInfo *group_info, int x_pos, int y_pos ) { DTB_GROUP_TYPES group_type; WidgetList children_list = NULL; Widget ret_child = NULL; int num_children = 0, num_rows, num_columns, i = -1; if (!parent || !group_info || (x_pos < 0) || (y_pos < 0)) return (NULL); group_type = group_info->group_type; num_rows = group_info->num_rows; num_columns = group_info->num_cols; /* * Get number of children */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return (NULL); switch (group_type) { case DTB_GROUP_NONE: break; case DTB_GROUP_ROWS: /* * num_rows = 1 * y_pos is ignored */ i = x_pos; break; case DTB_GROUP_COLUMNS: /* * num_columns = 1 * x_pos is ignored */ i = y_pos; break; case DTB_GROUP_ROWSCOLUMNS: if (!num_rows && !num_columns) break; if (num_rows > 0) { /* * ROWFIRST */ if (y_pos < num_rows) i = (x_pos * num_rows) + y_pos; } else { /* * COLFIRST */ if (x_pos < num_columns) i = x_pos + (y_pos * num_columns); } break; default: break; } if ((i >= 0) && (i < num_children)) { ret_child = children_list[i]; } return (ret_child); } void dtb_children_align( Widget parent, DTB_GROUP_TYPES group_type, DTB_ALIGN_TYPES row_align, DTB_ALIGN_TYPES col_align, int margin, int num_rows, int num_cols, int hoffset, int voffset ) { DtbGroupInfo *group_info; switch (group_type) { case DTB_GROUP_COLUMNS: num_rows = 0; num_cols = 1; break; case DTB_GROUP_ROWS: num_rows = 1; num_cols = 0; break; } group_info = (DtbGroupInfo *)XtMalloc(sizeof(DtbGroupInfo)); group_info->group_type = group_type; group_info->row_align = row_align; group_info->col_align = col_align; group_info->margin = margin; group_info->num_rows = num_rows; group_info->num_cols = num_cols; group_info->hoffset = hoffset; group_info->voffset = voffset; group_info->ref_widget = NULL; align_children(parent, group_info, True); /* * Register expose handler * Some group objects depend on it's members' sizes for their layout. * Unfortunately, some group members have invalid sizes prior to * XtRealize(), so the group layout has to be recalculated after the * group is realized or exposed in this case, since there is no realize * callback. */ switch(group_info->group_type) { case DTB_GROUP_NONE: break; case DTB_GROUP_ROWS: if (group_info->row_align == DTB_ALIGN_HCENTER) XtAddEventHandler(parent, ExposureMask, False, expose_handler, (XtPointer)group_info); break; case DTB_GROUP_COLUMNS: if ((group_info->col_align == DTB_ALIGN_LABELS) || (group_info->col_align == DTB_ALIGN_VCENTER)) XtAddEventHandler(parent, ExposureMask, False, expose_handler, (XtPointer)group_info); break; case DTB_GROUP_ROWSCOLUMNS: if ((group_info->row_align == DTB_ALIGN_HCENTER) || (group_info->col_align == DTB_ALIGN_LABELS) || (group_info->col_align == DTB_ALIGN_VCENTER)) XtAddEventHandler(parent, ExposureMask, False, expose_handler, (XtPointer)group_info); break; } XtAddCallback(parent, XtNdestroyCallback, free_group_info, (XtPointer)group_info); } static void align_children( Widget parent, DtbGroupInfo *group_info, Boolean init ) { if (!parent || !group_info) return; switch(group_info->group_type) { case DTB_GROUP_NONE: break; case DTB_GROUP_ROWS: align_rows(parent, group_info, init); align_left(parent, group_info); break; case DTB_GROUP_COLUMNS: align_cols(parent, group_info, init); align_top(parent, group_info); break; case DTB_GROUP_ROWSCOLUMNS: align_rows(parent, group_info, init); align_cols(parent, group_info, init); break; } } static void align_handler( Widget widget, XtPointer client_data, XEvent *event, Boolean *cont_dispatch ) { DtbGroupInfo *group_info = (DtbGroupInfo *)client_data; WidgetList children_list; int i, num_children = 0; Boolean relayout_all = False; /* * Get children list */ XtVaGetValues(widget, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return; XtRemoveEventHandler(widget, SubstructureNotifyMask, False, align_handler, (XtPointer)client_data); if (event->type == ConfigureNotify) { XConfigureEvent *xcon = &event->xconfigure; Widget resized_child; if (xcon->window != xcon->event) { resized_child = XtWindowToWidget(XtDisplay(widget), xcon->window); switch(group_info->group_type) { case DTB_GROUP_NONE: break; case DTB_GROUP_ROWS: if (group_info->row_align == DTB_ALIGN_HCENTER) relayout_all = True; break; case DTB_GROUP_COLUMNS: if ((group_info->col_align == DTB_ALIGN_LABELS) || (group_info->col_align == DTB_ALIGN_VCENTER)) relayout_all = True; break; case DTB_GROUP_ROWSCOLUMNS: if ((group_info->row_align == DTB_ALIGN_HCENTER) || (group_info->col_align == DTB_ALIGN_LABELS) || (group_info->col_align == DTB_ALIGN_VCENTER)) relayout_all = True; break; } } } /* * Relayout when new widgets are created */ if (event->type == CreateNotify) { XCreateWindowEvent *xcreate = &event->xcreatewindow; relayout_all = True; } /* * Relayout when widgets are destroyed */ if (event->type == DestroyNotify) { XDestroyWindowEvent *xdestroy = &event->xdestroywindow; Widget destroyed_child; destroyed_child = XtWindowToWidget(XtDisplay(widget), xdestroy->window); relayout_all = True; } if (relayout_all) { align_children(widget, group_info, False); } XtAddEventHandler(widget, SubstructureNotifyMask, False, align_handler, (XtPointer)client_data); } static void expose_handler( Widget widget, XtPointer client_data, XEvent *event, Boolean *cont_dispatch ) { DtbGroupInfo *group_info = (DtbGroupInfo *)client_data; WidgetList children_list; int i, num_children = 0; Boolean relayout_all = False, register_align_handler = False; if (event->type != Expose) return; if (!group_info) return; /* * Get children list */ XtVaGetValues(widget, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return; XtRemoveEventHandler(widget, ExposureMask, False, expose_handler, (XtPointer)client_data); switch(group_info->group_type) { case DTB_GROUP_NONE: break; case DTB_GROUP_ROWS: if (group_info->row_align == DTB_ALIGN_HCENTER) { relayout_all = True; register_align_handler = True; } break; case DTB_GROUP_COLUMNS: if ((group_info->col_align == DTB_ALIGN_LABELS) || (group_info->col_align == DTB_ALIGN_VCENTER)) { relayout_all = True; register_align_handler = True; } break; case DTB_GROUP_ROWSCOLUMNS: if ((group_info->row_align == DTB_ALIGN_HCENTER) || (group_info->col_align == DTB_ALIGN_LABELS) || (group_info->col_align == DTB_ALIGN_VCENTER)) { relayout_all = True; register_align_handler = True; } break; } if (relayout_all) { align_children(widget, group_info, False); } if (register_align_handler) { /* * Register align handler to relayout group if/when * any of it's members resize */ XtAddEventHandler(widget, SubstructureNotifyMask, False, align_handler, (XtPointer)group_info); } } static void free_group_info( Widget widget, XtPointer client_data, XtPointer call_data ) { DtbGroupInfo *group_info = (DtbGroupInfo *)client_data;; XtFree((char *)group_info); } static void align_rows( Widget parent, DtbGroupInfo *group_info, Boolean init ) { if (!parent || !group_info || (group_info->group_type == DTB_GROUP_COLUMNS)) return; switch (group_info->row_align) { case DTB_ALIGN_TOP: align_top(parent, group_info); break; case DTB_ALIGN_HCENTER: align_hcenter(parent, group_info, init); break; case DTB_ALIGN_BOTTOM: align_bottom(parent, group_info); break; default: break; } } static void align_cols( Widget parent, DtbGroupInfo *group_info, Boolean init ) { if (!parent || !group_info || (group_info->group_type == DTB_GROUP_ROWS)) return; switch (group_info->col_align) { case DTB_ALIGN_LEFT: align_left(parent, group_info); break; case DTB_ALIGN_LABELS: align_labels(parent, group_info); break; case DTB_ALIGN_VCENTER: align_vcenter(parent, group_info, init); break; case DTB_ALIGN_RIGHT: align_right(parent, group_info); break; default: break; } } static void align_left( Widget parent, DtbGroupInfo *group_info ) { WidgetList children_list; Widget child, previous_child; int num_children = 0, num_columns, num_rows, cell_width, cell_height, i, j; if (!parent || !group_info) return; /* * Get children list */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return; get_group_cell_size(parent, group_info, &cell_width, &cell_height); get_group_row_col(parent, group_info, &num_rows, &num_columns); for (j = 0; j < num_rows; j++) { for (i = 0; i < num_columns; i++) { Arg args[12]; int n = 0; child = get_group_child(parent, group_info, i, j); if (!child) continue; if ((i == 0) && (j == 0)) { XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 0); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); continue; } if (j == 0) { int offset = group_info->hoffset; DTB_GROUP_TYPES group_type = group_info->group_type; previous_child = get_group_child(parent, group_info, i-1, j); if (!previous_child) continue; if (group_type == DTB_GROUP_ROWSCOLUMNS) { Dimension width = 0; XtVaGetValues(previous_child, XmNwidth, &width, NULL); offset += (cell_width - (int)(width)); } XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, previous_child); n++; XtSetArg(args[n], XmNleftOffset, offset); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); continue; } previous_child = get_group_child(parent, group_info, i, j-1); if (previous_child) { XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, previous_child); n++; XtSetArg(args[n], XmNleftOffset, 0); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); } } } } static void align_right( Widget parent, DtbGroupInfo *group_info ) { WidgetList children_list; Widget child, previous_child; int num_children = 0, num_columns, num_rows, cell_width, cell_height, offset, i, j; if (!parent || !group_info) return; /* * Get children list */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return; get_group_cell_size(parent, group_info, &cell_width, &cell_height); get_group_row_col(parent, group_info, &num_rows, &num_columns); for (j = 0; j < num_rows; j++) { for (i = 0; i < num_columns; i++) { Arg args[12]; int n = 0; child = get_group_child(parent, group_info, i, j); if (!child) continue; if ((i == 0) && (j == 0)) { Dimension width = 0; XtVaGetValues(child, XmNwidth, &width, NULL); offset = (cell_width - width); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, offset); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); continue; } if (j == 0) { previous_child = get_group_child(parent, group_info, i-1, j); if (!previous_child) continue; offset = group_info->hoffset; if (group_info->group_type == DTB_GROUP_ROWSCOLUMNS) { Dimension width = 0; XtVaGetValues(child, XmNwidth, &width, NULL); offset += (cell_width - width); } XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, previous_child); n++; XtSetArg(args[n], XmNleftOffset, offset); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); continue; } previous_child = get_group_child(parent, group_info, i, j-1); if (previous_child) { XtSetArg(args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, previous_child); n++; XtSetArg(args[n], XmNrightOffset, 0); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); } } } } static void align_labels( Widget parent, DtbGroupInfo *group_info ) { WidgetList children_list = NULL, one_col; Widget previous_child = NULL, child, ref_widget, previous_ref_widget = NULL; Dimension ref_lbl_width = 0, max_label_width = 0, max_value_width = 0; int num_children = 0, num_rows, num_columns, cell_width, cell_height, offset, i, j, ref_x; if (!parent || !group_info) return; /* * Get children list */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return; get_group_cell_size(parent, group_info, &cell_width, &cell_height); get_widest_label(children_list, num_children, &child, &max_label_width); get_widest_value(children_list, num_children, &child, &max_value_width); if (cell_width < (int)(max_label_width + max_value_width)) cell_width = (int)(max_label_width + max_value_width); get_group_row_col(parent, group_info, &num_rows, &num_columns); if (num_rows > 0) one_col = (WidgetList)XtMalloc(num_rows * sizeof(WidgetList)); for (i = 0; i < num_columns; i++) { Widget ref_widget; Dimension ref_width; Arg args[12]; int n = 0; for (j = 0; j < num_rows; j++) one_col[j] = get_group_child(parent, group_info, i, j); get_widest_label(one_col, num_rows, &ref_widget, &ref_width); if (!ref_widget) continue; if (previous_ref_widget) offset = (i * (group_info->hoffset + cell_width)); else offset = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, offset); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetValues(ref_widget, args, n); for (j = 0; j < num_rows; j++) { child = get_group_child(parent, group_info, i, j); if (!child || (child == ref_widget)) continue; offset = (i * (group_info->hoffset + cell_width)); offset += (int)(ref_width - get_label_width(child)); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, offset); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); } previous_ref_widget = ref_widget; } if (num_rows > 0) XtFree((char*)one_col); } static void align_vcenter( Widget parent, DtbGroupInfo *group_info, Boolean init ) { WidgetList children_list; Widget child, previous_child; DTB_GROUP_TYPES group_type; int num_children = 0, num_columns, num_rows, cell_width, cell_height, group_width, group_height, offset, gridline, i, j; if (!parent || !group_info) return; /* * Get children list */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return; get_group_cell_size(parent, group_info, &cell_width, &cell_height); get_group_row_col(parent, group_info, &num_rows, &num_columns); offset = group_info->hoffset; group_type = group_info->group_type; if (group_type == DTB_GROUP_ROWSCOLUMNS) { group_width = (num_columns * cell_width) + ((num_columns-1) * offset); } for (i = 0; i < num_columns; i++) { if (group_type == DTB_GROUP_ROWSCOLUMNS) gridline = (((i * (cell_width + offset)) + (cell_width/2)) * 100)/group_width; else gridline = 50; for (j = 0; j < num_rows; j++) { Arg args[12]; int n = 0; Dimension width = 0; child = get_group_child(parent, group_info, i, j); if (!child) continue; XtVaGetValues(child, XmNwidth, &width, NULL); if (init) { int offset = 0; if (!XtIsSubclass(child, compositeWidgetClass)) { offset = (cell_width - (int)width)/2; if (group_type == DTB_GROUP_ROWSCOLUMNS) offset += (i * (cell_width + group_info->hoffset)); } XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, offset); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; } else { XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, gridline); n++; XtSetArg(args[n], XmNleftOffset, (int)(-(width/2))); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; } XtSetValues(child, args, n); } } } static void align_top( Widget parent, DtbGroupInfo *group_info ) { WidgetList children_list; Widget previous_child = NULL, child, cur_child; int num_children = 0, num_columns, num_rows, cell_width, cell_height, i, j; if (!parent || !group_info) return; /* * Get children list */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return; get_group_cell_size(parent, group_info, &cell_width, &cell_height); get_group_row_col(parent, group_info, &num_rows, &num_columns); for (j = 0; j < num_rows; j++) { for (i = 0; i < num_columns; i++) { Arg args[12]; int n = 0; child = get_group_child(parent, group_info, i, j); if (!child) continue; if ((i == 0) && (j == 0)) { XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, 0); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); continue; } if (i == 0) { previous_child = get_group_child(parent, group_info, 0, j-1); if (previous_child) { DTB_GROUP_TYPES group_type = group_info->group_type; int offset = group_info->voffset; if (group_type == DTB_GROUP_ROWSCOLUMNS) { Dimension height = 0; XtVaGetValues(previous_child, XmNheight, &height, NULL); offset += (cell_height - (int)(height)); } XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, previous_child); n++; XtSetArg(args[n], XmNtopOffset, offset); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); } continue; } previous_child = get_group_child(parent, group_info, i-1, j); if (previous_child) { XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, previous_child); n++; XtSetArg(args[n], XmNtopOffset, 0); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); } } } } static void align_bottom( Widget parent, DtbGroupInfo *group_info ) { WidgetList children_list; Widget child, previous_child; DTB_GROUP_TYPES group_type; int num_children = 0, num_columns, num_rows, cell_height, cell_width, offset, i, j; if (!parent || !group_info) return; /* * Get children list */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return; get_group_cell_size(parent, group_info, &cell_width, &cell_height); get_group_row_col(parent, group_info, &num_rows, &num_columns); for (j = 0; j < num_rows; j++) { for (i = 0; i < num_columns; i++) { Arg args[12]; int n = 0; child = get_group_child(parent, group_info, i, j); if (!child) continue; if ((i == 0) && (j == 0)) { Dimension height = 0; XtVaGetValues(child, XmNheight, &height, NULL); offset = cell_height - height; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, offset); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); continue; } if (i == 0) { previous_child = get_group_child(parent, group_info, 0, j-1); if (previous_child) { Dimension height = 0; XtVaGetValues(child, XmNheight, &height, NULL); offset = group_info->voffset; if (group_info->group_type == DTB_GROUP_ROWSCOLUMNS) offset += (cell_height - height); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, previous_child); n++; XtSetArg(args[n], XmNtopOffset, offset); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); } continue; } previous_child = get_group_child(parent, group_info, i-1, j); if (child && previous_child) { XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, previous_child); n++; XtSetArg(args[n], XmNbottomOffset, 0); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++; XtSetValues(child, args, n); } } } } static void align_hcenter( Widget parent, DtbGroupInfo *group_info, Boolean init ) { WidgetList children_list = NULL; Widget child, previous_child; DTB_GROUP_TYPES group_type; int num_children = 0, num_columns, num_rows, cell_width, cell_height, group_width, group_height, offset, gridline, i, j; if (!parent || !group_info) return; /* * Get children list */ XtVaGetValues(parent, XmNnumChildren, &num_children, XmNchildren, &children_list, NULL); if (num_children <= 0) return; group_type = group_info->group_type; get_group_cell_size(parent, group_info, &cell_width, &cell_height); get_group_row_col(parent, group_info, &num_rows, &num_columns); offset = group_info->voffset; if (group_type == DTB_GROUP_ROWSCOLUMNS) { group_height = (num_rows * cell_height) + ((num_rows-1) * offset); } for (j = 0; j < num_rows; j++) { if (group_type == DTB_GROUP_ROWSCOLUMNS) gridline = (((j * (cell_height + offset)) + (cell_height/2)) * 100)/group_height; else gridline = 50; for (i = 0; i < num_columns; i++) { Arg args[12]; int n = 0; Dimension height = 0; child = get_group_child(parent, group_info, i, j); if (!child) continue; XtVaGetValues(child, XmNheight, &height, NULL); if (init) { int init_offset = 0; if (!XtIsSubclass(child, compositeWidgetClass)) { init_offset = (cell_height - (int)height)/2; if (group_type == DTB_GROUP_ROWSCOLUMNS) init_offset += (j * (cell_height + group_info->voffset)); } XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, init_offset); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; } else { XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNtopPosition, gridline); n++; XtSetArg(args[n], XmNtopOffset, (int)(-(height/2))); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; } XtSetValues(child, args, n); } } } /************************************************************************* * ** * Determine the directory the executable for this process was ** * loaded from. This is used find data files associated with the ** * executable. ** * ** *************************************************************************/ /* * Returns the directory that the executable for this process was loaded * from. */ String dtb_get_exe_dir(void) { return dtb_exe_dir; } /* * Determines the directory the executable for this process was loaded from. */ static int determine_exe_dir( char *argv0, char *buf, int bufSize ) { Boolean foundDir= False; if ((buf == NULL) || (bufSize < 1)) { return -1; } if (determine_exe_dir_from_argv(argv0, buf, bufSize) >= 0) { foundDir = True; } if (!foundDir) { if (determine_exe_dir_from_path(argv0, buf, bufSize) >= 0) { foundDir = True; } } /* * Convert relative path to absolute, so that directory changes will * not affect us. */ if (foundDir && (buf[0] != '/')) { char cwd[MAXPATHLEN+1]; char *env_pwd = NULL; char *path_prefix = NULL; char abs_exe_dir[MAXPATHLEN+1]; if (getcwd(cwd, MAXPATHLEN+1) != NULL) { path_prefix = cwd; } else { env_pwd = getenv("PWD"); if (env_pwd != NULL) { path_prefix = env_pwd; } } if (path_prefix != NULL) { strcpy(abs_exe_dir, path_prefix); if (strcmp(buf, ".") != 0) { strcat(abs_exe_dir, "/"); strcat(abs_exe_dir, buf); } strcpy(buf, abs_exe_dir); } } return foundDir? 0:-1; } /* * Looks for absolute path in arv[0]. */ static int determine_exe_dir_from_argv( char *argv0, char *buf, int bufSize ) { int i= 0; Boolean foundit= False; for (i= strlen(argv0)-1; (i >= 0) && (argv0[i] != '/'); --i) { } if (i >= 0) { int maxStringSize= min(i, bufSize); strncpy(buf, argv0, maxStringSize); buf[min(maxStringSize, bufSize-1)]= 0; foundit = True; } return foundit? 0:-1; } /* * Assumes: bufSize > 0 */ static int determine_exe_dir_from_path ( char *argv0, char *buf, int bufSize ) { Boolean foundDir= False; Boolean moreDirs= True; char *szExeName= argv0; int iExeNameLen= strlen(szExeName); char *szTemp= NULL; char szPathVar[MAXPATHLEN+1]; int iPathVarLen= 0; char szCurrentPath[MAXPATHLEN+1]; int iCurrentPathLen= 0; int iCurrentPathStart= 0; int i = 0; uid_t euid= geteuid(); uid_t egid= getegid(); szTemp= getenv("PATH"); if (szTemp == NULL) { moreDirs= False; } else { strncpy(szPathVar, szTemp, MAXPATHLEN); szPathVar[MAXPATHLEN]= 0; iPathVarLen= strlen(szPathVar); } while ((!foundDir) && (moreDirs)) { /* find the current directory name */ for (i= iCurrentPathStart; (i < iPathVarLen) && (szPathVar[i] != ':'); ) { ++i; } iCurrentPathLen= i - iCurrentPathStart; if ((iCurrentPathLen + iExeNameLen + 2) > MAXPATHLEN) { iCurrentPathLen= MAXPATHLEN - (iExeNameLen + 2); } /* create a possible path to the executable */ strncpy(szCurrentPath, &szPathVar[iCurrentPathStart], iCurrentPathLen); szCurrentPath[iCurrentPathLen]= 0; strcat(szCurrentPath, "/"); strcat(szCurrentPath, szExeName); /* see if the executable exists (and we can execute it) */ if (path_is_executable(szCurrentPath, euid, egid)) { foundDir= True; } /* skip past the current directory name */ if (!foundDir) { iCurrentPathStart+= iCurrentPathLen; while ( (iCurrentPathStart < iPathVarLen) && (szPathVar[iCurrentPathStart] != ':') ) { ++iCurrentPathStart; /* find : */ } if (iCurrentPathStart < iPathVarLen) { ++iCurrentPathStart; /* skip : */ } if (iCurrentPathStart >= iPathVarLen) { moreDirs= False; } } } /* while !foundDir */ if (foundDir) { szCurrentPath[iCurrentPathLen]= 0; strncpy(buf, szCurrentPath, bufSize); buf[bufSize-1]= 0; } return foundDir? 0:-1; } /* determine_exe_dir_from_path */ /* * returns False is path does not exist or is not executable */ static Boolean path_is_executable( char *path, uid_t euid, gid_t egid ) { Boolean bExecutable= False; struct stat sStat; if (stat(path, &sStat) == 0) { Boolean bDetermined= False; if (!bDetermined) { if (!S_ISREG(sStat.st_mode)) { /* not a regular file */ bDetermined= True; bExecutable= False; } } if (!bDetermined) { if ( (euid == 0) && ( ((sStat.st_mode & S_IXOTH) != 0) || ((sStat.st_mode & S_IXGRP) != 0) || ((sStat.st_mode & S_IXUSR) != 0) ) ) { bDetermined= True; bExecutable= True; } } if (!bDetermined) { if ( (((sStat.st_mode & S_IXOTH) != 0) ) || (((sStat.st_mode & S_IXGRP) != 0) && (sStat.st_gid == egid)) || (((sStat.st_mode & S_IXUSR) != 0) && (sStat.st_gid == euid)) ) { bDetermined= True; bExecutable= True; } } } /* if stat */ return bExecutable; } /* path is executable */ /* * dtb_set_tt_msg_quitCB() */ void dtb_set_tt_msg_quitCB( DtbTTMsgHandlerCB msg_quitCB ) { dtb_tt_msg_quitCB = msg_quitCB; } /* * dtb_get_tt_msg_quitCB() */ static DtbTTMsgHandlerCB dtb_get_tt_msg_quitCB() { return(dtb_tt_msg_quitCB); } /* * dtb_tt_msg_quit() * Handle the ToolTalk Desktop "Quit" message. * Call Application-defined callback if it exists. */ static Boolean dtb_tt_msg_quit( Tt_message msg ) { DtbTTMsgHandlerCB msg_quitCB = NULL; Boolean handled = True; msg_quitCB = dtb_get_tt_msg_quitCB(); if (msg_quitCB) handled = msg_quitCB(msg, (void *)NULL); return handled; } /* * dtb_set_tt_msg_do_commandCB() */ void dtb_set_tt_msg_do_commandCB( DtbTTMsgHandlerCB msg_do_commandCB ) { dtb_tt_msg_do_commandCB = msg_do_commandCB; } /* * dtb_get_tt_msg_do_commandCB() */ static DtbTTMsgHandlerCB dtb_get_tt_msg_do_commandCB() { return(dtb_tt_msg_do_commandCB); } /* * dtb_tt_msg_do_command() * Handle the ToolTalk Desktop "Do Command" message. * Call Application-defined callback if it exists. */ static Boolean dtb_tt_msg_do_command( Tt_message msg ) { DtbTTMsgHandlerCB msg_do_commandCB = NULL; Boolean handled = True; msg_do_commandCB = dtb_get_tt_msg_do_commandCB(); if (msg_do_commandCB) handled = msg_do_commandCB(msg, (void *)NULL); return handled; } /* * dtb_set_tt_msg_get_statusCB() */ void dtb_set_tt_msg_get_statusCB( DtbTTMsgHandlerCB msg_get_statusCB ) { dtb_tt_msg_get_statusCB = msg_get_statusCB; } /* * dtb_get_tt_msg_get_statusCB() */ static DtbTTMsgHandlerCB dtb_get_tt_msg_get_statusCB() { return(dtb_tt_msg_get_statusCB); } /* * dtb_tt_msg_get_status() * Handle the ToolTalk Desktop "Get Status" message. * Call Application-defined callback if it exists. */ static Boolean dtb_tt_msg_get_status( Tt_message msg ) { DtbTTMsgHandlerCB msg_get_statusCB = NULL; Boolean handled = True; msg_get_statusCB = dtb_get_tt_msg_get_statusCB(); if (msg_get_statusCB) handled = msg_get_statusCB(msg, (void *)NULL); return handled; } /* * dtb_set_tt_msg_pause_resumeCB() */ void dtb_set_tt_msg_pause_resumeCB( DtbTTMsgHandlerCB msg_pause_resumeCB ) { dtb_tt_msg_pause_resumeCB = msg_pause_resumeCB; } /* * dtb_get_tt_msg_pause_resumeCB() */ static DtbTTMsgHandlerCB dtb_get_tt_msg_pause_resumeCB() { return(dtb_tt_msg_pause_resumeCB); } /* * dtb_tt_msg_pause_resume() * Handle the ToolTalk Desktop "Pause/Resume" messages. * Call Application-defined callback if it exists. */ static Boolean dtb_tt_msg_pause_resume( Tt_message msg, Boolean sensitive ) { DtbTTMsgHandlerCB msg_pause_resumeCB = NULL; Boolean handled = True; msg_pause_resumeCB = dtb_get_tt_msg_pause_resumeCB(); if (msg_pause_resumeCB) handled = msg_pause_resumeCB(msg, (void *)sensitive); return handled; } /* * dtb_tt_contractCB() * Receives any ToolTalk Desktop messages sent to application * and dispatches them to the appropriate Application-defined callbacks * if they exist. */ Tt_message dtb_tt_contractCB( Tt_message msg, void *client_data, Tt_message contract ) { char *op_string; Tttk_op op; Boolean sensitive = True; if (contract != 0) { tttk_message_fail( msg, TT_DESKTOP_ENOMSG, 0, 1 ); return 0; } op_string = tt_message_op(msg); op = tttk_string_op(op_string); tt_free(op_string); switch(op) { case TTDT_QUIT: if (dtb_tt_msg_quit(msg) == True) return 0; break; case TTDT_GET_STATUS: if (dtb_tt_msg_get_status(msg) == True) return 0; break; case TTDT_PAUSE: sensitive = False; case TTDT_RESUME: if (dtb_tt_msg_pause_resume(msg, sensitive) == True) return 0; break; case TTDT_DO_COMMAND: if (dtb_tt_msg_do_command(msg) == True) return 0; break; } return msg; } /* * dtb_tt_close() * Close ToolTalk Connection */ void dtb_tt_close() { ttdt_close(NULL, NULL, True); } /* ** dtb_call_help_callback() ** Utility routine to call the help callbacks on a target widget. This ** is predominantly used to display help data on a dialog by having this ** function as the activate callback on the dialog's help button. */ void dtb_call_help_callback( Widget widget, XtPointer clientData, XtPointer callData ) { Widget target = (Widget)clientData; XtCallCallbacks(target,XmNhelpCallback,(XtPointer)NULL); } static void dtb_drag_button1_motion_handler( Widget dragInitiator, XtPointer clientData, XEvent *event ); static int dtb_drag_start( DtbDragSite dragSite, XEvent *event ); static void dtb_drag_convertCB( Widget dragContext, XtPointer clientData, XtPointer callData ); static void dtb_drag_to_rootCB( Widget dragContext, XtPointer clientData, XtPointer callData ); static void dtb_drag_finishCB( Widget dragContext, XtPointer clientData, XtPointer callData ); static int dtb_drag_terminate(DtbDragSite dragSite); /* * Registers a popup menu to be brought by button three on the parent */ int dtb_popup_menu_register(Widget popupMenu, Widget parent) { static XtTranslations popupMenuTrans = NULL; static XtActionsRec menuActions[] = { {"DtbPopupMenu", (XtActionProc)dtb_popup_menu } }; int i = 0; Boolean foundEntry = False; if (popupMenuTrans == NULL) { XtAppContext appContext = XtWidgetToApplicationContext(dtb_get_toplevel_widget()); XtAppAddActions(appContext, menuActions, XtNumber(menuActions)); popupMenuTrans = XtParseTranslationTable( ": DtbPopupMenu()"); } XtOverrideTranslations(parent, popupMenuTrans); /* * Save the reference from this widget to the menu */ /* see if an entry already exists */ for (i = 0; i < numPopupMenus; ++i) { if ( (popupMenus[i].widget == parent) || (popupMenus[i].menu == popupMenu) ) { foundEntry = True; break; } } /* look for an empty slot */ if (!foundEntry) { /* look for an empty slot */ for (i = 0; i < numPopupMenus; ++i) { if (popupMenus[i].widget == NULL) { foundEntry = True; break; } } } /* make a new slot, if necessary */ if (!foundEntry) { /* It's not in the list - add it */ DtbMenuRef newPopupMenus = (DtbMenuRef) realloc(popupMenus, sizeof(DtbMenuRefRec)*(numPopupMenus+1)); if (newPopupMenus != NULL) { popupMenus = newPopupMenus; ++numPopupMenus; i = numPopupMenus-1; foundEntry = True; } } /* we have a slot; fill it in */ if (foundEntry) { popupMenus[i].widget = parent; popupMenus[i].menu = popupMenu; XtAddCallback(popupMenus[i].widget, XmNdestroyCallback, dtb_popup_menu_destroyCB, (XtPointer)NULL); XtAddCallback(popupMenus[i].menu, XmNdestroyCallback, dtb_popup_menu_destroyCB, (XtPointer)NULL); } return 0; } static void dtb_popup_menu( Widget widget, XEvent *event, String *params, Cardinal *num_params ) { int i = 0; Widget menu = NULL; if (event->type == ButtonPress) { for (i = 0 ; i < numPopupMenus; ++i) { if (popupMenus[i].widget == widget) { menu = popupMenus[i].menu; } } } if (menu != NULL) { XmMenuPosition(menu, (XButtonPressedEvent*)event); XtManageChild(menu); } } /* * This keeps the list of popup menus up-to-date, if widgets are destroyed */ static void dtb_popup_menu_destroyCB( Widget widget, XtPointer clientData, XtPointer callData ) { int i = 0; for (i = 0; i < numPopupMenus; ++i) { if ( (popupMenus[i].widget == widget) || (popupMenus[i].menu == widget) ) { popupMenus[i].widget = NULL; popupMenus[i].menu = NULL; break; } } } /* * Returns non-negative if successful. */ int dtb_drag_site_register( Widget widget, DtbDndDragCallback callback, DtDndProtocol protocol, unsigned char operations, Boolean bufferIsText, Boolean allowDropOnRootWindow, Pixmap cursor, Pixmap cursorMask, DtbDragSiteHandle *dragSiteHandleOut ) { DtbDragSite dragSite = (DtbDragSite)XtCalloc(1,sizeof(DtbDragSiteRec)); Widget sourceIcon = NULL; if (dragSite != NULL) { dragSite->widget = widget; dragSite->protocol = protocol; dragSite->operations = operations; dragSite->bufferIsText = bufferIsText; dragSite->allowDropOnRootWindow = allowDropOnRootWindow; if ((cursor != NULL) && (cursorMask != NULL)) { dragSite->sourceIcon = DtDndCreateSourceIcon(widget, cursor, cursorMask); } dragSite->callback = callback; dragSite->convertCBRec[0].callback = dtb_drag_convertCB; dragSite->dragToRootCBRec[0].callback = dtb_drag_to_rootCB; dragSite->dragFinishCBRec[0].callback = dtb_drag_finishCB; XtAddEventHandler(widget, Button1MotionMask, False, (XtEventHandler)dtb_drag_button1_motion_handler, (XtPointer)dragSite); } /* * Pass back a handle, so that this can be freed, later. Unregistering * drag sites is not currently implemented, but this gives the ability * to provide this functionality in the future. */ if (dragSiteHandleOut != NULL) { *dragSiteHandleOut = (DtbDragSiteHandle)dragSite; } return 0; } int dtb_drop_site_register( Widget widget, DtbDndDropCallback callback, DtDndProtocol protocols, unsigned char operations, Boolean dropsOnChildren, Boolean preservePreviousRegistration, DtbDropSiteHandle *dropSiteHandleOut ) { DtbDropSite dropSite = (DtbDropSite)NULL; if ( (callback != NULL) && ((dropSite = (DtbDropSite)XtCalloc(1,sizeof(DtbDropSiteRec))) != NULL) ) { DtbDndDropRegisterInfoRec regInfo; /* initialize the data */ dropSite->widget = widget; dropSite->callback = callback; dropSite->protocols = protocols; dropSite->operations = operations; dropSite->dropsOnChildren = dropsOnChildren; dropSite->preservePreviousRegistration = preservePreviousRegistration; dropSite->animateCBRec[0].callback = dtb_drop_animateCB; dropSite->animateCBRec[0].closure = (XtPointer)dropSite; dropSite->transferCBRec[0].callback = dtb_drop_transferCB; dropSite->transferCBRec[0].closure = (XtPointer)dropSite; /* Let the client modify the drop site initialization */ regInfo.protocols = dropSite->protocols; regInfo.operations = dropSite->operations; regInfo.textIsBuffer = dropSite->textIsBuffer; regInfo.preservePreviousRegistration = dropSite->preservePreviousRegistration; regInfo.respondToDropsOnChildren = dropSite->dropsOnChildren; dropSite->callback(widget, DTB_DND_REGISTER, ®Info, NULL, NULL); /* actually register it! */ DtDndVaDropRegister( widget, regInfo.protocols, regInfo.operations, dropSite->transferCBRec, DtNregisterChildren, regInfo.respondToDropsOnChildren, DtNtextIsBuffer, regInfo.textIsBuffer, #ifdef DtNpreserveRegistration DtNpreserveRegistration, regInfo.preservePreviousRegistration, #endif DtNdropAnimateCallback, dropSite->animateCBRec, NULL); } if (dropSiteHandleOut != NULL) { *dropSiteHandleOut = (DtbDropSiteHandle)dropSite; } return ((dropSite == NULL)? -1:0); } static int dtb_drag_terminate(DtbDragSite dragSite) { dragInProgress = False; dragInitialX = -1; dragInitialY = -1; dragSite->convertCBRec[0].closure = NULL; dragSite->dragToRootCBRec[0].closure = NULL; dragSite->dragFinishCBRec[0].closure = NULL; return 0; } /* * dragMotionHandler * * Determine if the pointer has moved beyond the drag threshold while button 1 * was being held down. */ static void dtb_drag_button1_motion_handler( Widget dragInitiator, XtPointer clientData, XEvent *event ) { int diffX, diffY; DtbDragSite dragSite = (DtbDragSite)clientData; if (!dragInProgress) { /* * If the drag is just starting, set initial button down coords */ if (dragInitialX == -1 && dragInitialY == -1) { dragInitialX = event->xmotion.x; dragInitialY = event->xmotion.y; } /* * Find out how far pointer has moved since button press */ diffX = dragInitialX - event->xmotion.x; diffY = dragInitialY - event->xmotion.y; if ((ABS(diffX) >= DRAG_THRESHOLD) || (ABS(diffY) >= DRAG_THRESHOLD)) { dtb_drag_start(dragSite, event); dragInitialX = -1; dragInitialY = -1; } } } static int dtb_drag_start(DtbDragSite dragSite, XEvent *event) { DtbDndDragStartInfoRec dragStart; Arg args[3]; int n = 0; dragInProgress = True; dragSite->convertCBRec[0].closure = (XtPointer)dragSite; dragSite->dragToRootCBRec[0].closure = (XtPointer)dragSite; dragSite->dragFinishCBRec[0].closure = (XtPointer)dragSite; /* * Call the client callback to update values for drag start */ memset((void*)&dragStart, 0, sizeof(DtbDndDragStartInfoRec)); dragStart.protocol= dragSite->protocol; dragStart.operations = dragSite->operations; dragStart.cursor = dragSite->sourceIcon; dragStart.bufferIsText = dragSite->bufferIsText; dragStart.allowDropOnRootWindow = dragSite->allowDropOnRootWindow; dragStart.numItems = 1; if (dragSite->callback != NULL) { dragSite->callback(DTB_DND_DRAG_START, &dragStart, NULL,NULL,NULL,NULL); } n = 0; if (dragStart.cursor != NULL) { XtSetArg(args[n], DtNsourceIcon, dragStart.cursor); ++n; } if ( (dragStart.bufferIsText) && (dragStart.protocol == DtDND_BUFFER_TRANSFER) ) { XtSetArg(args[n], DtNbufferIsText, True); ++n; } if (dragStart.allowDropOnRootWindow) { XtSetArg(args[n], DtNdropOnRootCallback, (XtPointer)dragSite->dragToRootCBRec); ++n; } if (DtDndDragStart(dragSite->widget, event, dragStart.protocol, dragStart.numItems, dragStart.operations, dragSite->convertCBRec, dragSite->dragFinishCBRec, args, n) == NULL) { /* drag start failed */ dtb_drag_terminate(dragSite); return -1; } return 0; } static void dtb_drag_convertCB( Widget dragContext, XtPointer clientData, XtPointer callData ) { DtbDragSite dragSite = (DtbDragSite)clientData; DtDndConvertCallback convert = (DtDndConvertCallback)callData; DtDndContext *dragData = convert->dragData; int i = 0; switch (convert->reason) { case DtCR_DND_CONVERT_DATA: for (i = 0; i < dragData->numItems; ++i) { switch (dragData->protocol) { case DtDND_BUFFER_TRANSFER: dragData->data.buffers[i].bp = NULL; dragData->data.buffers[i].size = 0; break; case DtDND_FILENAME_TRANSFER: dragData->data.files[i] = "/etc/passwd"; break; case DtDND_TEXT_TRANSFER: dragData->data.strings[i] = XmStringCreateLocalized("Hello, world!\n"); break; } } dragSite->callback(DTB_DND_CONVERT,NULL,convert,NULL,NULL,NULL); break; case DtCR_DND_CONVERT_DELETE: dragSite->callback(DTB_DND_DELETE,NULL,NULL,NULL,convert,NULL); break; } } static void dtb_drag_to_rootCB( Widget dragContext, XtPointer clientData, XtPointer callData ) { DtbDragSite dragSite = (DtbDragSite)clientData; DtbDndDroppedOnRootWindowInfoRec dropInfo; memset(&dropInfo, 0, sizeof(DtbDndDroppedOnRootWindowInfoRec)); dropInfo.droppedOnRootWindow = True; dragSite->callback(DTB_DND_DROPPED_ON_ROOT_WINDOW, NULL,NULL,&dropInfo,NULL,NULL); } static void dtb_drag_finishCB( Widget dragContext, XtPointer clientData, XtPointer callData ) { DtbDragSite dragSite = (DtbDragSite)clientData; DtDndDragFinishCallback finish = (DtDndDragFinishCallback)callData; dragSite->callback(DTB_DND_FINISH,NULL,NULL,NULL,NULL,finish); dtb_drag_terminate((DtbDragSite)clientData); } void dtb_default_dragCB( DTB_DND_REQUEST request, DtbDndDragStartInfo dragStart, DtDndConvertCallback convert, DtbDndDroppedOnRootWindowInfo dropOnRootWindow, DtDndConvertCallback deleteSource, DtDndDragFinishCallback finish ) { /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/ /*** DTB_USER_CODE_END ^^^ Add C variables and code above ^^^ ***/ switch (request) { case DTB_DND_DRAG_START: /** DTB_USER_CODE_START ** ** The drag will start normally, using the defaults for this ** drag site, and one item to transfer assumed. ** ** To override the default protocol, operations, cursor, or ** number of of items to transfer, add code after this comment. **/ printf("action: dtb_default_dragCB(DTB_DND_DRAG_START)\n"); /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ break; case DTB_DND_CONVERT: /** DTB_USER_CODE_START ** ** Here, the data must be supplied to the dropped-on object. **/ printf("action: dtb_default_dragCB(DTB_DND_CONVERT)\n"); /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ break; case DTB_DND_DELETE: /** DTB_USER_CODE_START ** ** A move has been completed. Add code to delete the source ** object, after this comment. **/ printf("action: dtb_default_dragCB(DTB_DND_DELETE)\n"); /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ break; case DTB_DND_DROPPED_ON_ROOT_WINDOW: /** DTB_USER_CODE_START ** ** The dragged data was dropped on the root window. **/ printf("action: dtb_default_dragCB(DTB_DND_DROPPED_ON_ROOT_WINDOW)\n"); /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ break; case DTB_DND_FINISH: /** DTB_USER_CODE_START ** ** The drag and drop operation has completed (successfully or ** unsuccessfully). Clean up and allocated memory or other ** resources allocated during this drag. **/ printf("action: dtb_default_dragCB(DTB_DND_FINISH)\n"); /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ break; } /*** DTB_USER_CODE_START vvv Add C code below vvv ***/ /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ } /* * NOTE: THE PARAMETERS OF TYPE *Callback ARE NOT CALLBACKS! THEY ARE * STANDARD DATA STRUCTURES. */ void dtb_default_dropCB( Widget widget, DTB_DND_REQUEST request, DtbDndDropRegisterInfo registerInfo, DtDndTransferCallback receiveInfo, DtDndDropAnimateCallback animateInfo ) { /*** DTB_USER_CODE_START vvv Add C variables and code below vvv ***/ /*** DTB_USER_CODE_END ^^^ Add C variables and code above ^^^ ***/ /* * The cases in this switch statement have been written in the order * that these requests will normally be received. */ switch (request) { case DTB_DND_REGISTER: /** DTB_USER_CODE_START ** ** The drag site will be automatically be registered with the ** options chosen in the Application Builder, with default values ** for any implementation-specific options. ** ** To override the options chosen for this drop site, or to ** affect implementation-specific options not available from ** the Application Builder, add code after this comment. **/ printf("action: dtb_default_dropCB(DTB_DND_REGISTER)\n"); /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ break; case DTB_DND_RECEIVE_DATA: /** DTB_USER_CODE_START ** ** The data has been supplied by the dragged-from object. The ** dragged data will be freed after this function returns, so ** any data needed in the future must be copied. **/ printf("action: dtb_default_dropCB(DTB_DND_RECEIVE_DATA)\n"); /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ break; case DTB_DND_ANIMATE: /** DTB_USER_CODE_START ** ** Give visual feedback on the acceptability of the provided ** data. **/ printf("action: dtb_default_dropCB(DTB_DND_ANIMATE)\n"); /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ break; } /*** DTB_USER_CODE_START vvv Add C code below vvv ***/ /*** DTB_USER_CODE_END ^^^ Add C code above ^^^ ***/ } static void dtb_drop_animateCB( Widget dragContext, XtPointer clientData, XtPointer callData ) { DtbDropSite dropSite = (DtbDropSite)clientData; DtDndDropAnimateCallback animateInfo = (DtDndDropAnimateCallback)callData; dropSite->callback( dropSite->widget, DTB_DND_ANIMATE, NULL, NULL, animateInfo); } static void dtb_drop_transferCB( Widget dragContext, XtPointer clientData, XtPointer callData ) { DtbDropSite dropSite = (DtbDropSite)clientData; DtDndTransferCallback transferInfo = (DtDndTransferCallback)callData; dropSite->callback( dropSite->widget, DTB_DND_RECEIVE_DATA, NULL, transferInfo, NULL); }