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 "textSel.h"
34 #include "textP.h"
35 #include "text.h"
36 #include "textDisp.h"
37 #include "textBuf.h"
38 #include "../util/misc.h"
39 #include "../util/nedit_malloc.h"
40
41 #include <stdio.h>
42 #include <string.h>
43 #include <limits.h>
44
45 #include <Xm/Xm.h>
46 #include <Xm/CutPaste.h>
47 #include <Xm/Text.h>
48 #include <X11/Xatom.h>
49 #if XmVersion >=
1002
50 #include <Xm/PrimitiveP.h>
51 #endif
52
53 #ifdef HAVE_DEBUG_H
54 #include "../debug.h"
55 #endif
56
57
58 static Time selectionTime =
0;
59
60 #define N_SELECT_TARGETS 8
61 #define N_ATOMS 12
62 enum atomIndex {
A_TEXT,
A_TARGETS,
A_MULTIPLE,
A_TIMESTAMP,
63 A_INSERT_SELECTION,
A_DELETE,
A_CLIPBOARD,
A_INSERT_INFO,
64 A_ATOM_PAIR,
A_MOTIF_DESTINATION,
A_COMPOUND_TEXT,
A_UTF8_STRING};
65
66
67
68
69 enum insertResultFlags {
INSERT_WAITING,
UNSUCCESSFUL_INSERT,
SUCCESSFUL_INSERT};
70
71
72
73 enum selectNotifyActions {
UNSELECT_SECONDARY,
REMOVE_SECONDARY,
74 EXCHANGE_SECONDARY};
75
76
77
78 typedef struct {
79 int action;
80 XtIntervalId timeoutProcID;
81 Time timeStamp;
82 Widget widget;
83 char *actionText;
84 int length;
85 } selectNotifyInfo;
86
87 typedef struct {
88 char *utf8String;
89 char *string;
90 size_t utf8slen;
91 size_t slen;
92 int isColFlag;
93 int cbCount;
94 } stringSelection;
95
96 static void modifiedCB(
int pos,
int nInserted,
int nDeleted,
97 int nRestyled,
const char *deletedText,
void *cbArg);
98 static void sendSecondary(Widget w, Time time, Atom sel,
int action,
99 char *actionText,
int actionTextLen);
100 static void getSelectionCB(Widget w, XtPointer clientData, Atom *selType,
101 Atom *type, XtPointer value,
unsigned long *length,
int *format);
102 static void getInsertSelectionCB(Widget w, XtPointer clientData,Atom *selType,
103 Atom *type, XtPointer value,
unsigned long *length,
int *format);
104 static void getExchSelCB(Widget w, XtPointer clientData, Atom *selType,
105 Atom *type, XtPointer value,
unsigned long *length,
int *format);
106 static Boolean convertSelectionCB(Widget w, Atom *selType, Atom *target,
107 Atom *type, XtPointer *value,
unsigned long *length,
int *format);
108 static void loseSelectionCB(Widget w, Atom *selType);
109 static Boolean convertSecondaryCB(Widget w, Atom *selType, Atom *target,
110 Atom *type, XtPointer *value,
unsigned long *length,
int *format);
111 static void loseSecondaryCB(Widget w, Atom *selType);
112 static Boolean convertMotifDestCB(Widget w, Atom *selType, Atom *target,
113 Atom *type, XtPointer *value,
unsigned long *length,
int *format);
114 static void loseMotifDestCB(Widget w, Atom *selType);
115 static void selectNotifyEH(Widget w, XtPointer data, XEvent *event,
116 Boolean *continueDispatch);
117 static void selectNotifyTimerProc(XtPointer clientData, XtIntervalId *id);
118 static Atom getAtom(Display *display,
int atomNum);
119
120
121
122
123
124 void HandleXSelections(Widget w)
125 {
126 int i;
127 textBuffer *buf = ((TextWidget)w)->text.textD->buffer;
128
129
130 for (i=
0; i<buf->nModifyProcs; i++) {
131 if (buf->modifyProcs[i] == modifiedCB) {
132 BufRemoveModifyCB(buf, modifiedCB, buf->cbArgs[i]);
133 break;
134 }
135 }
136
137
138 BufAddModifyCB(((TextWidget)w)->text.textD->buffer, modifiedCB, w);
139 }
140
141
142
143
144
145 void StopHandlingXSelections(Widget w)
146 {
147 int i;
148 textBuffer *buf = ((TextWidget)w)->text.textD->buffer;
149
150 for (i=
0; i<buf->nModifyProcs; i++) {
151 if (buf->modifyProcs[i] == modifiedCB && buf->cbArgs[i] == w) {
152 BufRemoveModifyCB(buf, modifiedCB, buf->cbArgs[i]);
153 return;
154 }
155 }
156 }
157
158
159
160 void CopyStringToClipboard(Widget w, Time time,
const char *text,
size_t length) {
161 long itemID =
0;
162 XmString s;
163 int stat;
164 int res;
165
166 if(!text || text[
0] ==
'\0')
167 {
168 return;
169 }
170
171 char *locale_text =
NULL;
172 if(!IsUtf8Locale()) {
173 locale_text = ConvertEncodingLen(text, length, GetLocaleEncoding(),
"UTF-8");
174 }
175
176
177 if (SpinClipboardLock(XtDisplay(w), XtWindow(w)) != ClipboardSuccess) {
178 if(locale_text) NEditFree(locale_text);
179 return;
180 }
181
182
183
184 s = XmStringCreateSimple(
"NEdit");
185 stat = SpinClipboardStartCopy(XtDisplay(w), XtWindow(w), s,
186 time, w,
NULL, &itemID);
187 XmStringFree(s);
188 if (stat != ClipboardSuccess) {
189 SpinClipboardUnlock(XtDisplay(w), XtWindow(w));
190 return;
191 }
192
193
194
195
196
197 res = SpinClipboardCopy(XtDisplay(w), XtWindow(w), itemID,
"UTF8_STRING",
198 (
char*)text, length,
0,
NULL);
199 if(res == ClipboardSuccess) {
200 int l_length = length;
201 const char *l_text = text;
202 if(locale_text) {
203 l_text = locale_text;
204 l_length = strlen(locale_text);
205 }
206 res = SpinClipboardCopy(XtDisplay(w), XtWindow(w), itemID,
"STRING",
207 (
char*)l_text, l_length,
0,
NULL);
208 }
209
210 if(locale_text) {
211 NEditFree(locale_text);
212 }
213
214 SpinClipboardEndCopy(XtDisplay(w), XtWindow(w), itemID);
215 SpinClipboardUnlock(XtDisplay(w), XtWindow(w));
216 }
217
218
219
220
221 void CopyToClipboard(Widget w, Time time)
222 {
223 char *text = BufGetSelectionText(((TextWidget)w)->text.textD->buffer);
224 size_t length = strlen(text);
225 BufUnsubstituteNullChars(text, ((TextWidget)w)->text.textD->buffer);
226
227 CopyStringToClipboard(w, time, text, length);
228 NEditFree(text);
229 }
230
231
232
233
234
235 void InsertPrimarySelection(Widget w, Time time,
int isColumnar)
236 {
237
238
239
240
241
242 stringSelection *sel = NEditMalloc(
sizeof(stringSelection));
243 sel->utf8String =
NULL;
244 sel->string =
NULL;
245 sel->utf8slen =
0;
246 sel->slen =
0;
247 sel->cbCount =
0;
248 sel->isColFlag = isColumnar;
249
250 Atom targets[
2] = {
XA_STRING, getAtom(XtDisplay(w),
A_UTF8_STRING)};
251
252 selectionTime = time;
253
254 XtGetSelectionValue(w,
XA_PRIMARY, targets[
1], getSelectionCB, sel, time);
255 XtGetSelectionValue(w,
XA_PRIMARY, targets[
0], getSelectionCB, sel, time);
256 }
257
258
259
260
261
262
263
264
265 void SendSecondarySelection(Widget w, Time time,
int removeAfter)
266 {
267 sendSecondary(w, time, getAtom(XtDisplay(w),
A_MOTIF_DESTINATION),
268 removeAfter ?
REMOVE_SECONDARY :
UNSELECT_SECONDARY,
NULL,
0);
269 }
270
271
272
273
274
275 void ExchangeSelections(Widget w, Time time)
276 {
277 if (!((TextWidget)w)->text.textD->buffer->secondary.selected)
278 return;
279
280
281
282
283
284
285
286
287
288
289
290
291 XtGetSelectionValue(w,
XA_PRIMARY,
XA_STRING, getExchSelCB,
NULL, time);
292 }
293
294
295
296
297
298
299 void MovePrimarySelection(Widget w, Time time,
int isColumnar)
300 {
301 stringSelection *sel = NEditMalloc(
sizeof(stringSelection));
302 sel->utf8String =
NULL;
303 sel->string =
NULL;
304 sel->cbCount =
0;
305 sel->isColFlag = isColumnar;
306
307 Atom targets[
3] = {
308 XA_STRING,
309 getAtom(XtDisplay(w),
A_UTF8_STRING),
310 getAtom(XtDisplay(w),
A_DELETE)};
311 void *data[
3] = { sel, sel, sel};
312
313 selectionTime = time;
314
315 XtGetSelectionValues(w,
XA_PRIMARY, targets,
3, getSelectionCB, data, time);
316 }
317
318
319 char* GetClipboard(Widget w) {
320 unsigned long length, retLength;
321 int res;
322 char *string;
323 char *type =
"UTF8_STRING";
324 long id =
0;
325 int convert =
FALSE;
326
327
328
329
330
331
332
333
334
335
336
337
338 res = SpinClipboardInquireLength(XtDisplay(w), XtWindow(w),
339 type, &length);
340 if(res != ClipboardSuccess || length ==
0) {
341 type =
"STRING";
342 res = SpinClipboardInquireLength(XtDisplay(w), XtWindow(w),
343 type, &length);
344 if(!IsUtf8Locale()) {
345 convert =
TRUE;
346 }
347 }
348
349 if (res != ClipboardSuccess || length ==
0) {
350
351
352
353
354 SpinClipboardUnlock(XtDisplay(w), XtWindow(w));
355 return NULL;
356 }
357 string = (
char*)NEditMalloc(length+
1);
358 if (SpinClipboardRetrieve(XtDisplay(w), XtWindow(w), type, string,
359 length, &retLength, &id) != ClipboardSuccess || retLength ==
0) {
360 NEditFree(string);
361
362
363
364
365 SpinClipboardUnlock(XtDisplay(w), XtWindow(w));
366 return NULL;
367 }
368 string[retLength] =
'\0';
369
370 if(convert) {
371 char *c_string = ConvertEncoding(string,
"UTF-8", GetLocaleEncoding());
372 if(c_string) {
373 NEditFree(string);
374 string = c_string;
375 retLength = strlen(c_string);
376 }
377 }
378
379 return string;
380 }
381
382
383
384
385
386 void InsertClipboard(Widget w,
int isColumnar)
387 {
388 unsigned long retLength;
389 textDisp *textD = ((TextWidget)w)->text.textD;
390 textBuffer *buf = ((TextWidget)w)->text.textD->buffer;
391 int cursorLineStart, column, cursorPos;
392
393 char *string = GetClipboard(w);
394 if(!string) {
395 return;
396 }
397 retLength = strlen(string);
398
399
400
401 if (!BufSubstituteNullChars(string, retLength, buf)) {
402 fprintf(stderr,
"Too much binary data, text not pasted\n");
403 NEditFree(string);
404 return;
405 }
406
407
408 if (isColumnar && !buf->primary.selected) {
409 cursorPos = TextDGetInsertPosition(textD);
410 cursorLineStart = BufStartOfLine(buf, cursorPos);
411 column = BufCountDispChars(buf, cursorLineStart, cursorPos);
412 if (((TextWidget)w)->text.overstrike) {
413 BufOverlayRect(buf, cursorLineStart, column, -
1, string,
NULL,
414 NULL);
415 }
else {
416 BufInsertCol(buf, column, cursorLineStart, string,
NULL,
NULL);
417 }
418 TextDSetInsertPosition(textD,
419 BufCountForwardDispChars(buf, cursorLineStart, column));
420 if (((TextWidget)w)->text.autoShowInsertPos)
421 TextDMakeInsertPosVisible(textD);
422 }
else
423 TextInsertAtCursor(w, string,
NULL, True,
424 ((TextWidget)w)->text.autoWrapPastedText);
425 NEditFree(string);
426 }
427
428
429
430
431
432
433
434 void TakeMotifDestination(Widget w, Time time)
435 {
436 if (((TextWidget)w)->text.motifDestOwner || ((TextWidget)w)->text.readOnly)
437 return;
438
439
440 if (!XtOwnSelection(w, getAtom(XtDisplay(w),
A_MOTIF_DESTINATION), time,
441 convertMotifDestCB, loseMotifDestCB,
NULL)) {
442 return;
443 }
444 ((TextWidget)w)->text.motifDestOwner = True;
445 }
446
447
448
449
450
451
452
453
454
455
456
457
458 static void modifiedCB(
int pos,
int nInserted,
int nDeleted,
459 int nRestyled,
const char *deletedText,
void *cbArg)
460 {
461 TextWidget w = (TextWidget)cbArg;
462 Time time = XtLastTimestampProcessed(XtDisplay((Widget)w));
463 int selected = w->text.textD->buffer->primary.selected;
464 int isOwner = w->text.selectionOwner;
465
466
467
468 if ((isOwner && selected) || (!isOwner && !selected))
469 return;
470
471
472
473
474
475
476
477
478 if (!XtOwnSelection((Widget)w,
XA_PRIMARY, time, convertSelectionCB,
479 loseSelectionCB,
NULL))
480 BufUnselect(w->text.textD->buffer);
481 else
482 w->text.selectionOwner = True;
483 }
484
485
486
487
488
489
490
491 static void sendSecondary(Widget w, Time time, Atom sel,
int action,
492 char *actionText,
int actionTextLen)
493 {
494 static Atom selInfoProp[
2] = {
XA_SECONDARY,
XA_STRING};
495 Display *disp = XtDisplay(w);
496 selectNotifyInfo *cbInfo;
497 XtAppContext context = XtWidgetToApplicationContext((Widget)w);
498
499
500 if (!XtOwnSelection(w,
XA_SECONDARY, time, convertSecondaryCB,
501 loseSecondaryCB,
NULL)) {
502 BufSecondaryUnselect(((TextWidget)w)->text.textD->buffer);
503 return;
504 }
505
506
507
508
509 XChangeProperty(disp, XtWindow(w), getAtom(disp,
A_INSERT_INFO),
510 getAtom(disp,
A_ATOM_PAIR),
32, PropModeReplace,
511 (
unsigned char *)selInfoProp,
2 );
512
513
514
515
516
517
518
519 XConvertSelection(XtDisplay(w), sel, getAtom(disp,
A_INSERT_SELECTION),
520 getAtom(disp,
A_INSERT_INFO), XtWindow(w), time);
521 cbInfo = (selectNotifyInfo *)NEditMalloc(
sizeof(selectNotifyInfo));
522 cbInfo->action = action;
523 cbInfo->timeStamp = time;
524 cbInfo->widget = (Widget)w;
525 cbInfo->actionText = actionText;
526 cbInfo->length = actionTextLen;
527 XtAddEventHandler(w,
0, True, selectNotifyEH, (XtPointer)cbInfo);
528 cbInfo->timeoutProcID = XtAppAddTimeOut(context,
529 XtAppGetSelectionTimeout(context),
530 selectNotifyTimerProc, (XtPointer)cbInfo);
531 }
532
533
534
535 static void selectionSetValue(
536 Widget w,
537 stringSelection *selection,
538 Atom selType,
539 Atom type,
540 XtPointer value,
541 unsigned long length,
542 int format)
543 {
544 selection->cbCount++;
545
546 Atom utf8 = getAtom(XtDisplay(w),
A_UTF8_STRING);
547
548 if(value && (type ==
XA_STRING || type == utf8) && format ==
8) {
549 char *string = NEditMalloc(length+
1);
550 memcpy(string, value, length);
551 string[length] =
'\0';
552
553 if(type ==
XA_STRING) {
554 selection->string = string;
555 selection->slen = length;
556 }
else {
557 selection->utf8String = string;
558 selection->utf8slen = length;
559 }
560 }
561
562 XtFree(value);
563
564 if(selection->cbCount ==
2) {
565 char *insertStr;
566 size_t insertStrLen;
567 if(selection->utf8String) {
568 insertStr = selection->utf8String;
569 insertStrLen = selection->utf8slen;
570 }
else {
571 insertStr = selection->string;
572 insertStrLen = selection->slen;
573 }
574 if(insertStr) {
575 textDisp *textD = ((TextWidget)w)->text.textD;
576
577 if (!BufSubstituteNullChars(insertStr, insertStrLen, textD->buffer)) {
578 fprintf(stderr,
"Too much binary data, giving up\n");
579 }
if (selection->isColFlag) {
580
581 int cursorPos = TextDGetInsertPosition(textD);
582 int cursorLineStart = BufStartOfLine(textD->buffer, cursorPos);
583 int row, column;
584 TextDXYToUnconstrainedPosition(textD, ((TextWidget)w)->text.btnDownX,
585 ((TextWidget)w)->text.btnDownY, &row, &column);
586 BufInsertCol(textD->buffer, column, cursorLineStart, insertStr,
NULL,
NULL);
587 TextDSetInsertPosition(textD, textD->buffer->cursorPosHint);
588 }
else {
589 TextInsertAtCursor(w, insertStr,
NULL, False,
590 ((TextWidget)w)->text.autoWrapPastedText);
591 }
592 }
593
594 if(selection->utf8String) {
595 NEditFree(selection->utf8String);
596 }
597 if(selection->string) {
598 NEditFree(selection->string);
599 }
600 NEditFree(selection);
601 }
602 }
603
604
605
606
607
608
609 static void getSelectionCB(Widget w, XtPointer clientData, Atom *selType,
610 Atom *type, XtPointer value,
unsigned long *length,
int *format)
611 {
612 selectionSetValue(w, clientData, *selType, *type, value, *length, *format);
613 }
614
615
616
617
618
619
620
621
622 static void getInsertSelectionCB(Widget w, XtPointer clientData,Atom *selType,
623 Atom *type, XtPointer value,
unsigned long *length,
int *format)
624 {
625 textBuffer *buf = ((TextWidget)w)->text.textD->buffer;
626 char *string;
627 int *resultFlag = (
int *)clientData;
628
629
630 if (*type !=
XA_STRING || *format !=
8 || value ==
NULL) {
631 NEditFree(value);
632 *resultFlag =
UNSUCCESSFUL_INSERT;
633 return;
634 }
635
636
637 string = (
char*)NEditMalloc(*length +
1);
638 memcpy(string, (
char *)value, *length);
639 string[*length] =
'\0';
640
641
642
643 if (!BufSubstituteNullChars(string, *length, buf)) {
644 fprintf(stderr,
"Too much binary data, giving up\n");
645 NEditFree(string);
646 NEditFree(value);
647 return;
648 }
649
650
651 TextInsertAtCursor(w, string,
NULL, True,
652 ((TextWidget)w)->text.autoWrapPastedText);
653 NEditFree(string);
654 *resultFlag =
SUCCESSFUL_INSERT;
655
656
657 NEditFree(value);
658 }
659
660
661
662
663
664
665
666
667 static void getExchSelCB(Widget w, XtPointer clientData, Atom *selType,
668 Atom *type, XtPointer value,
unsigned long *length,
int *format)
669 {
670
671 if (*length ==
0 || value ==
NULL || *type !=
XA_STRING || *format !=
8) {
672 NEditFree(value);
673 XBell(XtDisplay(w),
0);
674 BufSecondaryUnselect(((TextWidget)w)->text.textD->buffer);
675 return;
676 }
677
678
679
680
681 sendSecondary(w, XtLastTimestampProcessed(XtDisplay(w)),
XA_PRIMARY,
682 EXCHANGE_SECONDARY, (
char *)value, *length);
683 }
684
685
686
687
688
689
690
691
692
693 static Boolean convertSelectionCB(Widget w, Atom *selType, Atom *target,
694 Atom *type, XtPointer *value,
unsigned long *length,
int *format)
695 {
696 XSelectionRequestEvent *event = XtGetSelectionRequest(w, *selType,
0);
697 textBuffer *buf = ((TextWidget)w)->text.textD->buffer;
698 Display *display = XtDisplay(w);
699 Atom *targets, dummyAtom;
700 unsigned long nItems, dummyULong;
701 Atom *reqAtoms;
702 int getFmt, result =
INSERT_WAITING;
703 XEvent nextEvent;
704
705 Atom utf8 = getAtom(display,
A_UTF8_STRING);
706
707
708 if (*target ==
XA_STRING || *target == getAtom(display,
A_TEXT) ||
709 *target == getAtom(display,
A_COMPOUND_TEXT) || *target == utf8) {
710
711
712
713 *type = *target == utf8 ? utf8 :
XA_STRING;
714 *value = (XtPointer)BufGetSelectionText(buf);
715 *length = strlen((
char *)*value);
716 *format =
8;
717 BufUnsubstituteNullChars(*value, buf);
718 return True;
719 }
720
721
722 if (*target == getAtom(display,
A_TARGETS)) {
723 targets = (Atom *)NEditMalloc(
sizeof(Atom) *
N_SELECT_TARGETS);
724 targets[
0] =
XA_STRING;
725 targets[
1] = utf8;
726 targets[
2] = getAtom(display,
A_TEXT);
727 targets[
3] = getAtom(display,
A_TARGETS);
728 targets[
4] = getAtom(display,
A_MULTIPLE);
729 targets[
5] = getAtom(display,
A_TIMESTAMP);
730 targets[
6] = getAtom(display,
A_INSERT_SELECTION);
731 targets[
7] = getAtom(display,
A_DELETE);
732 *type =
XA_ATOM;
733 *value = (XtPointer)targets;
734 *length =
N_SELECT_TARGETS;
735 *format =
32;
736 return True;
737 }
738
739
740
741
742
743
744 if (*target == getAtom(display,
A_INSERT_SELECTION)) {
745 if (((TextWidget)w)->text.readOnly)
746 return False;
747 if (XGetWindowProperty(event->display, event->requestor,
748 event->property,
0,
2, False, AnyPropertyType, &dummyAtom,
749 &getFmt, &nItems, &dummyULong,
750 (
unsigned char **)&reqAtoms) != Success ||
751 getFmt !=
32 || nItems !=
2)
752 return False;
753 if (reqAtoms[
1] !=
XA_STRING)
754 return False;
755 XtGetSelectionValue(w, reqAtoms[
0], reqAtoms[
1],
756 getInsertSelectionCB, &result, event->time);
757 XFree((
char *)reqAtoms);
758 while (result ==
INSERT_WAITING) {
759 XtAppNextEvent(XtWidgetToApplicationContext(w), &nextEvent);
760 XtDispatchEvent(&nextEvent);
761 }
762 *type = getAtom(display,
A_INSERT_SELECTION);
763 *format =
8;
764 *value =
NULL;
765 *length =
0;
766 return result ==
SUCCESSFUL_INSERT;
767 }
768
769
770 if (*target == getAtom(display,
A_DELETE)) {
771 BufRemoveSelected(buf);
772 *length =
0;
773 *format =
8;
774 *type = getAtom(display,
A_DELETE);
775 *value =
NULL;
776 return True;
777 }
778
779
780
781 return False;
782 }
783
784 static void loseSelectionCB(Widget w, Atom *selType)
785 {
786 TextWidget tw = (TextWidget)w;
787 selection *sel = &tw->text.textD->buffer->primary;
788 char zeroWidth = sel->rectangular ? sel->zeroWidth :
0;
789
790
791
792 tw->text.selectionOwner = False;
793 BufUnselect(tw->text.textD->buffer);
794 sel->zeroWidth = zeroWidth;
795 }
796
797
798
799
800
801
802 static Boolean convertSecondaryCB(Widget w, Atom *selType, Atom *target,
803 Atom *type, XtPointer *value,
unsigned long *length,
int *format)
804 {
805 textBuffer *buf = ((TextWidget)w)->text.textD->buffer;
806
807
808 if (*target !=
XA_STRING && *target != getAtom(XtDisplay(w),
A_TEXT))
809 return False;
810
811
812
813 *type =
XA_STRING;
814 *value = (XtPointer)BufGetSecSelectText(buf);
815 *length = strlen((
char *)*value);
816 *format =
8;
817 BufUnsubstituteNullChars(*value, buf);
818 return True;
819 }
820
821 static void loseSecondaryCB(Widget w, Atom *selType)
822 {
823
824
825 }
826
827
828
829
830
831 static Boolean convertMotifDestCB(Widget w, Atom *selType, Atom *target,
832 Atom *type, XtPointer *value,
unsigned long *length,
int *format)
833 {
834 XSelectionRequestEvent *event = XtGetSelectionRequest(w, *selType,
0);
835 Display *display = XtDisplay(w);
836 Atom *targets, dummyAtom;
837 unsigned long nItems, dummyULong;
838 Atom *reqAtoms;
839 int getFmt, result =
INSERT_WAITING;
840 XEvent nextEvent;
841
842
843 if (*target == getAtom(display,
A_TARGETS)) {
844 targets = (Atom *)NEditMalloc(
sizeof(Atom) *
3);
845 targets[
0] = getAtom(display,
A_TARGETS);
846 targets[
1] = getAtom(display,
A_TIMESTAMP);
847 targets[
2] = getAtom(display,
A_INSERT_SELECTION);
848 *type =
XA_ATOM;
849 *value = (XtPointer)targets;
850 *length =
3;
851 *format =
32;
852 return True;
853 }
854
855
856
857
858
859
860 if (*target == getAtom(display,
A_INSERT_SELECTION)) {
861 if (((TextWidget)w)->text.readOnly)
862 return False;
863 if (XGetWindowProperty(event->display, event->requestor,
864 event->property,
0,
2, False, AnyPropertyType, &dummyAtom,
865 &getFmt, &nItems, &dummyULong,
866 (
unsigned char **)&reqAtoms) != Success ||
867 getFmt !=
32 || nItems !=
2)
868 return False;
869 if (reqAtoms[
1] !=
XA_STRING)
870 return False;
871 XtGetSelectionValue(w, reqAtoms[
0], reqAtoms[
1],
872 getInsertSelectionCB, &result, event->time);
873 XFree((
char *)reqAtoms);
874 while (result ==
INSERT_WAITING) {
875 XtAppNextEvent(XtWidgetToApplicationContext(w), &nextEvent);
876 XtDispatchEvent(&nextEvent);
877 }
878 *type = getAtom(display,
A_INSERT_SELECTION);
879 *format =
8;
880 *value =
NULL;
881 *length =
0;
882 return result ==
SUCCESSFUL_INSERT;
883 }
884
885
886
887 return False;
888 }
889
890 static void loseMotifDestCB(Widget w, Atom *selType)
891 {
892 ((TextWidget)w)->text.motifDestOwner = False;
893 if (((TextWidget)w)->text.textD->cursorStyle ==
CARET_CURSOR)
894 TextDSetCursorStyle(((TextWidget)w)->text.textD,
DIM_CURSOR);
895 }
896
897
898
899
900
901
902
903
904
905
906
907 static void selectNotifyEH(Widget w, XtPointer data, XEvent *event,
908 Boolean *continueDispatch)
909 {
910 textBuffer *buf = ((TextWidget)w)->text.textD->buffer;
911 XSelectionEvent *e = (XSelectionEvent *)event;
912 selectNotifyInfo *cbInfo = (selectNotifyInfo *)data;
913 int selStart, selEnd;
914 char *string;
915
916
917
918 if (event->type != SelectionNotify || e->time != cbInfo->timeStamp)
919 return;
920
921
922
923 XtRemoveEventHandler(w,
0, True, selectNotifyEH, data);
924 XtRemoveTimeOut(cbInfo->timeoutProcID);
925
926
927
928 if (e->property == None) {
929 XBell(XtDisplay(w),
0);
930 BufSecondaryUnselect(buf);
931 XtDisownSelection(w,
XA_SECONDARY, e->time);
932 NEditFree(cbInfo->actionText);
933 NEditFree(cbInfo);
934 return;
935 }
936
937
938
939
940 if (cbInfo->action ==
REMOVE_SECONDARY) {
941 BufRemoveSecSelect(buf);
942 }
else if (cbInfo->action ==
EXCHANGE_SECONDARY) {
943 string = (
char*)NEditMalloc(cbInfo->length +
1);
944 memcpy(string, cbInfo->actionText, cbInfo->length);
945 string[cbInfo->length] =
'\0';
946 selStart = buf->secondary.start;
947 if (BufSubstituteNullChars(string, cbInfo->length, buf)) {
948 BufReplaceSecSelect(buf, string);
949 if (buf->secondary.rectangular) {
950
951 TextDSetInsertPosition(((TextWidget)w)->text.textD,
952 buf->cursorPosHint);
953 }
else {
954 selEnd = selStart + cbInfo->length;
955 BufSelect(buf, selStart, selEnd);
956 TextDSetInsertPosition(((TextWidget)w)->text.textD, selEnd);
957 }
958 }
else
959 fprintf(stderr,
"Too much binary data\n");
960 NEditFree(string);
961 }
962 BufSecondaryUnselect(buf);
963 XtDisownSelection(w,
XA_SECONDARY, e->time);
964 NEditFree(cbInfo->actionText);
965 NEditFree(cbInfo);
966 }
967
968
969
970
971
972
973 static void selectNotifyTimerProc(XtPointer clientData, XtIntervalId *id)
974 {
975 selectNotifyInfo *cbInfo = (selectNotifyInfo *)clientData;
976 textBuffer *buf = ((TextWidget)cbInfo->widget)->text.textD->buffer;
977
978 fprintf(stderr,
"NEdit: timeout on selection request\n");
979 XtRemoveEventHandler(cbInfo->widget,
0, True, selectNotifyEH, cbInfo);
980 BufSecondaryUnselect(buf);
981 XtDisownSelection(cbInfo->widget,
XA_SECONDARY, cbInfo->timeStamp);
982 NEditFree(cbInfo->actionText);
983 NEditFree(cbInfo);
984 }
985
986
987
988
989
990 static Atom getAtom(Display *display,
int atomNum)
991 {
992 static Atom atomList[
N_ATOMS] = {
0};
993 static char *atomNames[
N_ATOMS] = {
"TEXT",
"TARGETS",
"MULTIPLE",
994 "TIMESTAMP",
"INSERT_SELECTION",
"DELETE",
"CLIPBOARD",
995 "INSERT_INFO",
"ATOM_PAIR",
"MOTIF_DESTINATION",
"COMPOUND_TEXT",
996 "UTF8_STRING"};
997
998 if (atomList[atomNum] ==
0)
999 atomList[atomNum] = XInternAtom(display, atomNames[atomNum], False);
1000 return atomList[atomNum];
1001 }
1002