Fix periodic focus bug
[wmaker-crm.git] / WINGs / wtextfield.c
blobc528541e0ee50c7740de60159185f3e022a88bd3
5 #include "WINGsP.h"
6 #include "wconfig.h"
8 #include <X11/keysym.h>
9 #include <X11/Xatom.h>
11 #include <ctype.h>
13 #define CURSOR_BLINK_ON_DELAY 600
14 #define CURSOR_BLINK_OFF_DELAY 300
18 char *WMTextDidChangeNotification = "WMTextDidChangeNotification";
19 char *WMTextDidBeginEditingNotification = "WMTextDidBeginEditingNotification";
20 char *WMTextDidEndEditingNotification = "WMTextDidEndEditingNotification";
23 typedef struct W_TextField {
24 W_Class widgetClass;
25 W_View *view;
27 #if 0
28 struct W_TextField *nextField; /* next textfield in the chain */
29 struct W_TextField *prevField;
30 #endif
32 char *text;
33 int textLen; /* size of text */
34 int bufferSize; /* memory allocated for text */
36 int viewPosition; /* position of text being shown */
38 int cursorPosition; /* position of the insertion cursor */
40 short usableWidth;
41 short offsetWidth; /* offset of text from border */
43 WMRange selection;
45 WMFont *font;
47 WMTextFieldDelegate *delegate;
49 #if 0
50 WMHandlerID timerID; /* for cursor blinking */
51 #endif
52 struct {
53 WMAlignment alignment:2;
55 unsigned int bordered:1;
57 unsigned int beveled:1;
59 unsigned int enabled:1;
61 unsigned int focused:1;
63 unsigned int cursorOn:1;
65 unsigned int secure:1; /* password entry style */
67 unsigned int pointerGrabbed:1;
69 unsigned int ownsSelection:1;
71 unsigned int waitingSelection:1; /* requested selection, but
72 * didnt get yet */
75 unsigned int notIllegalMovement:1;
76 } flags;
77 } TextField;
80 #define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
81 if ((T)->delegate && (T)->delegate->C)\
82 (*(T)->delegate->C)((T)->delegate,notif);\
83 WMPostNotification(notif);\
84 WMReleaseNotification(notif);}
87 #define MIN_TEXT_BUFFER 2
88 #define TEXT_BUFFER_INCR 8
91 #define WM_EMACSKEYMASK ControlMask
93 #define WM_EMACSKEY_LEFT XK_b
94 #define WM_EMACSKEY_RIGHT XK_f
95 #define WM_EMACSKEY_HOME XK_a
96 #define WM_EMACSKEY_END XK_e
97 #define WM_EMACSKEY_BS XK_h
98 #define WM_EMACSKEY_DEL XK_d
102 #define DEFAULT_WIDTH 60
103 #define DEFAULT_HEIGHT 20
104 #define DEFAULT_BORDERED True
105 #define DEFAULT_ALIGNMENT WALeft
109 static void destroyTextField(TextField *tPtr);
110 static void paintTextField(TextField *tPtr);
112 static void handleEvents(XEvent *event, void *data);
113 static void handleTextFieldActionEvents(XEvent *event, void *data);
114 static void didResizeTextField();
116 struct W_ViewDelegate _TextFieldViewDelegate = {
117 NULL,
118 NULL,
119 didResizeTextField,
120 NULL,
121 NULL
126 static void lostSelection(WMView *view, Atom selection, void *cdata);
128 static WMData *requestHandler(WMView *view, Atom selection, Atom target,
129 void *cdata, Atom *type);
132 static WMSelectionProcs selectionHandler = {
133 requestHandler,
134 lostSelection,
135 NULL
139 #define TEXT_WIDTH(tPtr, start) (WMWidthOfString((tPtr)->font, \
140 &((tPtr)->text[(start)]), (tPtr)->textLen - (start)))
142 #define TEXT_WIDTH2(tPtr, start, end) (WMWidthOfString((tPtr)->font, \
143 &((tPtr)->text[(start)]), (end) - (start)))
146 static INLINE int
147 oneUTF8CharBackward(char *str, int len)
149 unsigned char* ustr = (unsigned char*) str;
150 int pos = 0;
152 while (len-- > 0 && ustr[--pos] >= 0x80 && ustr[pos] <= 0xbf);
153 return pos;
157 static INLINE int
158 oneUTF8CharForward(char *str, int len)
160 unsigned char* ustr = (unsigned char*) str;
161 int pos = 0;
163 while (len-- > 0 && ustr[++pos] >= 0x80 && ustr[pos] <= 0xbf);
164 return pos;
168 // find the beginning of the UTF8 char pointed by str
169 static INLINE int
170 seekUTF8CharStart(char *str, int len)
172 unsigned char* ustr = (unsigned char*) str;
173 int pos = 0;
175 while (len-- > 0 && ustr[pos] >= 0x80 && ustr[pos] <= 0xbf) --pos;
176 return pos;
180 static void
181 normalizeRange(TextField *tPtr, WMRange *range)
183 if (range->position < 0 && range->count < 0)
184 range->count = 0;
186 if (range->count == 0) {
187 /*range->position = 0; why is this?*/
188 return;
191 /* (1,-2) ~> (0,1) ; (1,-1) ~> (0,1) ; (2,-1) ~> (1,1) */
192 if (range->count < 0) { /* && range->position >= 0 */
193 if (range->position + range->count < 0) {
194 range->count = range->position;
195 range->position = 0;
196 } else {
197 range->count = -range->count;
198 range->position -= range->count;
200 /* (-2,1) ~> (0,0) ; (-1,1) ~> (0,0) ; (-1,2) ~> (0,1) */
201 } else if (range->position < 0) { /* && range->count > 0 */
202 if (range->position + range->count < 0) {
203 range->position = range->count = 0;
204 } else {
205 range->count += range->position;
206 range->position = 0;
210 if (range->position + range->count > tPtr->textLen)
211 range->count = tPtr->textLen - range->position;
215 static void
216 memmv(char *dest, char *src, int size)
218 int i;
220 if (dest > src) {
221 for (i=size-1; i>=0; i--) {
222 dest[i] = src[i];
224 } else if (dest < src) {
225 for (i=0; i<size; i++) {
226 dest[i] = src[i];
232 static int
233 incrToFit(TextField *tPtr)
235 int vp = tPtr->viewPosition;
237 while (TEXT_WIDTH(tPtr, tPtr->viewPosition) > tPtr->usableWidth) {
238 tPtr->viewPosition += oneUTF8CharForward(&tPtr->text[tPtr->viewPosition],
239 tPtr->textLen - tPtr->viewPosition);
241 return vp!=tPtr->viewPosition;
245 static int
246 incrToFit2(TextField *tPtr)
248 int vp = tPtr->viewPosition;
250 while (TEXT_WIDTH2(tPtr, tPtr->viewPosition, tPtr->cursorPosition)
251 >= tPtr->usableWidth)
252 tPtr->viewPosition += oneUTF8CharForward(&tPtr->text[tPtr->viewPosition],
253 tPtr->cursorPosition - tPtr->viewPosition);
254 return vp!=tPtr->viewPosition;
258 static void
259 decrToFit(TextField *tPtr)
261 int vp = tPtr->viewPosition;
263 while (vp > 0 && (vp += oneUTF8CharBackward(&tPtr->text[vp], vp),
264 TEXT_WIDTH(tPtr, vp)) < tPtr->usableWidth) {
265 tPtr->viewPosition = vp;
269 #undef TEXT_WIDTH
270 #undef TEXT_WIDTH2
273 static WMData*
274 requestHandler(WMView *view, Atom selection, Atom target, void *cdata,
275 Atom *type)
277 TextField *tPtr = view->self;
278 int count;
279 Display *dpy = tPtr->view->screen->display;
280 Atom _TARGETS;
281 Atom TEXT = XInternAtom(dpy, "TEXT", False);
282 Atom COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False);
283 WMData *data;
285 count = tPtr->selection.count < 0
286 ? tPtr->selection.position + tPtr->selection.count
287 : tPtr->selection.position;
289 if (target == XA_STRING || target == TEXT || target == COMPOUND_TEXT) {
291 data = WMCreateDataWithBytes(&(tPtr->text[count]),
292 abs(tPtr->selection.count));
293 WMSetDataFormat(data, 8);
294 *type = target;
296 return data;
299 _TARGETS = XInternAtom(dpy, "TARGETS", False);
300 if (target == _TARGETS) {
301 Atom *ptr;
303 ptr = wmalloc(4 * sizeof(Atom));
304 ptr[0] = _TARGETS;
305 ptr[1] = XA_STRING;
306 ptr[2] = TEXT;
307 ptr[3] = COMPOUND_TEXT;
309 data = WMCreateDataWithBytes(ptr, 4*4);
310 WMSetDataFormat(data, 32);
312 *type = target;
313 return data;
316 return NULL;
321 static void
322 lostSelection(WMView *view, Atom selection, void *cdata)
324 TextField *tPtr = (WMTextField*)view->self;
326 if (tPtr->flags.ownsSelection) {
327 WMDeleteSelectionHandler(view, selection, CurrentTime);
328 tPtr->flags.ownsSelection = 0;
330 if (tPtr->selection.count != 0) {
331 tPtr->selection.count = 0;
332 paintTextField(tPtr);
337 static void
338 selectionNotification(void *observerData, WMNotification *notification)
340 WMView *observerView = (WMView*)observerData;
341 WMView *newOwnerView = (WMView*)WMGetNotificationClientData(notification);
343 if (observerView != newOwnerView) {
345 //if (tPtr->flags.ownsSelection)
346 // WMDeleteSelectionHandler(observerView, XA_PRIMARY, CurrentTime);
348 lostSelection(observerView, XA_PRIMARY, NULL);
353 static void
354 realizeObserver(void *self, WMNotification *not)
356 W_CreateIC(((TextField*)self)->view);
360 WMTextField*
361 WMCreateTextField(WMWidget *parent)
363 TextField *tPtr;
365 tPtr = wmalloc(sizeof(TextField));
366 memset(tPtr, 0, sizeof(TextField));
368 tPtr->widgetClass = WC_TextField;
370 tPtr->view = W_CreateView(W_VIEW(parent));
371 if (!tPtr->view) {
372 wfree(tPtr);
373 return NULL;
375 tPtr->view->self = tPtr;
377 tPtr->view->delegate = &_TextFieldViewDelegate;
379 tPtr->view->attribFlags |= CWCursor;
380 tPtr->view->attribs.cursor = tPtr->view->screen->textCursor;
382 W_SetViewBackgroundColor(tPtr->view, tPtr->view->screen->white);
384 tPtr->text = wmalloc(MIN_TEXT_BUFFER);
385 tPtr->text[0] = 0;
386 tPtr->textLen = 0;
387 tPtr->bufferSize = MIN_TEXT_BUFFER;
389 tPtr->flags.enabled = 1;
391 WMCreateEventHandler(tPtr->view, ExposureMask|StructureNotifyMask
392 |FocusChangeMask, handleEvents, tPtr);
394 tPtr->font = WMRetainFont(tPtr->view->screen->normalFont);
396 tPtr->flags.bordered = DEFAULT_BORDERED;
397 tPtr->flags.beveled = True;
398 tPtr->flags.alignment = DEFAULT_ALIGNMENT;
399 tPtr->offsetWidth =
400 WMAX((tPtr->view->size.height - WMFontHeight(tPtr->font))/2, 1);
402 W_ResizeView(tPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
404 WMCreateEventHandler(tPtr->view, EnterWindowMask|LeaveWindowMask
405 |ButtonReleaseMask|ButtonPressMask|KeyPressMask|Button1MotionMask,
406 handleTextFieldActionEvents, tPtr);
408 WMAddNotificationObserver(selectionNotification, tPtr->view,
409 WMSelectionOwnerDidChangeNotification,
410 (void*)XA_PRIMARY);
412 WMAddNotificationObserver(realizeObserver, tPtr,
413 WMViewRealizedNotification, tPtr->view);
415 tPtr->flags.cursorOn = 1;
417 return tPtr;
421 void
422 WMSetTextFieldDelegate(WMTextField *tPtr, WMTextFieldDelegate *delegate)
424 CHECK_CLASS(tPtr, WC_TextField);
426 tPtr->delegate = delegate;
430 WMTextFieldDelegate*
431 WMGetTextFieldDelegate(WMTextField *tPtr)
433 CHECK_CLASS(tPtr, WC_TextField);
435 return tPtr->delegate;
439 void
440 WMInsertTextFieldText(WMTextField *tPtr, char *text, int position)
442 int len;
444 CHECK_CLASS(tPtr, WC_TextField);
446 if (!text)
447 return;
449 len = strlen(text);
451 /* check if buffer will hold the text */
452 if (len + tPtr->textLen >= tPtr->bufferSize) {
453 tPtr->bufferSize = tPtr->textLen + len + TEXT_BUFFER_INCR;
454 tPtr->text = wrealloc(tPtr->text, tPtr->bufferSize);
457 if (position < 0 || position >= tPtr->textLen) {
458 /* append the text at the end */
459 strcat(tPtr->text, text);
460 tPtr->textLen += len;
461 tPtr->cursorPosition += len;
462 incrToFit(tPtr);
463 } else {
464 /* insert text at position */
465 memmv(&(tPtr->text[position+len]), &(tPtr->text[position]),
466 tPtr->textLen-position+1);
468 memcpy(&(tPtr->text[position]), text, len);
470 tPtr->textLen += len;
471 if (position >= tPtr->cursorPosition) {
472 tPtr->cursorPosition += len;
473 incrToFit2(tPtr);
474 } else {
475 incrToFit(tPtr);
479 paintTextField(tPtr);
482 void
483 WMDeleteTextFieldRange(WMTextField *tPtr, WMRange range)
485 CHECK_CLASS(tPtr, WC_TextField);
487 normalizeRange(tPtr, &range);
489 if (!range.count)
490 return;
492 memmv(&(tPtr->text[range.position]), &(tPtr->text[range.position+range.count]),
493 tPtr->textLen - (range.position+range.count) + 1);
495 /* better than nothing ;) */
496 if (tPtr->cursorPosition > range.position)
497 tPtr->viewPosition += oneUTF8CharBackward(&tPtr->text[tPtr->viewPosition],
498 tPtr->viewPosition);
499 tPtr->textLen -= range.count;
500 tPtr->cursorPosition = range.position;
502 decrToFit(tPtr);
504 paintTextField(tPtr);
509 char*
510 WMGetTextFieldText(WMTextField *tPtr)
512 CHECK_CLASS(tPtr, WC_TextField);
514 return wstrdup(tPtr->text);
518 void
519 WMSetTextFieldText(WMTextField *tPtr, char *text)
521 CHECK_CLASS(tPtr, WC_TextField);
523 if ((text && strcmp(tPtr->text, text) == 0) ||
524 (!text && tPtr->textLen == 0))
525 return;
527 if (text==NULL) {
528 tPtr->text[0] = 0;
529 tPtr->textLen = 0;
530 } else {
531 tPtr->textLen = strlen(text);
533 if (tPtr->textLen >= tPtr->bufferSize) {
534 tPtr->bufferSize = tPtr->textLen + TEXT_BUFFER_INCR;
535 tPtr->text = wrealloc(tPtr->text, tPtr->bufferSize);
537 strcpy(tPtr->text, text);
540 tPtr->cursorPosition = tPtr->selection.position = tPtr->textLen;
541 tPtr->viewPosition = 0;
542 tPtr->selection.count = 0;
544 if (tPtr->view->flags.realized)
545 paintTextField(tPtr);
549 void
550 WMSetTextFieldAlignment(WMTextField *tPtr, WMAlignment alignment)
552 CHECK_CLASS(tPtr, WC_TextField);
554 tPtr->flags.alignment = alignment;
556 if (alignment!=WALeft) {
557 wwarning("only left alignment is supported in textfields");
558 return;
561 if (tPtr->view->flags.realized) {
562 paintTextField(tPtr);
567 void
568 WMSetTextFieldBordered(WMTextField *tPtr, Bool bordered)
570 CHECK_CLASS(tPtr, WC_TextField);
572 tPtr->flags.bordered = bordered;
574 if (tPtr->view->flags.realized) {
575 paintTextField(tPtr);
580 void
581 WMSetTextFieldBeveled(WMTextField *tPtr, Bool flag)
583 CHECK_CLASS(tPtr, WC_TextField);
585 tPtr->flags.beveled = ((flag==0) ? 0 : 1);
587 if (tPtr->view->flags.realized) {
588 paintTextField(tPtr);
594 void
595 WMSetTextFieldSecure(WMTextField *tPtr, Bool flag)
597 CHECK_CLASS(tPtr, WC_TextField);
599 tPtr->flags.secure = ((flag==0) ? 0 : 1);
601 if (tPtr->view->flags.realized) {
602 paintTextField(tPtr);
607 Bool
608 WMGetTextFieldEditable(WMTextField *tPtr)
610 CHECK_CLASS(tPtr, WC_TextField);
612 return tPtr->flags.enabled;
616 void
617 WMSetTextFieldEditable(WMTextField *tPtr, Bool flag)
619 CHECK_CLASS(tPtr, WC_TextField);
621 tPtr->flags.enabled = ((flag==0) ? 0 : 1);
623 if (tPtr->view->flags.realized) {
624 paintTextField(tPtr);
629 void
630 WMSelectTextFieldRange(WMTextField *tPtr, WMRange range)
632 CHECK_CLASS(tPtr, WC_TextField);
634 if (tPtr->flags.enabled) {
635 normalizeRange(tPtr, &range);
637 tPtr->selection = range;
639 tPtr->cursorPosition = range.position + range.count;
641 if (tPtr->view->flags.realized) {
642 paintTextField(tPtr);
648 void
649 WMSetTextFieldCursorPosition(WMTextField *tPtr, unsigned int position)
651 CHECK_CLASS(tPtr, WC_TextField);
653 if (tPtr->flags.enabled) {
654 if (position > tPtr->textLen)
655 position = tPtr->textLen;
657 tPtr->cursorPosition = position;
658 if (tPtr->view->flags.realized) {
659 paintTextField(tPtr);
665 void
666 WMSetTextFieldNextTextField(WMTextField *tPtr, WMTextField *next)
668 CHECK_CLASS(tPtr, WC_TextField);
669 if (next == NULL) {
670 if (tPtr->view->nextFocusChain)
671 tPtr->view->nextFocusChain->prevFocusChain = NULL;
672 tPtr->view->nextFocusChain = NULL;
673 return;
676 CHECK_CLASS(next, WC_TextField);
678 if (tPtr->view->nextFocusChain)
679 tPtr->view->nextFocusChain->prevFocusChain = NULL;
680 if (next->view->prevFocusChain)
681 next->view->prevFocusChain->nextFocusChain = NULL;
683 tPtr->view->nextFocusChain = next->view;
684 next->view->prevFocusChain = tPtr->view;
688 void
689 WMSetTextFieldPrevTextField(WMTextField *tPtr, WMTextField *prev)
691 CHECK_CLASS(tPtr, WC_TextField);
692 if (prev == NULL) {
693 if (tPtr->view->prevFocusChain)
694 tPtr->view->prevFocusChain->nextFocusChain = NULL;
695 tPtr->view->prevFocusChain = NULL;
696 return;
699 CHECK_CLASS(prev, WC_TextField);
701 if (tPtr->view->prevFocusChain)
702 tPtr->view->prevFocusChain->nextFocusChain = NULL;
703 if (prev->view->nextFocusChain)
704 prev->view->nextFocusChain->prevFocusChain = NULL;
706 tPtr->view->prevFocusChain = prev->view;
707 prev->view->nextFocusChain = tPtr->view;
711 void
712 WMSetTextFieldFont(WMTextField *tPtr, WMFont *font)
714 CHECK_CLASS(tPtr, WC_TextField);
716 if (tPtr->font)
717 WMReleaseFont(tPtr->font);
718 tPtr->font = WMRetainFont(font);
720 tPtr->offsetWidth =
721 WMAX((tPtr->view->size.height - WMFontHeight(tPtr->font))/2, 1);
723 if (tPtr->view->flags.realized) {
724 paintTextField(tPtr);
730 WMFont*
731 WMGetTextFieldFont(WMTextField *tPtr)
733 return tPtr->font;
737 static void
738 didResizeTextField(W_ViewDelegate *self, WMView *view)
740 WMTextField *tPtr = (WMTextField*)view->self;
742 tPtr->offsetWidth =
743 WMAX((tPtr->view->size.height - WMFontHeight(tPtr->font))/2, 1);
745 tPtr->usableWidth = tPtr->view->size.width - 2*tPtr->offsetWidth /*+ 2*/;
749 static char*
750 makeHiddenString(int length)
752 char *data = wmalloc(length+1);
754 memset(data, '*', length);
755 data[length] = '\0';
757 return data;
761 static void
762 paintCursor(TextField *tPtr)
764 int cx;
765 WMScreen *screen = tPtr->view->screen;
766 int textWidth;
767 char *text;
769 if (tPtr->flags.secure)
770 text = makeHiddenString(strlen(tPtr->text));
771 else
772 text = tPtr->text;
774 cx = WMWidthOfString(tPtr->font, &(text[tPtr->viewPosition]),
775 tPtr->cursorPosition-tPtr->viewPosition);
777 switch (tPtr->flags.alignment) {
778 case WARight:
779 textWidth = WMWidthOfString(tPtr->font, text, tPtr->textLen);
780 if (textWidth < tPtr->usableWidth)
781 cx += tPtr->offsetWidth + tPtr->usableWidth - textWidth + 1;
782 else
783 cx += tPtr->offsetWidth + 1;
784 break;
785 case WALeft:
786 cx += tPtr->offsetWidth + 1;
787 break;
788 case WAJustified:
789 /* not supported */
790 case WACenter:
791 textWidth = WMWidthOfString(tPtr->font, text, tPtr->textLen);
792 if (textWidth < tPtr->usableWidth)
793 cx += tPtr->offsetWidth + (tPtr->usableWidth-textWidth)/2;
794 else
795 cx += tPtr->offsetWidth;
796 break;
799 XDrawRectangle(screen->display, tPtr->view->window, screen->xorGC,
800 cx, tPtr->offsetWidth, 1,
801 tPtr->view->size.height - 2*tPtr->offsetWidth - 1);
802 printf("%d %d\n",cx,tPtr->cursorPosition);
805 XDrawLine(screen->display, tPtr->view->window, screen->xorGC,
806 cx, tPtr->offsetWidth, cx,
807 tPtr->view->size.height - tPtr->offsetWidth - 1);
809 W_SetPreeditPositon(tPtr->view, cx, 0);
811 if (tPtr->flags.secure) {
812 wfree(text);
818 static void
819 drawRelief(WMView *view, Bool beveled)
821 WMScreen *scr = view->screen;
822 Display *dpy = scr->display;
823 GC wgc;
824 GC lgc;
825 GC dgc;
826 int width = view->size.width;
827 int height = view->size.height;
829 dgc = WMColorGC(scr->darkGray);
831 if (!beveled) {
832 XDrawRectangle(dpy, view->window, dgc, 0, 0, width-1, height-1);
834 return;
836 wgc = WMColorGC(scr->white);
837 lgc = WMColorGC(scr->gray);
839 /* top left */
840 XDrawLine(dpy, view->window, dgc, 0, 0, width-1, 0);
841 XDrawLine(dpy, view->window, dgc, 0, 1, width-2, 1);
843 XDrawLine(dpy, view->window, dgc, 0, 0, 0, height-2);
844 XDrawLine(dpy, view->window, dgc, 1, 0, 1, height-3);
846 /* bottom right */
847 XDrawLine(dpy, view->window, wgc, 0, height-1, width-1, height-1);
848 XDrawLine(dpy, view->window, lgc, 1, height-2, width-2, height-2);
850 XDrawLine(dpy, view->window, wgc, width-1, 0, width-1, height-1);
851 XDrawLine(dpy, view->window, lgc, width-2, 1, width-2, height-3);
855 static void
856 paintTextField(TextField *tPtr)
858 W_Screen *screen = tPtr->view->screen;
859 W_View *view = tPtr->view;
860 W_View viewbuffer;
861 int tx, ty, tw, th;
862 int rx;
863 int bd;
864 int totalWidth;
865 char *text;
866 Pixmap drawbuffer;
867 WMColor *color;
870 if (!view->flags.realized || !view->flags.mapped)
871 return;
873 if (!tPtr->flags.bordered) {
874 bd = 0;
875 } else {
876 bd = 2;
879 if (tPtr->flags.secure) {
880 text = makeHiddenString(strlen(tPtr->text));
881 } else {
882 text = tPtr->text;
885 totalWidth = tPtr->view->size.width - 2*bd;
887 drawbuffer = XCreatePixmap(screen->display, view->window,
888 view->size.width, view->size.height, screen->depth);
889 XFillRectangle(screen->display, drawbuffer, WMColorGC(screen->white),
890 0,0, view->size.width,view->size.height);
891 /* this is quite dirty */
892 viewbuffer.screen = view->screen;
893 viewbuffer.size = view->size;
894 viewbuffer.window = drawbuffer;
897 if (tPtr->textLen > 0) {
898 tw = WMWidthOfString(tPtr->font, &(text[tPtr->viewPosition]),
899 tPtr->textLen - tPtr->viewPosition);
901 th = WMFontHeight(tPtr->font);
903 ty = tPtr->offsetWidth;
904 switch (tPtr->flags.alignment) {
905 case WALeft:
906 tx = tPtr->offsetWidth + 1;
907 if (tw < tPtr->usableWidth)
908 XFillRectangle(screen->display, drawbuffer,
909 WMColorGC(screen->white),
910 bd+tw,bd, totalWidth-tw,view->size.height-2*bd);
911 break;
913 case WACenter:
914 tx = tPtr->offsetWidth + (tPtr->usableWidth - tw) / 2;
915 if (tw < tPtr->usableWidth)
916 XClearArea(screen->display, view->window, bd, bd,
917 totalWidth, view->size.height-2*bd, False);
918 break;
920 default:
921 case WARight:
922 tx = tPtr->offsetWidth + tPtr->usableWidth - tw - 1;
923 if (tw < tPtr->usableWidth)
924 XClearArea(screen->display, view->window, bd, bd,
925 totalWidth-tw, view->size.height-2*bd, False);
926 break;
929 color = tPtr->flags.enabled ? screen->black : screen->darkGray;
931 WMDrawImageString(screen, drawbuffer, color, screen->white,
932 tPtr->font, tx, ty, &(text[tPtr->viewPosition]),
933 tPtr->textLen - tPtr->viewPosition);
935 if (tPtr->selection.count) {
936 int count,count2;
938 count = tPtr->selection.count < 0
939 ? tPtr->selection.position + tPtr->selection.count
940 : tPtr->selection.position;
941 count2 = abs(tPtr->selection.count);
942 if (count < tPtr->viewPosition) {
943 count2 = abs(count2 - abs(tPtr->viewPosition - count));
944 count = tPtr->viewPosition;
947 rx = tPtr->offsetWidth + 1 + WMWidthOfString(tPtr->font,text,count)
948 - WMWidthOfString(tPtr->font,text,tPtr->viewPosition);
950 WMDrawImageString(screen, drawbuffer, color, screen->gray,
951 tPtr->font, rx, ty, &(text[count]), count2);
953 } else {
954 XFillRectangle(screen->display, drawbuffer, WMColorGC(screen->white),
955 bd, bd, totalWidth,view->size.height-2*bd);
958 /* draw relief */
959 if (tPtr->flags.bordered) {
960 drawRelief(&viewbuffer, tPtr->flags.beveled);
963 if (tPtr->flags.secure)
964 wfree(text);
965 XCopyArea(screen->display, drawbuffer, view->window,
966 screen->copyGC, 0,0, view->size.width,
967 view->size.height,0,0);
968 XFreePixmap(screen->display, drawbuffer);
970 /* draw cursor */
971 if (tPtr->flags.focused && tPtr->flags.enabled && tPtr->flags.cursorOn) {
972 paintCursor(tPtr);
977 #if 0
978 static void
979 blinkCursor(void *data)
981 TextField *tPtr = (TextField*)data;
983 if (tPtr->flags.cursorOn) {
984 tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY, blinkCursor,
985 data);
986 } else {
987 tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_ON_DELAY, blinkCursor,
988 data);
990 paintCursor(tPtr);
991 tPtr->flags.cursorOn = !tPtr->flags.cursorOn;
993 #endif
996 static void
997 handleEvents(XEvent *event, void *data)
999 TextField *tPtr = (TextField*)data;
1001 CHECK_CLASS(data, WC_TextField);
1003 switch (event->type) {
1004 case FocusIn:
1005 W_FocusIC(tPtr->view);
1006 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr->view))!=tPtr->view)
1007 return;
1008 tPtr->flags.focused = 1;
1009 #if 0
1010 if (!tPtr->timerID) {
1011 tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_ON_DELAY,
1012 blinkCursor, tPtr);
1014 #endif
1015 paintTextField(tPtr);
1017 NOTIFY(tPtr, didBeginEditing, WMTextDidBeginEditingNotification, NULL);
1019 tPtr->flags.notIllegalMovement = 0;
1020 break;
1022 case FocusOut:
1023 W_UnFocusIC(tPtr->view);
1024 tPtr->flags.focused = 0;
1025 #if 0
1026 if (tPtr->timerID)
1027 WMDeleteTimerHandler(tPtr->timerID);
1028 tPtr->timerID = NULL;
1029 #endif
1031 paintTextField(tPtr);
1032 if (!tPtr->flags.notIllegalMovement) {
1033 NOTIFY(tPtr, didEndEditing, WMTextDidEndEditingNotification,
1034 (void*)WMIllegalTextMovement);
1036 break;
1038 case Expose:
1039 if (event->xexpose.count!=0)
1040 break;
1041 paintTextField(tPtr);
1042 break;
1044 case DestroyNotify:
1045 destroyTextField(tPtr);
1046 break;
1051 static void
1052 handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
1054 char buffer[64];
1055 KeySym ksym;
1056 char *textEvent = NULL;
1057 void *data = NULL;
1058 int count, refresh = 0;
1059 int control_pressed = 0;
1060 int cancelSelection = 1;
1061 Bool shifted, controled, modified;
1062 Bool relay = True;
1064 /*printf("(%d,%d) -> ", tPtr->selection.position, tPtr->selection.count);*/
1065 if (((XKeyEvent *) event)->state & WM_EMACSKEYMASK)
1066 control_pressed = 1;
1068 shifted = (event->xkey.state & ShiftMask ? True : False);
1069 controled = (event->xkey.state & ControlMask ? True : False);
1070 modified = shifted || controled;
1072 count = W_LookupString(tPtr->view, &event->xkey, buffer, 63, &ksym, NULL);
1073 //count = XLookupString(&event->xkey, buffer, 63, &ksym, NULL);
1074 buffer[count] = '\0';
1076 switch (ksym) {
1077 case XK_Tab:
1078 #ifdef XK_ISO_Left_Tab
1079 case XK_ISO_Left_Tab:
1080 #endif
1081 if (!controled) {
1082 if (shifted) {
1083 if (tPtr->view->prevFocusChain) {
1084 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
1085 tPtr->view->prevFocusChain);
1086 tPtr->flags.notIllegalMovement = 1;
1088 data = (void*)WMBacktabTextMovement;
1089 } else {
1090 if (tPtr->view->nextFocusChain) {
1091 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
1092 tPtr->view->nextFocusChain);
1093 tPtr->flags.notIllegalMovement = 1;
1095 data = (void*)WMTabTextMovement;
1097 textEvent = WMTextDidEndEditingNotification;
1099 cancelSelection = 0;
1101 relay = False;
1103 break;
1105 case XK_Escape:
1106 if (!modified) {
1107 data = (void*)WMEscapeTextMovement;
1108 textEvent = WMTextDidEndEditingNotification;
1110 relay = False;
1112 break;
1114 case XK_Return:
1115 if (!modified) {
1116 data = (void*)WMReturnTextMovement;
1117 textEvent = WMTextDidEndEditingNotification;
1119 relay = False;
1121 break;
1123 case WM_EMACSKEY_LEFT:
1124 if (!control_pressed)
1125 goto normal_key;
1126 else
1127 controled = False;
1129 #ifdef XK_KP_Left
1130 case XK_KP_Left:
1131 #endif
1132 case XK_Left:
1133 if (tPtr->cursorPosition > 0) {
1134 int i;
1135 paintCursor(tPtr);
1137 i = tPtr->cursorPosition;
1138 i += oneUTF8CharBackward(&tPtr->text[i], i);
1139 if (controled) {
1140 while (i > 0 && tPtr->text[i] != ' ') i--;
1141 while (i > 0 && tPtr->text[i] == ' ') i--;
1143 tPtr->cursorPosition = (i > 0) ? i + 1 : 0;
1144 } else
1145 tPtr->cursorPosition = i;
1147 if (tPtr->cursorPosition < tPtr->viewPosition) {
1148 tPtr->viewPosition = tPtr->cursorPosition;
1149 refresh = 1;
1150 } else
1151 paintCursor(tPtr);
1153 if (shifted)
1154 cancelSelection = 0;
1156 relay = False;
1158 break;
1160 case WM_EMACSKEY_RIGHT:
1161 if (!control_pressed)
1162 goto normal_key;
1163 else
1164 controled = False;
1166 #ifdef XK_KP_Right
1167 case XK_KP_Right:
1168 #endif
1169 case XK_Right:
1170 if (tPtr->cursorPosition < tPtr->textLen) {
1171 int i;
1172 paintCursor(tPtr);
1174 i = tPtr->cursorPosition;
1175 if (controled) {
1176 while (tPtr->text[i] && tPtr->text[i] != ' ') i++;
1177 while (tPtr->text[i] == ' ') i++;
1178 } else {
1179 i += oneUTF8CharForward(&tPtr->text[i], tPtr->textLen - i);
1181 tPtr->cursorPosition = i;
1183 refresh = incrToFit2(tPtr);
1185 if (!refresh)
1186 paintCursor(tPtr);
1188 if (shifted)
1189 cancelSelection = 0;
1191 relay = False;
1193 break;
1195 case WM_EMACSKEY_HOME:
1196 if (!control_pressed)
1197 goto normal_key;
1198 else
1199 controled = False;
1201 #ifdef XK_KP_Home
1202 case XK_KP_Home:
1203 #endif
1204 case XK_Home:
1205 if (!controled) {
1206 if (tPtr->cursorPosition > 0) {
1207 paintCursor(tPtr);
1208 tPtr->cursorPosition = 0;
1209 if (tPtr->viewPosition > 0) {
1210 tPtr->viewPosition = 0;
1211 refresh = 1;
1212 } else
1213 paintCursor(tPtr);
1215 if (shifted)
1216 cancelSelection = 0;
1218 relay = False;
1220 break;
1222 case WM_EMACSKEY_END:
1223 if (!control_pressed)
1224 goto normal_key;
1225 else
1226 controled = False;
1228 #ifdef XK_KP_End
1229 case XK_KP_End:
1230 #endif
1231 case XK_End:
1232 if (!controled) {
1233 if (tPtr->cursorPosition < tPtr->textLen) {
1234 paintCursor(tPtr);
1235 tPtr->cursorPosition = tPtr->textLen;
1236 tPtr->viewPosition = 0;
1238 refresh = incrToFit(tPtr);
1240 if (!refresh)
1241 paintCursor(tPtr);
1243 if (shifted)
1244 cancelSelection = 0;
1246 relay = False;
1248 break;
1250 case WM_EMACSKEY_BS:
1251 if (!control_pressed)
1252 goto normal_key;
1253 else
1254 modified = False;
1256 case XK_BackSpace:
1257 if (!modified) {
1258 if (tPtr->selection.count) {
1259 WMDeleteTextFieldRange(tPtr, tPtr->selection);
1260 data = (void*)WMDeleteTextEvent;
1261 textEvent = WMTextDidChangeNotification;
1262 } else if (tPtr->cursorPosition > 0) {
1263 int i = oneUTF8CharBackward(&tPtr->text[tPtr->cursorPosition],
1264 tPtr->cursorPosition);
1265 WMRange range;
1266 range.position = tPtr->cursorPosition + i;
1267 range.count = -i;
1268 WMDeleteTextFieldRange(tPtr, range);
1269 data = (void*)WMDeleteTextEvent;
1270 textEvent = WMTextDidChangeNotification;
1273 relay = False;
1275 break;
1277 case WM_EMACSKEY_DEL:
1278 if (!control_pressed)
1279 goto normal_key;
1280 else
1281 modified = False;
1283 #ifdef XK_KP_Delete
1284 case XK_KP_Delete:
1285 #endif
1286 case XK_Delete:
1287 if (!modified) {
1288 if (tPtr->selection.count) {
1289 WMDeleteTextFieldRange(tPtr, tPtr->selection);
1290 data = (void*)WMDeleteTextEvent;
1291 textEvent = WMTextDidChangeNotification;
1292 } else if (tPtr->cursorPosition < tPtr->textLen) {
1293 WMRange range;
1294 range.position = tPtr->cursorPosition;
1295 range.count = oneUTF8CharForward(&tPtr->text[tPtr->cursorPosition],
1296 tPtr->textLen - tPtr->cursorPosition);
1297 WMDeleteTextFieldRange(tPtr, range);
1298 data = (void*)WMDeleteTextEvent;
1299 textEvent = WMTextDidChangeNotification;
1302 relay = False;
1304 break;
1306 normal_key:
1307 default:
1308 if (!controled) {
1309 if (count > 0 && !iscntrl(buffer[0])) {
1310 if (tPtr->selection.count)
1311 WMDeleteTextFieldRange(tPtr, tPtr->selection);
1312 WMInsertTextFieldText(tPtr, buffer, tPtr->cursorPosition);
1313 data = (void*)WMInsertTextEvent;
1314 textEvent = WMTextDidChangeNotification;
1316 relay = False;
1319 break;
1322 if (relay) {
1323 WMRelayToNextResponder(W_VIEW(tPtr), event);
1324 return;
1327 /* Do not allow text selection in secure text fields */
1328 if (cancelSelection || tPtr->flags.secure) {
1329 lostSelection(tPtr->view, XA_PRIMARY, NULL);
1331 if (tPtr->selection.count) {
1332 tPtr->selection.count = 0;
1333 refresh = 1;
1335 tPtr->selection.position = tPtr->cursorPosition;
1336 } else {
1337 if (tPtr->selection.count != tPtr->cursorPosition - tPtr->selection.position) {
1339 tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position;
1341 refresh = 1;
1345 /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/
1347 if (textEvent) {
1348 WMNotification *notif = WMCreateNotification(textEvent, tPtr, data);
1350 if (tPtr->delegate) {
1351 if (textEvent==WMTextDidBeginEditingNotification &&
1352 tPtr->delegate->didBeginEditing)
1353 (*tPtr->delegate->didBeginEditing)(tPtr->delegate, notif);
1355 else if (textEvent==WMTextDidEndEditingNotification &&
1356 tPtr->delegate->didEndEditing)
1357 (*tPtr->delegate->didEndEditing)(tPtr->delegate, notif);
1359 else if (textEvent==WMTextDidChangeNotification &&
1360 tPtr->delegate->didChange)
1361 (*tPtr->delegate->didChange)(tPtr->delegate, notif);
1364 WMPostNotification(notif);
1365 WMReleaseNotification(notif);
1368 if (refresh)
1369 paintTextField(tPtr);
1371 /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/
1375 static int
1376 pointToCursorPosition(TextField *tPtr, int x)
1378 int a, b, pos, prev, tw;
1380 if (tPtr->flags.bordered)
1381 x -= 2;
1383 if (WMWidthOfString(tPtr->font, &(tPtr->text[tPtr->viewPosition]),
1384 tPtr->textLen - tPtr->viewPosition) <= x)
1385 return tPtr->textLen;
1387 a = tPtr->viewPosition;
1388 b = tPtr->textLen;
1390 /* we halve the text until we get into a 10 byte vicinity of x */
1391 while (b - a > 10) {
1392 pos = (a+b)/2;
1393 pos += seekUTF8CharStart(&tPtr->text[pos], pos - a);
1394 tw = WMWidthOfString(tPtr->font, &(tPtr->text[tPtr->viewPosition]),
1395 pos - tPtr->viewPosition);
1396 if (tw > x) {
1397 b = pos;
1398 } else if (tw < x) {
1399 a = pos;
1400 } else {
1401 return pos;
1405 /* at this point x can be positioned on any glyph between 'a' and 'b-1'
1406 * inclusive, with the exception of the left border of the 'a' glyph and
1407 * the right border or the 'b-1' glyph
1409 * ( <--- range for x's position ---> )
1410 * a a+1 .......................... b-1 b
1412 pos = prev = a;
1413 while (pos <= b) {
1414 tw = WMWidthOfString(tPtr->font, &(tPtr->text[tPtr->viewPosition]),
1415 pos - tPtr->viewPosition);
1416 if (tw > x) {
1417 return prev;
1418 } else if (pos == b) {
1419 break;
1421 prev = pos;
1422 pos += oneUTF8CharForward(&tPtr->text[pos], b - pos);
1425 return b;
1429 static void
1430 pasteText(WMView *view, Atom selection, Atom target, Time timestamp,
1431 void *cdata, WMData *data)
1433 TextField *tPtr = (TextField*)view->self;
1434 char *str;
1436 tPtr->flags.waitingSelection = 0;
1438 if (data != NULL) {
1439 str = (char*)WMDataBytes(data);
1441 WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition);
1442 NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
1443 (void*)WMInsertTextEvent);
1444 } else {
1445 int n;
1447 str = XFetchBuffer(tPtr->view->screen->display, &n, 0);
1449 if (str != NULL) {
1450 str[n] = 0;
1451 WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition);
1452 XFree(str);
1453 NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
1454 (void*)WMInsertTextEvent);
1460 static void
1461 handleTextFieldActionEvents(XEvent *event, void *data)
1463 TextField *tPtr = (TextField*)data;
1464 static int move = 0;
1465 static Time lastButtonReleasedEvent = 0;
1466 static Time lastButtonReleasedEvent2 = 0;
1467 Display *dpy = event->xany.display;
1469 CHECK_CLASS(data, WC_TextField);
1471 switch (event->type) {
1472 case KeyPress:
1473 if (tPtr->flags.waitingSelection) {
1474 return;
1476 if (tPtr->flags.enabled && tPtr->flags.focused) {
1477 handleTextFieldKeyPress(tPtr, event);
1478 XDefineCursor(dpy, W_VIEW(tPtr)->window,
1479 W_VIEW(tPtr)->screen->invisibleCursor);
1480 tPtr->flags.pointerGrabbed = 1;
1482 break;
1484 case MotionNotify:
1486 if (tPtr->flags.pointerGrabbed) {
1487 tPtr->flags.pointerGrabbed = 0;
1488 XDefineCursor(dpy, W_VIEW(tPtr)->window,
1489 W_VIEW(tPtr)->screen->textCursor);
1491 if (tPtr->flags.waitingSelection) {
1492 return;
1495 if (tPtr->flags.enabled && (event->xmotion.state & Button1Mask)) {
1497 if (tPtr->viewPosition < tPtr->textLen && event->xmotion.x >
1498 tPtr->usableWidth) {
1499 if (WMWidthOfString(tPtr->font,
1500 &(tPtr->text[tPtr->viewPosition]),
1501 tPtr->cursorPosition-tPtr->viewPosition)
1502 > tPtr->usableWidth) {
1503 tPtr->viewPosition += oneUTF8CharForward(&tPtr->text[tPtr->viewPosition],
1504 tPtr->textLen - tPtr->viewPosition);
1506 } else if (tPtr->viewPosition > 0 && event->xmotion.x < 0) {
1507 paintCursor(tPtr);
1508 tPtr->viewPosition += oneUTF8CharBackward(&tPtr->text[tPtr->viewPosition],
1509 tPtr->viewPosition);
1512 tPtr->cursorPosition =
1513 pointToCursorPosition(tPtr, event->xmotion.x);
1515 /* Do not allow text selection in secure textfields */
1516 if (tPtr->flags.secure) {
1517 tPtr->selection.position = tPtr->cursorPosition;
1520 tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position;
1522 paintCursor(tPtr);
1523 paintTextField(tPtr);
1526 break;
1528 case ButtonPress:
1529 if (tPtr->flags.pointerGrabbed) {
1530 tPtr->flags.pointerGrabbed = 0;
1531 XDefineCursor(dpy, W_VIEW(tPtr)->window,
1532 W_VIEW(tPtr)->screen->textCursor);
1533 break;
1536 if (tPtr->flags.waitingSelection) {
1537 break;
1540 move = 1;
1541 switch (tPtr->flags.alignment) {
1542 int textWidth;
1543 case WARight:
1544 textWidth = WMWidthOfString(tPtr->font, tPtr->text, tPtr->textLen);
1545 if (tPtr->flags.enabled && !tPtr->flags.focused) {
1546 WMSetFocusToWidget(tPtr);
1548 if (tPtr->flags.focused) {
1549 tPtr->selection.position = tPtr->cursorPosition;
1550 tPtr->selection.count = 0;
1552 if (textWidth < tPtr->usableWidth) {
1553 tPtr->cursorPosition = pointToCursorPosition(tPtr,
1554 event->xbutton.x - tPtr->usableWidth
1555 + textWidth);
1556 } else tPtr->cursorPosition = pointToCursorPosition(tPtr,
1557 event->xbutton.x);
1559 paintTextField(tPtr);
1560 break;
1562 case WALeft:
1563 if (tPtr->flags.enabled && !tPtr->flags.focused) {
1564 WMSetFocusToWidget(tPtr);
1566 if (tPtr->flags.focused && event->xbutton.button == Button1) {
1567 tPtr->cursorPosition = pointToCursorPosition(tPtr,
1568 event->xbutton.x);
1569 tPtr->selection.position = tPtr->cursorPosition;
1570 tPtr->selection.count = 0;
1571 paintTextField(tPtr);
1573 if (event->xbutton.button == Button2 && tPtr->flags.enabled) {
1574 char *text;
1575 int n;
1577 if (!WMRequestSelection(tPtr->view, XA_PRIMARY, XA_STRING,
1578 event->xbutton.time,
1579 pasteText, NULL)) {
1580 text = XFetchBuffer(tPtr->view->screen->display, &n, 0);
1582 if (text) {
1583 text[n] = 0;
1584 WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition);
1585 XFree(text);
1586 NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
1587 (void*)WMInsertTextEvent);
1589 } else {
1590 tPtr->flags.waitingSelection = 1;
1593 break;
1594 default:
1595 break;
1597 break;
1599 case ButtonRelease:
1600 if (tPtr->flags.pointerGrabbed) {
1601 tPtr->flags.pointerGrabbed = 0;
1602 XDefineCursor(dpy, W_VIEW(tPtr)->window,
1603 W_VIEW(tPtr)->screen->textCursor);
1605 if (tPtr->flags.waitingSelection) {
1606 break;
1609 if (!tPtr->flags.secure && tPtr->selection.count!=0) {
1610 int start, count;
1611 XRotateBuffers(dpy, 1);
1613 count = abs(tPtr->selection.count);
1614 if (tPtr->selection.count < 0)
1615 start = tPtr->selection.position - count;
1616 else
1617 start = tPtr->selection.position;
1619 XStoreBuffer(dpy, &tPtr->text[start], count, 0);
1622 move = 0;
1624 if (!tPtr->flags.secure &&
1625 event->xbutton.time - lastButtonReleasedEvent
1626 <= WINGsConfiguration.doubleClickDelay) {
1628 if (event->xbutton.time - lastButtonReleasedEvent2 <= 2*WINGsConfiguration.doubleClickDelay) {
1629 tPtr->selection.position = 0;
1630 tPtr->selection.count = tPtr->textLen;
1631 } else {
1632 int pos, cnt;
1633 char *txt;
1634 pos = tPtr->selection.position;
1635 cnt = tPtr->selection.count;
1636 txt = tPtr->text;
1637 while(pos >= 0) {
1638 if (txt[pos] == ' ' || txt[pos] == '\t') break;
1639 pos--;
1641 pos++;
1643 while(pos + cnt < tPtr->textLen) {
1644 if (txt[pos + cnt] == ' ' || txt[pos + cnt] == '\t')
1645 break;
1646 cnt++;
1648 tPtr->selection.position = pos;
1649 tPtr->selection.count = cnt;
1651 paintTextField(tPtr);
1653 if (!tPtr->flags.ownsSelection) {
1654 tPtr->flags.ownsSelection =
1655 WMCreateSelectionHandler(tPtr->view,
1656 XA_PRIMARY,
1657 event->xbutton.time,
1658 &selectionHandler, NULL);
1660 } else if (!tPtr->flags.secure && tPtr->selection.count!=0 &&
1661 !tPtr->flags.ownsSelection) {
1662 tPtr->flags.ownsSelection =
1663 WMCreateSelectionHandler(tPtr->view,
1664 XA_PRIMARY,
1665 event->xbutton.time,
1666 &selectionHandler, NULL);
1669 lastButtonReleasedEvent2 = lastButtonReleasedEvent;
1670 lastButtonReleasedEvent = event->xbutton.time;
1672 break;
1677 static void
1678 destroyTextField(TextField *tPtr)
1680 #if 0
1681 if (tPtr->timerID)
1682 WMDeleteTimerHandler(tPtr->timerID);
1683 #endif
1685 W_DestroyIC(tPtr->view);
1687 WMReleaseFont(tPtr->font);
1688 /*// use lostSelection() instead of WMDeleteSelectionHandler here?*/
1689 WMDeleteSelectionHandler(tPtr->view, XA_PRIMARY, CurrentTime);
1690 WMRemoveNotificationObserver(tPtr);
1692 if (tPtr->text)
1693 wfree(tPtr->text);
1695 wfree(tPtr);