1 /*
2 * Motif
3 *
4 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5 *
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
22 */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27
28 #ifdef REV_INFO
29 #ifndef lint
30 static char rcsid[] = "$TOG: TextFSel.c /main/22 1997/10/14 15:38:30 cshi $"
31 #endif
32 #endif
33
34 #include <X11/Xatom.h>
35 #include <Xm/AtomMgr.h>
36 #include <Xm/DragC.h>
37 #include <Xm/TraitP.h> /* for XmeTraitSet() */
38 #include <Xm/TransferP.h>
39 #include <Xm/TransferT.h>
40 #include <Xm/XmosP.h>
41 #include "TextFI.h"
42 #include "TextFSelI.h"
43 #include "TransferI.h" /* for _XmConvertComplete() */
44 #include "TraversalI.h" /* for _XmGetFocusPolicy() */
45 #include "XmI.h"
46
47 /******** Static Function Declarations ********/
48
49 static void InsertSelection(
50 Widget w,
51 XtPointer closure,
52 Atom *seltype,
53 Atom *type,
54 XtPointer value,
55 unsigned long *length,
56 int *format,
57 XtPointer tid) ;
58 static void HandleInsertTargets(
59 Widget w,
60 XtPointer closure,
61 Atom *seltype,
62 Atom *type,
63 XtPointer value,
64 unsigned long *length,
65 int *format,
66 XtPointer tid);
67 static void HandleDrop(Widget w,
68 XmDropProcCallbackStruct *cb,
69 XmDestinationCallbackStruct *ds);
70 static void TextFieldConvertCallback(Widget,
71 XtPointer,
72 XmConvertCallbackStruct*);
73
74 static void TextFieldDestinationCallback(Widget,
75 XtPointer,
76 XmDestinationCallbackStruct*);
77 static void SetDropContext(Widget w);
78
79 static void DeleteDropContext(Widget w);
80
81 static void HandleTargets(Widget w,
82 XtPointer ignore,
83 XmSelectionCallbackStruct *ds);
84
85 static void HandleDrop(Widget w,
86 XmDropProcCallbackStruct *cb,
87 XmDestinationCallbackStruct *ds);
88
89 static void DropDestroyCB(Widget w,
90 XtPointer clientData,
91 XtPointer callData);
92
93 static void DropTransferProc(Widget w,
94 XtPointer ignore,
95 XmSelectionCallbackStruct *ds);
96 static void DoStuff(Widget w,
97 XtPointer ignore,
98 XmSelectionCallbackStruct *ds);
99
100 /******** End Static Function Declarations ********/
101
102
103 /* Transfer Trait record for TextField */
104
105 static XmConst XmTransferTraitRec textFieldTT = {
106 0, /* version */
107 (XmConvertCallbackProc) TextFieldConvertCallback,
108 (XmDestinationCallbackProc) TextFieldDestinationCallback,
109 (XmDestinationCallbackProc) NULL,
110 };
111
112 static XContext _XmTextFDNDContext = 0;
113 static _XmInsertSelect insert_select;
114 static _XmTextPrimSelect *prim_select;
115
116 /*ARGSUSED*/
117 static void
SetPrimarySelection(Widget w,XtEnum op,XmTransferDoneCallbackStruct * ts)118 SetPrimarySelection(Widget w,
119 XtEnum op, /* unused */
120 XmTransferDoneCallbackStruct *ts) /* unused */
121 {
122 XmTextFieldWidget tf = (XmTextFieldWidget) w;
123 XmTextPosition cursorPos = tf->text.cursor_position;
124
125 _XmProcessLock();
126 if (!prim_select) {
127 _XmProcessUnlock();
128 return;
129 }
130
131 if (prim_select->num_chars > 0) {
132 tf->text.prim_anchor = prim_select->position;
133 cursorPos = prim_select->position + prim_select->num_chars;
134 _XmTextFieldStartSelection(tf, tf->text.prim_anchor, cursorPos,
135 prim_select->time);
136 tf->text.pending_off = False;
137 _XmTextFieldSetCursorPosition(tf, NULL, cursorPos, True, True);
138 }
139 if (--prim_select->ref_count == 0) {
140 XtFree((char *)prim_select);
141 prim_select = NULL;
142 }
143 _XmProcessUnlock();
144 }
145
146
147 /*ARGSUSED*/
148 static void
CleanPrimarySelection(Widget w,XtEnum op,XmTransferDoneCallbackStruct * ts)149 CleanPrimarySelection(Widget w,
150 XtEnum op, /* unused */
151 XmTransferDoneCallbackStruct *ts) /* unused */
152 {
153 _XmProcessLock();
154 if (!prim_select)
155 {
156 _XmProcessUnlock();
157 return;
158 }
159
160 if (--prim_select->ref_count == 0) {
161 XtFree((char *)prim_select);
162 prim_select = NULL;
163 }
164 _XmProcessUnlock();
165 }
166
167
168 static void
TextFieldSecondaryWrapper(Widget w,XtPointer closure,XmSelectionCallbackStruct * ds)169 TextFieldSecondaryWrapper(Widget w, XtPointer closure,
170 XmSelectionCallbackStruct *ds)
171 {
172 Atom XA_TARGETS = XInternAtom(XtDisplay(w), XmSTARGETS, False);
173
174 if (ds -> target == XA_TARGETS)
175 HandleInsertTargets(w, closure, &(ds -> selection), &(ds -> type),
176 ds -> value, &(ds -> length), &(ds -> format),
177 ds -> transfer_id);
178 else
179 InsertSelection(w, closure, &(ds -> selection), &(ds -> type),
180 ds -> value, &(ds -> length), &(ds -> format),
181 ds -> transfer_id);
182 }
183
184 /* ARGSUSED */
185 static void
InsertSelection(Widget w,XtPointer closure,Atom * seltype,Atom * type,XtPointer value,unsigned long * length,int * format,XtPointer tid)186 InsertSelection(
187 Widget w,
188 XtPointer closure,
189 Atom *seltype,
190 Atom *type,
191 XtPointer value,
192 unsigned long *length,
193 int *format,
194 XtPointer tid)
195 {
196 _XmInsertSelect *insert_select = (_XmInsertSelect *) closure;
197 XmTextFieldWidget tf = (XmTextFieldWidget) w;
198 XmTextPosition left = 0;
199 XmTextPosition right = 0;
200 Boolean replace_res = False;
201 Boolean dest_disjoint = False;
202 wchar_t * wc_value;
203 char * temp;
204 int num_chars = 0;
205 Atom COMPOUND_TEXT = XInternAtom(XtDisplay(w), XmSCOMPOUND_TEXT, False);
206 Atom UTF8_STRING = XInternAtom(XtDisplay(w), XmSUTF8_STRING, False);
207 char * total_value = NULL;
208 XmAnyCallbackStruct cb;
209
210 if (!value) {
211 insert_select->done_status = True;
212 return;
213 }
214
215 /* Don't do replace if there is not text to add */
216 if (*(char *) value == (char)'\0' || *length == 0){
217 XtFree((char *)value);
218 insert_select->done_status = True;
219 return;
220 }
221
222 if (insert_select->select_type == XmPRIM_SELECT) {
223 if (!tf->text.has_primary ||
224 tf->text.prim_pos_left == tf->text.prim_pos_right) {
225 XBell(XtDisplay(w), 0);
226 XtFree((char *)value);
227 insert_select->done_status = True;
228 insert_select->success_status = False;
229 return;
230 }
231 } else if (insert_select->select_type == XmDEST_SELECT) {
232 if (tf->text.has_primary &&
233 (left = tf->text.prim_pos_left) != (right = tf->text.prim_pos_right)) {
234 if ( TextF_CursorPosition(tf) < left ||
235 TextF_CursorPosition(tf) > right ||
236 !tf->text.pending_delete) {
237 left = right = TextF_CursorPosition(tf);
238 dest_disjoint = True;
239 }
240 } else
241 left = right = TextF_CursorPosition(tf);
242 }
243
244
245 if (*type == COMPOUND_TEXT || *type == XA_STRING || *type == UTF8_STRING) {
246 total_value = _XmTextToLocaleText(w, value, *type, *format,
247 *length, NULL);
248 if (total_value) {
249 if (tf->text.max_char_size == 1) {
250 num_chars = strlen(total_value);
251 replace_res = _XmTextFieldReplaceText(tf,
252 (XEvent *)insert_select->event,
253 left, right, total_value,
254 num_chars, True);
255 } else { /* must convert to wchar_t before passing to Replace */
256 int len = strlen(total_value) + 1;
257 wc_value = (wchar_t *)XtMalloc((unsigned) len * sizeof(wchar_t));
258 num_chars = mbstowcs(wc_value, total_value, len);
259 if (num_chars < 0)
260 num_chars = 0;
261 else
262 replace_res = _XmTextFieldReplaceText(tf,
263 (XEvent *)insert_select->event,
264 left, right, (char*) wc_value,
265 num_chars, True);
266 XtFree((char *)wc_value);
267 }
268 XtFree(total_value);
269 }
270 } else { /* it must be either TEXT or codeset of the locale */
271 if (tf->text.max_char_size == 1) {
272 /* NOTE: casting *length could result in a truncated long. */
273 num_chars = *length;
274 replace_res = _XmTextFieldReplaceText(tf,
275 (XEvent *)insert_select->event,
276 left, right, (char *)value,
277 (unsigned)*length, True);
278 } else {
279 temp = XtMalloc((unsigned) *length + 1);
280 /* NOTE: casting *length could result in a truncated long. */
281 (void)memcpy((void*)temp, (void*)value, (size_t)*length);
282 temp[*length] = '\0';
283 wc_value = (wchar_t*)XtMalloc((unsigned)
284 (*length + 1) * sizeof(wchar_t));
285
286 /* NOTE: casting *length could result in a truncated long. */
287 num_chars = mbstowcs(wc_value, temp, (unsigned)*length + 1);
288 if (num_chars < 0)
289 num_chars = 0;
290 else
291 replace_res = _XmTextFieldReplaceText(tf,
292 (XEvent *)insert_select->event,
293 left, right, (char*) wc_value,
294 num_chars, True);
295 XtFree(temp);
296 XtFree((char *)wc_value);
297 }
298 }
299
300 if (!replace_res) {
301 insert_select->success_status = False;
302 } else {
303 insert_select->success_status = True;
304
305 if (!tf->text.add_mode) tf->text.prim_anchor = left;
306
307 tf->text.pending_off = True;
308 _XmTextFieldSetCursorPosition(tf, NULL, left + num_chars, False, True);
309 (void) _XmTextFieldSetDestination(w, TextF_CursorPosition(tf),
310 insert_select->event->time);
311 if (insert_select->select_type == XmDEST_SELECT) {
312 if (left != right) {
313 if (!dest_disjoint || !tf->text.add_mode) {
314 _XmTextFieldStartSelection(tf, TextF_CursorPosition(tf),
315 TextF_CursorPosition(tf),
316 insert_select->event->time);
317 }
318 }
319 }
320 cb.reason = XmCR_VALUE_CHANGED;
321 cb.event = (XEvent *)insert_select->event;
322 XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
323 (XtPointer) &cb);
324 }
325
326 XtFree((char *)value);
327 value = NULL;
328 insert_select->done_status = True;
329 }
330
331 /* ARGSUSED */
332 static void
HandleInsertTargets(Widget w,XtPointer closure,Atom * seltype,Atom * type,XtPointer value,unsigned long * length,int * format,XtPointer tid)333 HandleInsertTargets(
334 Widget w,
335 XtPointer closure,
336 Atom *seltype,
337 Atom *type,
338 XtPointer value,
339 unsigned long *length,
340 int *format,
341 XtPointer tid )
342 {
343 enum { XmATEXT, XmACOMPOUND_TEXT, XmAUTF8_STRING, NUM_ATOMS };
344 static char *atom_names[] = { XmSTEXT, XmSCOMPOUND_TEXT, XmSUTF8_STRING };
345
346 _XmInsertSelect *insert_select = (_XmInsertSelect *) closure;
347 Atom atoms[XtNumber(atom_names)];
348 Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
349 Atom target;
350 Atom *atom_ptr;
351 Boolean supports_encoding_data = False;
352 Boolean supports_CT = False;
353 Boolean supports_text = False;
354 Boolean supports_utf8_string = False;
355 int i;
356
357 if (0 == *length) {
358 XtFree((char *)value);
359 insert_select->done_status = True;
360 return; /* Supports no targets, so don't bother sending anything */
361 }
362
363 assert(XtNumber(atom_names) == NUM_ATOMS);
364 XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
365
366 atom_ptr = (Atom *)value;
367
368 for (i = 0; i < *length; i++, atom_ptr++) {
369 if (*atom_ptr == atoms[XmATEXT])
370 supports_text = True;
371
372 if (*atom_ptr == CS_OF_ENCODING)
373 supports_encoding_data = True;
374
375 if (*atom_ptr == atoms[XmACOMPOUND_TEXT])
376 supports_CT = True;
377
378 #ifdef UTF8_SUPPORTED
379 if (*atom_ptr == atoms[XmAUTF8_STRING])
380 supports_utf8_string = True;
381 #endif
382 }
383
384 if (supports_text && supports_encoding_data)
385 target = atoms[XmATEXT];
386 else if (supports_CT)
387 target = atoms[XmACOMPOUND_TEXT];
388 #ifdef UTF8_SUPPORTED
389 else if (supports_utf8_string)
390 target = atoms[XmAUTF8_STRING];
391 #endif
392 else if (supports_encoding_data)
393 target = CS_OF_ENCODING;
394 else
395 target = XA_STRING;
396
397 XmTransferValue(tid, target,
398 (XtCallbackProc) TextFieldSecondaryWrapper,
399 closure, insert_select -> event -> time);
400 }
401
402
403 /* ARGSUSED */
404 Boolean
_XmTextFieldConvert(Widget w,Atom * selection,Atom * target,Atom * type,XtPointer * value,unsigned long * length,int * format,Widget drag_context,XEvent * event)405 _XmTextFieldConvert(
406 Widget w,
407 Atom *selection,
408 Atom *target,
409 Atom *type,
410 XtPointer *value,
411 unsigned long *length,
412 int *format,
413 Widget drag_context,
414 XEvent *event)
415 {
416 enum { XmA_MOTIF_DESTINATION, XmAINSERT_SELECTION, XmADELETE,
417 XmATARGETS, XmATEXT, XmACOMPOUND_TEXT, XmATIMESTAMP,
418 XmA_MOTIF_DROP, XmACLIPBOARD, XmANULL, XmAUTF8_STRING,
419 NUM_ATOMS };
420 static char *atom_names[] = {
421 XmS_MOTIF_DESTINATION, XmSINSERT_SELECTION, XmSDELETE,
422 XmSTARGETS, XmSTEXT, XmSCOMPOUND_TEXT, XmSTIMESTAMP,
423 XmS_MOTIF_DROP, XmSCLIPBOARD, XmSNULL, XmSUTF8_STRING };
424
425 XmTextFieldWidget tf;
426 Atom atoms[XtNumber(atom_names)];
427 Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
428 XSelectionRequestEvent * req_event = (XSelectionRequestEvent *) event;
429 Boolean has_selection = False;
430 XmTextPosition left = 0;
431 XmTextPosition right = 0;
432 Boolean is_primary;
433 Boolean is_secondary;
434 Boolean is_destination;
435 Boolean is_drop;
436 int target_count = 0;
437 XTextProperty tmp_prop;
438 char *tmp_value;
439 int ret_status = 0;
440 Time _time;
441 XmAnyCallbackStruct cb;
442
443 assert(XtNumber(atom_names) == NUM_ATOMS);
444 XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
445
446 if (req_event == NULL)
447 _time = XtLastTimestampProcessed(XtDisplay(w));
448 else
449 _time = req_event -> time;
450
451 tf = (XmTextFieldWidget) w;
452
453 if (tf == NULL) return False;
454
455 if (*selection == XA_PRIMARY || *selection == atoms[XmACLIPBOARD]) {
456 has_selection = tf->text.has_primary;
457 left = tf->text.prim_pos_left;
458 right = tf->text.prim_pos_right;
459 is_primary = True;
460 is_secondary = is_destination = is_drop = False;
461 } else if (*selection == atoms[XmA_MOTIF_DESTINATION]) {
462 has_selection = tf->text.has_destination;
463 is_destination = True;
464 is_secondary = is_primary = is_drop = False;
465 } else if (*selection == XA_SECONDARY) {
466 has_selection = tf->text.has_secondary;
467 left = tf->text.sec_pos_left;
468 right = tf->text.sec_pos_right;
469 is_secondary = True;
470 is_destination = is_primary = is_drop = False;
471 } else if (*selection == atoms[XmA_MOTIF_DROP]) {
472 has_selection = tf->text.has_primary;
473 left = tf->text.prim_pos_left;
474 right = tf->text.prim_pos_right;
475 is_drop = True;
476 is_destination = is_primary = is_secondary = False;
477 } else {
478 return False;
479 }
480
481 /*
482 * TARGETS identifies what targets the textfield widget can
483 * provide data for.
484 */
485 if (*target == atoms[XmATARGETS]) {
486 Atom *targs = XmeStandardTargets(w, 10, &target_count);
487
488 *value = (XtPointer) targs;
489 if (XA_STRING != CS_OF_ENCODING) {
490 targs[target_count] = CS_OF_ENCODING; target_count++;
491 }
492 if (is_primary || is_destination) {
493 targs[target_count] = atoms[XmAINSERT_SELECTION]; target_count++;
494 }
495 if (is_primary || is_secondary || is_drop) {
496 targs[target_count] = atoms[XmACOMPOUND_TEXT]; target_count++;
497 targs[target_count] = atoms[XmATEXT]; target_count++;
498 targs[target_count] = XA_STRING; target_count++;
499 targs[target_count] = atoms[XmAUTF8_STRING]; target_count++;
500 }
501 if (is_primary || is_drop) {
502 targs[target_count] = atoms[XmADELETE]; target_count++;
503 }
504 *type = XA_ATOM;
505 *length = target_count;
506 *format = 32;
507 } else if (*target == atoms[XmATIMESTAMP]) {
508 Time *timestamp;
509 timestamp = (Time *) XtMalloc(sizeof(Time));
510 if (is_primary)
511 *timestamp = tf->text.prim_time;
512 else if (is_destination)
513 *timestamp = tf->text.dest_time;
514 else if (is_secondary)
515 *timestamp = tf->text.sec_time;
516 else if (is_drop)
517 *timestamp = tf->text.prim_time;
518 *value = (XtPointer) timestamp;
519 *type = XA_INTEGER;
520 *length = sizeof(Time) / 4;
521 *format = 32;
522 } else if (*target == XA_STRING) {
523 *type = (Atom) XA_STRING;
524 *format = 8;
525 if (is_destination || !has_selection) return False;
526
527 /* put a char* value into tmp_value, then convert to 8859.1 */
528 if (tf->text.max_char_size != 1) {
529 int stat ;
530
531 /* NOTE: casting (right - left) could result in a truncated long. */
532 *length = _XmTextFieldCountBytes(tf, TextF_WcValue(tf) + left,
533 (int)(right - left));
534 tmp_value = XtMalloc((unsigned) *length + 1);
535 stat = wcstombs(tmp_value, TextF_WcValue(tf) + left,
536 (unsigned)*length); /* NOTE: casting *length could
537 result in a truncated long. */
538 if (stat < 0) /* wcstombs will return neg value on conv failure */
539 *length = 0;
540 else *length = (unsigned long) stat ;
541 } else {
542 *length = right - left;
543 tmp_value = XtMalloc((unsigned) *length + 1);
544 /* get the selection value */
545 (void)memcpy((void*)tmp_value, (void*)(TextF_Value(tf) + left),
546 (size_t)*length); /* NOTE: casting *length could result
547 in a truncated long. */
548 }
549 tmp_value[*length] = '\0';
550 tmp_prop.value = NULL;
551 /* convert tmp_value to 8859.1 */
552 ret_status = XmbTextListToTextProperty(XtDisplay(w), &tmp_value, 1,
553 (XICCEncodingStyle)XStringStyle,
554 &tmp_prop);
555 XtFree(tmp_value);
556 if (ret_status == Success || ret_status > 0){
557 *value = (XtPointer) tmp_prop.value;
558 *length = tmp_prop.nitems;
559 } else {
560 *value = NULL;
561 *length = 0;
562 return False;
563 }
564 } else if (*target == atoms[XmATEXT] || *target == CS_OF_ENCODING) {
565 *type = CS_OF_ENCODING;
566 *format = 8;
567 if (is_destination || !has_selection) return False;
568 if (tf->text.max_char_size != 1) {
569 int stat ;
570
571 /* NOTE: casting (right - left) could result in a truncated long. */
572 *length = _XmTextFieldCountBytes(tf, TextF_WcValue(tf) + left,
573 (int)(right - left));
574 *value = XtMalloc((unsigned) *length + 1);
575 stat = wcstombs((char *)*value, TextF_WcValue(tf) + left,
576 (unsigned)*length); /* NOTE: casting *length could
577 result in a truncated long */
578 if (stat < 0) /* wcstombs return neg value on conv failure */
579 *length = 0;
580 else *length = (unsigned long) stat ;
581 } else {
582 *length = right - left;
583 *value = XtMalloc((unsigned) *length + 1);
584 /* get the selection value */
585 (void)memcpy((void*)*value, (void*)(TextF_Value(tf) + left),
586 (size_t)*length); /* NOTE: casting *length could result
587 in a truncated long. */
588 }
589 (*(char **)value)[*length]='\0';
590 } else if (*target == atoms[XmACOMPOUND_TEXT]) {
591 *type = atoms[XmACOMPOUND_TEXT];
592 *format = 8;
593 if (is_destination || !has_selection) return False;
594 if (tf->text.max_char_size != 1) {
595 int stat ;
596
597 /* convert to char* before converting to CT. NOTE: casting
598 * (right - left) could result in a truncated long.
599 */
600 *length = _XmTextFieldCountBytes(tf, TextF_WcValue(tf) + left,
601 (int)(right - left));
602 tmp_value = XtMalloc((unsigned) *length + 1);
603 stat = wcstombs(tmp_value, TextF_WcValue(tf) + left,
604 (unsigned)*length); /* NOTE: casting *length could
605 result in a truncated long. */
606 if (stat < 0) /* wcstombs will return neg value on conv failure */
607 *length = 0;
608 else *length = (unsigned long) stat ;
609 } else { /* malloc the space and copy the data to be converted */
610 *length = right - left;
611 tmp_value = XtMalloc((unsigned) *length + 1);
612 /* get the selection value */
613 (void)memcpy((void*)tmp_value, (void*)(TextF_Value(tf) + left),
614 (size_t)*length); /* NOTE: casting *length could result
615 in a truncated long. */
616 }
617 tmp_value[*length] = '\0';
618 tmp_prop.value = NULL;
619 /* Convert to compound text */
620 ret_status =
621 XmbTextListToTextProperty(XtDisplay(w), &tmp_value, 1,
622 (XICCEncodingStyle)XCompoundTextStyle,
623 &tmp_prop);
624 XtFree(tmp_value);
625 if (ret_status == Success || ret_status > 0){
626 *length = tmp_prop.nitems;
627 *value = (XtPointer)tmp_prop.value;
628 } else {
629 *value = NULL;
630 *length = 0;
631 return False;
632 }
633 #ifdef UTF8_SUPPORTED
634 } else if (*target == atoms[XmAUTF8_STRING]) {
635 *type = atoms[XmAUTF8_STRING];
636 *format = 8;
637 if (is_destination || !has_selection) return False;
638 if (tf->text.max_char_size != 1) {
639 int stat ;
640
641 /* convert to char* before converting to CT. NOTE: casting
642 * (right - left) could result in a truncated long.
643 */
644 *length = _XmTextFieldCountBytes(tf, TextF_WcValue(tf) + left,
645 (int)(right - left));
646 tmp_value = XtMalloc((unsigned) *length + 1);
647 stat = wcstombs(tmp_value, TextF_WcValue(tf) + left,
648 (unsigned)*length); /* NOTE: casting *length could
649 result in a truncated long. */
650 if (stat < 0) /* wcstombs will return neg value on conv failure */
651 *length = 0;
652 else *length = (unsigned long) stat ;
653 } else { /* malloc the space and copy the data to be converted */
654 *length = right - left;
655 tmp_value = XtMalloc((unsigned) *length + 1);
656 /* get the selection value */
657 (void)memcpy((void*)tmp_value, (void*)(TextF_Value(tf) + left),
658 (size_t)*length); /* NOTE: casting *length could result
659 in a truncated long. */
660 }
661 tmp_value[*length] = '\0';
662 tmp_prop.value = NULL;
663 /* Convert to compound text */
664 ret_status =
665 XmbTextListToTextProperty(XtDisplay(w), &tmp_value, 1,
666 (XICCEncodingStyle)XUTF8StringStyle,
667 &tmp_prop);
668 XtFree(tmp_value);
669 if (ret_status == Success || ret_status > 0){
670 *length = tmp_prop.nitems;
671 *value = (XtPointer)tmp_prop.value;
672 } else {
673 *value = NULL;
674 *length = 0;
675 return False;
676 }
677 #endif
678 } else if (*target == atoms[XmAINSERT_SELECTION]) {
679 if (is_secondary)
680 return False;
681 else
682 return True;
683 /* Delete the selection */
684 } else if (*target == atoms[XmADELETE]) {
685 XmTextPosition left, right;
686 Boolean move_cursor = True;
687
688 if (!(is_primary || is_drop)) return False;
689
690 left = tf->text.prim_pos_left;
691 right = tf->text.prim_pos_right;
692
693 if (is_drop) {
694 if (_XmTextFieldGetDropReciever((Widget)tf) == (Widget) tf)
695 move_cursor = False;
696 } else {
697 if (req_event != NULL &&
698 req_event->requestor == XtWindow((Widget)tf))
699 move_cursor = False;
700 }
701
702 if (!_XmTextFieldReplaceText(tf, (XEvent *) req_event,
703 left, right, NULL, 0, move_cursor)) {
704 tf->text.has_primary = True;
705 return False;
706 }
707
708 _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
709 tf->text.prim_anchor, _time);
710
711 cb.reason = XmCR_VALUE_CHANGED;
712 cb.event = (XEvent *) req_event;
713 XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
714 (XtPointer) &cb);
715
716 tf->text.has_primary = True;
717
718 if (tf->text.has_destination)
719 tf->text.prim_anchor = TextF_CursorPosition(tf);
720
721 *type = atoms[XmANULL];
722 *value = NULL;
723 *length = 0;
724 *format = 8;
725 } else
726 /* unknown selection type */
727 return FALSE;
728 return TRUE;
729 }
730
731 /* ARGSUSED */
732 void
_XmTextFieldLoseSelection(Widget w,Atom * selection)733 _XmTextFieldLoseSelection(
734 Widget w,
735 Atom *selection )
736 {
737 XmTextFieldWidget tf = (XmTextFieldWidget) w;
738 Atom MOTIF_DESTINATION = XInternAtom(XtDisplay(w),
739 XmS_MOTIF_DESTINATION, False);
740 /* Losing Primary Selection */
741 if (*selection == XA_PRIMARY && tf->text.has_primary) {
742 XmAnyCallbackStruct cb;
743 _XmTextFieldDeselectSelection(w, False, 0);
744
745 cb.reason = XmCR_LOSE_PRIMARY;
746 cb.event = NULL;
747 XtCallCallbackList(w, tf->text.lose_primary_callback, (XtPointer) &cb);
748 /* Losing Destination Selection */
749 } else if (*selection == MOTIF_DESTINATION) {
750 Boolean orig_ibeam_off = tf->text.refresh_ibeam_off;
751 tf->text.has_destination = False;
752 /* if we have focus, we have a valid putback area. If we don't have
753 * focus, don't want to update the putback with the destination cursor
754 * image.
755 */
756 tf->text.refresh_ibeam_off = False;
757 _XmTextFieldDrawInsertionPoint(tf, False);
758 tf->text.blink_on = True;
759 _XmTextFieldDrawInsertionPoint(tf, True);
760 /* Restore the state of the refresh_ibeam_off flag. */
761 tf->text.refresh_ibeam_off = orig_ibeam_off;
762 /* Losing Secondary Selection */
763 } else if (*selection == XA_SECONDARY && tf->text.has_secondary){
764 _XmTextFieldSetSel2(w, 0, 0, True,
765 XtLastTimestampProcessed(XtDisplay(w)));
766 }
767 }
768
769
770 static void
SetDropContext(Widget w)771 SetDropContext(Widget w)
772 {
773 Display *display = XtDisplay(w);
774 Screen *screen = XtScreen(w);
775 XContext loc_context;
776
777
778 _XmProcessLock();
779 if (_XmTextFDNDContext == 0)
780 _XmTextFDNDContext = XUniqueContext();
781 loc_context = _XmTextFDNDContext;
782 _XmProcessUnlock();
783
784 XSaveContext(display, (Window)screen,
785 loc_context, (XPointer)w);
786 }
787
788 static void
DeleteDropContext(Widget w)789 DeleteDropContext(Widget w)
790 {
791 Display *display = XtDisplay(w);
792 Screen *screen = XtScreen(w);
793 XContext loc_context;
794
795 _XmProcessLock();
796 loc_context = _XmTextFDNDContext;
797 _XmProcessUnlock();
798
799 XDeleteContext(display, (Window)screen, loc_context);
800 }
801
802 Widget
_XmTextFieldGetDropReciever(Widget w)803 _XmTextFieldGetDropReciever(Widget w)
804 {
805 Widget widget;
806 XContext loc_context;
807
808 _XmProcessLock();
809 loc_context = _XmTextFDNDContext;
810 _XmProcessUnlock();
811
812 if (loc_context == 0) return NULL;
813
814 if (!XFindContext(XtDisplay(w), (Window) XtScreen(w),
815 loc_context, (char **) &widget)) {
816 return widget;
817 }
818
819 return NULL;
820 }
821
822
823 /* ARGSUSED */
824 static void
DropDestroyCB(Widget w,XtPointer clientData,XtPointer callData)825 DropDestroyCB(Widget w,
826 XtPointer clientData,
827 XtPointer callData)
828 {
829 XmTransferDoneCallbackStruct *ts =
830 (XmTransferDoneCallbackStruct *) callData;
831
832 DeleteDropContext(w);
833 if (ts->client_data != NULL) XtFree((char*) ts->client_data);
834 }
835
836 static void
DropTransferProc(Widget w,XtPointer closure,XmSelectionCallbackStruct * ds)837 DropTransferProc(Widget w, XtPointer closure,
838 XmSelectionCallbackStruct *ds)
839 {
840 enum { XmACOMPOUND_TEXT, XmANULL, XmADELETE,
841 #ifdef UTF8_SUPPORTED
842 XmAUTF8_STRING,
843 #endif
844 NUM_ATOMS };
845 static char *atom_names[] = { XmSCOMPOUND_TEXT, XmSNULL, XmSDELETE,
846 #ifdef UTF8_SUPPORTED
847 XmSUTF8_STRING
848 #endif
849 };
850
851 _XmTextDropTransferRec *transfer_rec = (_XmTextDropTransferRec *) closure;
852 XmTextFieldWidget tf = (XmTextFieldWidget) w;
853 Atom atoms[XtNumber(atom_names)];
854 Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
855 XmTextPosition insertPosLeft, insertPosRight, left, right, cursorPos;
856 int max_length = 0;
857 Boolean local = tf->text.has_primary;
858 char * total_value = NULL;
859 wchar_t * wc_total_value;
860 unsigned long total_length = 0;
861 int wc_total_length;
862 Boolean replace = False;
863 XmAnyCallbackStruct cb;
864
865 assert(XtNumber(atom_names) == NUM_ATOMS);
866 XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
867
868 /* When type = NULL, we are assuming a DELETE request has been requested */
869 if (ds->type == atoms[XmANULL]) {
870 if (transfer_rec->num_chars > 0 && transfer_rec->move) {
871 tf->text.prim_anchor = transfer_rec->insert_pos;
872 cursorPos = transfer_rec->insert_pos + transfer_rec->num_chars;
873 _XmTextFieldSetCursorPosition(tf, NULL, cursorPos,
874 False, True);
875 _XmTextFieldStartSelection(tf, tf->text.prim_anchor,
876 TextF_CursorPosition(tf),
877 XtLastTimestampProcessed(XtDisplay(w)));
878 tf->text.pending_off = False;
879 _XmTextFieldSetCursorPosition(tf, NULL, TextF_CursorPosition(tf),
880 True, True);
881 }
882 if (ds->value) {
883 XtFree((char*) ds->value);
884 ds->value = NULL;
885 }
886 return;
887 }
888
889 if (!(ds->value) ||
890 (ds->type != CS_OF_ENCODING &&
891 ds->type != atoms[XmACOMPOUND_TEXT] &&
892 #ifdef UTF8_SUPPORTED
893 ds->type != atoms[XmAUTF8_STRING] &&
894 #endif
895 ds->type != XA_STRING)) {
896 XmTransferDone(ds->transfer_id, XmTRANSFER_DONE_FAIL);
897 if (ds->value) {
898 XtFree((char*) ds->value);
899 ds->value = NULL;
900 }
901 return;
902 }
903
904 insertPosLeft = insertPosRight = transfer_rec->insert_pos;
905
906 if (ds->type == XA_STRING
907 #ifdef UTF8_SUPPORTED
908 || ds->type == atoms[XmAUTF8_STRING]
909 #endif
910 || ds->type == atoms[XmACOMPOUND_TEXT]) {
911 if ((total_value = _XmTextToLocaleText(w, ds->value, ds->type,
912 8, ds->length, NULL)) != NULL)
913 total_length = strlen(total_value);
914 else
915 if (ds->value) {
916 XtFree((char*) ds->value);
917 ds->value = NULL;
918 }
919 } else {
920 total_value = (char*) ds->value;
921 total_length = ds->length;
922 }
923
924 if (total_value == NULL) return;
925
926 if (TextF_PendingDelete(tf) && tf->text.has_primary &&
927 tf->text.prim_pos_left != tf->text.prim_pos_right) {
928 if(insertPosLeft > tf->text.prim_pos_left
929 && insertPosLeft < tf->text.prim_pos_right)
930 insertPosLeft = tf->text.prim_pos_left;
931 if(insertPosRight < tf->text.prim_pos_right
932 && insertPosRight > tf->text.prim_pos_left)
933 insertPosRight = tf->text.prim_pos_right;
934 }
935
936 transfer_rec->num_chars = _XmTextFieldCountCharacters(tf, total_value,
937 total_length);
938
939 _XmTextFieldDrawInsertionPoint(tf, False);
940
941 if (transfer_rec->move && local) {
942 max_length = TextF_MaxLength(tf);
943 TextF_MaxLength(tf) = INT_MAX;
944 }
945
946 if (tf->text.max_char_size == 1) {
947 replace = _XmTextFieldReplaceText(tf, ds->event, insertPosLeft,
948 insertPosRight, (char *) total_value,
949 (int)total_length, False);
950 } else {
951 wc_total_length = _XmTextFieldCountCharacters(tf, total_value,
952 total_length);
953 wc_total_value = (wchar_t*)XtMalloc((unsigned)
954 (wc_total_length+1) * sizeof(wchar_t));
955 wc_total_length = mbstowcs(wc_total_value, total_value, wc_total_length+1);
956 if (wc_total_length > 0)
957 replace = _XmTextFieldReplaceText(tf, ds->event, insertPosLeft,
958 insertPosRight, (char *)wc_total_value,
959 wc_total_length, False);
960 XtFree((char*)wc_total_value);
961 }
962
963 if (replace) {
964 tf->text.pending_off = FALSE;
965 if (transfer_rec->num_chars > 0 && !transfer_rec->move) {
966 cursorPos = transfer_rec->insert_pos + transfer_rec->num_chars;
967 _XmTextFieldSetCursorPosition(tf, NULL, cursorPos,
968 True, True);
969 _XmTextFieldSetDestination((Widget)tf, TextF_CursorPosition(tf),
970 transfer_rec->timestamp);
971 }
972 left = tf->text.prim_pos_left;
973 right = tf->text.prim_pos_right;
974 if (tf->text.has_primary) {
975 if (transfer_rec->move && left < transfer_rec->insert_pos)
976 transfer_rec->insert_pos -= transfer_rec->num_chars;
977 if (TextF_CursorPosition(tf) < left ||
978 TextF_CursorPosition(tf) > right)
979 tf->text.pending_off = TRUE;
980 } else {
981 if (!transfer_rec->move && !tf->text.add_mode &&
982 transfer_rec->num_chars != 0)
983 tf->text.prim_anchor = insertPosLeft;
984 }
985 if (transfer_rec->move) {
986 XmTransferValue(ds->transfer_id,
987 atoms[XmADELETE],
988 (XtCallbackProc) DropTransferProc,
989 (XtPointer) transfer_rec, 0);
990 }
991 cb.reason = XmCR_VALUE_CHANGED;
992 cb.event = ds->event;
993 XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
994 (XtPointer) &cb);
995 }
996
997 if (transfer_rec->move && local) {
998 TextF_MaxLength(tf) = max_length;
999 }
1000
1001 if (total_value && (total_value != (char*)ds->value))
1002 XtFree(total_value);
1003 if (ds->value) {
1004 XtFree((char*) ds->value);
1005 ds->value = NULL;
1006 }
1007
1008 _XmTextFieldDrawInsertionPoint(tf, True);
1009 }
1010
1011 #define CR1228
1012 /*ARGSUSED*/
1013 static void
DoStuff(Widget w,XtPointer closure,XmSelectionCallbackStruct * ds)1014 DoStuff(Widget w,
1015 #ifdef CR1228
1016 XtPointer closure,
1017 #else
1018 XtPointer closure, /* unused */
1019 #endif
1020 XmSelectionCallbackStruct *ds)
1021 {
1022 enum { XmANULL, XmACLIPBOARD, XmATEXT, XmACOMPOUND_TEXT,
1023 #ifdef UTF8_SUPPORTED
1024 XmAUTF8_STRING,
1025 #endif
1026 NUM_ATOMS };
1027 static char *atom_names[] = {
1028 XmSNULL, XmSCLIPBOARD, XmSTEXT, XmSCOMPOUND_TEXT,
1029 #ifdef UTF8_SUPPORTED
1030 XmSUTF8_STRING
1031 #endif
1032 };
1033
1034 XmTextFieldWidget tf = (XmTextFieldWidget) w;
1035 XmTextPosition right=0, left=0, replace_from, replace_to;
1036 int prim_char_length = 0;
1037 Boolean replace_res = False;
1038 XmAnyCallbackStruct cb;
1039 Atom atoms[XtNumber(atom_names)];
1040 #ifdef CR1228
1041 _XmTextPrimSelect *prim_select = (_XmTextPrimSelect *) closure;
1042 #endif
1043
1044 assert(XtNumber(atom_names) == NUM_ATOMS);
1045 XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
1046
1047 if (!tf->text.has_focus && _XmGetFocusPolicy(w) == XmEXPLICIT)
1048 (void) XmProcessTraversal(w, XmTRAVERSE_CURRENT);
1049
1050 if (ds->selection != atoms[XmACLIPBOARD] &&
1051 ds->length == 0 &&
1052 ds->type != atoms[XmANULL]) {
1053 /* Backwards compatibility for 1.0 Selections */
1054 _XmProcessLock();
1055 if (prim_select->target == atoms[XmATEXT]) {
1056 prim_select->target = XA_STRING;
1057 XmTransferValue(ds->transfer_id, XA_STRING, (XtCallbackProc) DoStuff,
1058 (XtPointer) prim_select, prim_select->time);
1059 }
1060 _XmProcessUnlock();
1061 XtFree((char *)ds->value);
1062 ds->value = NULL;
1063 return;
1064 }
1065
1066 /* if ds->length == 0 and ds->type is the NULL atom we are assuming
1067 * that a DELETE target is requested.
1068 */
1069 if (ds->type == atoms[XmANULL]) {
1070 _XmProcessLock();
1071 if (prim_select->num_chars > 0 && tf->text.selection_move) {
1072 prim_char_length = prim_select->num_chars;
1073 _XmTextFieldStartSelection(tf, prim_select->position,
1074 prim_select->position + prim_char_length,
1075 prim_select->time);
1076 tf->text.pending_off = False;
1077 _XmTextFieldSetCursorPosition(tf, NULL,
1078 prim_select->position + prim_char_length,
1079 True, True);
1080 tf->text.prim_anchor = prim_select->position;
1081 }
1082 _XmProcessUnlock(); /* for prim_select */
1083 } else {
1084 int max_length = 0;
1085 Boolean local = tf->text.has_primary;
1086 Boolean dest_disjoint = True;
1087
1088 if (tf->text.selection_move && local) {
1089 max_length = TextF_MaxLength(tf);
1090 TextF_MaxLength(tf) = INT_MAX;
1091 }
1092 _XmProcessLock();
1093 replace_from = replace_to = prim_select->position;
1094 _XmProcessUnlock();
1095 if (ds->selection == atoms[XmACLIPBOARD]) {
1096 if (tf->text.has_primary) {
1097 left = tf->text.prim_pos_left;
1098 right = tf->text.prim_pos_right;
1099 if (tf->text.pending_delete &&
1100 replace_from >= left && replace_to <= right) {
1101 replace_from = left;
1102 replace_to = right;
1103 dest_disjoint = False;
1104 }
1105 }
1106 }
1107
1108 if (ds->type == atoms[XmACOMPOUND_TEXT] ||
1109 #ifdef UTF8_SUPPORTED
1110 ds->type == atoms[XmAUTF8_STRING] ||
1111 #endif
1112 ds->type == XA_STRING) {
1113 char *total_value;
1114
1115 if ((total_value =
1116 _XmTextToLocaleText(w, ds->value, ds->type, ds->format, ds->length,
1117 NULL))
1118 != NULL) {
1119 if (tf->text.max_char_size == 1) {
1120 _XmProcessLock();
1121 prim_select->num_chars = strlen(total_value);
1122 replace_res =
1123 _XmTextFieldReplaceText (tf, ds->event,
1124 replace_from,
1125 replace_to,
1126 total_value,
1127 prim_select->num_chars,
1128 ds->selection == atoms[XmACLIPBOARD]);
1129 _XmProcessUnlock();
1130 XtFree(total_value);
1131 } else {
1132 wchar_t * wc_value;
1133 int tmp_len = strlen(total_value) + 1;
1134
1135 _XmProcessLock();
1136 prim_select->num_chars = 0;
1137 wc_value = (wchar_t*)XtMalloc ((unsigned) tmp_len * sizeof(wchar_t));
1138 prim_select->num_chars = mbstowcs(wc_value, total_value, tmp_len);
1139 if (prim_select->num_chars < 0)
1140 prim_select->num_chars = 0;
1141 else
1142 replace_res =
1143 _XmTextFieldReplaceText(tf, ds->event,
1144 replace_from,
1145 replace_to,
1146 (char*)wc_value,
1147 prim_select->num_chars,
1148 ds->selection == atoms[XmACLIPBOARD]);
1149 _XmProcessUnlock();
1150 XtFree((char*)wc_value);
1151 XtFree(total_value);
1152 }
1153 } else { /* initialize prim_select values for possible delete oper */
1154 _XmProcessLock();
1155 prim_select->num_chars = 0;
1156 _XmProcessUnlock();
1157 }
1158 } else {
1159 if (tf->text.max_char_size == 1) {
1160 /* Note: length may be truncated during cast to int */
1161 _XmProcessLock();
1162 prim_select->num_chars = (int) ds->length;
1163 replace_res =
1164 _XmTextFieldReplaceText(tf, ds->event,
1165 replace_from,
1166 replace_to,
1167 (char *) ds->value,
1168 prim_select->num_chars,
1169 ds->selection == atoms[XmACLIPBOARD]);
1170 _XmProcessUnlock();
1171 } else {
1172 wchar_t * wc_value;
1173 char *temp;
1174
1175 temp = XtMalloc((unsigned) ds->length + 1);
1176 (void)memcpy((void*)temp, (void*)ds->value, (size_t)ds->length);
1177 temp[(size_t)ds->length] = '\0';
1178
1179 wc_value = (wchar_t*)XtMalloc ((unsigned)
1180 ((ds->length + 1) * sizeof(wchar_t)));
1181 _XmProcessLock();
1182
1183 prim_select->num_chars = mbstowcs(wc_value, (char *) temp,
1184 (size_t) ds->length+1);
1185
1186 if (prim_select->num_chars < 0)
1187 prim_select->num_chars = 0;
1188 else {
1189 wc_value[prim_select->num_chars] = 0;
1190 replace_res =
1191 _XmTextFieldReplaceText(tf, ds->event,
1192 replace_from,
1193 replace_to,
1194 (char*)wc_value,
1195 prim_select->num_chars,
1196 ds->selection == atoms[XmACLIPBOARD]);
1197 }
1198 _XmProcessUnlock();
1199 XtFree(temp);
1200 XtFree((char*)wc_value);
1201 }
1202 }
1203
1204 if (replace_res) {
1205 XmTextPosition cursorPos = 0;
1206
1207 if (ds->selection != atoms[XmACLIPBOARD]) {
1208 tf->text.pending_off = FALSE;
1209 _XmProcessLock();
1210 cursorPos = replace_from + prim_select->num_chars;
1211 if (prim_select->num_chars > 0 && !tf->text.selection_move) {
1212 _XmTextFieldSetCursorPosition(tf, NULL, cursorPos,
1213 True, True);
1214 (void) _XmTextFieldSetDestination(w, cursorPos, prim_select->time);
1215 _XmProcessUnlock();
1216 }
1217 } else {
1218 _XmProcessLock();
1219 (void) _XmTextFieldSetDestination(w, TextF_CursorPosition(tf),
1220 prim_select->time);
1221 _XmProcessUnlock();
1222 }
1223 left = tf->text.prim_pos_left;
1224 right = tf->text.prim_pos_right;
1225 if (tf->text.has_primary) {
1226 if (ds->selection == atoms[XmACLIPBOARD]) {
1227 if (left != right && (!dest_disjoint || !tf->text.add_mode))
1228 _XmProcessLock();
1229 _XmTextFieldStartSelection(tf, TextF_CursorPosition(tf),
1230 TextF_CursorPosition(tf),
1231 prim_select->time);
1232 _XmProcessUnlock();
1233 } else {
1234 _XmProcessLock();
1235 if (tf->text.selection_move && left < prim_select->position)
1236 prim_select->position -= prim_select->num_chars;
1237 if (left <= cursorPos && right >= cursorPos)
1238 tf->text.pending_off = TRUE;
1239 _XmProcessUnlock();
1240 }
1241 } else {
1242 _XmProcessLock();
1243 if (ds->selection == atoms[XmACLIPBOARD])
1244 tf->text.prim_anchor = replace_from;
1245 else if (!tf->text.selection_move && !tf->text.add_mode &&
1246 prim_select->num_chars != 0)
1247 tf->text.prim_anchor = prim_select->position;
1248 _XmProcessUnlock();
1249 }
1250 cb.reason = XmCR_VALUE_CHANGED;
1251 cb.event = ds->event;
1252 XtCallCallbackList((Widget) tf, TextF_ValueChangedCallback(tf),
1253 (XtPointer) &cb);
1254 } else {
1255 _XmProcessLock();
1256 prim_select->num_chars = 0; /* Stop SetPrimarySelection from doing
1257 anything */
1258 _XmProcessUnlock();
1259 }
1260
1261 if (tf->text.selection_move && local) {
1262 TextF_MaxLength(tf) = max_length;
1263 }
1264 }
1265
1266 XtFree((char *)ds->value);
1267 ds->value = NULL;
1268 }
1269
1270 static void
HandleTargets(Widget w,XtPointer closure,XmSelectionCallbackStruct * ds)1271 HandleTargets(Widget w, XtPointer closure,
1272 XmSelectionCallbackStruct *ds)
1273 {
1274 enum { XmACOMPOUND_TEXT, XmACLIPBOARD, XmATEXT,
1275 #ifdef UTF8_SUPPORTED
1276 XmAUTF8_STRING,
1277 #endif
1278 NUM_ATOMS };
1279 static char *atom_names[] = { XmSCOMPOUND_TEXT, XmSCLIPBOARD, XmSTEXT,
1280 #ifdef UTF8_SUPPORTED
1281 XmSUTF8_STRING
1282 #endif
1283 };
1284
1285 XmTextFieldWidget tf = (XmTextFieldWidget) w;
1286 Atom atoms[XtNumber(atom_names)];
1287 Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
1288 XmTextPosition left, right;
1289 Boolean supports_encoding_data = False;
1290 Boolean supports_CT = False;
1291 Boolean supports_utf8_string = False;
1292 Boolean supports_text = False;
1293 XPoint *point = (XPoint *)closure;
1294 Atom *atom_ptr;
1295 Atom targets[2];
1296 XmTextPosition select_pos;
1297 int i;
1298
1299 if (!ds->length) {
1300 XtFree((char *)ds->value);
1301 ds->value = NULL;
1302 return; /* Supports no targets, so don't bother sending anything */
1303 }
1304
1305 assert(XtNumber(atom_names) == NUM_ATOMS);
1306 XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
1307
1308 atom_ptr = (Atom *)ds->value;
1309
1310 for (i = 0; i < ds->length; i++, atom_ptr++) {
1311 if (*atom_ptr == atoms[XmATEXT])
1312 supports_text = True;
1313
1314 if (*atom_ptr == CS_OF_ENCODING)
1315 supports_encoding_data = True;
1316
1317 if (*atom_ptr == atoms[XmACOMPOUND_TEXT])
1318 supports_CT = True;
1319
1320 #ifdef UTF8_SUPPORTED
1321 if (*atom_ptr == atoms[XmAUTF8_STRING])
1322 supports_utf8_string = True;
1323 #endif
1324 }
1325
1326
1327 /*
1328 * Set stuff position to the x and y position of
1329 * the button pressed event for primary pastes.
1330 */
1331 if (ds->selection != atoms[XmACLIPBOARD] && point) {
1332 select_pos = XmTextFieldXYToPos((Widget)tf, (Position)point->x, 0);
1333 } else {
1334 select_pos = TextF_CursorPosition(tf);
1335 }
1336
1337 if (ds->selection != atoms[XmACLIPBOARD]) {
1338 left = tf->text.prim_pos_left;
1339 right = tf->text.prim_pos_right;
1340 if (tf->text.has_primary &&
1341 left != right && select_pos > left && select_pos < right) {
1342 XtFree((char *)ds->value);
1343 ds->value = NULL;
1344 return;
1345 }
1346 }
1347
1348 _XmProcessLock();
1349 if (prim_select) {
1350 prim_select->ref_count++;
1351 } else {
1352 prim_select = (_XmTextPrimSelect *)
1353 XtMalloc((unsigned) sizeof(_XmTextPrimSelect));
1354 }
1355 prim_select->position = select_pos;
1356 prim_select->time = XtLastTimestampProcessed(XtDisplay(w));
1357 prim_select->num_chars = 0;
1358
1359 if (supports_text && supports_encoding_data)
1360 prim_select->target = targets[0] = atoms[XmATEXT];
1361 #ifdef UTF8_SUPPORTED
1362 else if (supports_utf8_string)
1363 prim_select->target = targets[0] = atoms[XmAUTF8_STRING];
1364 #endif
1365 else if (supports_CT)
1366 prim_select->target = targets[0] = atoms[XmACOMPOUND_TEXT];
1367 else if (supports_encoding_data)
1368 prim_select->target = targets[0] = CS_OF_ENCODING;
1369 else
1370 prim_select->target = targets[0] = XA_STRING;
1371
1372 prim_select->ref_count = 1;
1373 /* Make request to call DoStuff() with the primary selection. */
1374 XmTransferValue(ds->transfer_id, targets[0], (XtCallbackProc) DoStuff,
1375 (XtPointer) prim_select, prim_select->time);
1376 _XmProcessUnlock();
1377 XtFree((char *)ds->value);
1378 ds->value = NULL;
1379 }
1380
1381 static void
HandleDrop(Widget w,XmDropProcCallbackStruct * cb,XmDestinationCallbackStruct * ds)1382 HandleDrop(Widget w,
1383 XmDropProcCallbackStruct *cb,
1384 XmDestinationCallbackStruct *ds)
1385 {
1386 Widget drag_cont, initiator;
1387 Cardinal numExportTargets, n;
1388 Atom *exportTargets;
1389 Atom desiredTarget = None;
1390 Arg args[10];
1391 XmTextPosition insert_pos, left, right;
1392 Display *display = XtDisplay(w);
1393 Boolean doTransfer = False;
1394 _XmTextDropTransferRec *transfer_rec;
1395 XtPointer tid = ds->transfer_id;
1396
1397 drag_cont = cb->dragContext;
1398 transfer_rec = (_XmTextDropTransferRec *) NULL;
1399
1400 n = 0;
1401 XtSetArg(args[n], XmNsourceWidget, &initiator); n++;
1402 XtSetArg(args[n], XmNexportTargets, &exportTargets); n++;
1403 XtSetArg(args[n], XmNnumExportTargets, &numExportTargets); n++;
1404 XtGetValues((Widget) drag_cont, args, n);
1405
1406 insert_pos = XmTextFieldXYToPos(w, cb->x, 0);
1407
1408 left = ((XmTextFieldWidget)w)->text.prim_pos_left;
1409 right = ((XmTextFieldWidget)w)->text.prim_pos_right;
1410 if (cb->operation & XmDROP_MOVE && w == initiator &&
1411 ((XmTextFieldWidget)w)->text.has_primary &&
1412 left != right && insert_pos >= left && insert_pos <= right) {
1413 /*EMPTY*/
1414 } else {
1415 enum { XmATEXT, XmACOMPOUND_TEXT,
1416 #ifdef UTF8_SUPPORTED
1417 XmAUTF8_STRING,
1418 #endif
1419 NUM_ATOMS };
1420 static char *atom_names[] = { XmSTEXT, XmSCOMPOUND_TEXT,
1421 #ifdef UTF8_SUPPORTED
1422 XmSUTF8_STRING
1423 #endif
1424 };
1425
1426 Atom atoms[XtNumber(atom_names)];
1427 Atom CS_OF_ENCODING = XmeGetEncodingAtom(w);
1428 Boolean encoding_found = False;
1429 Boolean utf8_string_found = False;
1430 Boolean c_text_found = False;
1431 Boolean string_found = False;
1432 Boolean text_found = False;
1433
1434 assert(XtNumber(atom_names) == NUM_ATOMS);
1435 XInternAtoms(display, atom_names, XtNumber(atom_names), False, atoms);
1436
1437 /* intialize data to send to drop transfer callback */
1438 transfer_rec = (_XmTextDropTransferRec *)
1439 XtMalloc(sizeof(_XmTextDropTransferRec));
1440 transfer_rec->widget = w;
1441 transfer_rec->insert_pos = insert_pos;
1442 transfer_rec->num_chars = 0;
1443 transfer_rec->timestamp = cb->timeStamp;
1444 transfer_rec->move = False;
1445
1446 if (cb->operation & XmDROP_MOVE) {
1447 transfer_rec->move = True;
1448 } else {
1449 transfer_rec->move = False;
1450 }
1451
1452 for (n = 0; n < numExportTargets; n++) {
1453 if (exportTargets[n] == CS_OF_ENCODING) {
1454 desiredTarget = CS_OF_ENCODING;
1455 encoding_found = True;
1456 break;
1457 }
1458 #ifdef UTF8_SUPPORTED
1459 if (exportTargets[n] == atoms[XmAUTF8_STRING]) utf8_string_found = True;
1460 #endif
1461 if (exportTargets[n] == atoms[XmACOMPOUND_TEXT]) c_text_found = True;
1462 if (exportTargets[n] == XA_STRING) string_found = True;
1463 if (exportTargets[n] == atoms[XmATEXT]) text_found = True;
1464 }
1465
1466 n = 0;
1467 if (encoding_found || c_text_found || string_found || text_found) {
1468 if (!encoding_found) {
1469 #ifdef UTF8_SUPPORTED
1470 if (utf8_string_found)
1471 desiredTarget = atoms[XmAUTF8_STRING];
1472 else
1473 #endif
1474 if (c_text_found)
1475 desiredTarget = atoms[XmACOMPOUND_TEXT];
1476 else if (string_found)
1477 desiredTarget = XA_STRING;
1478 else
1479 desiredTarget = atoms[XmATEXT];
1480 }
1481
1482 if (cb->operation & XmDROP_MOVE || cb->operation & XmDROP_COPY) {
1483 doTransfer = True;
1484 } else {
1485 XmTransferDone(tid, XmTRANSFER_DONE_FAIL);
1486 }
1487
1488 } else {
1489 XmTransferDone(tid, XmTRANSFER_DONE_FAIL);
1490 }
1491 }
1492 SetDropContext(w);
1493
1494 if (doTransfer) {
1495 XmeTransferAddDoneProc(tid, (XmSelectionFinishedProc) DropDestroyCB);
1496 XmTransferValue(tid, desiredTarget,
1497 (XtCallbackProc) DropTransferProc,
1498 (XtPointer) transfer_rec, 0);
1499 }
1500 }
1501
1502
1503 /*ARGSUSED*/
1504 static void
TextFieldConvertCallback(Widget w,XtPointer ignore,XmConvertCallbackStruct * cs)1505 TextFieldConvertCallback(Widget w,
1506 XtPointer ignore, /* unused */
1507 XmConvertCallbackStruct *cs)
1508 {
1509 enum { XmADELETE, XmA_MOTIF_LOSE_SELECTION,
1510 XmA_MOTIF_EXPORT_TARGETS, XmA_MOTIF_CLIPBOARD_TARGETS,
1511 XmACOMPOUND_TEXT, XmATEXT, XmATARGETS, XmACLIPBOARD,
1512 #ifdef UTF8_SUPPORTED
1513 XmAUTF8_STRING,
1514 #endif
1515 NUM_ATOMS };
1516 static char *atom_names[] = { XmSDELETE, XmS_MOTIF_LOSE_SELECTION,
1517 XmS_MOTIF_EXPORT_TARGETS, XmS_MOTIF_CLIPBOARD_TARGETS,
1518 XmSCOMPOUND_TEXT, XmSTEXT, XmSTARGETS, XmSCLIPBOARD,
1519 #ifdef UTF8_SUPPORTED
1520 XmSUTF8_STRING
1521 #endif
1522 };
1523
1524 Atom XA_CS_OF_ENCODING = XmeGetEncodingAtom(w);
1525 XtPointer value;
1526 Atom type;
1527 unsigned long size;
1528 int format;
1529 Atom atoms[XtNumber(atom_names)];
1530
1531 assert(XtNumber(atom_names) == NUM_ATOMS);
1532 XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
1533
1534 value = NULL;
1535
1536 if (cs->target == atoms[XmA_MOTIF_LOSE_SELECTION]) {
1537 _XmTextFieldLoseSelection(w, &(cs->selection));
1538 cs->status = XmCONVERT_DONE;
1539 return;
1540 }
1541
1542 if (cs->target == atoms[XmADELETE] &&
1543 cs->selection == XA_SECONDARY) {
1544 _XmTextFieldHandleSecondaryFinished(w, cs->event);
1545 cs->status = XmCONVERT_DONE;
1546 return;
1547 }
1548
1549 /* When this is called as a result of a clipboard copy link, we
1550 don't have any available targets. Make sure to return immediately
1551 without modification */
1552 if (cs->selection == atoms[XmACLIPBOARD] &&
1553 cs->parm == (XtPointer) XmLINK &&
1554 (cs->target == atoms[XmA_MOTIF_CLIPBOARD_TARGETS] ||
1555 cs->target == atoms[XmATARGETS])) return;
1556
1557 if (!_XmTextFieldConvert(w, &cs->selection, &cs->target,
1558 &type, &value, &size, &format,
1559 (Widget) cs->source_data, cs->event)) {
1560 value = NULL;
1561 type = XA_INTEGER;
1562 size = 0;
1563 format = 8;
1564 }
1565
1566 if (cs->target == atoms[XmADELETE]) {
1567 cs->status = XmCONVERT_DONE;
1568 cs->type = type;
1569 cs->value = value;
1570 cs->length = size;
1571 cs->format = format;
1572 return;
1573 }
1574
1575 if (cs->target == atoms[XmA_MOTIF_EXPORT_TARGETS] ||
1576 cs->target == atoms[XmA_MOTIF_CLIPBOARD_TARGETS]) {
1577 Atom *targs = (Atom *) XtMalloc(sizeof(Atom) * 5);
1578 int n = 0;
1579
1580 value = (XtPointer) targs;
1581 #ifdef UTF8_SUPPORTED
1582 targs[n] = atoms[XmAUTF8_STRING]; n++;
1583 #endif
1584 targs[n] = atoms[XmACOMPOUND_TEXT]; n++;
1585 targs[n] = atoms[XmATEXT]; n++;
1586 targs[n] = XA_STRING; n++;
1587 if (XA_CS_OF_ENCODING != XA_STRING) {
1588 targs[n] = XA_CS_OF_ENCODING; n++;
1589 }
1590 format = 32;
1591 size = n;
1592 type = XA_ATOM;
1593 }
1594
1595 _XmConvertComplete(w, value, size, format, type, cs);
1596 }
1597
1598 /************************************************
1599 * Free data allocated for destination callback
1600 ************************************************/
1601
1602 /*ARGSUSED*/
1603 static void
FreeLocationData(Widget w,XtEnum op,XmTransferDoneCallbackStruct * ts)1604 FreeLocationData(Widget w, /* unused */
1605 XtEnum op, /* unused */
1606 XmTransferDoneCallbackStruct *ts)
1607 {
1608 XmDestinationCallbackStruct *ds;
1609
1610 ds = _XmTransferGetDestinationCBStruct(ts->transfer_id);
1611
1612 XtFree((char*) ds->location_data);
1613
1614 ds->location_data = NULL;
1615 }
1616
1617 /*ARGSUSED*/
1618 static void
TextFieldDestinationCallback(Widget w,XtPointer closure,XmDestinationCallbackStruct * ds)1619 TextFieldDestinationCallback(Widget w,
1620 XtPointer closure, /* unused */
1621 XmDestinationCallbackStruct *ds)
1622 {
1623 enum { XmATARGETS, XmA_MOTIF_DROP, NUM_ATOMS };
1624 static char *atom_names[] = { XmSTARGETS, XmS_MOTIF_DROP };
1625 Atom atoms[XtNumber(atom_names)];
1626 XPoint DropPoint;
1627
1628 assert(XtNumber(atom_names) == NUM_ATOMS);
1629 XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms);
1630
1631 /*
1632 ** In case of a primary transfer operation where a location_data
1633 ** has been allocated, register a done proc to be called when
1634 ** the data transfer is complete to free the location_data
1635 */
1636 if (ds->selection == XA_PRIMARY && ds->location_data)
1637 XmeTransferAddDoneProc(ds->transfer_id, FreeLocationData);
1638
1639 /* If we aren't sensitive, don't allow transfer */
1640 if (! w -> core.sensitive ||
1641 ! w -> core.ancestor_sensitive)
1642 XmTransferDone(ds -> transfer_id, XmTRANSFER_DONE_FAIL);
1643
1644 /* We don't handle LINKs internally */
1645 if (ds->operation == XmLINK) return;
1646
1647 if (ds->selection == XA_PRIMARY && ds->operation == XmMOVE)
1648 XmeTransferAddDoneProc(ds->transfer_id, SetPrimarySelection);
1649 else
1650 XmeTransferAddDoneProc(ds->transfer_id, CleanPrimarySelection);
1651
1652 if (ds->selection == atoms[XmA_MOTIF_DROP]) {
1653 XmDropProcCallbackStruct *cb =
1654 (XmDropProcCallbackStruct *) ds->destination_data;
1655
1656 DropPoint.x = cb->x;
1657 DropPoint.y = cb->y;
1658
1659 ds->location_data = (XtPointer) &DropPoint;
1660
1661 if (cb->dropAction != XmDROP_HELP) {
1662 HandleDrop(w, cb, ds);
1663 }
1664 } else if (ds->selection == XA_SECONDARY) {
1665 Atom CS_OF_ENCODING;
1666
1667 CS_OF_ENCODING = XmeGetEncodingAtom(w);
1668
1669 _XmProcessLock();
1670 insert_select.done_status = False;
1671 insert_select.success_status = False;
1672 insert_select.event = (XSelectionRequestEvent *) ds->event;
1673 insert_select.select_type = XmDEST_SELECT;
1674
1675 if (((Atom) ds->location_data) != CS_OF_ENCODING) {
1676 /*
1677 * Make selection request to find out which targets
1678 * the selection can provide.
1679 */
1680 XmTransferValue(ds->transfer_id, atoms[XmATARGETS],
1681 (XtCallbackProc) TextFieldSecondaryWrapper,
1682 (XtPointer) &insert_select, ds->time);
1683 } else {
1684 /*
1685 * Make selection request to replace the selection
1686 * with the insert selection.
1687 */
1688 XmTransferValue(ds->transfer_id, ((Atom) ds->location_data),
1689 (XtCallbackProc) TextFieldSecondaryWrapper,
1690 (XtPointer) &insert_select, ds->time);
1691 }
1692 _XmProcessUnlock();
1693 } else
1694 /* CLIPBOARD or PRIMARY */
1695 XmTransferValue(ds->transfer_id, atoms[XmATARGETS],
1696 (XtCallbackProc) HandleTargets,
1697 ds->location_data, ds->time);
1698 }
1699
1700 void
_XmTextFieldInstallTransferTrait(void)1701 _XmTextFieldInstallTransferTrait(void)
1702 {
1703 XmeTraitSet((XtPointer)xmTextFieldWidgetClass, XmQTtransfer,
1704 (XtPointer) &textFieldTT);
1705 }
1706