#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "misc.h"
#include "DialogF.h"
#include "nedit_malloc.h"
#include "xdnd.h"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#ifdef __sun
#define _XPG6
#endif
#include <iconv.h>
#include <langinfo.h>
#ifdef __unix__
#include <sys/time.h>
#include <sys/select.h>
#endif
#ifdef __APPLE__
#ifdef __MACH__
#include <sys/select.h>
#endif
#endif
#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>
#include <Xm/TextF.h>
#ifdef HAVE_DEBUG_H
#include "../debug.h"
#endif
Boolean GetWindowDarkTheme(
void);
#ifndef LESSTIF_VERSION
extern void _XmDismissTearOff(Widget w, XtPointer call, XtPointer x);
#endif
typedef struct {
char ***list;
int *nItems;
int index;
} histInfo;
typedef Widget (*MotifDialogCreationCall)(Widget, String, ArgList, Cardinal);
#define HISTORY_LIST_TRIM_TO 1000
#define HISTORY_LIST_MAX 2000
static int RemapDeleteEnabled = True;
static int PointerCenteredDialogsEnabled = False;
#define watch_x_hot
7
#define watch_y_hot
7
#define watch_width
16
#define watch_height
16
static 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
16
static 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 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);
static long queryDesktop(Display *display, Window window, Atom deskTopAtom);
static void warning(
const char* mesg);
static void microsleep(
long usecs);
void AddMotifCloseCallback(Widget shell, XtCallbackProc closeCB,
void *arg)
{
static Atom wmpAtom, dwAtom =
0;
Display *display = XtDisplay(shell);
XtVaSetValues(shell, XmNdeleteResponse, XmDO_NOTHING,
NULL);
if (dwAtom ==
0) {
wmpAtom = XmInternAtom(display,
"WM_PROTOCOLS",
FALSE);
dwAtom = XmInternAtom(display,
"WM_DELETE_WINDOW",
FALSE);
}
XmAddProtocolCallback(shell, wmpAtom, dwAtom, closeCB, arg);
}
void SuppressPassiveGrabWarnings(
void)
{
#if !defined(__alpha) && !defined(
__EMX__)
XtSetWarningHandler(warnHandlerCB);
#endif
}
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;
}
static void setWindowGroup(Widget shell) {
static int firstTime = True;
static Window groupLeader;
Display *display = XtDisplay(shell);
XWMHints *wmHints;
if (firstTime) {
String name, class;
XClassHint *classHint;
groupLeader = XCreateSimpleWindow(display,
RootWindow(display, DefaultScreen(display)),
1,
1,
1,
1,
0,
0,
0);
XtGetApplicationNameAndClass(display, &name, &class);
classHint = XAllocClassHint();
classHint->res_name = name;
classHint->res_class = class;
XSetClassHint(display, groupLeader, classHint);
XFree(classHint);
firstTime = False;
}
wmHints = XGetWMHints(display, XtWindow(shell));
wmHints->window_group = groupLeader;
wmHints->flags |= WindowGroupHint;
XSetWMHints(display, XtWindow(shell), wmHints);
XFree(wmHints);
}
void RemovePPositionHint(Widget shell)
{
XSizeHints *hints = XAllocSizeHints();
long suppliedHints;
if (XGetWMNormalHints(XtDisplay(shell), XtWindow(shell), hints,
&suppliedHints))
{
hints->flags &= ~PPosition;
XSetWMNormalHints(XtDisplay(shell), XtWindow(shell), hints);
}
XFree(hints);
}
void RealizeWithoutForcingPosition(Widget shell)
{
Boolean mappedWhenManaged;
XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged,
NULL);
XtVaSetValues(shell, XmNmappedWhenManaged, False,
NULL);
XtRealizeWidget(shell);
RemovePPositionHint(shell);
setWindowGroup(shell);
XtMapWidget(shell);
XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged,
NULL);
if(GetWindowDarkTheme()) {
SetWindowGtkThemeVariant(XtDisplay(shell), XtWindow(shell),
2);
}
XdndEnable(shell);
}
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;
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 (cachedVisual !=
NULL) {
*visual = cachedVisual;
*depth = cachedDepth;
*colormap = cachedColormap;
return (*visual == DefaultVisual(display, screen));
}
sprintf(rsrcName,
"%s.%s", appName,
"visualID");
sprintf(rsrcClass,
"%s.%s", appClass,
"VisualID");
if (XrmGetResource(XtDatabase(display), rsrcName, rsrcClass, &type,
&value)) {
valueString = value.addr;
reqID = (
int)strtol(valueString, &endPtr,
0);
if (endPtr == valueString) {
reqID = -
1;
if (stripCaseCmp(valueString,
"Default"))
reqID = DefaultVisual(display, screen)->visualid;
else if (stripCaseCmp(valueString,
"StaticGray"))
reqClass = StaticGray;
else if (stripCaseCmp(valueString,
"StaticColor"))
reqClass = StaticColor;
else if (stripCaseCmp(valueString,
"TrueColor"))
reqClass = TrueColor;
else if (stripCaseCmp(valueString,
"GrayScale"))
reqClass = GrayScale;
else if (stripCaseCmp(valueString,
"PseudoColor"))
reqClass = PseudoColor;
else if (stripCaseCmp(valueString,
"DirectColor"))
reqClass = DirectColor;
else if (!stripCaseCmp(valueString,
"Best"))
fprintf(stderr,
"Invalid visualID resource value\n");
}
}
sprintf(rsrcName,
"%s.%s", appName,
"installColormap");
sprintf(rsrcClass,
"%s.%s", appClass,
"InstallColormap");
if (XrmGetResource(XtDatabase(display), rsrcName, rsrcClass, &type,
&value)) {
if (stripCaseCmp(value.addr,
"Yes") || stripCaseCmp(value.addr,
"True"))
installColormap =
TRUE;
}
visTemplate.screen = screen;
if (reqID != -
1) {
visTemplate.visualid = reqID;
visList = XGetVisualInfo(display, VisualScreenMask|VisualIDMask,
&visTemplate, &nVis);
if (visList ==
NULL)
fprintf(stderr,
"VisualID resource value not valid\n");
}
if (visList ==
NULL && reqClass != -
1 && reqDepth != -
1) {
visTemplate.class = reqClass;
visTemplate.depth = reqDepth;
visList = XGetVisualInfo(display,
VisualScreenMask| VisualClassMask | VisualDepthMask,
&visTemplate, &nVis);
if (visList ==
NULL)
fprintf(stderr,
"Visual class/depth combination not available\n");
}
if (visList ==
NULL && reqClass != -
1) {
visTemplate.class = reqClass;
visList = XGetVisualInfo(display, VisualScreenMask|VisualClassMask,
&visTemplate, &nVis);
if (visList ==
NULL)
fprintf(stderr,
"Visual Class from resource \"visualID\" not available\n");
}
if (visList ==
NULL && reqDepth != -
1) {
visTemplate.depth = reqDepth;
visList = XGetVisualInfo(display, VisualScreenMask|VisualDepthMask,
&visTemplate, &nVis);
if (visList ==
NULL)
fprintf(stderr,
"Requested visual depth not available\n");
}
if (visList ==
NULL) {
visList = XGetVisualInfo(display, VisualScreenMask, &visTemplate, &nVis);
if (visList ==
NULL) {
fprintf(stderr,
"Internal Error: no visuals available?\n");
*visual = DefaultVisual(display, screen);
*depth = DefaultDepth(display, screen);
*colormap = DefaultColormap(display, screen);
return True;
}
}
maxDepth =
0;
bestClass =
0;
bestVisual =
0;
for (i=
0; i < nVis; i++) {
if (visList[i].depth >=
32 &&
strstr(ServerVendor(display),
"X.Org") !=
0) {
continue;
}
if (visList[i].depth > maxDepth) {
maxDepth = visList[i].depth;
bestClass =
0;
bestVisual = i;
}
if (visList[i].depth == maxDepth) {
if (visList[i].visual == DefaultVisual(display, screen))
bestVisual = i;
if (visList[bestVisual].visual != DefaultVisual(display, screen)) {
for (j =
0; j < (
int)XtNumber(bestClasses); j++) {
if (visList[i].class == bestClasses[j] && j > bestClass) {
bestClass = j;
bestVisual = i;
}
}
}
}
}
*visual = cachedVisual = visList[bestVisual].visual;
*depth = cachedDepth = visList[bestVisual].depth;
if (*visual == DefaultVisual(display, screen) && !installColormap)
*colormap = cachedColormap = DefaultColormap(display, screen);
else {
*colormap = cachedColormap = XCreateColormap(display,
RootWindow(display, screen), cachedVisual, AllocNone);
XInstallColormap(display, cachedColormap);
}
if (visList !=
NULL) {
XFree(visList);
}
return (*visual == DefaultVisual(display, screen));
}
Widget CreateDialogShell(Widget parent,
char *name,
ArgList arglist, Cardinal argcount)
{
return addParentVisArgsAndCall(XmCreateDialogShell, parent, name, arglist,
argcount);
}
Widget CreatePopupMenu(Widget parent,
char *name, ArgList arglist,
Cardinal argcount)
{
return addParentVisArgsAndCall(XmCreatePopupMenu, parent, name,
arglist, argcount);
}
Widget CreatePulldownMenu(Widget parent,
char *name,
ArgList arglist, Cardinal argcount)
{
return addParentVisArgsAndCall(XmCreatePulldownMenu, parent, name, arglist,
argcount);
}
Widget CreatePromptDialog(Widget parent,
char *name,
ArgList arglist, Cardinal argcount)
{
return addParentVisArgsAndCall(XmCreatePromptDialog, parent, name, arglist,
argcount);
}
Widget CreateSelectionDialog(Widget parent,
char *name,
ArgList arglist, Cardinal argcount)
{
Widget dialog = addParentVisArgsAndCall(XmCreateSelectionDialog, parent, name,
arglist, argcount);
AddMouseWheelSupport(XmSelectionBoxGetChild(dialog, XmDIALOG_LIST));
return dialog;
}
Widget CreateFormDialog(Widget parent,
char *name,
ArgList arglist, Cardinal argcount)
{
return addParentVisArgsAndCall(XmCreateFormDialog, parent, name, arglist,
argcount);
}
Widget CreateFileSelectionDialog(Widget parent,
char *name,
ArgList arglist, Cardinal argcount)
{
Widget dialog = addParentVisArgsAndCall(XmCreateFileSelectionDialog, parent,
name, arglist, argcount);
AddMouseWheelSupport(XmFileSelectionBoxGetChild(dialog, XmDIALOG_LIST));
AddMouseWheelSupport(XmFileSelectionBoxGetChild(dialog, XmDIALOG_DIR_LIST));
return dialog;
}
Widget CreateQuestionDialog(Widget parent,
char *name,
ArgList arglist, Cardinal argcount)
{
return addParentVisArgsAndCall(XmCreateQuestionDialog, parent, name,
arglist, argcount);
}
Widget CreateMessageDialog(Widget parent,
char *name,
ArgList arglist, Cardinal argcount)
{
return addParentVisArgsAndCall(XmCreateMessageDialog, parent, name,
arglist, argcount);
}
Widget CreateErrorDialog(Widget parent,
char *name,
ArgList arglist, Cardinal argcount)
{
return addParentVisArgsAndCall(XmCreateErrorDialog, parent, name, arglist,
argcount);
}
Widget CreateWidget(Widget parent,
const char *name, WidgetClass class,
ArgList arglist, Cardinal argcount)
{
Widget result;
ArgList al = addParentVisArgs(parent, arglist, &argcount);
result = XtCreateWidget(name, class, parent, al, argcount);
NEditFree((
char *)al);
return result;
}
Widget CreateShellWithBestVis(String appName, String appClass,
WidgetClass class, Display *display, ArgList args, Cardinal nArgs)
{
Visual *visual;
int depth;
Colormap colormap;
ArgList al;
Cardinal ac = nArgs;
Widget result;
FindBestVisual(display, appName, appClass, &visual, &depth, &colormap);
al = (ArgList)NEditMalloc(
sizeof(Arg) * (nArgs +
3));
if (nArgs !=
0)
memcpy(al, args,
sizeof(Arg) * nArgs);
XtSetArg(al[ac], XtNvisual, visual); ac++;
XtSetArg(al[ac], XtNdepth, depth); ac++;
XtSetArg(al[ac], XtNcolormap, colormap); ac++;
result = XtAppCreateShell(appName, appClass, class, display, al, ac);
NEditFree((
char *)al);
return result;
}
Widget CreatePopupShellWithBestVis(String shellName, WidgetClass class,
Widget parent, ArgList arglist, Cardinal argcount)
{
Widget result;
ArgList al = addParentVisArgs(parent, arglist, &argcount);
result = XtCreatePopupShell(shellName, class, parent, al, argcount);
NEditFree((
char *)al);
return result;
}
static ArgList addParentVisArgs(Widget parent, ArgList arglist,
Cardinal *argcount)
{
Visual *visual;
int depth;
Colormap colormap;
ArgList al;
Widget parentShell = parent;
while (True) {
if (XtIsShell(parentShell))
break;
if (parentShell ==
NULL) {
fprintf(stderr,
"failed to find shell\n");
exit(
EXIT_FAILURE);
}
parentShell = XtParent(parentShell);
}
XtVaGetValues(parentShell, XtNvisual, &visual, XtNdepth, &depth,
XtNcolormap, &colormap,
NULL);
al = (ArgList)NEditMalloc(
sizeof(Arg) * ((*argcount) +
3));
if ((*argcount) !=
0)
memcpy(al, arglist,
sizeof(Arg) * (*argcount));
XtSetArg(al[*argcount], XtNvisual, visual); (*argcount)++;
XtSetArg(al[*argcount], XtNdepth, depth); (*argcount)++;
XtSetArg(al[*argcount], XtNcolormap, colormap); (*argcount)++;
return al;
}
static Widget addParentVisArgsAndCall(MotifDialogCreationCall createRoutine,
Widget parent,
char *name, ArgList arglist, Cardinal argcount)
{
Widget result;
ArgList al = addParentVisArgs(parent, arglist, &argcount);
result = (*createRoutine)(parent, name, al, argcount);
NEditFree((
char *)al);
return result;
}
void ManageDialogCenteredOnPointer(Widget dialogChild)
{
Widget shell = XtParent(dialogChild);
Window root, child;
unsigned int mask;
unsigned int width, height, borderWidth, depth;
int x, y, winX, winY, maxX, maxY, maxWidth, maxHeight;
Dimension xtWidth, xtHeight;
Boolean mappedWhenManaged;
static const int slop =
25;
XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged,
NULL);
XtVaSetValues(shell, XmNmappedWhenManaged, False,
NULL);
maxWidth = XtScreen(shell)->width - slop;
maxHeight = XtScreen(shell)->height - slop;
XtVaSetValues(shell,
XmNmaxWidth, maxWidth,
XmNmaxHeight, maxHeight,
NULL);
XtManageChild(dialogChild);
XtVaGetValues(shell, XmNwidth, &xtWidth, XmNheight, &xtHeight,
NULL);
if (xtWidth > maxWidth)
XtVaSetValues(shell, XmNwidth, (Dimension) maxWidth,
NULL);
if (xtHeight > maxHeight)
XtVaSetValues(shell, XmNheight, (Dimension) maxHeight,
NULL);
if (PointerCenteredDialogsEnabled) {
XQueryPointer(XtDisplay(shell), XtWindow(shell), &root, &child,
&x, &y, &winX, &winY, &mask);
XGetGeometry(XtDisplay(shell), XtWindow(shell), &root, &winX, &winY,
&width, &height, &borderWidth, &depth);
width +=
2 * borderWidth;
height +=
2 * borderWidth;
x -= width/
2;
y -= height/
2;
maxX = maxWidth - width;
maxY = maxHeight - height;
if (x > maxX) x = maxX;
if (x <
0) x =
0;
if (y > maxY) y = maxY;
if (y <
0) y =
0;
XtVaSetValues(shell, XmNuseAsyncGeometry, True,
NULL);
XtVaSetValues(shell, XmNx, x, XmNy, y,
NULL);
}
XtMapWidget(shell);
XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged,
NULL);
if(GetWindowDarkTheme()) {
SetWindowGtkThemeVariant(XtDisplay(shell), XtWindow(shell),
2);
}
}
void SetPointerCenteredDialogs(
int state)
{
PointerCenteredDialogsEnabled = state;
}
void RaiseDialogWindow(Widget shell)
{
RaiseWindow(XtDisplay(shell), XtWindow(shell), True);
}
void RaiseShellWindow(Widget shell, Boolean focus)
{
RaiseWindow(XtDisplay(shell), XtWindow(shell), focus);
}
void RaiseWindow(Display *display, Window w, Boolean focus)
{
if (focus) {
XWindowAttributes winAttr;
XGetWindowAttributes(display, w, &winAttr);
if (winAttr.map_state == IsViewable)
XSetInputFocus(display, w, RevertToParent, CurrentTime);
}
WmClientMsg(display, w,
"_NET_ACTIVE_WINDOW",
0,
0,
0,
0,
0);
XMapRaised(display, w);
}
void AddDialogMnemonicHandler(Widget dialog,
int unmodifiedToo)
{
XtAddEventHandler(dialog, KeyPressMask, False,
(XtEventHandler)mnemonicCB, (XtPointer)
0);
addMnemonicGrabs(dialog, dialog, unmodifiedToo);
}
void RemoveDialogMnemonicHandler(Widget dialog)
{
XtUngrabKey(dialog, AnyKey, Mod1Mask);
XtRemoveEventHandler(dialog, KeyPressMask, False,
(XtEventHandler)mnemonicCB, (XtPointer)
0);
}
void AccelLockBugPatch(Widget topWidget, Widget topMenuContainer)
{
XtAddEventHandler(topWidget, KeyPressMask, False, lockCB, topMenuContainer);
addAccelGrabs(topWidget, topMenuContainer);
}
void UpdateAccelLockPatch(Widget topWidget, Widget newButton)
{
addAccelGrab(topWidget, newButton);
}
void PopDownBugPatch(Widget w)
{
time_t stopTime;
stopTime = time(
NULL) +
1;
while (time(
NULL) <= stopTime) {
XEvent event;
XtAppContext context = XtWidgetToApplicationContext(w);
XtAppPeekEvent(context, &event);
if (event.xany.type == ReparentNotify)
return;
XtAppProcessEvent(context, XtIMAll);
}
}
char *GetXmStringText(XmString fromString)
{
XmStringContext context;
char *text, *toPtr, *toString, *fromPtr;
XmStringCharSet charset;
XmStringDirection direction;
Boolean separator;
toString = (
char*)NEditMalloc(XmStringLength(fromString));
XmStringInitContext(&context, fromString);
toPtr = toString;
while (XmStringGetNextSegment(context, &text,
&charset, &direction, &separator)) {
for (fromPtr=text; *fromPtr!=
'\0'; fromPtr++)
*toPtr++ = *fromPtr;
if (separator)
*toPtr++ =
'\n';
NEditFree(text);
NEditFree(charset);
}
*toPtr++ =
'\0';
XmStringFreeContext(context);
return toString;
}
XFontStruct *GetDefaultFontStruct(Display *d, XmFontList font)
{
XFontStruct *fs;
XmFontContext context;
XmStringCharSet charset;
XmFontListInitFontContext(&context, font);
XmFontListGetNextFont(context, &charset, &fs);
XmFontListFreeFontContext(context);
NEditFree(charset);
if (fs ==
NULL) {
fs = XLoadQueryFont(d,
"fixed");
}
if (fs ==
NULL) {
fprintf(stderr,
"Unabled to load any fallback fonts.\n");
exit(
EXIT_FAILURE);
}
return fs;
}
XmString* StringTable(
int count, ... )
{
va_list ap;
XmString *array;
int i;
char *str;
va_start(ap, count);
array = (XmString*)NEditMalloc((count+
1) *
sizeof(XmString));
for(i =
0; i < count; i++ ) {
str = va_arg(ap,
char *);
array[i] = XmStringCreateSimple(str);
}
array[i] = (XmString)
0;
va_end(ap);
return(array);
}
void FreeStringTable(XmString *table)
{
int i;
for(i =
0; table[i] !=
0; i++)
XmStringFree(table[i]);
NEditFree((
char *)table);
}
void SimulateButtonPress(Widget widget)
{
XEvent keyEvent;
memset((
char *)&keyEvent,
0,
sizeof(XKeyPressedEvent));
keyEvent.type = KeyPress;
keyEvent.xkey.serial =
1;
keyEvent.xkey.send_event = True;
if (XtIsSubclass(widget, xmGadgetClass))
{
Widget parent = XtParent(widget);
keyEvent.xkey.display = XtDisplay(parent);
keyEvent.xkey.window = XtWindow(parent);
XtCallActionProc(parent,
"ManagerGadgetSelect",
&keyEvent,
NULL,
0);
}
else
{
keyEvent.xkey.display = XtDisplay(widget);
keyEvent.xkey.window = XtWindow(widget);
XtCallActionProc(widget,
"ArmAndActivate", &keyEvent,
NULL,
0);
}
}
Widget AddMenuItem(Widget parent,
char *name,
char *label,
char mnemonic,
char *acc,
char *accText,
XtCallbackProc callback,
void *cbArg)
{
Widget button;
XmString st1, st2;
button = XtVaCreateManagedWidget(name, xmPushButtonWidgetClass, parent,
XmNlabelString, st1=XmStringCreateSimple(label),
XmNmnemonic, mnemonic,
XmNacceleratorText, st2=XmStringCreateSimple(accText),
XmNaccelerator, acc,
NULL);
XtAddCallback(button, XmNactivateCallback, callback, cbArg);
XmStringFree(st1);
XmStringFree(st2);
return button;
}
Widget AddMenuToggle(Widget parent,
char *name,
char *label,
char mnemonic,
char *acc,
char *accText,
XtCallbackProc callback,
void *cbArg,
int set)
{
Widget button;
XmString st1, st2;
button = XtVaCreateManagedWidget(name, xmToggleButtonWidgetClass, parent,
XmNlabelString, st1=XmStringCreateSimple(label),
XmNmnemonic, mnemonic,
XmNacceleratorText, st2=XmStringCreateSimple(accText),
XmNaccelerator, acc,
XmNset, set,
NULL);
XtAddCallback(button, XmNvalueChangedCallback, callback, cbArg);
XmStringFree(st1);
XmStringFree(st2);
return button;
}
Widget AddSubMenu(Widget parent,
char *name,
char *label,
char mnemonic)
{
Widget menu;
XmString st1;
menu = CreatePulldownMenu(parent, name,
NULL,
0);
XtVaCreateManagedWidget(name, xmCascadeButtonWidgetClass, parent,
XmNlabelString, st1=XmStringCreateSimple(label),
XmNmnemonic, mnemonic,
XmNsubMenuId, menu,
NULL);
XmStringFree(st1);
return menu;
}
void SetIntText(Widget text,
int value)
{
char labelString[
20];
sprintf(labelString,
"%d", value);
XmTextSetString(text, labelString);
}
int GetFloatText(Widget text,
double *value)
{
char *strValue, *endPtr;
int retVal;
strValue = XmTextGetString(text);
removeWhiteSpace(strValue);
*value = strtod(strValue, &endPtr);
if (strlen(strValue) ==
0)
retVal =
TEXT_IS_BLANK;
else if (*endPtr !=
'\0')
retVal =
TEXT_NOT_NUMBER;
else
retVal =
TEXT_READ_OK;
NEditFree(strValue);
return retVal;
}
int GetIntText(Widget text,
int *value)
{
char *strValue, *endPtr;
int retVal;
strValue = XmTextGetString(text);
removeWhiteSpace(strValue);
*value = strtol(strValue, &endPtr,
10);
if (strlen(strValue) ==
0)
retVal =
TEXT_IS_BLANK;
else if (*endPtr !=
'\0')
retVal =
TEXT_NOT_NUMBER;
else
retVal =
TEXT_READ_OK;
NEditFree(strValue);
return retVal;
}
int GetFloatTextWarn(Widget text,
double *value,
const char *fieldName,
int warnBlank)
{
int result;
char *valueStr;
result = GetFloatText(text, value);
if (result ==
TEXT_READ_OK || (result ==
TEXT_IS_BLANK && !warnBlank))
return result;
valueStr = XmTextGetString(text);
if (result ==
TEXT_IS_BLANK)
{
DialogF(
DF_ERR, text,
1,
"Warning",
"Please supply %s value",
"OK",
fieldName);
}
else
{
DialogF (
DF_ERR, text,
1,
"Warning",
"Can''t read %s value: \"%s\"",
"OK", fieldName, valueStr);
}
NEditFree(valueStr);
return result;
}
int GetIntTextWarn(Widget text,
int *value,
const char *fieldName,
int warnBlank)
{
int result;
char *valueStr;
result = GetIntText(text, value);
if (result ==
TEXT_READ_OK || (result ==
TEXT_IS_BLANK && !warnBlank))
return result;
valueStr = XmTextGetString(text);
if (result ==
TEXT_IS_BLANK)
{
DialogF (
DF_ERR, text,
1,
"Warning",
"Please supply a value for %s",
"OK", fieldName);
}
else
{
DialogF (
DF_ERR, text,
1,
"Warning",
"Can''t read integer value \"%s\" in %s",
"OK", valueStr,
fieldName);
}
NEditFree(valueStr);
return result;
}
char* TextGetStringUtf8(Widget text) {
char *string = XmTextFieldGetString(text);
if(!string || strlen(string) ==
0) {
return string;
}
char *encoding = nl_langinfo(
CODESET);
if(encoding && strcmp(encoding,
"UTF-8")) {
char *newstring = ConvertEncoding(string,
"UTF-8", encoding);
if(newstring) {
XtFree(string);
string = newstring;
}
}
return string;
}
int TextWidgetIsBlank(Widget textW)
{
char *str;
int retVal;
str = XmTextGetString(textW);
removeWhiteSpace(str);
retVal = *str ==
'\0';
NEditFree(str);
return retVal;
}
void MakeSingleLineTextW(Widget textW)
{
static XtTranslations noReturnTable =
NULL;
static char *noReturnTranslations =
"<Key>Return: activate()\n";
if (noReturnTable ==
NULL)
noReturnTable = XtParseTranslationTable(noReturnTranslations);
XtOverrideTranslations(textW, noReturnTable);
}
void AddHistoryToTextWidget(Widget textW,
char ***historyList,
int *nItems)
{
histInfo *histData;
histData = (histInfo *)NEditMalloc(
sizeof(histInfo));
histData->list = historyList;
histData->nItems = nItems;
histData->index = -
1;
XtAddEventHandler(textW, KeyPressMask, False,
(XtEventHandler)histArrowKeyEH, histData);
XtAddCallback(textW, XmNdestroyCallback, histDestroyCB, histData);
}
static void histDestroyCB(Widget w, XtPointer clientData, XtPointer callData)
{
NEditFree((
char *)clientData);
}
static void histArrowKeyEH(Widget w, XtPointer callData, XEvent *event,
Boolean *continueDispatch)
{
histInfo *histData = (histInfo *)callData;
KeySym keysym = XLookupKeysym((XKeyEvent *)event,
0);
if (keysym != XK_Up && keysym != XK_Down)
return;
histData->index += (keysym == XK_Up) ?
1 : -
1;
if (histData->index < -
1) {
histData->index = -
1;
XBell(XtDisplay(w),
0);
return;
}
if (histData->index >= *histData->nItems) {
histData->index = *histData->nItems -
1;
XBell(XtDisplay(w),
0);
return;
}
XmTextSetString(w, histData->index == -
1 ?
"" :
(*histData->list)[histData->index]);
}
void AddToHistoryList(
char *newItem,
char ***historyList,
int *nItems)
{
char **newList;
int i;
if (*nItems !=
0 && !strcmp(newItem, **historyList))
return;
if (*nItems ==
HISTORY_LIST_MAX) {
for (i=
HISTORY_LIST_TRIM_TO; i<
HISTORY_LIST_MAX; i++)
NEditFree((*historyList)[i]);
*nItems =
HISTORY_LIST_TRIM_TO;
}
newList = (
char **)NEditMalloc(
sizeof(
char *) * (*nItems +
1));
for (i=
0; i < *nItems; i++)
newList[i+
1] = (*historyList)[i];
if (*nItems !=
0 && *historyList !=
NULL)
NEditFree(*historyList);
(*nItems)++;
newList[
0] = NEditStrdup(newItem);
*historyList = newList;
}
void BeginWait(Widget topCursorWidget)
{
Display *display = XtDisplay(topCursorWidget);
Pixmap pixmap;
Pixmap maskPixmap;
XColor xcolors[
2];
static Cursor waitCursor =
0;
if (!waitCursor) {
pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
(
char *)watch_bits, watch_width, watch_height);
maskPixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
(
char *)watch_mask_bits, watch_width, watch_height);
xcolors[
0].pixel = BlackPixelOfScreen(DefaultScreenOfDisplay(display));
xcolors[
1].pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(display));
XQueryColors(display, DefaultColormapOfScreen(
DefaultScreenOfDisplay(display)), xcolors,
2);
waitCursor = XCreatePixmapCursor(display, pixmap, maskPixmap,
&xcolors[
0], &xcolors[
1], watch_x_hot, watch_y_hot);
XFreePixmap(display, pixmap);
XFreePixmap(display, maskPixmap);
}
XDefineCursor(display, XtWindow(topCursorWidget), waitCursor);
}
void BusyWait(Widget widget)
{
#ifdef __unix__
static const int timeout =
100000;
static struct timeval last = {
0,
0 };
struct timeval current;
gettimeofday(¤t,
NULL);
if ((current.tv_sec != last.tv_sec) ||
(current.tv_usec - last.tv_usec > timeout))
{
XmUpdateDisplay(widget);
last = current;
}
#else
static time_t last =
0;
time_t current;
time(¤t);
if (difftime(current, last) >
0)
{
XmUpdateDisplay(widget);
last = current;
}
#endif
}
void EndWait(Widget topCursorWidget)
{
XUndefineCursor(XtDisplay(topCursorWidget), XtWindow(topCursorWidget));
}
void CreateGeometryString(
char *string,
int x,
int y,
int width,
int height,
int bitmask)
{
char *ptr = string;
int nChars;
if (bitmask & WidthValue) {
sprintf(ptr,
"%d%n", width, &nChars);
ptr += nChars;
}
if (bitmask & HeightValue) {
sprintf(ptr,
"x%d%n", height, &nChars);
ptr += nChars;
}
if (bitmask & XValue) {
if (bitmask & XNegative)
sprintf(ptr,
"-%d%n", -x, &nChars);
else
sprintf(ptr,
"+%d%n", x, &nChars);
ptr += nChars;
}
if (bitmask & YValue) {
if (bitmask & YNegative)
sprintf(ptr,
"-%d%n", -y, &nChars);
else
sprintf(ptr,
"+%d%n", y, &nChars);
ptr += nChars;
}
*ptr =
'\0';
}
static void removeWhiteSpace(
char *string)
{
char *outPtr = string;
while (
TRUE) {
if (*string ==
0) {
*outPtr =
0;
return;
}
else if (*string !=
' ' && *string !=
'\t')
*(outPtr++) = *(string++);
else
string++;
}
}
static int stripCaseCmp(
const char *str1,
const char *str2)
{
const char *c1, *c2;
for (c1=str1, c2=str2; *c1!=
'\0' && *c2!=
'\0'; c1++, c2++) {
while (*c1 ==
' ' || *c1 ==
'\t')
c1++;
while (*c2 ==
' ' || *c2 ==
'\t')
c2++;
if (toupper((
unsigned char)*c1) != toupper((
unsigned char)*c2))
return FALSE;
}
return *c1 ==
'\0' && *c2 ==
'\0';
}
static void warnHandlerCB(String message)
{
if (strstr(message,
"XtRemoveGrab"))
return;
if (strstr(message,
"Attempt to remove non-existant passive grab"))
return;
fputs(message, stderr);
fputc(
'\n', stderr);
}
static XModifierKeymap *getKeyboardMapping(Display *display) {
static XModifierKeymap *keyboardMap =
NULL;
if (keyboardMap ==
NULL) {
keyboardMap = XGetModifierMapping(display);
}
return(keyboardMap);
}
static Modifiers findModifierMapping(Display *display, KeyCode keyCode) {
int i, j;
KeyCode *mapentry;
XModifierKeymap *modMap = getKeyboardMapping(display);
if (modMap ==
NULL || keyCode ==
0) {
return(
0);
}
mapentry = modMap->modifiermap;
for (i =
0; i <
8; ++i) {
for (j =
0; j < (modMap->max_keypermod); ++j) {
if (keyCode == *mapentry) {
return(
1 << ((mapentry - modMap->modifiermap) / modMap->max_keypermod));
}
++mapentry;
}
}
return(
0);
}
Modifiers GetNumLockModMask(Display *display) {
static int numLockMask = -
1;
if (numLockMask == -
1) {
numLockMask = findModifierMapping(display, XKeysymToKeycode(display, XK_Num_Lock));
}
return(numLockMask);
}
static void reallyGrabAKey(Widget dialog,
int keyCode, Modifiers mask) {
Modifiers numLockMask = GetNumLockModMask(XtDisplay(dialog));
if (keyCode ==
0)
return;
XtGrabKey(dialog, keyCode, mask, True, GrabModeAsync, GrabModeAsync);
XtGrabKey(dialog, keyCode, mask|LockMask, True, GrabModeAsync, GrabModeAsync);
if (numLockMask && numLockMask != LockMask) {
XtGrabKey(dialog, keyCode, mask|numLockMask, True, GrabModeAsync, GrabModeAsync);
XtGrabKey(dialog, keyCode, mask|LockMask|numLockMask, True, GrabModeAsync, GrabModeAsync);
}
}
static void addMnemonicGrabs(Widget dialog, Widget w,
int unmodifiedToo)
{
char mneString[
2];
WidgetList children;
Cardinal numChildren;
int i, isMenu;
KeySym mnemonic =
'\0';
unsigned char rowColType;
unsigned int keyCode;
if (XtIsComposite(w)) {
if (XtClass(w) == xmRowColumnWidgetClass) {
XtVaGetValues(w, XmNrowColumnType, &rowColType,
NULL);
isMenu = rowColType != XmWORK_AREA;
}
else
isMenu = False;
if (!isMenu) {
XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
&numChildren,
NULL);
for (i=
0; i<(
int)numChildren; i++)
addMnemonicGrabs(dialog, children[i], unmodifiedToo);
}
}
else {
XtVaGetValues(w, XmNmnemonic, &mnemonic,
NULL);
if (mnemonic != XK_VoidSymbol && mnemonic !=
'\0') {
mneString[
0] = mnemonic; mneString[
1] =
'\0';
keyCode = XKeysymToKeycode(XtDisplay(dialog),
XStringToKeysym(mneString));
reallyGrabAKey(dialog, keyCode, Mod1Mask);
if (unmodifiedToo)
reallyGrabAKey(dialog, keyCode,
0);
}
}
}
static void mnemonicCB(Widget w, XtPointer callData, XKeyEvent *event)
{
findAndActivateMnemonic(w, event->keycode);
}
static void findAndActivateMnemonic(Widget w,
unsigned int keycode)
{
WidgetList children;
Cardinal numChildren;
int i, isMenu;
KeySym mnemonic =
'\0';
char mneString[
2];
Widget userData;
unsigned char rowColType;
if (XtIsComposite(w)) {
if (XtClass(w) == xmRowColumnWidgetClass) {
XtVaGetValues(w, XmNrowColumnType, &rowColType,
NULL);
isMenu = rowColType != XmWORK_AREA;
}
else
isMenu = False;
if (!isMenu) {
XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
&numChildren,
NULL);
for (i=
0; i<(
int)numChildren; i++)
findAndActivateMnemonic(children[i], keycode);
}
}
else {
XtVaGetValues(w, XmNmnemonic, &mnemonic,
NULL);
if (mnemonic !=
'\0') {
mneString[
0] = mnemonic; mneString[
1] =
'\0';
if (XKeysymToKeycode(XtDisplay(XtParent(w)),
XStringToKeysym(mneString)) == keycode) {
if (XtClass(w) == xmLabelWidgetClass ||
XtClass(w) == xmLabelGadgetClass) {
XtVaGetValues(w, XmNuserData, &userData,
NULL);
if (userData!=
NULL && XtIsWidget(userData) &&
XmIsTraversable(userData))
XmProcessTraversal(userData, XmTRAVERSE_CURRENT);
}
else if (XmIsTraversable(w)) {
XmProcessTraversal(w, XmTRAVERSE_CURRENT);
SimulateButtonPress(w);
}
}
}
}
}
static void addAccelGrabs(Widget topWidget, Widget w)
{
WidgetList children;
Widget menu;
Cardinal numChildren;
int i;
if (XtIsComposite(w)) {
XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
&numChildren,
NULL);
for (i=
0; i<(
int)numChildren; i++)
addAccelGrabs(topWidget, children[i]);
}
else if (XtClass(w) == xmCascadeButtonWidgetClass) {
XtVaGetValues(w, XmNsubMenuId, &menu,
NULL);
if (menu !=
NULL)
addAccelGrabs(topWidget, menu);
}
else
addAccelGrab(topWidget, w);
}
static void addAccelGrab(Widget topWidget, Widget w)
{
char *accelString =
NULL;
KeySym keysym;
unsigned int modifiers;
KeyCode code;
Modifiers numLockMask = GetNumLockModMask(XtDisplay(topWidget));
XtVaGetValues(w, XmNaccelerator, &accelString,
NULL);
if (accelString ==
NULL || *accelString ==
'\0') {
NEditFree(accelString);
return;
}
if (!parseAccelString(XtDisplay(topWidget), accelString, &keysym, &modifiers)) {
NEditFree(accelString);
return;
}
NEditFree(accelString);
code = XKeysymToKeycode(XtDisplay(topWidget), keysym);
if (code ==
0)
return;
XtGrabKey(topWidget, code,
modifiers | LockMask, True, GrabModeAsync, GrabModeAsync);
if (numLockMask && numLockMask != LockMask) {
XtGrabKey(topWidget, code,
modifiers | numLockMask, True, GrabModeAsync, GrabModeAsync);
XtGrabKey(topWidget, code,
modifiers | LockMask | numLockMask, True, GrabModeAsync, GrabModeAsync);
}
}
static int parseAccelString(Display *display,
const char *string, KeySym *keySym,
unsigned int *modifiers)
{
#define N_MODIFIERS 12
static char *modifierNames[
N_MODIFIERS] = {
"Ctrl",
"Shift",
"Alt",
"Mod2",
"Mod3",
"Mod4",
"Mod5",
"Button1",
"Button2",
"Button3",
"Button4",
"Button5"};
static unsigned int modifierMasks[
N_MODIFIERS] = {ControlMask, ShiftMask,
Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, Button1Mask, Button2Mask,
Button3Mask, Button4Mask, Button5Mask};
Modifiers numLockMask = GetNumLockModMask(display);
char modStr[
MAX_ACCEL_LEN];
char evtStr[
MAX_ACCEL_LEN];
char keyStr[
MAX_ACCEL_LEN];
const char *c, *evtStart, *keyStart;
int i;
if (strlen(string) >=
MAX_ACCEL_LEN)
return FALSE;
for (c = string; *c !=
'<'; c++)
if (*c ==
'\0')
return FALSE;
strncpy(modStr, string, c - string);
modStr[c - string] =
'\0';
evtStart = c;
for ( ; *c !=
'>'; c++)
if (*c ==
'\0')
return FALSE;
c++;
strncpy(evtStr, evtStart, c - evtStart);
evtStr[c - evtStart] =
'\0';
if (!stripCaseCmp(evtStr,
"<key>") && !stripCaseCmp(evtStr,
"<keypress>"))
return FALSE;
keyStart = c;
for ( ; *c !=
'\0' && !(c != keyStart && *c ==
':'); c++);
strncpy(keyStr, keyStart, c - keyStart);
keyStr[c - keyStart] =
'\0';
*keySym = XStringToKeysym(keyStr);
*modifiers =
0;
c = modStr;
while (*c !=
'\0') {
while (*c ==
' ' || *c ==
'\t')
c++;
if (*c ==
'\0')
break;
for (i =
0; i <
N_MODIFIERS; i++) {
if (!strncmp(c, modifierNames[i], strlen(modifierNames[i]))) {
c += strlen(modifierNames[i]);
if (modifierMasks[i] != numLockMask) {
*modifiers |= modifierMasks[i];
}
break;
}
}
if (i ==
N_MODIFIERS)
return FALSE;
}
return TRUE;
}
static void lockCB(Widget w, XtPointer callData, XEvent *event,
Boolean *continueDispatch)
{
Modifiers numLockMask = GetNumLockModMask(XtDisplay(w));
Widget topMenuWidget = (Widget)callData;
*continueDispatch =
TRUE;
if (!(((XKeyEvent *)event)->state & (LockMask | numLockMask)))
return;
if (findAndActivateAccel(topMenuWidget, ((XKeyEvent*) event)->keycode,
((XKeyEvent*) event)->state & ~(LockMask | numLockMask), event)) {
*continueDispatch =
FALSE;
}
}
static int findAndActivateAccel(Widget w,
unsigned int keyCode,
unsigned int modifiers, XEvent *event)
{
WidgetList children;
Widget menu;
Cardinal numChildren;
int i;
char *accelString =
NULL;
KeySym keysym;
unsigned int mods;
if (XtIsComposite(w)) {
XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
&numChildren,
NULL);
for (i=
0; i<(
int)numChildren; i++)
if (findAndActivateAccel(children[i], keyCode, modifiers, event))
return TRUE;
}
else if (XtClass(w) == xmCascadeButtonWidgetClass) {
XtVaGetValues(w, XmNsubMenuId, &menu,
NULL);
if (menu !=
NULL)
if (findAndActivateAccel(menu, keyCode, modifiers, event))
return TRUE;
}
else {
XtVaGetValues(w, XmNaccelerator, &accelString,
NULL);
if (accelString !=
NULL && *accelString !=
'\0') {
if (!parseAccelString(XtDisplay(w), accelString, &keysym, &mods))
return FALSE;
if (keyCode == XKeysymToKeycode(XtDisplay(w), keysym) &&
modifiers == mods) {
if (XtIsSensitive(w)) {
XtCallActionProc(w,
"ArmAndActivate", event,
NULL,
0);
return TRUE;
}
}
}
}
return FALSE;
}
void InstallMouseWheelActions(XtAppContext context)
{
static XtActionsRec Actions[] = {
{
"scrolled-window-scroll-up", scrollUpAP},
{
"scrolled-window-page-up", pageUpAP},
{
"scrolled-window-scroll-down", scrollDownAP},
{
"scrolled-window-page-down", pageDownAP}
};
XtAppAddActions(context, Actions, XtNumber(Actions));
}
static Widget getScrolledWindow(Widget w)
{
Widget scrolledWindow = XtParent(w);
if (!XmIsScrolledWindow(scrolledWindow)) {
scrolledWindow = XtParent(scrolledWindow);
}
return scrolledWindow;
}
void AddMouseWheelSupport(Widget w)
{
if (XmIsScrolledWindow(getScrolledWindow(w)))
{
static const char scrollTranslations[] =
"Shift<Btn4Down>,<Btn4Up>: scrolled-window-scroll-up(1)\n"
"Shift<Btn5Down>,<Btn5Up>: scrolled-window-scroll-down(1)\n"
"Ctrl<Btn4Down>,<Btn4Up>: scrolled-window-page-up()\n"
"Ctrl<Btn5Down>,<Btn5Up>: scrolled-window-page-down()\n"
"<Btn4Down>,<Btn4Up>: scrolled-window-scroll-up(3)\n"
"<Btn5Down>,<Btn5Up>: scrolled-window-scroll-down(3)\n";
static XtTranslations trans_table =
NULL;
if (trans_table ==
NULL)
{
trans_table = XtParseTranslationTable(scrollTranslations);
}
XtOverrideTranslations(w, trans_table);
}
}
void XmContainerAddMouseWheelSupport(Widget w)
{
if (XmIsScrolledWindow(getScrolledWindow(w)))
{
static const char scrollTranslations[] =
"Shift<Btn4Down>,<Btn4Up>: scrolled-window-scroll-up(1)\n"
"Shift<Btn5Down>,<Btn5Up>: scrolled-window-scroll-down(1)\n"
"Ctrl<Btn4Down>,<Btn4Up>: scrolled-window-scroll-up(3)\n"
"Ctrl<Btn5Down>,<Btn5Up>: scrolled-window-scroll-down(3)\n"
"<Btn4Down>,<Btn4Up>: scrolled-window-page-up()\n"
"<Btn5Down>,<Btn5Up>: scrolled-window-page-down()\n";
static XtTranslations trans_table =
NULL;
if (trans_table ==
NULL)
{
trans_table = XtParseTranslationTable(scrollTranslations);
}
XtOverrideTranslations(w, trans_table);
}
}
static void pageUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
{
Widget scrolledWindow, scrollBar;
String al[
1];
al[
0] =
"Up";
scrolledWindow = getScrolledWindow(w);
scrollBar = XtNameToWidget (scrolledWindow,
"VertScrollBar");
if (scrollBar)
XtCallActionProc(scrollBar,
"PageUpOrLeft", event, al,
1) ;
return;
}
static void pageDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
{
Widget scrolledWindow, scrollBar;
String al[
1];
al[
0] =
"Down";
scrolledWindow = getScrolledWindow(w);
scrollBar = XtNameToWidget (scrolledWindow,
"VertScrollBar");
if (scrollBar)
XtCallActionProc(scrollBar,
"PageDownOrRight", event, al,
1) ;
return;
}
static void scrollUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
{
Widget scrolledWindow, scrollBar;
String al[
1];
int i, nLines;
if (*nArgs ==
0 || sscanf(args[
0],
"%d", &nLines) !=
1)
return;
al[
0] =
"Up";
scrolledWindow = getScrolledWindow(w);
scrollBar = XtNameToWidget (scrolledWindow,
"VertScrollBar");
if (scrollBar)
for (i=
0; i<nLines; i++)
XtCallActionProc(scrollBar,
"IncrementUpOrLeft", event, al,
1) ;
return;
}
static void scrollDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
{
Widget scrolledWindow, scrollBar;
String al[
1];
int i, nLines;
if (*nArgs ==
0 || sscanf(args[
0],
"%d", &nLines) !=
1)
return;
al[
0] =
"Down";
scrolledWindow = getScrolledWindow(w);
scrollBar = XtNameToWidget (scrolledWindow,
"VertScrollBar");
if (scrollBar)
for (i=
0; i<nLines; i++)
XtCallActionProc(scrollBar,
"IncrementDownOrRight", event, al,
1) ;
return;
}
void RadioButtonChangeState(Widget widget, Boolean state, Boolean notify)
{
#ifndef LESSTIF_VERSION
#if XmVersion ==
2001 || (XmVersion ==
2002 && XmUPDATE_LEVEL <
3)
Widget focusW, shellW = widget;
while (shellW && !XtIsShell(shellW)) {
shellW = XtParent(shellW);
}
focusW = XtGetKeyboardFocusWidget(shellW);
if (state && XtIsRealized(widget))
{
XEvent ev;
if (XtIsManaged(widget))
{
Position x, y;
XtTranslateCoords(XtParent(widget), widget->core.x, widget->core.y,
&x, &y);
ev.xbutton.x_root = x + widget->core.border_width;
ev.xbutton.y_root = y + widget->core.border_width;
}
else
{
ev.xbutton.x_root =
0;
ev.xbutton.y_root =
0;
}
ev.xany.type = ButtonPress;
XtCallActionProc(widget,
"Arm", &ev,
NULL,
0);
ev.xany.type = ButtonRelease;
XtCallActionProc(widget,
"Select", &ev,
NULL,
0);
XtCallActionProc(widget,
"Disarm", &ev,
NULL,
0);
}
if (focusW) {
XtSetKeyboardFocus(shellW, focusW);
}
#endif
#endif
XmToggleButtonSetState(widget, state, notify);
}
void CloseAllPopupsFor(Widget shell)
{
#ifndef LESSTIF_VERSION
Widget app = XtParent(shell);
int i;
for (i =
0; i < app->core.num_popups; i++) {
Widget pop = app->core.popup_list[i];
Widget shellFor;
XtVaGetValues(pop, XtNtransientFor, &shellFor,
NULL);
if (shell == shellFor)
_XmDismissTearOff(pop,
NULL,
NULL);
}
#endif
}
static long queryDesktop(Display *display, Window window, Atom deskTopAtom)
{
long deskTopNumber =
0;
Atom actualType;
int actualFormat;
unsigned long nItems, bytesAfter;
unsigned char *prop;
if (XGetWindowProperty(display, window, deskTopAtom,
0,
1,
False, AnyPropertyType, &actualType, &actualFormat, &nItems,
&bytesAfter, &prop) != Success) {
return -
1;
}
if (actualType == None) {
return -
1;
}
if (actualFormat !=
32 || nItems !=
1) {
XFree((
char*)prop);
return -
1;
}
deskTopNumber = *(
long*)prop;
XFree((
char*)prop);
return deskTopNumber;
}
long QueryCurrentDesktop(Display *display, Window rootWindow)
{
static Atom currentDesktopAtom = (Atom)-
1;
if (currentDesktopAtom == (Atom)-
1)
currentDesktopAtom = XInternAtom(display,
"_NET_CURRENT_DESKTOP", True);
if (currentDesktopAtom != None)
return queryDesktop(display, rootWindow, currentDesktopAtom);
return -
1;
}
long QueryDesktop(Display *display, Widget shell)
{
static Atom wmDesktopAtom = (Atom)-
1;
if (wmDesktopAtom == (Atom)-
1)
wmDesktopAtom = XInternAtom(display,
"_NET_WM_DESKTOP", True);
if (wmDesktopAtom != None)
return queryDesktop(display, XtWindow(shell), wmDesktopAtom);
return -
1;
}
#define SPINCOUNT 10
#define USLEEPTIME 1000
static void warning(
const char* mesg)
{
fprintf(stderr,
"XNEdit warning:\n%s\n", mesg);
}
static void microsleep(
long usecs)
{
static struct timeval timeoutVal;
timeoutVal.tv_sec = usecs/
1000000;
timeoutVal.tv_usec = usecs - timeoutVal.tv_sec*
1000000;
select(
0,
NULL,
NULL,
NULL, &timeoutVal);
}
int SpinClipboardStartCopy(Display *display, Window window,
XmString clip_label, Time timestamp, Widget widget,
XmCutPasteProc callback,
long *item_id)
{
int i, res;
for (i=
0; i<
SPINCOUNT; ++i) {
res = XmClipboardStartCopy(display, window, clip_label, timestamp,
widget, callback, item_id);
if (res == XmClipboardSuccess) {
return res;
}
microsleep(
USLEEPTIME);
}
warning(
"XmClipboardStartCopy() failed: clipboard locked.");
return res;
}
int SpinClipboardCopy(Display *display, Window window,
long item_id,
char *format_name, XtPointer buffer,
unsigned long length,
long private_id,
long *data_id)
{
int i, res;
for (i=
0; i<
SPINCOUNT; ++i) {
res = XmClipboardCopy(display, window, item_id, format_name,
buffer, length, private_id, data_id);
if (res == XmClipboardSuccess) {
return res;
}
if (res == XmClipboardFail) {
warning(
"XmClipboardCopy() failed: XmClipboardStartCopy not "
"called or too many formats.");
return res;
}
microsleep(
USLEEPTIME);
}
warning(
"XmClipboardCopy() failed: clipboard locked.");
return res;
}
int SpinClipboardEndCopy(Display *display, Window window,
long item_id)
{
int i, res;
for (i=
0; i<
SPINCOUNT; ++i) {
res = XmClipboardEndCopy(display, window, item_id);
if (res == XmClipboardSuccess) {
return res;
}
if (res == XmClipboardFail) {
warning(
"XmClipboardEndCopy() failed: XmClipboardStartCopy not "
"called.");
return res;
}
microsleep(
USLEEPTIME);
}
warning(
"XmClipboardEndCopy() failed: clipboard locked.");
return res;
}
int SpinClipboardInquireLength(Display *display, Window window,
char *format_name,
unsigned long *length)
{
int i, res;
for (i=
0; i<
SPINCOUNT; ++i) {
res = XmClipboardInquireLength(display, window, format_name, length);
if (res == XmClipboardSuccess) {
return res;
}
if (res == XmClipboardNoData) {
return res;
}
microsleep(
USLEEPTIME);
}
warning(
"XmClipboardInquireLength() failed: clipboard locked.");
return res;
}
int SpinClipboardRetrieve(Display *display, Window window,
char *format_name,
XtPointer buffer,
unsigned long length,
unsigned long *num_bytes,
long *private_id)
{
int i, res;
for (i=
0; i<
SPINCOUNT; ++i) {
res = XmClipboardRetrieve(display, window, format_name, buffer,
length, num_bytes, private_id);
if (res == XmClipboardSuccess) {
return res;
}
if (res == XmClipboardTruncate) {
warning(
"XmClipboardRetrieve() failed: buffer too small.");
return res;
}
if (res == XmClipboardNoData) {
return res;
}
microsleep(
USLEEPTIME);
}
warning(
"XmClipboardRetrieve() failed: clipboard locked.");
return res;
}
int SpinClipboardLock(Display *display, Window window)
{
int i, res;
for (i=
0; i<
SPINCOUNT; ++i) {
res = XmClipboardLock(display, window);
if (res == XmClipboardSuccess) {
return res;
}
microsleep(
USLEEPTIME);
}
warning(
"XmClipboardLock() failed: clipboard locked.");
return res;
}
int SpinClipboardUnlock(Display *display, Window window)
{
int i, res;
for (i=
0; i<
SPINCOUNT; ++i) {
res = XmClipboardUnlock(display, window, True);
if (res == XmClipboardSuccess) {
return res;
}
microsleep(
USLEEPTIME);
}
return res;
}
void WmClientMsg(Display *disp, Window win,
const char *msg,
unsigned long data0,
unsigned long data1,
unsigned long data2,
unsigned long data3,
unsigned long data4)
{
XEvent event;
long mask = SubstructureRedirectMask | SubstructureNotifyMask;
event.xclient.type = ClientMessage;
event.xclient.serial =
0;
event.xclient.send_event = True;
event.xclient.message_type = XInternAtom(disp, msg, False);
event.xclient.window = win;
event.xclient.format =
32;
event.xclient.data.l[
0] = data0;
event.xclient.data.l[
1] = data1;
event.xclient.data.l[
2] = data2;
event.xclient.data.l[
3] = data3;
event.xclient.data.l[
4] = data4;
if (!XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) {
fprintf(stderr,
"nedit: cannot send %s EWMH event.\n", msg);
}
}
char* ConvertEncodingLen(
const char *string,
size_t len,
const char *to,
const char *from) {
if(!to || !from) {
return NULL;
}
iconv_t ic = iconv_open(to, from);
if(ic == (
iconv_t) -
1) {
return NULL;
}
size_t size = len +
16;
size_t pos =
0;
size_t inleft = len;
size_t outleft = size;
char *result = NEditMalloc(size+
1);
char *in = (
char*)string;
char *out = result;
while(inleft >=
0) {
if (inleft ==
0) {
in =
NULL;
}
size_t rc = iconv(ic, &in, &inleft, &out, &outleft);
pos = out - result;
if(rc == (
size_t)-
1) {
switch(errno) {
case EILSEQ:
case EINVAL: {
in++;
inleft--;
break;
}
case E2BIG: {
size +=
32;
result = NEditRealloc(result, size+
1);
out = result + pos;
outleft = size - pos;
break;
}
}
}
if(!in) {
break;
}
}
iconv_close(ic);
result[pos] =
'\0';
return result;
}
char* ConvertEncoding(
const char *string,
const char *to,
const char *from) {
return ConvertEncodingLen(string, strlen(string), to, from);
}
char* GetLocaleEncoding(
void) {
return nl_langinfo(
CODESET);
}
int IsUtf8Locale(
void) {
char *encoding = nl_langinfo(
CODESET);
if(encoding && !strcmp(encoding,
"UTF-8")) {
return TRUE;
}
return FALSE;
}
void SetWindowGtkThemeVariant(Display *dp, Window window,
int theme)
{
Atom atom = XInternAtom(dp,
"_GTK_THEME_VARIANT", False);
Atom type = XInternAtom(dp,
"UTF8_STRING", False);
if(theme ==
0) {
XDeleteProperty(dp, window, atom);
}
else {
const char *themeStr = theme ==
1 ?
"light" :
"dark";
XChangeProperty(
dp,
window,
atom,
type,
8,
PropModeReplace,
(
unsigned char*)themeStr,
4);
}
}