1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
32
33 #include "misc.h"
34 #include "DialogF.h"
35 #include "nedit_malloc.h"
36
37 #include "xdnd.h"
38
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #include <ctype.h>
43 #include <stdio.h>
44 #include <time.h>
45 #include <errno.h>
46
47 #ifdef __sun
48 #define _XPG6
49 #endif
50 #include <iconv.h>
51
52
53 #include <langinfo.h>
54
55 #ifdef __unix__
56 #include <sys/time.h>
57 #include <sys/select.h>
58 #endif
59
60 #ifdef __APPLE__
61 #ifdef __MACH__
62 #include <sys/select.h>
63 #endif
64 #endif
65
66 #include <X11/Intrinsic.h>
67 #include <X11/Xatom.h>
68 #include <X11/keysym.h>
69 #include <X11/keysymdef.h>
70 #include <Xm/Xm.h>
71 #include <Xm/Label.h>
72 #include <Xm/LabelG.h>
73 #include <Xm/ToggleB.h>
74 #include <Xm/PushB.h>
75 #include <Xm/Separator.h>
76 #include <Xm/RowColumn.h>
77 #include <Xm/CascadeB.h>
78 #include <Xm/AtomMgr.h>
79 #include <Xm/Protocols.h>
80 #include <Xm/Text.h>
81 #include <Xm/MessageB.h>
82 #include <Xm/DialogS.h>
83 #include <Xm/SelectioB.h>
84 #include <Xm/Form.h>
85 #include <Xm/FileSB.h>
86 #include <Xm/ScrolledW.h>
87 #include <Xm/PrimitiveP.h>
88 #include <Xm/TextF.h>
89
90 #ifdef HAVE_DEBUG_H
91 #include "../debug.h"
92 #endif
93
94 Boolean GetWindowDarkTheme(
void);
95
96 #ifndef LESSTIF_VERSION
97 extern void _XmDismissTearOff(Widget w, XtPointer call, XtPointer x);
98 #endif
99
100
101 typedef struct {
102 char ***list;
103 int *nItems;
104 int index;
105 } histInfo;
106
107 typedef Widget (*MotifDialogCreationCall)(Widget, String, ArgList, Cardinal);
108
109
110
111
112
113 #define HISTORY_LIST_TRIM_TO 1000
114 #define HISTORY_LIST_MAX 2000
115
116
117 static int RemapDeleteEnabled = True;
118 static int PointerCenteredDialogsEnabled = False;
119
120
121 #define watch_x_hot
7
122 #define watch_y_hot
7
123 #define watch_width
16
124 #define watch_height
16
125 static unsigned char watch_bits[] = {
126 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0x10, 0x08, 0x08, 0x11,
127 0x04, 0x21, 0x04, 0x21, 0xe4, 0x21, 0x04, 0x20, 0x08, 0x10, 0x10, 0x08,
128 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x07
129 };
130 #define watch_mask_width
16
131 #define watch_mask_height
16
132 static unsigned char watch_mask_bits[] = {
133 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f,
134 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f,
135 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f
136 };
137
138 static void addMnemonicGrabs(Widget addTo, Widget w,
int unmodified);
139 static void mnemonicCB(Widget w, XtPointer callData, XKeyEvent *event);
140 static void findAndActivateMnemonic(Widget w,
unsigned int keycode);
141 static void addAccelGrabs(Widget topWidget, Widget w);
142 static void addAccelGrab(Widget topWidget, Widget w);
143 static int parseAccelString(Display *display,
const char *string, KeySym *keysym,
144 unsigned int *modifiers);
145 static void lockCB(Widget w, XtPointer callData, XEvent *event,
146 Boolean *continueDispatch);
147 static int findAndActivateAccel(Widget w,
unsigned int keyCode,
148 unsigned int modifiers, XEvent *event);
149 static void removeWhiteSpace(
char *string);
150 static int stripCaseCmp(
const char *str1,
const char *str2);
151 static void warnHandlerCB(String message);
152 static void histDestroyCB(Widget w, XtPointer clientData, XtPointer callData);
153 static void histArrowKeyEH(Widget w, XtPointer callData, XEvent *event,
154 Boolean *continueDispatch);
155 static ArgList addParentVisArgs(Widget parent, ArgList arglist,
156 Cardinal *argcount);
157 static Widget addParentVisArgsAndCall(MotifDialogCreationCall callRoutine,
158 Widget parent,
char *name, ArgList arglist, Cardinal argcount);
159 static void scrollDownAP(Widget w, XEvent *event, String *args,
160 Cardinal *nArgs);
161 static void scrollUpAP(Widget w, XEvent *event, String *args,
162 Cardinal *nArgs);
163 static void pageDownAP(Widget w, XEvent *event, String *args,
164 Cardinal *nArgs);
165 static void pageUpAP(Widget w, XEvent *event, String *args,
166 Cardinal *nArgs);
167 static long queryDesktop(Display *display, Window window, Atom deskTopAtom);
168 static void warning(
const char* mesg);
169 static void microsleep(
long usecs);
170
171
172
173
174
175
176 void AddMotifCloseCallback(Widget shell, XtCallbackProc closeCB,
void *arg)
177 {
178 static Atom wmpAtom, dwAtom =
0;
179 Display *display = XtDisplay(shell);
180
181
182 XtVaSetValues(shell, XmNdeleteResponse, XmDO_NOTHING,
NULL);
183
184
185 if (dwAtom ==
0) {
186 wmpAtom = XmInternAtom(display,
"WM_PROTOCOLS",
FALSE);
187 dwAtom = XmInternAtom(display,
"WM_DELETE_WINDOW",
FALSE);
188 }
189 XmAddProtocolCallback(shell, wmpAtom, dwAtom, closeCB, arg);
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203 void SuppressPassiveGrabWarnings(
void)
204 {
205 #if !defined(__alpha) && !defined(
__EMX__)
206 XtSetWarningHandler(warnHandlerCB);
207 #endif
208 }
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231 void RemapDeleteKey(Widget w)
232 {
233 static XtTranslations table =
NULL;
234 static char *translations =
235 "~Shift~Ctrl~Meta~Alt<Key>osfDelete: delete-previous-character()\n";
236
237 if (RemapDeleteEnabled) {
238 if (table ==
NULL)
239 table = XtParseTranslationTable(translations);
240 XtOverrideTranslations(w, table);
241 }
242 }
243
244 void SetDeleteRemap(
int state)
245 {
246 RemapDeleteEnabled = state;
247 }
248
249
250
251
252
253
254
255
256
257 static void setWindowGroup(Widget shell) {
258 static int firstTime = True;
259 static Window groupLeader;
260 Display *display = XtDisplay(shell);
261 XWMHints *wmHints;
262
263 if (firstTime) {
264
265 String name, class;
266 XClassHint *classHint;
267
268 groupLeader = XCreateSimpleWindow(display,
269 RootWindow(display, DefaultScreen(display)),
270 1,
1,
1,
1,
0,
0,
0);
271
272
273
274 XtGetApplicationNameAndClass(display, &name, &class);
275 classHint = XAllocClassHint();
276 classHint->res_name = name;
277 classHint->res_class = class;
278 XSetClassHint(display, groupLeader, classHint);
279 XFree(classHint);
280
281 firstTime = False;
282 }
283
284
285 wmHints = XGetWMHints(display, XtWindow(shell));
286 wmHints->window_group = groupLeader;
287 wmHints->flags |= WindowGroupHint;
288 XSetWMHints(display, XtWindow(shell), wmHints);
289 XFree(wmHints);
290 }
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312 void RemovePPositionHint(Widget shell)
313 {
314 XSizeHints *hints = XAllocSizeHints();
315 long suppliedHints;
316
317
318 if (XGetWMNormalHints(XtDisplay(shell), XtWindow(shell), hints,
319 &suppliedHints))
320 {
321 hints->flags &= ~PPosition;
322 XSetWMNormalHints(XtDisplay(shell), XtWindow(shell), hints);
323 }
324
325 XFree(hints);
326 }
327
328 void RealizeWithoutForcingPosition(Widget shell)
329 {
330 Boolean mappedWhenManaged;
331
332
333
334 XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged,
NULL);
335 XtVaSetValues(shell, XmNmappedWhenManaged, False,
NULL);
336
337
338 XtRealizeWidget(shell);
339
340
341 RemovePPositionHint(shell);
342
343
344
345 setWindowGroup(shell);
346
347
348 XtMapWidget(shell);
349
350
351 XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged,
NULL);
352
353 if(GetWindowDarkTheme()) {
354 SetWindowGtkThemeVariant(XtDisplay(shell), XtWindow(shell),
2);
355 }
356
357 XdndEnable(shell);
358 }
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392 Boolean FindBestVisual(Display *display,
const char *appName,
const char *appClass,
393 Visual **visual,
int *depth, Colormap *colormap)
394 {
395 char rsrcName[
256], rsrcClass[
256], *valueString, *type, *endPtr;
396 XrmValue value;
397 int screen = DefaultScreen(display);
398 int reqDepth = -
1;
399 long reqID = -
1;
400 int reqClass = -
1;
401 int installColormap =
FALSE;
402 int maxDepth, bestClass, bestVisual, nVis, i, j;
403 XVisualInfo visTemplate, *visList =
NULL;
404 static Visual *cachedVisual =
NULL;
405 static Colormap cachedColormap;
406 static int cachedDepth =
0;
407 int bestClasses[] = {StaticGray, GrayScale, StaticColor, PseudoColor,
408 DirectColor, TrueColor};
409
410
411 if (cachedVisual !=
NULL) {
412 *visual = cachedVisual;
413 *depth = cachedDepth;
414 *colormap = cachedColormap;
415 return (*visual == DefaultVisual(display, screen));
416 }
417
418
419
420
421 sprintf(rsrcName,
"%s.%s", appName,
"visualID");
422 sprintf(rsrcClass,
"%s.%s", appClass,
"VisualID");
423 if (XrmGetResource(XtDatabase(display), rsrcName, rsrcClass, &type,
424 &value)) {
425 valueString = value.addr;
426 reqID = (
int)strtol(valueString, &endPtr,
0);
427 if (endPtr == valueString) {
428 reqID = -
1;
429 if (stripCaseCmp(valueString,
"Default"))
430 reqID = DefaultVisual(display, screen)->visualid;
431 else if (stripCaseCmp(valueString,
"StaticGray"))
432 reqClass = StaticGray;
433 else if (stripCaseCmp(valueString,
"StaticColor"))
434 reqClass = StaticColor;
435 else if (stripCaseCmp(valueString,
"TrueColor"))
436 reqClass = TrueColor;
437 else if (stripCaseCmp(valueString,
"GrayScale"))
438 reqClass = GrayScale;
439 else if (stripCaseCmp(valueString,
"PseudoColor"))
440 reqClass = PseudoColor;
441 else if (stripCaseCmp(valueString,
"DirectColor"))
442 reqClass = DirectColor;
443 else if (!stripCaseCmp(valueString,
"Best"))
444 fprintf(stderr,
"Invalid visualID resource value\n");
445 }
446 }
447 sprintf(rsrcName,
"%s.%s", appName,
"installColormap");
448 sprintf(rsrcClass,
"%s.%s", appClass,
"InstallColormap");
449 if (XrmGetResource(XtDatabase(display), rsrcName, rsrcClass, &type,
450 &value)) {
451 if (stripCaseCmp(value.addr,
"Yes") || stripCaseCmp(value.addr,
"True"))
452 installColormap =
TRUE;
453 }
454
455 visTemplate.screen = screen;
456
457
458
459
460 if (reqID != -
1) {
461 visTemplate.visualid = reqID;
462 visList = XGetVisualInfo(display, VisualScreenMask|VisualIDMask,
463 &visTemplate, &nVis);
464 if (visList ==
NULL)
465 fprintf(stderr,
"VisualID resource value not valid\n");
466 }
467 if (visList ==
NULL && reqClass != -
1 && reqDepth != -
1) {
468 visTemplate.class = reqClass;
469 visTemplate.depth = reqDepth;
470 visList = XGetVisualInfo(display,
471 VisualScreenMask| VisualClassMask | VisualDepthMask,
472 &visTemplate, &nVis);
473 if (visList ==
NULL)
474 fprintf(stderr,
"Visual class/depth combination not available\n");
475 }
476 if (visList ==
NULL && reqClass != -
1) {
477 visTemplate.class = reqClass;
478 visList = XGetVisualInfo(display, VisualScreenMask|VisualClassMask,
479 &visTemplate, &nVis);
480 if (visList ==
NULL)
481 fprintf(stderr,
482 "Visual Class from resource \"visualID\" not available\n");
483 }
484 if (visList ==
NULL && reqDepth != -
1) {
485 visTemplate.depth = reqDepth;
486 visList = XGetVisualInfo(display, VisualScreenMask|VisualDepthMask,
487 &visTemplate, &nVis);
488 if (visList ==
NULL)
489 fprintf(stderr,
"Requested visual depth not available\n");
490 }
491 if (visList ==
NULL) {
492 visList = XGetVisualInfo(display, VisualScreenMask, &visTemplate, &nVis);
493 if (visList ==
NULL) {
494 fprintf(stderr,
"Internal Error: no visuals available?\n");
495 *visual = DefaultVisual(display, screen);
496 *depth = DefaultDepth(display, screen);
497 *colormap = DefaultColormap(display, screen);
498 return True;
499 }
500 }
501
502
503
504
505 maxDepth =
0;
506 bestClass =
0;
507 bestVisual =
0;
508 for (i=
0; i < nVis; i++) {
509
510
511
512
513
514
515
516
517
518
519
520 if (visList[i].depth >=
32 &&
521 strstr(ServerVendor(display),
"X.Org") !=
0) {
522 continue;
523 }
524 if (visList[i].depth > maxDepth) {
525 maxDepth = visList[i].depth;
526 bestClass =
0;
527 bestVisual = i;
528 }
529 if (visList[i].depth == maxDepth) {
530 if (visList[i].visual == DefaultVisual(display, screen))
531 bestVisual = i;
532 if (visList[bestVisual].visual != DefaultVisual(display, screen)) {
533 for (j =
0; j < (
int)XtNumber(bestClasses); j++) {
534 if (visList[i].class == bestClasses[j] && j > bestClass) {
535 bestClass = j;
536 bestVisual = i;
537 }
538 }
539 }
540 }
541 }
542 *visual = cachedVisual = visList[bestVisual].visual;
543 *depth = cachedDepth = visList[bestVisual].depth;
544
545
546 if (*visual == DefaultVisual(display, screen) && !installColormap)
547 *colormap = cachedColormap = DefaultColormap(display, screen);
548 else {
549 *colormap = cachedColormap = XCreateColormap(display,
550 RootWindow(display, screen), cachedVisual, AllocNone);
551 XInstallColormap(display, cachedColormap);
552 }
553
554
555
556
557 if (visList !=
NULL) {
558 XFree(visList);
559 }
560
561 return (*visual == DefaultVisual(display, screen));
562 }
563
564
565
566
567
568
569
570
571 Widget CreateDialogShell(Widget parent,
char *name,
572 ArgList arglist, Cardinal argcount)
573 {
574 return addParentVisArgsAndCall(XmCreateDialogShell, parent, name, arglist,
575 argcount);
576 }
577
578
579 Widget CreatePopupMenu(Widget parent,
char *name, ArgList arglist,
580 Cardinal argcount)
581 {
582 return addParentVisArgsAndCall(XmCreatePopupMenu, parent, name,
583 arglist, argcount);
584 }
585
586
587 Widget CreatePulldownMenu(Widget parent,
char *name,
588 ArgList arglist, Cardinal argcount)
589 {
590 return addParentVisArgsAndCall(XmCreatePulldownMenu, parent, name, arglist,
591 argcount);
592 }
593
594
595 Widget CreatePromptDialog(Widget parent,
char *name,
596 ArgList arglist, Cardinal argcount)
597 {
598 return addParentVisArgsAndCall(XmCreatePromptDialog, parent, name, arglist,
599 argcount);
600 }
601
602
603 Widget CreateSelectionDialog(Widget parent,
char *name,
604 ArgList arglist, Cardinal argcount)
605 {
606 Widget dialog = addParentVisArgsAndCall(XmCreateSelectionDialog, parent, name,
607 arglist, argcount);
608 AddMouseWheelSupport(XmSelectionBoxGetChild(dialog, XmDIALOG_LIST));
609 return dialog;
610 }
611
612
613 Widget CreateFormDialog(Widget parent,
char *name,
614 ArgList arglist, Cardinal argcount)
615 {
616 return addParentVisArgsAndCall(XmCreateFormDialog, parent, name, arglist,
617 argcount);
618 }
619
620
621 Widget CreateFileSelectionDialog(Widget parent,
char *name,
622 ArgList arglist, Cardinal argcount)
623 {
624 Widget dialog = addParentVisArgsAndCall(XmCreateFileSelectionDialog, parent,
625 name, arglist, argcount);
626
627 AddMouseWheelSupport(XmFileSelectionBoxGetChild(dialog, XmDIALOG_LIST));
628 AddMouseWheelSupport(XmFileSelectionBoxGetChild(dialog, XmDIALOG_DIR_LIST));
629 return dialog;
630 }
631
632
633 Widget CreateQuestionDialog(Widget parent,
char *name,
634 ArgList arglist, Cardinal argcount)
635 {
636 return addParentVisArgsAndCall(XmCreateQuestionDialog, parent, name,
637 arglist, argcount);
638 }
639
640
641 Widget CreateMessageDialog(Widget parent,
char *name,
642 ArgList arglist, Cardinal argcount)
643 {
644 return addParentVisArgsAndCall(XmCreateMessageDialog, parent, name,
645 arglist, argcount);
646 }
647
648
649 Widget CreateErrorDialog(Widget parent,
char *name,
650 ArgList arglist, Cardinal argcount)
651 {
652 return addParentVisArgsAndCall(XmCreateErrorDialog, parent, name, arglist,
653 argcount);
654 }
655
656 Widget CreateWidget(Widget parent,
const char *name, WidgetClass class,
657 ArgList arglist, Cardinal argcount)
658 {
659 Widget result;
660 ArgList al = addParentVisArgs(parent, arglist, &argcount);
661 result = XtCreateWidget(name, class, parent, al, argcount);
662 NEditFree((
char *)al);
663 return result;
664 }
665
666 Widget CreateShellWithBestVis(String appName, String appClass,
667 WidgetClass class, Display *display, ArgList args, Cardinal nArgs)
668 {
669 Visual *visual;
670 int depth;
671 Colormap colormap;
672 ArgList al;
673 Cardinal ac = nArgs;
674 Widget result;
675
676 FindBestVisual(display, appName, appClass, &visual, &depth, &colormap);
677 al = (ArgList)NEditMalloc(
sizeof(Arg) * (nArgs +
3));
678 if (nArgs !=
0)
679 memcpy(al, args,
sizeof(Arg) * nArgs);
680 XtSetArg(al[ac], XtNvisual, visual); ac++;
681 XtSetArg(al[ac], XtNdepth, depth); ac++;
682 XtSetArg(al[ac], XtNcolormap, colormap); ac++;
683 result = XtAppCreateShell(appName, appClass, class, display, al, ac);
684 NEditFree((
char *)al);
685 return result;
686 }
687
688
689 Widget CreatePopupShellWithBestVis(String shellName, WidgetClass class,
690 Widget parent, ArgList arglist, Cardinal argcount)
691 {
692 Widget result;
693 ArgList al = addParentVisArgs(parent, arglist, &argcount);
694 result = XtCreatePopupShell(shellName, class, parent, al, argcount);
695 NEditFree((
char *)al);
696 return result;
697 }
698
699
700
701
702
703
704 static ArgList addParentVisArgs(Widget parent, ArgList arglist,
705 Cardinal *argcount)
706 {
707 Visual *visual;
708 int depth;
709 Colormap colormap;
710 ArgList al;
711 Widget parentShell = parent;
712
713
714
715 while (True) {
716 if (XtIsShell(parentShell))
717 break;
718 if (parentShell ==
NULL) {
719 fprintf(stderr,
"failed to find shell\n");
720 exit(
EXIT_FAILURE);
721 }
722 parentShell = XtParent(parentShell);
723 }
724
725
726 XtVaGetValues(parentShell, XtNvisual, &visual, XtNdepth, &depth,
727 XtNcolormap, &colormap,
NULL);
728 al = (ArgList)NEditMalloc(
sizeof(Arg) * ((*argcount) +
3));
729 if ((*argcount) !=
0)
730 memcpy(al, arglist,
sizeof(Arg) * (*argcount));
731
732
733
734
735
736
737
738
739 XtSetArg(al[*argcount], XtNvisual, visual); (*argcount)++;
740 XtSetArg(al[*argcount], XtNdepth, depth); (*argcount)++;
741 XtSetArg(al[*argcount], XtNcolormap, colormap); (*argcount)++;
742 return al;
743 }
744
745
746
747
748
749
750 static Widget addParentVisArgsAndCall(MotifDialogCreationCall createRoutine,
751 Widget parent,
char *name, ArgList arglist, Cardinal argcount)
752 {
753 Widget result;
754 ArgList al = addParentVisArgs(parent, arglist, &argcount);
755 result = (*createRoutine)(parent, name, al, argcount);
756 NEditFree((
char *)al);
757 return result;
758 }
759
760
761
762
763
764
765
766
767
768
769 void ManageDialogCenteredOnPointer(Widget dialogChild)
770 {
771 Widget shell = XtParent(dialogChild);
772 Window root, child;
773 unsigned int mask;
774 unsigned int width, height, borderWidth, depth;
775 int x, y, winX, winY, maxX, maxY, maxWidth, maxHeight;
776 Dimension xtWidth, xtHeight;
777 Boolean mappedWhenManaged;
778 static const int slop =
25;
779
780
781
782 XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged,
NULL);
783 XtVaSetValues(shell, XmNmappedWhenManaged, False,
NULL);
784
785
786
787
788
789
790
791 maxWidth = XtScreen(shell)->width - slop;
792 maxHeight = XtScreen(shell)->height - slop;
793
794 XtVaSetValues(shell,
795 XmNmaxWidth, maxWidth,
796 XmNmaxHeight, maxHeight,
797 NULL);
798
799
800 XtManageChild(dialogChild);
801
802
803
804
805
806 XtVaGetValues(shell, XmNwidth, &xtWidth, XmNheight, &xtHeight,
NULL);
807 if (xtWidth > maxWidth)
808 XtVaSetValues(shell, XmNwidth, (Dimension) maxWidth,
NULL);
809 if (xtHeight > maxHeight)
810 XtVaSetValues(shell, XmNheight, (Dimension) maxHeight,
NULL);
811
812
813
814
815 if (PointerCenteredDialogsEnabled) {
816
817 XQueryPointer(XtDisplay(shell), XtWindow(shell), &root, &child,
818 &x, &y, &winX, &winY, &mask);
819
820
821
822 XGetGeometry(XtDisplay(shell), XtWindow(shell), &root, &winX, &winY,
823 &width, &height, &borderWidth, &depth);
824 width +=
2 * borderWidth;
825 height +=
2 * borderWidth;
826
827 x -= width/
2;
828 y -= height/
2;
829
830
831 maxX = maxWidth - width;
832 maxY = maxHeight - height;
833 if (x > maxX) x = maxX;
834 if (x <
0) x =
0;
835 if (y > maxY) y = maxY;
836 if (y <
0) y =
0;
837
838
839
840
841
842
843 XtVaSetValues(shell, XmNuseAsyncGeometry, True,
NULL);
844
845
846 XtVaSetValues(shell, XmNx, x, XmNy, y,
NULL);
847 }
848
849
850 XtMapWidget(shell);
851
852
853 XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged,
NULL);
854
855 if(GetWindowDarkTheme()) {
856 SetWindowGtkThemeVariant(XtDisplay(shell), XtWindow(shell),
2);
857 }
858 }
859
860
861
862
863
864
865
866 void SetPointerCenteredDialogs(
int state)
867 {
868 PointerCenteredDialogsEnabled = state;
869 }
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888 void RaiseDialogWindow(Widget shell)
889 {
890 RaiseWindow(XtDisplay(shell), XtWindow(shell), True);
891 }
892
893 void RaiseShellWindow(Widget shell, Boolean focus)
894 {
895 RaiseWindow(XtDisplay(shell), XtWindow(shell), focus);
896 }
897
898 void RaiseWindow(Display *display, Window w, Boolean focus)
899 {
900 if (focus) {
901 XWindowAttributes winAttr;
902
903 XGetWindowAttributes(display, w, &winAttr);
904 if (winAttr.map_state == IsViewable)
905 XSetInputFocus(display, w, RevertToParent, CurrentTime);
906 }
907
908 WmClientMsg(display, w,
"_NET_ACTIVE_WINDOW",
0,
0,
0,
0,
0);
909 XMapRaised(display, w);
910 }
911
912
913
914
915
916
917
918
919
920
921
922
923 void AddDialogMnemonicHandler(Widget dialog,
int unmodifiedToo)
924 {
925 XtAddEventHandler(dialog, KeyPressMask, False,
926 (XtEventHandler)mnemonicCB, (XtPointer)
0);
927 addMnemonicGrabs(dialog, dialog, unmodifiedToo);
928 }
929
930
931
932
933 void RemoveDialogMnemonicHandler(Widget dialog)
934 {
935 XtUngrabKey(dialog, AnyKey, Mod1Mask);
936 XtRemoveEventHandler(dialog, KeyPressMask, False,
937 (XtEventHandler)mnemonicCB, (XtPointer)
0);
938 }
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953 void AccelLockBugPatch(Widget topWidget, Widget topMenuContainer)
954 {
955 XtAddEventHandler(topWidget, KeyPressMask, False, lockCB, topMenuContainer);
956 addAccelGrabs(topWidget, topMenuContainer);
957 }
958
959
960
961
962
963
964 void UpdateAccelLockPatch(Widget topWidget, Widget newButton)
965 {
966 addAccelGrab(topWidget, newButton);
967 }
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982 void PopDownBugPatch(Widget w)
983 {
984 time_t stopTime;
985
986 stopTime = time(
NULL) +
1;
987 while (time(
NULL) <= stopTime) {
988 XEvent event;
989 XtAppContext context = XtWidgetToApplicationContext(w);
990 XtAppPeekEvent(context, &event);
991 if (event.xany.type == ReparentNotify)
992 return;
993 XtAppProcessEvent(context, XtIMAll);
994 }
995 }
996
997
998
999
1000
1001 char *GetXmStringText(XmString fromString)
1002 {
1003 XmStringContext context;
1004 char *text, *toPtr, *toString, *fromPtr;
1005 XmStringCharSet charset;
1006 XmStringDirection direction;
1007 Boolean separator;
1008
1009
1010
1011
1012 toString = (
char*)NEditMalloc(XmStringLength(fromString));
1013
1014
1015
1016 XmStringInitContext(&context, fromString);
1017 toPtr = toString;
1018 while (XmStringGetNextSegment(context, &text,
1019 &charset, &direction, &separator)) {
1020 for (fromPtr=text; *fromPtr!=
'\0'; fromPtr++)
1021 *toPtr++ = *fromPtr;
1022 if (separator)
1023 *toPtr++ =
'\n';
1024 NEditFree(text);
1025 NEditFree(charset);
1026 }
1027
1028
1029 *toPtr++ =
'\0';
1030 XmStringFreeContext(context);
1031 return toString;
1032 }
1033
1034
1035
1036
1037
1038
1039 XFontStruct *GetDefaultFontStruct(Display *d, XmFontList font)
1040 {
1041 XFontStruct *fs;
1042 XmFontContext context;
1043 XmStringCharSet charset;
1044
1045 XmFontListInitFontContext(&context, font);
1046 XmFontListGetNextFont(context, &charset, &fs);
1047 XmFontListFreeFontContext(context);
1048 NEditFree(charset);
1049
1050
1051 if (fs ==
NULL) {
1052 fs = XLoadQueryFont(d,
"fixed");
1053 }
1054
1055 if (fs ==
NULL) {
1056 fprintf(stderr,
"Unabled to load any fallback fonts.\n");
1057 exit(
EXIT_FAILURE);
1058 }
1059
1060 return fs;
1061 }
1062
1063
1064
1065
1066 XmString* StringTable(
int count, ... )
1067 {
1068 va_list ap;
1069 XmString *array;
1070 int i;
1071 char *str;
1072
1073 va_start(ap, count);
1074 array = (XmString*)NEditMalloc((count+
1) *
sizeof(XmString));
1075 for(i =
0; i < count; i++ ) {
1076 str = va_arg(ap,
char *);
1077 array[i] = XmStringCreateSimple(str);
1078 }
1079 array[i] = (XmString)
0;
1080 va_end(ap);
1081 return(array);
1082 }
1083
1084 void FreeStringTable(XmString *table)
1085 {
1086 int i;
1087
1088 for(i =
0; table[i] !=
0; i++)
1089 XmStringFree(table[i]);
1090 NEditFree((
char *)table);
1091 }
1092
1093
1094
1095
1096
1097
1098
1099 void SimulateButtonPress(Widget widget)
1100 {
1101 XEvent keyEvent;
1102
1103 memset((
char *)&keyEvent,
0,
sizeof(XKeyPressedEvent));
1104 keyEvent.type = KeyPress;
1105 keyEvent.xkey.serial =
1;
1106 keyEvent.xkey.send_event = True;
1107
1108 if (XtIsSubclass(widget, xmGadgetClass))
1109 {
1110
1111
1112
1113 Widget parent = XtParent(widget);
1114 keyEvent.xkey.display = XtDisplay(parent);
1115 keyEvent.xkey.window = XtWindow(parent);
1116
1117 XtCallActionProc(parent,
"ManagerGadgetSelect",
1118 &keyEvent,
NULL,
0);
1119 }
1120 else
1121 {
1122 keyEvent.xkey.display = XtDisplay(widget);
1123 keyEvent.xkey.window = XtWindow(widget);
1124
1125 XtCallActionProc(widget,
"ArmAndActivate", &keyEvent,
NULL,
0);
1126 }
1127 }
1128
1129
1130
1131
1132
1133 Widget AddMenuItem(Widget parent,
char *name,
char *label,
1134 char mnemonic,
char *acc,
char *accText,
1135 XtCallbackProc callback,
void *cbArg)
1136 {
1137 Widget button;
1138 XmString st1, st2;
1139
1140 button = XtVaCreateManagedWidget(name, xmPushButtonWidgetClass, parent,
1141 XmNlabelString, st1=XmStringCreateSimple(label),
1142 XmNmnemonic, mnemonic,
1143 XmNacceleratorText, st2=XmStringCreateSimple(accText),
1144 XmNaccelerator, acc,
NULL);
1145 XtAddCallback(button, XmNactivateCallback, callback, cbArg);
1146 XmStringFree(st1);
1147 XmStringFree(st2);
1148 return button;
1149 }
1150
1151
1152
1153
1154
1155 Widget AddMenuToggle(Widget parent,
char *name,
char *label,
1156 char mnemonic,
char *acc,
char *accText,
1157 XtCallbackProc callback,
void *cbArg,
int set)
1158 {
1159 Widget button;
1160 XmString st1, st2;
1161
1162 button = XtVaCreateManagedWidget(name, xmToggleButtonWidgetClass, parent,
1163 XmNlabelString, st1=XmStringCreateSimple(label),
1164 XmNmnemonic, mnemonic,
1165 XmNacceleratorText, st2=XmStringCreateSimple(accText),
1166 XmNaccelerator, acc,
1167 XmNset, set,
NULL);
1168 XtAddCallback(button, XmNvalueChangedCallback, callback, cbArg);
1169 XmStringFree(st1);
1170 XmStringFree(st2);
1171 return button;
1172 }
1173
1174
1175
1176
1177
1178
1179 Widget AddSubMenu(Widget parent,
char *name,
char *label,
char mnemonic)
1180 {
1181 Widget menu;
1182 XmString st1;
1183
1184 menu = CreatePulldownMenu(parent, name,
NULL,
0);
1185 XtVaCreateManagedWidget(name, xmCascadeButtonWidgetClass, parent,
1186 XmNlabelString, st1=XmStringCreateSimple(label),
1187 XmNmnemonic, mnemonic,
1188 XmNsubMenuId, menu,
NULL);
1189 XmStringFree(st1);
1190 return menu;
1191 }
1192
1193
1194
1195
1196
1197
1198 void SetIntText(Widget text,
int value)
1199 {
1200 char labelString[
20];
1201
1202 sprintf(labelString,
"%d", value);
1203 XmTextSetString(text, labelString);
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217 int GetFloatText(Widget text,
double *value)
1218 {
1219 char *strValue, *endPtr;
1220 int retVal;
1221
1222 strValue = XmTextGetString(text);
1223 removeWhiteSpace(strValue);
1224 *value = strtod(strValue, &endPtr);
1225 if (strlen(strValue) ==
0)
1226 retVal =
TEXT_IS_BLANK;
1227 else if (*endPtr !=
'\0')
1228 retVal =
TEXT_NOT_NUMBER;
1229 else
1230 retVal =
TEXT_READ_OK;
1231 NEditFree(strValue);
1232 return retVal;
1233 }
1234
1235 int GetIntText(Widget text,
int *value)
1236 {
1237 char *strValue, *endPtr;
1238 int retVal;
1239
1240 strValue = XmTextGetString(text);
1241 removeWhiteSpace(strValue);
1242 *value = strtol(strValue, &endPtr,
10);
1243 if (strlen(strValue) ==
0)
1244 retVal =
TEXT_IS_BLANK;
1245 else if (*endPtr !=
'\0')
1246 retVal =
TEXT_NOT_NUMBER;
1247 else
1248 retVal =
TEXT_READ_OK;
1249 NEditFree(strValue);
1250 return retVal;
1251 }
1252
1253 int GetFloatTextWarn(Widget text,
double *value,
const char *fieldName,
1254 int warnBlank)
1255 {
1256 int result;
1257 char *valueStr;
1258
1259 result = GetFloatText(text, value);
1260 if (result ==
TEXT_READ_OK || (result ==
TEXT_IS_BLANK && !warnBlank))
1261 return result;
1262 valueStr = XmTextGetString(text);
1263
1264 if (result ==
TEXT_IS_BLANK)
1265 {
1266 DialogF(
DF_ERR, text,
1,
"Warning",
"Please supply %s value",
"OK",
1267 fieldName);
1268 }
else
1269 {
1270 DialogF (
DF_ERR, text,
1,
"Warning",
"Can''t read %s value: \"%s\"",
1271 "OK", fieldName, valueStr);
1272 }
1273
1274 NEditFree(valueStr);
1275 return result;
1276 }
1277
1278 int GetIntTextWarn(Widget text,
int *value,
const char *fieldName,
int warnBlank)
1279 {
1280 int result;
1281 char *valueStr;
1282
1283 result = GetIntText(text, value);
1284 if (result ==
TEXT_READ_OK || (result ==
TEXT_IS_BLANK && !warnBlank))
1285 return result;
1286 valueStr = XmTextGetString(text);
1287
1288 if (result ==
TEXT_IS_BLANK)
1289 {
1290 DialogF (
DF_ERR, text,
1,
"Warning",
"Please supply a value for %s",
1291 "OK", fieldName);
1292 }
else
1293 {
1294 DialogF (
DF_ERR, text,
1,
"Warning",
1295 "Can''t read integer value \"%s\" in %s",
"OK", valueStr,
1296 fieldName);
1297 }
1298
1299 NEditFree(valueStr);
1300 return result;
1301 }
1302
1303 char* TextGetStringUtf8(Widget text) {
1304 char *string = XmTextFieldGetString(text);
1305 if(!string || strlen(string) ==
0) {
1306 return string;
1307 }
1308 char *encoding = nl_langinfo(
CODESET);
1309 if(encoding && strcmp(encoding,
"UTF-8")) {
1310 char *newstring = ConvertEncoding(string,
"UTF-8", encoding);
1311 if(newstring) {
1312 XtFree(string);
1313 string = newstring;
1314 }
1315 }
1316 return string;
1317 }
1318
1319 int TextWidgetIsBlank(Widget textW)
1320 {
1321 char *str;
1322 int retVal;
1323
1324 str = XmTextGetString(textW);
1325 removeWhiteSpace(str);
1326 retVal = *str ==
'\0';
1327 NEditFree(str);
1328 return retVal;
1329 }
1330
1331
1332
1333
1334
1335
1336
1337
1338 void MakeSingleLineTextW(Widget textW)
1339 {
1340 static XtTranslations noReturnTable =
NULL;
1341 static char *noReturnTranslations =
"<Key>Return: activate()\n";
1342
1343 if (noReturnTable ==
NULL)
1344 noReturnTable = XtParseTranslationTable(noReturnTranslations);
1345 XtOverrideTranslations(textW, noReturnTable);
1346 }
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358 void AddHistoryToTextWidget(Widget textW,
char ***historyList,
int *nItems)
1359 {
1360 histInfo *histData;
1361
1362
1363 histData = (histInfo *)NEditMalloc(
sizeof(histInfo));
1364 histData->list = historyList;
1365 histData->nItems = nItems;
1366 histData->index = -
1;
1367
1368
1369 XtAddEventHandler(textW, KeyPressMask, False,
1370 (XtEventHandler)histArrowKeyEH, histData);
1371
1372
1373 XtAddCallback(textW, XmNdestroyCallback, histDestroyCB, histData);
1374 }
1375
1376 static void histDestroyCB(Widget w, XtPointer clientData, XtPointer callData)
1377 {
1378 NEditFree((
char *)clientData);
1379 }
1380
1381 static void histArrowKeyEH(Widget w, XtPointer callData, XEvent *event,
1382 Boolean *continueDispatch)
1383 {
1384 histInfo *histData = (histInfo *)callData;
1385 KeySym keysym = XLookupKeysym((XKeyEvent *)event,
0);
1386
1387
1388 if (keysym != XK_Up && keysym != XK_Down)
1389 return;
1390
1391
1392 histData->index += (keysym == XK_Up) ?
1 : -
1;
1393
1394
1395 if (histData->index < -
1) {
1396 histData->index = -
1;
1397 XBell(XtDisplay(w),
0);
1398 return;
1399 }
1400 if (histData->index >= *histData->nItems) {
1401 histData->index = *histData->nItems -
1;
1402 XBell(XtDisplay(w),
0);
1403 return;
1404 }
1405
1406
1407 XmTextSetString(w, histData->index == -
1 ?
"" :
1408 (*histData->list)[histData->index]);
1409 }
1410
1411
1412
1413
1414
1415
1416
1417
1418 void AddToHistoryList(
char *newItem,
char ***historyList,
int *nItems)
1419 {
1420 char **newList;
1421 int i;
1422
1423 if (*nItems !=
0 && !strcmp(newItem, **historyList))
1424 return;
1425 if (*nItems ==
HISTORY_LIST_MAX) {
1426 for (i=
HISTORY_LIST_TRIM_TO; i<
HISTORY_LIST_MAX; i++)
1427 NEditFree((*historyList)[i]);
1428 *nItems =
HISTORY_LIST_TRIM_TO;
1429 }
1430 newList = (
char **)NEditMalloc(
sizeof(
char *) * (*nItems +
1));
1431 for (i=
0; i < *nItems; i++)
1432 newList[i+
1] = (*historyList)[i];
1433 if (*nItems !=
0 && *historyList !=
NULL)
1434 NEditFree(*historyList);
1435 (*nItems)++;
1436 newList[
0] = NEditStrdup(newItem);
1437 *historyList = newList;
1438 }
1439
1440
1441
1442
1443
1444
1445 void BeginWait(Widget topCursorWidget)
1446 {
1447 Display *display = XtDisplay(topCursorWidget);
1448 Pixmap pixmap;
1449 Pixmap maskPixmap;
1450 XColor xcolors[
2];
1451 static Cursor waitCursor =
0;
1452
1453
1454 if (!waitCursor) {
1455 pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
1456 (
char *)watch_bits, watch_width, watch_height);
1457
1458 maskPixmap = XCreateBitmapFromData(display, DefaultRootWindow(display),
1459 (
char *)watch_mask_bits, watch_width, watch_height);
1460
1461 xcolors[
0].pixel = BlackPixelOfScreen(DefaultScreenOfDisplay(display));
1462 xcolors[
1].pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(display));
1463
1464 XQueryColors(display, DefaultColormapOfScreen(
1465 DefaultScreenOfDisplay(display)), xcolors,
2);
1466 waitCursor = XCreatePixmapCursor(display, pixmap, maskPixmap,
1467 &xcolors[
0], &xcolors[
1], watch_x_hot, watch_y_hot);
1468 XFreePixmap(display, pixmap);
1469 XFreePixmap(display, maskPixmap);
1470 }
1471
1472
1473 XDefineCursor(display, XtWindow(topCursorWidget), waitCursor);
1474 }
1475
1476 void BusyWait(Widget widget)
1477 {
1478 #ifdef __unix__
1479 static const int timeout =
100000;
1480 static struct timeval last = {
0,
0 };
1481 struct timeval current;
1482 gettimeofday(¤t,
NULL);
1483
1484 if ((current.tv_sec != last.tv_sec) ||
1485 (current.tv_usec - last.tv_usec > timeout))
1486 {
1487 XmUpdateDisplay(widget);
1488 last = current;
1489 }
1490 #else
1491 static time_t last =
0;
1492 time_t current;
1493 time(¤t);
1494
1495 if (difftime(current, last) >
0)
1496 {
1497 XmUpdateDisplay(widget);
1498 last = current;
1499 }
1500 #endif
1501 }
1502
1503 void EndWait(Widget topCursorWidget)
1504 {
1505 XUndefineCursor(XtDisplay(topCursorWidget), XtWindow(topCursorWidget));
1506 }
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518 void CreateGeometryString(
char *string,
int x,
int y,
1519 int width,
int height,
int bitmask)
1520 {
1521 char *ptr = string;
1522 int nChars;
1523
1524 if (bitmask & WidthValue) {
1525 sprintf(ptr,
"%d%n", width, &nChars);
1526 ptr += nChars;
1527 }
1528 if (bitmask & HeightValue) {
1529 sprintf(ptr,
"x%d%n", height, &nChars);
1530 ptr += nChars;
1531 }
1532 if (bitmask & XValue) {
1533 if (bitmask & XNegative)
1534 sprintf(ptr,
"-%d%n", -x, &nChars);
1535 else
1536 sprintf(ptr,
"+%d%n", x, &nChars);
1537 ptr += nChars;
1538 }
1539 if (bitmask & YValue) {
1540 if (bitmask & YNegative)
1541 sprintf(ptr,
"-%d%n", -y, &nChars);
1542 else
1543 sprintf(ptr,
"+%d%n", y, &nChars);
1544 ptr += nChars;
1545 }
1546 *ptr =
'\0';
1547 }
1548
1549
1550
1551
1552 static void removeWhiteSpace(
char *string)
1553 {
1554 char *outPtr = string;
1555
1556 while (
TRUE) {
1557 if (*string ==
0) {
1558 *outPtr =
0;
1559 return;
1560 }
else if (*string !=
' ' && *string !=
'\t')
1561 *(outPtr++) = *(string++);
1562 else
1563 string++;
1564 }
1565 }
1566
1567
1568
1569
1570
1571 static int stripCaseCmp(
const char *str1,
const char *str2)
1572 {
1573 const char *c1, *c2;
1574
1575 for (c1=str1, c2=str2; *c1!=
'\0' && *c2!=
'\0'; c1++, c2++) {
1576 while (*c1 ==
' ' || *c1 ==
'\t')
1577 c1++;
1578 while (*c2 ==
' ' || *c2 ==
'\t')
1579 c2++;
1580 if (toupper((
unsigned char)*c1) != toupper((
unsigned char)*c2))
1581 return FALSE;
1582 }
1583 return *c1 ==
'\0' && *c2 ==
'\0';
1584 }
1585
1586 static void warnHandlerCB(String message)
1587 {
1588 if (strstr(message,
"XtRemoveGrab"))
1589 return;
1590 if (strstr(message,
"Attempt to remove non-existant passive grab"))
1591 return;
1592 fputs(message, stderr);
1593 fputc(
'\n', stderr);
1594 }
1595
1596 static XModifierKeymap *getKeyboardMapping(Display *display) {
1597 static XModifierKeymap *keyboardMap =
NULL;
1598
1599 if (keyboardMap ==
NULL) {
1600 keyboardMap = XGetModifierMapping(display);
1601 }
1602 return(keyboardMap);
1603 }
1604
1605
1606
1607
1608
1609
1610 static Modifiers findModifierMapping(Display *display, KeyCode keyCode) {
1611 int i, j;
1612 KeyCode *mapentry;
1613 XModifierKeymap *modMap = getKeyboardMapping(display);
1614
1615 if (modMap ==
NULL || keyCode ==
0) {
1616 return(
0);
1617 }
1618
1619 mapentry = modMap->modifiermap;
1620 for (i =
0; i <
8; ++i) {
1621 for (j =
0; j < (modMap->max_keypermod); ++j) {
1622 if (keyCode == *mapentry) {
1623 return(
1 << ((mapentry - modMap->modifiermap) / modMap->max_keypermod));
1624 }
1625 ++mapentry;
1626 }
1627 }
1628 return(
0);
1629 }
1630
1631 Modifiers GetNumLockModMask(Display *display) {
1632 static int numLockMask = -
1;
1633
1634 if (numLockMask == -
1) {
1635 numLockMask = findModifierMapping(display, XKeysymToKeycode(display, XK_Num_Lock));
1636 }
1637 return(numLockMask);
1638 }
1639
1640
1641
1642
1643
1644
1645 static void reallyGrabAKey(Widget dialog,
int keyCode, Modifiers mask) {
1646 Modifiers numLockMask = GetNumLockModMask(XtDisplay(dialog));
1647
1648 if (keyCode ==
0)
1649 return;
1650
1651 XtGrabKey(dialog, keyCode, mask, True, GrabModeAsync, GrabModeAsync);
1652 XtGrabKey(dialog, keyCode, mask|LockMask, True, GrabModeAsync, GrabModeAsync);
1653 if (numLockMask && numLockMask != LockMask) {
1654 XtGrabKey(dialog, keyCode, mask|numLockMask, True, GrabModeAsync, GrabModeAsync);
1655 XtGrabKey(dialog, keyCode, mask|LockMask|numLockMask, True, GrabModeAsync, GrabModeAsync);
1656 }
1657 }
1658
1659
1660
1661
1662
1663
1664
1665 static void addMnemonicGrabs(Widget dialog, Widget w,
int unmodifiedToo)
1666 {
1667 char mneString[
2];
1668 WidgetList children;
1669 Cardinal numChildren;
1670 int i, isMenu;
1671 KeySym mnemonic =
'\0';
1672 unsigned char rowColType;
1673 unsigned int keyCode;
1674
1675 if (XtIsComposite(w)) {
1676 if (XtClass(w) == xmRowColumnWidgetClass) {
1677 XtVaGetValues(w, XmNrowColumnType, &rowColType,
NULL);
1678 isMenu = rowColType != XmWORK_AREA;
1679 }
else
1680 isMenu = False;
1681 if (!isMenu) {
1682 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
1683 &numChildren,
NULL);
1684 for (i=
0; i<(
int)numChildren; i++)
1685 addMnemonicGrabs(dialog, children[i], unmodifiedToo);
1686 }
1687 }
else {
1688 XtVaGetValues(w, XmNmnemonic, &mnemonic,
NULL);
1689 if (mnemonic != XK_VoidSymbol && mnemonic !=
'\0') {
1690 mneString[
0] = mnemonic; mneString[
1] =
'\0';
1691 keyCode = XKeysymToKeycode(XtDisplay(dialog),
1692 XStringToKeysym(mneString));
1693 reallyGrabAKey(dialog, keyCode, Mod1Mask);
1694 if (unmodifiedToo)
1695 reallyGrabAKey(dialog, keyCode,
0);
1696 }
1697 }
1698 }
1699
1700
1701
1702
1703 static void mnemonicCB(Widget w, XtPointer callData, XKeyEvent *event)
1704 {
1705 findAndActivateMnemonic(w, event->keycode);
1706 }
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717 static void findAndActivateMnemonic(Widget w,
unsigned int keycode)
1718 {
1719 WidgetList children;
1720 Cardinal numChildren;
1721 int i, isMenu;
1722 KeySym mnemonic =
'\0';
1723 char mneString[
2];
1724 Widget userData;
1725 unsigned char rowColType;
1726
1727 if (XtIsComposite(w)) {
1728 if (XtClass(w) == xmRowColumnWidgetClass) {
1729 XtVaGetValues(w, XmNrowColumnType, &rowColType,
NULL);
1730 isMenu = rowColType != XmWORK_AREA;
1731 }
else
1732 isMenu = False;
1733 if (!isMenu) {
1734 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
1735 &numChildren,
NULL);
1736 for (i=
0; i<(
int)numChildren; i++)
1737 findAndActivateMnemonic(children[i], keycode);
1738 }
1739 }
else {
1740 XtVaGetValues(w, XmNmnemonic, &mnemonic,
NULL);
1741 if (mnemonic !=
'\0') {
1742 mneString[
0] = mnemonic; mneString[
1] =
'\0';
1743 if (XKeysymToKeycode(XtDisplay(XtParent(w)),
1744 XStringToKeysym(mneString)) == keycode) {
1745 if (XtClass(w) == xmLabelWidgetClass ||
1746 XtClass(w) == xmLabelGadgetClass) {
1747 XtVaGetValues(w, XmNuserData, &userData,
NULL);
1748 if (userData!=
NULL && XtIsWidget(userData) &&
1749 XmIsTraversable(userData))
1750 XmProcessTraversal(userData, XmTRAVERSE_CURRENT);
1751 }
else if (XmIsTraversable(w)) {
1752 XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1753 SimulateButtonPress(w);
1754 }
1755 }
1756 }
1757 }
1758 }
1759
1760
1761
1762
1763
1764
1765
1766
1767 static void addAccelGrabs(Widget topWidget, Widget w)
1768 {
1769 WidgetList children;
1770 Widget menu;
1771 Cardinal numChildren;
1772 int i;
1773
1774 if (XtIsComposite(w)) {
1775 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
1776 &numChildren,
NULL);
1777 for (i=
0; i<(
int)numChildren; i++)
1778 addAccelGrabs(topWidget, children[i]);
1779 }
else if (XtClass(w) == xmCascadeButtonWidgetClass) {
1780 XtVaGetValues(w, XmNsubMenuId, &menu,
NULL);
1781 if (menu !=
NULL)
1782 addAccelGrabs(topWidget, menu);
1783 }
else
1784 addAccelGrab(topWidget, w);
1785 }
1786
1787
1788
1789
1790
1791 static void addAccelGrab(Widget topWidget, Widget w)
1792 {
1793 char *accelString =
NULL;
1794 KeySym keysym;
1795 unsigned int modifiers;
1796 KeyCode code;
1797 Modifiers numLockMask = GetNumLockModMask(XtDisplay(topWidget));
1798
1799 XtVaGetValues(w, XmNaccelerator, &accelString,
NULL);
1800 if (accelString ==
NULL || *accelString ==
'\0') {
1801 NEditFree(accelString);
1802 return;
1803 }
1804
1805 if (!parseAccelString(XtDisplay(topWidget), accelString, &keysym, &modifiers)) {
1806 NEditFree(accelString);
1807 return;
1808 }
1809 NEditFree(accelString);
1810
1811
1812
1813
1814
1815
1816
1817 code = XKeysymToKeycode(XtDisplay(topWidget), keysym);
1818 if (code ==
0)
1819 return;
1820
1821 XtGrabKey(topWidget, code,
1822 modifiers | LockMask, True, GrabModeAsync, GrabModeAsync);
1823 if (numLockMask && numLockMask != LockMask) {
1824 XtGrabKey(topWidget, code,
1825 modifiers | numLockMask, True, GrabModeAsync, GrabModeAsync);
1826 XtGrabKey(topWidget, code,
1827 modifiers | LockMask | numLockMask, True, GrabModeAsync, GrabModeAsync);
1828 }
1829 }
1830
1831
1832
1833
1834
1835 static int parseAccelString(Display *display,
const char *string, KeySym *keySym,
1836 unsigned int *modifiers)
1837 {
1838 #define N_MODIFIERS 12
1839
1840 static char *modifierNames[
N_MODIFIERS] = {
"Ctrl",
"Shift",
"Alt",
"Mod2",
1841 "Mod3",
"Mod4",
"Mod5",
"Button1",
"Button2",
"Button3",
"Button4",
1842 "Button5"};
1843 static unsigned int modifierMasks[
N_MODIFIERS] = {ControlMask, ShiftMask,
1844 Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, Button1Mask, Button2Mask,
1845 Button3Mask, Button4Mask, Button5Mask};
1846 Modifiers numLockMask = GetNumLockModMask(display);
1847 char modStr[
MAX_ACCEL_LEN];
1848 char evtStr[
MAX_ACCEL_LEN];
1849 char keyStr[
MAX_ACCEL_LEN];
1850 const char *c, *evtStart, *keyStart;
1851 int i;
1852
1853 if (strlen(string) >=
MAX_ACCEL_LEN)
1854 return FALSE;
1855
1856
1857 for (c = string; *c !=
'<'; c++)
1858 if (*c ==
'\0')
1859 return FALSE;
1860 strncpy(modStr, string, c - string);
1861 modStr[c - string] =
'\0';
1862
1863
1864 evtStart = c;
1865 for ( ; *c !=
'>'; c++)
1866 if (*c ==
'\0')
1867 return FALSE;
1868 c++;
1869 strncpy(evtStr, evtStart, c - evtStart);
1870 evtStr[c - evtStart] =
'\0';
1871 if (!stripCaseCmp(evtStr,
"<key>") && !stripCaseCmp(evtStr,
"<keypress>"))
1872 return FALSE;
1873
1874
1875 keyStart = c;
1876 for ( ; *c !=
'\0' && !(c != keyStart && *c ==
':'); c++);
1877 strncpy(keyStr, keyStart, c - keyStart);
1878 keyStr[c - keyStart] =
'\0';
1879 *keySym = XStringToKeysym(keyStr);
1880
1881
1882 *modifiers =
0;
1883 c = modStr;
1884 while (*c !=
'\0') {
1885 while (*c ==
' ' || *c ==
'\t')
1886 c++;
1887 if (*c ==
'\0')
1888 break;
1889 for (i =
0; i <
N_MODIFIERS; i++) {
1890 if (!strncmp(c, modifierNames[i], strlen(modifierNames[i]))) {
1891 c += strlen(modifierNames[i]);
1892 if (modifierMasks[i] != numLockMask) {
1893 *modifiers |= modifierMasks[i];
1894 }
1895 break;
1896 }
1897 }
1898 if (i ==
N_MODIFIERS)
1899 return FALSE;
1900 }
1901
1902 return TRUE;
1903 }
1904
1905
1906
1907
1908
1909
1910 static void lockCB(Widget w, XtPointer callData, XEvent *event,
1911 Boolean *continueDispatch)
1912 {
1913 Modifiers numLockMask = GetNumLockModMask(XtDisplay(w));
1914 Widget topMenuWidget = (Widget)callData;
1915 *continueDispatch =
TRUE;
1916
1917 if (!(((XKeyEvent *)event)->state & (LockMask | numLockMask)))
1918 return;
1919
1920 if (findAndActivateAccel(topMenuWidget, ((XKeyEvent*) event)->keycode,
1921 ((XKeyEvent*) event)->state & ~(LockMask | numLockMask), event)) {
1922 *continueDispatch =
FALSE;
1923 }
1924 }
1925
1926
1927
1928
1929
1930 static int findAndActivateAccel(Widget w,
unsigned int keyCode,
1931 unsigned int modifiers, XEvent *event)
1932 {
1933 WidgetList children;
1934 Widget menu;
1935 Cardinal numChildren;
1936 int i;
1937 char *accelString =
NULL;
1938 KeySym keysym;
1939 unsigned int mods;
1940
1941 if (XtIsComposite(w)) {
1942 XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
1943 &numChildren,
NULL);
1944 for (i=
0; i<(
int)numChildren; i++)
1945 if (findAndActivateAccel(children[i], keyCode, modifiers, event))
1946 return TRUE;
1947 }
else if (XtClass(w) == xmCascadeButtonWidgetClass) {
1948 XtVaGetValues(w, XmNsubMenuId, &menu,
NULL);
1949 if (menu !=
NULL)
1950 if (findAndActivateAccel(menu, keyCode, modifiers, event))
1951 return TRUE;
1952 }
else {
1953 XtVaGetValues(w, XmNaccelerator, &accelString,
NULL);
1954 if (accelString !=
NULL && *accelString !=
'\0') {
1955 if (!parseAccelString(XtDisplay(w), accelString, &keysym, &mods))
1956 return FALSE;
1957 if (keyCode == XKeysymToKeycode(XtDisplay(w), keysym) &&
1958 modifiers == mods) {
1959 if (XtIsSensitive(w)) {
1960 XtCallActionProc(w,
"ArmAndActivate", event,
NULL,
0);
1961 return TRUE;
1962 }
1963 }
1964 }
1965 }
1966 return FALSE;
1967 }
1968
1969
1970
1971
1972 void InstallMouseWheelActions(XtAppContext context)
1973 {
1974 static XtActionsRec Actions[] = {
1975 {
"scrolled-window-scroll-up", scrollUpAP},
1976 {
"scrolled-window-page-up", pageUpAP},
1977 {
"scrolled-window-scroll-down", scrollDownAP},
1978 {
"scrolled-window-page-down", pageDownAP}
1979 };
1980
1981 XtAppAddActions(context, Actions, XtNumber(Actions));
1982 }
1983
1984 static Widget getScrolledWindow(Widget w)
1985 {
1986 Widget scrolledWindow = XtParent(w);
1987 if (!XmIsScrolledWindow(scrolledWindow)) {
1988 scrolledWindow = XtParent(scrolledWindow);
1989 }
1990 return scrolledWindow;
1991 }
1992
1993
1994
1995
1996
1997 void AddMouseWheelSupport(Widget w)
1998 {
1999 if (XmIsScrolledWindow(getScrolledWindow(w)))
2000 {
2001 static const char scrollTranslations[] =
2002 "Shift<Btn4Down>,<Btn4Up>: scrolled-window-scroll-up(1)\n"
2003 "Shift<Btn5Down>,<Btn5Up>: scrolled-window-scroll-down(1)\n"
2004 "Ctrl<Btn4Down>,<Btn4Up>: scrolled-window-page-up()\n"
2005 "Ctrl<Btn5Down>,<Btn5Up>: scrolled-window-page-down()\n"
2006 "<Btn4Down>,<Btn4Up>: scrolled-window-scroll-up(3)\n"
2007 "<Btn5Down>,<Btn5Up>: scrolled-window-scroll-down(3)\n";
2008 static XtTranslations trans_table =
NULL;
2009
2010 if (trans_table ==
NULL)
2011 {
2012 trans_table = XtParseTranslationTable(scrollTranslations);
2013 }
2014 XtOverrideTranslations(w, trans_table);
2015 }
2016 }
2017
2018
2019 void XmContainerAddMouseWheelSupport(Widget w)
2020 {
2021 if (XmIsScrolledWindow(getScrolledWindow(w)))
2022 {
2023 static const char scrollTranslations[] =
2024 "Shift<Btn4Down>,<Btn4Up>: scrolled-window-scroll-up(1)\n"
2025 "Shift<Btn5Down>,<Btn5Up>: scrolled-window-scroll-down(1)\n"
2026 "Ctrl<Btn4Down>,<Btn4Up>: scrolled-window-scroll-up(3)\n"
2027 "Ctrl<Btn5Down>,<Btn5Up>: scrolled-window-scroll-down(3)\n"
2028 "<Btn4Down>,<Btn4Up>: scrolled-window-page-up()\n"
2029 "<Btn5Down>,<Btn5Up>: scrolled-window-page-down()\n";
2030 static XtTranslations trans_table =
NULL;
2031
2032 if (trans_table ==
NULL)
2033 {
2034 trans_table = XtParseTranslationTable(scrollTranslations);
2035 }
2036 XtOverrideTranslations(w, trans_table);
2037 }
2038 }
2039
2040 static void pageUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
2041 {
2042 Widget scrolledWindow, scrollBar;
2043 String al[
1];
2044
2045 al[
0] =
"Up";
2046 scrolledWindow = getScrolledWindow(w);
2047 scrollBar = XtNameToWidget (scrolledWindow,
"VertScrollBar");
2048 if (scrollBar)
2049 XtCallActionProc(scrollBar,
"PageUpOrLeft", event, al,
1) ;
2050 return;
2051 }
2052
2053 static void pageDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
2054 {
2055 Widget scrolledWindow, scrollBar;
2056 String al[
1];
2057
2058 al[
0] =
"Down";
2059 scrolledWindow = getScrolledWindow(w);
2060 scrollBar = XtNameToWidget (scrolledWindow,
"VertScrollBar");
2061 if (scrollBar)
2062 XtCallActionProc(scrollBar,
"PageDownOrRight", event, al,
1) ;
2063 return;
2064 }
2065
2066 static void scrollUpAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
2067 {
2068 Widget scrolledWindow, scrollBar;
2069 String al[
1];
2070 int i, nLines;
2071
2072 if (*nArgs ==
0 || sscanf(args[
0],
"%d", &nLines) !=
1)
2073 return;
2074 al[
0] =
"Up";
2075 scrolledWindow = getScrolledWindow(w);
2076 scrollBar = XtNameToWidget (scrolledWindow,
"VertScrollBar");
2077 if (scrollBar)
2078 for (i=
0; i<nLines; i++)
2079 XtCallActionProc(scrollBar,
"IncrementUpOrLeft", event, al,
1) ;
2080 return;
2081 }
2082
2083 static void scrollDownAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
2084 {
2085 Widget scrolledWindow, scrollBar;
2086 String al[
1];
2087 int i, nLines;
2088
2089 if (*nArgs ==
0 || sscanf(args[
0],
"%d", &nLines) !=
1)
2090 return;
2091 al[
0] =
"Down";
2092 scrolledWindow = getScrolledWindow(w);
2093 scrollBar = XtNameToWidget (scrolledWindow,
"VertScrollBar");
2094 if (scrollBar)
2095 for (i=
0; i<nLines; i++)
2096 XtCallActionProc(scrollBar,
"IncrementDownOrRight", event, al,
1) ;
2097 return;
2098 }
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118 void RadioButtonChangeState(Widget widget, Boolean state, Boolean notify)
2119 {
2120
2121
2122
2123
2124
2125 #ifndef LESSTIF_VERSION
2126 #if XmVersion ==
2001 || (XmVersion ==
2002 && XmUPDATE_LEVEL <
3)
2127
2128 Widget focusW, shellW = widget;
2129 while (shellW && !XtIsShell(shellW)) {
2130 shellW = XtParent(shellW);
2131 }
2132 focusW = XtGetKeyboardFocusWidget(shellW);
2133
2134 if (state && XtIsRealized(widget))
2135 {
2136
2137
2138
2139
2140
2141
2142
2143 XEvent ev;
2144 if (XtIsManaged(widget))
2145 {
2146 Position x, y;
2147
2148 XtTranslateCoords(XtParent(widget), widget->core.x, widget->core.y,
2149 &x, &y);
2150 ev.xbutton.x_root = x + widget->core.border_width;
2151 ev.xbutton.y_root = y + widget->core.border_width;
2152 }
2153 else
2154 {
2155 ev.xbutton.x_root =
0;
2156 ev.xbutton.y_root =
0;
2157 }
2158
2159
2160
2161 ev.xany.type = ButtonPress;
2162 XtCallActionProc(widget,
"Arm", &ev,
NULL,
0);
2163 ev.xany.type = ButtonRelease;
2164 XtCallActionProc(widget,
"Select", &ev,
NULL,
0);
2165 XtCallActionProc(widget,
"Disarm", &ev,
NULL,
0);
2166 }
2167
2168 if (focusW) {
2169 XtSetKeyboardFocus(shellW, focusW);
2170 }
2171 #endif
2172 #endif
2173
2174
2175 XmToggleButtonSetState(widget, state, notify);
2176 }
2177
2178
2179
2180
2181
2182
2183
2184 void CloseAllPopupsFor(Widget shell)
2185 {
2186 #ifndef LESSTIF_VERSION
2187
2188
2189
2190
2191
2192 Widget app = XtParent(shell);
2193 int i;
2194
2195 for (i =
0; i < app->core.num_popups; i++) {
2196 Widget pop = app->core.popup_list[i];
2197 Widget shellFor;
2198
2199 XtVaGetValues(pop, XtNtransientFor, &shellFor,
NULL);
2200 if (shell == shellFor)
2201 _XmDismissTearOff(pop,
NULL,
NULL);
2202 }
2203 #endif
2204 }
2205
2206 static long queryDesktop(Display *display, Window window, Atom deskTopAtom)
2207 {
2208 long deskTopNumber =
0;
2209 Atom actualType;
2210 int actualFormat;
2211 unsigned long nItems, bytesAfter;
2212 unsigned char *prop;
2213
2214 if (XGetWindowProperty(display, window, deskTopAtom,
0,
1,
2215 False, AnyPropertyType, &actualType, &actualFormat, &nItems,
2216 &bytesAfter, &prop) != Success) {
2217 return -
1;
2218 }
2219
2220 if (actualType == None) {
2221 return -
1;
2222 }
2223
2224 if (actualFormat !=
32 || nItems !=
1) {
2225 XFree((
char*)prop);
2226 return -
1;
2227 }
2228
2229 deskTopNumber = *(
long*)prop;
2230 XFree((
char*)prop);
2231 return deskTopNumber;
2232 }
2233
2234
2235
2236
2237
2238 long QueryCurrentDesktop(Display *display, Window rootWindow)
2239 {
2240 static Atom currentDesktopAtom = (Atom)-
1;
2241
2242 if (currentDesktopAtom == (Atom)-
1)
2243 currentDesktopAtom = XInternAtom(display,
"_NET_CURRENT_DESKTOP", True);
2244
2245 if (currentDesktopAtom != None)
2246 return queryDesktop(display, rootWindow, currentDesktopAtom);
2247
2248 return -
1;
2249 }
2250
2251
2252
2253
2254
2255
2256 long QueryDesktop(Display *display, Widget shell)
2257 {
2258 static Atom wmDesktopAtom = (Atom)-
1;
2259
2260 if (wmDesktopAtom == (Atom)-
1)
2261 wmDesktopAtom = XInternAtom(display,
"_NET_WM_DESKTOP", True);
2262
2263 if (wmDesktopAtom != None)
2264 return queryDesktop(display, XtWindow(shell), wmDesktopAtom);
2265
2266 return -
1;
2267 }
2268
2269
2270
2271
2272
2273
2274
2275
2276 #define SPINCOUNT 10
2277 #define USLEEPTIME 1000
2278
2279
2280
2281
2282 static void warning(
const char* mesg)
2283 {
2284 fprintf(stderr,
"XNEdit warning:\n%s\n", mesg);
2285 }
2286
2287
2288
2289
2290 static void microsleep(
long usecs)
2291 {
2292 static struct timeval timeoutVal;
2293 timeoutVal.tv_sec = usecs/
1000000;
2294 timeoutVal.tv_usec = usecs - timeoutVal.tv_sec*
1000000;
2295 select(
0,
NULL,
NULL,
NULL, &timeoutVal);
2296 }
2297
2298
2299
2300
2301 int SpinClipboardStartCopy(Display *display, Window window,
2302 XmString clip_label, Time timestamp, Widget widget,
2303 XmCutPasteProc callback,
long *item_id)
2304 {
2305 int i, res;
2306 for (i=
0; i<
SPINCOUNT; ++i) {
2307 res = XmClipboardStartCopy(display, window, clip_label, timestamp,
2308 widget, callback, item_id);
2309 if (res == XmClipboardSuccess) {
2310 return res;
2311 }
2312 microsleep(
USLEEPTIME);
2313 }
2314 warning(
"XmClipboardStartCopy() failed: clipboard locked.");
2315 return res;
2316 }
2317
2318
2319
2320
2321 int SpinClipboardCopy(Display *display, Window window,
long item_id,
2322 char *format_name, XtPointer buffer,
unsigned long length,
2323 long private_id,
long *data_id)
2324 {
2325 int i, res;
2326 for (i=
0; i<
SPINCOUNT; ++i) {
2327 res = XmClipboardCopy(display, window, item_id, format_name,
2328 buffer, length, private_id, data_id);
2329 if (res == XmClipboardSuccess) {
2330 return res;
2331 }
2332 if (res == XmClipboardFail) {
2333 warning(
"XmClipboardCopy() failed: XmClipboardStartCopy not "
2334 "called or too many formats.");
2335 return res;
2336 }
2337 microsleep(
USLEEPTIME);
2338 }
2339 warning(
"XmClipboardCopy() failed: clipboard locked.");
2340 return res;
2341 }
2342
2343
2344
2345
2346 int SpinClipboardEndCopy(Display *display, Window window,
long item_id)
2347 {
2348 int i, res;
2349 for (i=
0; i<
SPINCOUNT; ++i) {
2350 res = XmClipboardEndCopy(display, window, item_id);
2351 if (res == XmClipboardSuccess) {
2352 return res;
2353 }
2354 if (res == XmClipboardFail) {
2355 warning(
"XmClipboardEndCopy() failed: XmClipboardStartCopy not "
2356 "called.");
2357 return res;
2358 }
2359 microsleep(
USLEEPTIME);
2360 }
2361 warning(
"XmClipboardEndCopy() failed: clipboard locked.");
2362 return res;
2363 }
2364
2365
2366
2367
2368 int SpinClipboardInquireLength(Display *display, Window window,
2369 char *format_name,
unsigned long *length)
2370 {
2371 int i, res;
2372 for (i=
0; i<
SPINCOUNT; ++i) {
2373 res = XmClipboardInquireLength(display, window, format_name, length);
2374 if (res == XmClipboardSuccess) {
2375 return res;
2376 }
2377 if (res == XmClipboardNoData) {
2378 return res;
2379 }
2380 microsleep(
USLEEPTIME);
2381 }
2382 warning(
"XmClipboardInquireLength() failed: clipboard locked.");
2383 return res;
2384 }
2385
2386
2387
2388
2389 int SpinClipboardRetrieve(Display *display, Window window,
char *format_name,
2390 XtPointer buffer,
unsigned long length,
unsigned long *num_bytes,
2391 long *private_id)
2392 {
2393 int i, res;
2394 for (i=
0; i<
SPINCOUNT; ++i) {
2395 res = XmClipboardRetrieve(display, window, format_name, buffer,
2396 length, num_bytes, private_id);
2397 if (res == XmClipboardSuccess) {
2398 return res;
2399 }
2400 if (res == XmClipboardTruncate) {
2401 warning(
"XmClipboardRetrieve() failed: buffer too small.");
2402 return res;
2403 }
2404 if (res == XmClipboardNoData) {
2405 return res;
2406 }
2407 microsleep(
USLEEPTIME);
2408 }
2409 warning(
"XmClipboardRetrieve() failed: clipboard locked.");
2410 return res;
2411 }
2412
2413
2414
2415
2416 int SpinClipboardLock(Display *display, Window window)
2417 {
2418 int i, res;
2419 for (i=
0; i<
SPINCOUNT; ++i) {
2420 res = XmClipboardLock(display, window);
2421 if (res == XmClipboardSuccess) {
2422 return res;
2423 }
2424 microsleep(
USLEEPTIME);
2425 }
2426 warning(
"XmClipboardLock() failed: clipboard locked.");
2427 return res;
2428 }
2429
2430
2431
2432
2433 int SpinClipboardUnlock(Display *display, Window window)
2434 {
2435 int i, res;
2436
2437 for (i=
0; i<
SPINCOUNT; ++i) {
2438
2439 res = XmClipboardUnlock(display, window, True);
2440 if (res == XmClipboardSuccess) {
2441 return res;
2442 }
2443 microsleep(
USLEEPTIME);
2444 }
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454 return res;
2455 }
2456
2457
2458
2459
2460
2461 void WmClientMsg(Display *disp, Window win,
const char *msg,
2462 unsigned long data0,
unsigned long data1,
2463 unsigned long data2,
unsigned long data3,
2464 unsigned long data4)
2465 {
2466 XEvent event;
2467 long mask = SubstructureRedirectMask | SubstructureNotifyMask;
2468
2469 event.xclient.type = ClientMessage;
2470 event.xclient.serial =
0;
2471 event.xclient.send_event = True;
2472 event.xclient.message_type = XInternAtom(disp, msg, False);
2473 event.xclient.window = win;
2474 event.xclient.format =
32;
2475 event.xclient.data.l[
0] = data0;
2476 event.xclient.data.l[
1] = data1;
2477 event.xclient.data.l[
2] = data2;
2478 event.xclient.data.l[
3] = data3;
2479 event.xclient.data.l[
4] = data4;
2480
2481 if (!XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) {
2482 fprintf(stderr,
"nedit: cannot send %s EWMH event.\n", msg);
2483 }
2484 }
2485
2486 char* ConvertEncodingLen(
const char *string,
size_t len,
const char *to,
const char *from) {
2487 if(!to || !from) {
2488 return NULL;
2489 }
2490
2491 iconv_t ic = iconv_open(to, from);
2492 if(ic == (
iconv_t) -
1) {
2493 return NULL;
2494 }
2495
2496 size_t size = len +
16;
2497 size_t pos =
0;
2498 size_t inleft = len;
2499 size_t outleft = size;
2500
2501 char *result = NEditMalloc(size+
1);
2502 char *in = (
char*)string;
2503 char *out = result;
2504 while(inleft >=
0) {
2505 if (inleft ==
0) {
2506 in =
NULL;
2507 }
2508
2509 size_t rc = iconv(ic, &in, &inleft, &out, &outleft);
2510 pos = out - result;
2511 if(rc == (
size_t)-
1) {
2512 switch(errno) {
2513 case EILSEQ:
2514 case EINVAL: {
2515 in++;
2516 inleft--;
2517 break;
2518 }
2519 case E2BIG: {
2520 size +=
32;
2521 result = NEditRealloc(result, size+
1);
2522 out = result + pos;
2523 outleft = size - pos;
2524 break;
2525 }
2526 }
2527 }
2528
2529 if(!in) {
2530 break;
2531 }
2532 }
2533
2534 iconv_close(ic);
2535 result[pos] =
'\0';
2536 return result;
2537 }
2538
2539 char* ConvertEncoding(
const char *string,
const char *to,
const char *from) {
2540 return ConvertEncodingLen(string, strlen(string), to, from);
2541 }
2542
2543 char* GetLocaleEncoding(
void) {
2544 return nl_langinfo(
CODESET);
2545 }
2546
2547 int IsUtf8Locale(
void) {
2548 char *encoding = nl_langinfo(
CODESET);
2549 if(encoding && !strcmp(encoding,
"UTF-8")) {
2550 return TRUE;
2551 }
2552 return FALSE;
2553 }
2554
2555 void SetWindowGtkThemeVariant(Display *dp, Window window,
int theme)
2556 {
2557 Atom atom = XInternAtom(dp,
"_GTK_THEME_VARIANT", False);
2558 Atom type = XInternAtom(dp,
"UTF8_STRING", False);
2559
2560 if(theme ==
0) {
2561 XDeleteProperty(dp, window, atom);
2562 }
else {
2563 const char *themeStr = theme ==
1 ?
"light" :
"dark";
2564 XChangeProperty(
2565 dp,
2566 window,
2567 atom,
2568 type,
2569 8,
2570 PropModeReplace,
2571 (
unsigned char*)themeStr,
2572 4);
2573 }
2574 }
2575