📄 misc.c
字号:
static const char CVSID[] = "$Id: misc.c,v 1.57.2.1 2003/06/27 07:24:04 edg Exp $";/******************************************************************************** ** misc.c -- Miscelaneous Motif convenience functions ** ** Copyright (C) 1999 Mark Edel ** ** This is free software; you can redistribute it and/or modify it under the ** terms of the GNU General Public License as published by the Free Software ** Foundation; either version 2 of the License, or (at your option) any later ** version. ** ** This software is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ** for more details. ** ** You should have received a copy of the GNU General Public License along with ** software; if not, write to the Free Software Foundation, Inc., 59 Temple ** Place, Suite 330, Boston, MA 02111-1307 USA ** ** Nirvana Text Editor ** July 28, 1992 ** ** Written by Mark Edel ** ********************************************************************************/#ifdef HAVE_CONFIG_H#include "../config.h"#endif#include "misc.h"#include "DialogF.h"#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <ctype.h>#include <stdio.h>#include <time.h>#ifdef __unix__#include <sys/time.h>#endif#ifdef VMS#include <types.h>#include <unixio.h>#include <file.h>#endif /*VMS*/#include <X11/Intrinsic.h>#include <X11/Xatom.h>#include <X11/keysym.h>#include <X11/keysymdef.h>#include <Xm/Xm.h>#include <Xm/Label.h>#include <Xm/LabelG.h>#include <Xm/ToggleB.h>#include <Xm/PushB.h>#include <Xm/Separator.h>#include <Xm/RowColumn.h>#include <Xm/CascadeB.h>#include <Xm/AtomMgr.h>#include <Xm/Protocols.h>#include <Xm/Text.h>#include <Xm/MessageB.h>#include <Xm/DialogS.h>#include <Xm/SelectioB.h>#include <Xm/Form.h>#include <Xm/FileSB.h>#include <Xm/ScrolledW.h>#include <Xm/PrimitiveP.h>#ifdef HAVE_DEBUG_H#include "../debug.h"#endif/* structure for passing history-recall data to callbacks */typedef struct { char ***list; int *nItems; int index;} histInfo;typedef Widget (*MotifDialogCreationCall)(Widget, String, ArgList, Cardinal);/* Maximum size of a history-recall list. Typically never invoked, since user must first make this many entries in the text field, limited for safety, to the maximum reasonable number of times user can hit up-arrow before carpal tunnel syndrome sets in */#define HISTORY_LIST_TRIM_TO 1000#define HISTORY_LIST_MAX 2000/* flags to enable/disable delete key remapping and pointer centered dialogs */static int RemapDeleteEnabled = True;static int PointerCenteredDialogsEnabled = False;/* bitmap and mask for waiting (wrist-watch) cursor */#define watch_x_hot 7#define watch_y_hot 7#define watch_width 16#define watch_height 16static unsigned char watch_bits[] = { 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0x10, 0x08, 0x08, 0x11, 0x04, 0x21, 0x04, 0x21, 0xe4, 0x21, 0x04, 0x20, 0x08, 0x10, 0x10, 0x08, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07};#define watch_mask_width 16#define watch_mask_height 16static unsigned char watch_mask_bits[] = { 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f};static void addMnemonicGrabs(Widget addTo, Widget w, int unmodified);static void mnemonicCB(Widget w, XtPointer callData, XKeyEvent *event);static void findAndActivateMnemonic(Widget w, unsigned int keycode);static void addAccelGrabs(Widget topWidget, Widget w);static void addAccelGrab(Widget topWidget, Widget w);static int parseAccelString(Display *display, const char *string, KeySym *keysym, unsigned int *modifiers);static void lockCB(Widget w, XtPointer callData, XEvent *event, Boolean *continueDispatch);static int findAndActivateAccel(Widget w, unsigned int keyCode, unsigned int modifiers, XEvent *event);static void removeWhiteSpace(char *string);static int stripCaseCmp(const char *str1, const char *str2);static void warnHandlerCB(String message);static void passwdCB(Widget w, char * passTxt, XmTextVerifyCallbackStruct *txtVerStr);static void histDestroyCB(Widget w, XtPointer clientData, XtPointer callData);static void histArrowKeyEH(Widget w, XtPointer callData, XEvent *event, Boolean *continueDispatch);static ArgList addParentVisArgs(Widget parent, ArgList arglist, Cardinal *argcount);static Widget addParentVisArgsAndCall(MotifDialogCreationCall callRoutine, Widget parent, char *name, ArgList arglist, Cardinal argcount);static void scrollDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);static void scrollUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);static void pageDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);static void pageUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);/*** Set up closeCB to be called when the user selects close from the** window menu. The close menu item usually activates f.kill which** sends a WM_DELETE_WINDOW protocol request for the window.*/void AddMotifCloseCallback(Widget shell, XtCallbackProc closeCB, void *arg){ static Atom wmpAtom, dwAtom = 0; Display *display = XtDisplay(shell); /* deactivate the built in delete response of killing the application */ XtVaSetValues(shell, XmNdeleteResponse, XmDO_NOTHING, NULL); /* add a delete window protocol callback instead */ if (dwAtom == 0) { wmpAtom = XmInternAtom(display, "WM_PROTOCOLS", FALSE); dwAtom = XmInternAtom(display, "WM_DELETE_WINDOW", FALSE); } XmAddProtocolCallback(shell, wmpAtom, dwAtom, closeCB, arg);}/*** Motif still generates spurious passive grab warnings on both IBM and SGI** This routine suppresses them.** (amai, 20011121:)** And triggers an annoying message on DEC systems on alpha ->** See Xt sources, xc/lib/Xt/Error.c:DefaultMsg()):** actually for some obscure reasons they check for XtError/Warning** handlers being installed when running as a root process!** Since this handler doesn't help on non-effected systems we should only** use it if necessary.*/void SuppressPassiveGrabWarnings(void){#if !defined(__alpha) && !defined(__EMX__) XtSetWarningHandler(warnHandlerCB);#endif}/*** This routine kludges around the problem of backspace not being mapped** correctly when Motif is used between a server with a delete key in** the traditional typewriter backspace position and a client that** expects a backspace key in that position. Though there are three** distinct levels of key re-mapping in effect when a user is running** a Motif application, none of these is really appropriate or effective** for eliminating the delete v.s. backspace problem. Our solution is,** sadly, to eliminate the forward delete functionality of the delete key** in favor of backwards delete for both keys. So as not to prevent the** user or the application from applying other translation table re-mapping,** we apply re-map the key as a post-processing step, applied after widget** creation. As a result, the re-mapping necessarily becomes embedded** throughout an application (wherever text widgets are created), and** within library routines, including the Nirvana utility library. To** make this remapping optional, the SetDeleteRemap function provides a** way for an application to turn this functionality on and off. It is** recommended that applications that use this routine provide an** application resource called remapDeleteKey so savvy users can get** their forward delete functionality back.*/void RemapDeleteKey(Widget w){ static XtTranslations table = NULL; static char *translations = "~Shift~Ctrl~Meta~Alt<Key>osfDelete: delete-previous-character()\n"; if (RemapDeleteEnabled) { if (table == NULL) table = XtParseTranslationTable(translations); XtOverrideTranslations(w, table); }}void SetDeleteRemap(int state){ RemapDeleteEnabled = state;}/* ** The routine adds the passed in top-level Widget's window to our** window group. On the first call a dummy unmapped window will** be created to be our leader. This must not be called before the** Widget has be realized and should be called before the window is** mapped.*/void SetWindowGroup(Widget shell) { static int firstTime = True; static Window groupLeader; Display *display = XtDisplay(shell); XWMHints *wmHints; if (firstTime) { /* Create a dummy window to be the group leader for our windows */ String name, class; XClassHint *classHint; groupLeader = XCreateSimpleWindow(display, RootWindow(display, DefaultScreen(display)), 1, 1, 1, 1, 0, 0, 0); /* Set it's class hint so it will be identified correctly by the window manager */ XtGetApplicationNameAndClass(display, &name, &class); classHint = XAllocClassHint(); classHint->res_name = name; classHint->res_class = class; XSetClassHint(display, groupLeader, classHint); XFree(classHint); firstTime = False; } /* Set the window group hint for this shell's window */ wmHints = XGetWMHints(display, XtWindow(shell)); wmHints->window_group = groupLeader; wmHints->flags |= WindowGroupHint; XSetWMHints(display, XtWindow(shell), wmHints); XFree(wmHints);}/*** This routine resolves a window manager protocol incompatibility between** the X toolkit and several popular window managers. Using this in place** of XtRealizeWidget will realize the window in a way which allows the** affected window managers to apply their own placement strategy to the** window, as opposed to forcing the window to a specific location.**** One of the hints in the WM_NORMAL_HINTS protocol, PPlacement, gets set by** the X toolkit (probably part of the Core or Shell widget) when a shell** widget is realized to the value stored in the XmNx and XmNy resources of the** Core widget. While callers can set these values, there is no "unset" value** for these resources. On systems which are more Motif aware, a PPosition** hint of 0,0, which is the default for XmNx and XmNy, is interpreted as,** "place this as if no hints were specified". Unfortunately the fvwm family** of window managers, which are now some of the most popular, interpret this** as "place this window at (0,0)". This routine intervenes between the** realizing and the mapping of the window to remove the inappropriate** PPlacement hint.*/ void RealizeWithoutForcingPosition(Widget shell){ XSizeHints *hints = XAllocSizeHints(); long suppliedHints; Boolean mappedWhenManaged; /* Temporarily set value of XmNmappedWhenManaged to stop the window from popping up right away */ XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged, NULL); XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL); /* Realize the widget in unmapped state */ XtRealizeWidget(shell); /* Get rid of the incorrect WMNormal hint */ if (XGetWMNormalHints(XtDisplay(shell), XtWindow(shell), hints, &suppliedHints)) { hints->flags &= ~PPosition; XSetWMNormalHints(XtDisplay(shell), XtWindow(shell), hints); } XFree(hints); /* Set WindowGroupHint so the NEdit icons can be grouped; this seems to be necessary starting with Gnome 2.0 */ SetWindowGroup(shell); /* Map the widget */ XtMapWidget(shell); /* Restore the value of XmNmappedWhenManaged */ XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged, NULL);}/*** Older X applications and X servers were mostly designed to operate with** visual class PseudoColor, because older displays were at most 8 bits** deep. Modern X servers, however, usually support 24 bit depth and other** color models. Sun (and others?) still sets their default visual to** 8-bit PseudoColor, because some of their X applications don't work** properly with the other color models. The problem with PseudoColor, of** course, is that users run out of colors in the default colormap, and if** they install additional colormaps for individual applications, colors** flash and change weirdly when you change your focus from one application** to another.**** In addition to the poor choice of default, a design flaw in Xt makes it** impossible even for savvy users to specify the XtNvisual resource to** switch to a deeper visual. The problem is that the colormap resource is** processed independently of the visual resource, and usually results in a** colormap for the default visual rather than for the user-selected one.**** This routine should be called before creating a shell widget, to** pre-process the visual, depth, and colormap resources, and return the** proper values for these three resources to be passed to XtAppCreateShell.** Applications which actually require a particular color model (i.e. for** doing color table animation or dynamic color assignment) should not use** this routine.**** Note that a consequence of using the "best" as opposed to the default** visual is that some color resources are still converted with the default** visual (particularly *background), and these must be avoided by widgets** which are allowed to handle any visual.**** Returns True if the best visual is the default, False otherwise.*/Boolean FindBestVisual(Display *display, const char *appName, const char *appClass, Visual **visual, int *depth, Colormap *colormap){ char rsrcName[256], rsrcClass[256], *valueString, *type, *endPtr; XrmValue value; int screen = DefaultScreen(display); int reqDepth = -1; long reqID = -1; /* should hold a 'VisualID' and a '-1' ... */ int reqClass = -1; int installColormap = FALSE; int maxDepth, bestClass, bestVisual, nVis, i, j; XVisualInfo visTemplate, *visList = NULL; static Visual *cachedVisual = NULL; static Colormap cachedColormap; static int cachedDepth = 0; int bestClasses[] = {StaticGray, GrayScale, StaticColor, PseudoColor, DirectColor, TrueColor}; /* If results have already been computed, just return them */ if (cachedVisual != NULL) { *visual = cachedVisual; *depth = cachedDepth; *colormap = cachedColormap; return (*visual == DefaultVisual(display, screen)); } /* Read the visualID and installColormap resources for the application. visualID can be specified either as a number (the visual id as shown by xdpyinfo), as a visual class name, or as Best or Default. */ sprintf(rsrcName,"%s.%s", appName, "visualID"); sprintf(rsrcClass, "%s.%s", appClass, "VisualID");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -