7 #include <X11/keysym.h>
12 #define CURSOR_BLINK_ON_DELAY 600
13 #define CURSOR_BLINK_OFF_DELAY 300
17 char *WMTextDidChangeNotification
= "WMTextDidChangeNotification";
18 char *WMTextDidBeginEditingNotification
= "WMTextDidBeginEditingNotification";
19 char *WMTextDidEndEditingNotification
= "WMTextDidEndEditingNotification";
22 typedef struct W_TextField
{
27 struct W_TextField
*nextField
; /* next textfield in the chain */
28 struct W_TextField
*prevField
;
32 int textLen
; /* size of text */
33 int bufferSize
; /* memory allocated for text */
35 int viewPosition
; /* position of text being shown */
37 int cursorPosition
; /* position of the insertion cursor */
40 short offsetWidth
; /* offset of text from border */
46 WMTextFieldDelegate
*delegate
;
49 WMHandlerID timerID
; /* for cursor blinking */
52 WMAlignment alignment
:2;
54 unsigned int bordered
:1;
56 unsigned int beveled
:1;
58 unsigned int enabled
:1;
60 unsigned int focused
:1;
62 unsigned int cursorOn
:1;
64 unsigned int secure
:1; /* password entry style */
66 unsigned int pointerGrabbed
:1;
69 unsigned int notIllegalMovement
:1;
74 #define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
75 if ((T)->delegate && (T)->delegate->C)\
76 (*(T)->delegate->C)((T)->delegate,notif);\
77 WMPostNotification(notif);\
78 WMReleaseNotification(notif);}
81 #define MIN_TEXT_BUFFER 2
82 #define TEXT_BUFFER_INCR 8
85 #define WM_EMACSKEYMASK ControlMask
87 #define WM_EMACSKEY_LEFT XK_b
88 #define WM_EMACSKEY_RIGHT XK_f
89 #define WM_EMACSKEY_HOME XK_a
90 #define WM_EMACSKEY_END XK_e
91 #define WM_EMACSKEY_BS XK_h
92 #define WM_EMACSKEY_DEL XK_d
96 #define DEFAULT_WIDTH 60
97 #define DEFAULT_HEIGHT 20
98 #define DEFAULT_BORDERED True
99 #define DEFAULT_ALIGNMENT WALeft
103 static void destroyTextField(TextField
*tPtr
);
104 static void paintTextField(TextField
*tPtr
);
106 static void handleEvents(XEvent
*event
, void *data
);
107 static void handleTextFieldActionEvents(XEvent
*event
, void *data
);
108 static void didResizeTextField();
110 struct W_ViewDelegate _TextFieldViewDelegate
= {
119 #define TEXT_WIDTH(tPtr, start) (WMWidthOfString((tPtr)->font, \
120 &((tPtr)->text[(start)]), (tPtr)->textLen - (start) + 1))
122 #define TEXT_WIDTH2(tPtr, start, end) (WMWidthOfString((tPtr)->font, \
123 &((tPtr)->text[(start)]), (end) - (start) + 1))
127 normalizeRange(TextField
*tPtr
, WMRange
*range
)
129 if (range
->position
< 0 && range
->count
< 0)
132 if (range
->count
== 0) {
133 /*range->position = 0; why is this?*/
137 /* (1,-2) ~> (0,1) ; (1,-1) ~> (0,1) ; (2,-1) ~> (1,1) */
138 if (range
->count
< 0) { /* && range->position >= 0 */
139 if (range
->position
+ range
->count
< 0) {
140 range
->count
= range
->position
;
143 range
->count
= -range
->count
;
144 range
->position
-= range
->count
;
146 /* (-2,1) ~> (0,0) ; (-1,1) ~> (0,0) ; (-1,2) ~> (0,1) */
147 } else if (range
->position
< 0) { /* && range->count > 0 */
148 if (range
->position
+ range
->count
< 0) {
149 range
->position
= range
->count
= 0;
151 range
->count
+= range
->position
;
156 if (range
->position
+ range
->count
> tPtr
->textLen
)
157 range
->count
= tPtr
->textLen
- range
->position
;
161 memmv(char *dest
, char *src
, int size
)
166 for (i
=size
-1; i
>=0; i
--) {
169 } else if (dest
< src
) {
170 for (i
=0; i
<size
; i
++) {
178 incrToFit(TextField
*tPtr
)
180 int vp
= tPtr
->viewPosition
;
182 while (TEXT_WIDTH(tPtr
, tPtr
->viewPosition
) > tPtr
->usableWidth
) {
183 tPtr
->viewPosition
++;
185 return vp
!=tPtr
->viewPosition
;
190 incrToFit2(TextField
*tPtr
)
192 int vp
= tPtr
->viewPosition
;
193 while (TEXT_WIDTH2(tPtr
, tPtr
->viewPosition
, tPtr
->cursorPosition
)
194 >= tPtr
->usableWidth
)
195 tPtr
->viewPosition
++;
198 return vp
!=tPtr
->viewPosition
;
203 decrToFit(TextField
*tPtr
)
205 while (TEXT_WIDTH(tPtr
, tPtr
->viewPosition
-1) < tPtr
->usableWidth
206 && tPtr
->viewPosition
>0)
207 tPtr
->viewPosition
--;
214 requestHandler(WMWidget
*w
, Atom selection
, Atom target
, Atom
*type
,
215 void **value
, unsigned *length
, int *format
)
219 Display
*dpy
= tPtr
->view
->screen
->display
;
222 text
= XGetAtomName(tPtr
->view
->screen
->display
,target
);
224 text
= XGetAtomName(tPtr
->view
->screen
->display
,selection
);
230 count
= tPtr
->selection
.count
< 0
231 ? tPtr
->selection
.position
+ tPtr
->selection
.count
232 : tPtr
->selection
.position
;
234 if (target
== XA_STRING
||
235 target
== XInternAtom(dpy
, "TEXT", False
) ||
236 target
== XInternAtom(dpy
, "COMPOUND_TEXT", False
)) {
237 *value
= wstrdup(&(tPtr
->text
[count
]));
238 *length
= abs(tPtr
->selection
.count
);
244 _TARGETS
= XInternAtom(dpy
, "TARGETS", False
);
245 if (target
== _TARGETS
) {
249 ptr
= *value
= (char *) wmalloc(4 * sizeof(Atom
));
252 ptr
[2] = XInternAtom(dpy
, "TEXT", False
);
253 ptr
[3] = XInternAtom(dpy
, "COMPOUND_TEXT", False
);
258 *target = XA_PRIMARY;
266 lostHandler(WMWidget
*w
, Atom selection
)
268 TextField
*tPtr
= (WMTextField
*)w
;
270 tPtr
->selection
.count
= 0;
271 paintTextField(tPtr
);
275 _notification(void *observerData
, WMNotification
*notification
)
277 WMTextField
*to
= (WMTextField
*)observerData
;
278 WMTextField
*tw
= (WMTextField
*)WMGetNotificationClientData(notification
);
279 if (to
!= tw
) lostHandler(to
, 0);
283 WMCreateTextField(WMWidget
*parent
)
287 tPtr
= wmalloc(sizeof(TextField
));
288 memset(tPtr
, 0, sizeof(TextField
));
290 tPtr
->widgetClass
= WC_TextField
;
292 tPtr
->view
= W_CreateView(W_VIEW(parent
));
297 tPtr
->view
->self
= tPtr
;
299 tPtr
->view
->delegate
= &_TextFieldViewDelegate
;
301 tPtr
->view
->attribFlags
|= CWCursor
;
302 tPtr
->view
->attribs
.cursor
= tPtr
->view
->screen
->textCursor
;
304 W_SetViewBackgroundColor(tPtr
->view
, tPtr
->view
->screen
->white
);
306 tPtr
->text
= wmalloc(MIN_TEXT_BUFFER
);
309 tPtr
->bufferSize
= MIN_TEXT_BUFFER
;
311 tPtr
->flags
.enabled
= 1;
313 WMCreateEventHandler(tPtr
->view
, ExposureMask
|StructureNotifyMask
314 |FocusChangeMask
, handleEvents
, tPtr
);
316 tPtr
->font
= WMRetainFont(tPtr
->view
->screen
->normalFont
);
318 tPtr
->flags
.bordered
= DEFAULT_BORDERED
;
319 tPtr
->flags
.beveled
= True
;
320 tPtr
->flags
.alignment
= DEFAULT_ALIGNMENT
;
322 WMAX((tPtr
->view
->size
.height
- WMFontHeight(tPtr
->font
))/2, 1);
324 W_ResizeView(tPtr
->view
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
326 WMCreateEventHandler(tPtr
->view
, EnterWindowMask
|LeaveWindowMask
327 |ButtonReleaseMask
|ButtonPressMask
|KeyPressMask
|Button1MotionMask
,
328 handleTextFieldActionEvents
, tPtr
);
330 WMCreateSelectionHandler(tPtr
, XA_PRIMARY
, CurrentTime
, requestHandler
,
332 WMAddNotificationObserver(_notification
, tPtr
, "_lostOwnership", tPtr
);
335 tPtr
->flags
.cursorOn
= 1;
342 WMSetTextFieldDelegate(WMTextField
*tPtr
, WMTextFieldDelegate
*delegate
)
344 CHECK_CLASS(tPtr
, WC_TextField
);
346 tPtr
->delegate
= delegate
;
351 WMInsertTextFieldText(WMTextField
*tPtr
, char *text
, int position
)
355 CHECK_CLASS(tPtr
, WC_TextField
);
362 /* check if buffer will hold the text */
363 if (len
+ tPtr
->textLen
>= tPtr
->bufferSize
) {
364 tPtr
->bufferSize
= tPtr
->textLen
+ len
+ TEXT_BUFFER_INCR
;
365 tPtr
->text
= wrealloc(tPtr
->text
, tPtr
->bufferSize
);
368 if (position
< 0 || position
>= tPtr
->textLen
) {
369 /* append the text at the end */
370 strcat(tPtr
->text
, text
);
374 tPtr
->textLen
+= len
;
375 tPtr
->cursorPosition
+= len
;
377 /* insert text at position */
378 memmv(&(tPtr
->text
[position
+len
]), &(tPtr
->text
[position
]),
379 tPtr
->textLen
-position
+1);
381 memcpy(&(tPtr
->text
[position
]), text
, len
);
383 tPtr
->textLen
+= len
;
384 if (position
>= tPtr
->cursorPosition
) {
385 tPtr
->cursorPosition
+= len
;
392 paintTextField(tPtr
);
396 WMDeleteTextFieldRange(WMTextField
*tPtr
, WMRange range
)
398 CHECK_CLASS(tPtr
, WC_TextField
);
400 normalizeRange(tPtr
, &range
);
405 memmv(&(tPtr
->text
[range
.position
]), &(tPtr
->text
[range
.position
+range
.count
]),
406 tPtr
->textLen
- (range
.position
+range
.count
) + 1);
408 tPtr
->textLen
-= range
.count
;
410 /* try to keep cursorPosition at the same place */
411 tPtr
->viewPosition
-= range
.count
;
412 if (tPtr
->viewPosition
< 0)
413 tPtr
->viewPosition
= 0;
414 tPtr
->cursorPosition
= range
.position
;
418 paintTextField(tPtr
);
424 WMGetTextFieldText(WMTextField
*tPtr
)
426 CHECK_CLASS(tPtr
, WC_TextField
);
428 return wstrdup(tPtr
->text
);
433 WMSetTextFieldText(WMTextField
*tPtr
, char *text
)
435 CHECK_CLASS(tPtr
, WC_TextField
);
437 if ((text
&& strcmp(tPtr
->text
, text
) == 0) ||
438 (!text
&& tPtr
->textLen
== 0))
445 tPtr
->textLen
= strlen(text
);
447 if (tPtr
->textLen
>= tPtr
->bufferSize
) {
448 tPtr
->bufferSize
= tPtr
->textLen
+ TEXT_BUFFER_INCR
;
449 tPtr
->text
= wrealloc(tPtr
->text
, tPtr
->bufferSize
);
451 strcpy(tPtr
->text
, text
);
454 tPtr
->cursorPosition
= tPtr
->selection
.position
= tPtr
->textLen
;
455 tPtr
->viewPosition
= 0;
456 tPtr
->selection
.count
= 0;
458 if (tPtr
->view
->flags
.realized
)
459 paintTextField(tPtr
);
464 WMSetTextFieldAlignment(WMTextField
*tPtr
, WMAlignment alignment
)
466 CHECK_CLASS(tPtr
, WC_TextField
);
468 tPtr
->flags
.alignment
= alignment
;
470 if (alignment
!=WALeft
) {
471 wwarning("only left alignment is supported in textfields");
475 if (tPtr
->view
->flags
.realized
) {
476 paintTextField(tPtr
);
482 WMSetTextFieldBordered(WMTextField
*tPtr
, Bool bordered
)
484 CHECK_CLASS(tPtr
, WC_TextField
);
486 tPtr
->flags
.bordered
= bordered
;
488 if (tPtr
->view
->flags
.realized
) {
489 paintTextField(tPtr
);
495 WMSetTextFieldBeveled(WMTextField
*tPtr
, Bool flag
)
497 CHECK_CLASS(tPtr
, WC_TextField
);
499 tPtr
->flags
.beveled
= flag
;
501 if (tPtr
->view
->flags
.realized
) {
502 paintTextField(tPtr
);
509 WMSetTextFieldSecure(WMTextField
*tPtr
, Bool flag
)
511 CHECK_CLASS(tPtr
, WC_TextField
);
513 tPtr
->flags
.secure
= flag
;
515 if (tPtr
->view
->flags
.realized
) {
516 paintTextField(tPtr
);
522 WMGetTextFieldEditable(WMTextField
*tPtr
)
524 CHECK_CLASS(tPtr
, WC_TextField
);
526 return tPtr
->flags
.enabled
;
531 WMSetTextFieldEditable(WMTextField
*tPtr
, Bool flag
)
533 CHECK_CLASS(tPtr
, WC_TextField
);
535 tPtr
->flags
.enabled
= flag
;
537 if (tPtr
->view
->flags
.realized
) {
538 paintTextField(tPtr
);
544 WMSelectTextFieldRange(WMTextField
*tPtr
, WMRange range
)
546 CHECK_CLASS(tPtr
, WC_TextField
);
548 if (tPtr
->flags
.enabled
) {
549 normalizeRange(tPtr
, &range
);
551 tPtr
->selection
= range
;
553 tPtr
->cursorPosition
= range
.position
+ range
.count
;
555 if (tPtr
->view
->flags
.realized
) {
556 paintTextField(tPtr
);
563 WMSetTextFieldCursorPosition(WMTextField
*tPtr
, unsigned int position
)
565 CHECK_CLASS(tPtr
, WC_TextField
);
567 if (tPtr
->flags
.enabled
) {
568 if (position
> tPtr
->textLen
)
569 position
= tPtr
->textLen
;
571 tPtr
->cursorPosition
= position
;
572 if (tPtr
->view
->flags
.realized
) {
573 paintTextField(tPtr
);
580 WMSetTextFieldNextTextField(WMTextField
*tPtr
, WMTextField
*next
)
582 CHECK_CLASS(tPtr
, WC_TextField
);
584 if (tPtr
->view
->nextFocusChain
)
585 tPtr
->view
->nextFocusChain
->prevFocusChain
= NULL
;
586 tPtr
->view
->nextFocusChain
= NULL
;
590 CHECK_CLASS(next
, WC_TextField
);
592 if (tPtr
->view
->nextFocusChain
)
593 tPtr
->view
->nextFocusChain
->prevFocusChain
= NULL
;
594 if (next
->view
->prevFocusChain
)
595 next
->view
->prevFocusChain
->nextFocusChain
= NULL
;
597 tPtr
->view
->nextFocusChain
= next
->view
;
598 next
->view
->prevFocusChain
= tPtr
->view
;
603 WMSetTextFieldPrevTextField(WMTextField
*tPtr
, WMTextField
*prev
)
605 CHECK_CLASS(tPtr
, WC_TextField
);
607 if (tPtr
->view
->prevFocusChain
)
608 tPtr
->view
->prevFocusChain
->nextFocusChain
= NULL
;
609 tPtr
->view
->prevFocusChain
= NULL
;
613 CHECK_CLASS(prev
, WC_TextField
);
615 if (tPtr
->view
->prevFocusChain
)
616 tPtr
->view
->prevFocusChain
->nextFocusChain
= NULL
;
617 if (prev
->view
->nextFocusChain
)
618 prev
->view
->nextFocusChain
->prevFocusChain
= NULL
;
620 tPtr
->view
->prevFocusChain
= prev
->view
;
621 prev
->view
->nextFocusChain
= tPtr
->view
;
626 WMSetTextFieldFont(WMTextField
*tPtr
, WMFont
*font
)
628 CHECK_CLASS(tPtr
, WC_TextField
);
631 WMReleaseFont(tPtr
->font
);
632 tPtr
->font
= WMRetainFont(font
);
635 WMAX((tPtr
->view
->size
.height
- WMFontHeight(tPtr
->font
))/2, 1);
637 if (tPtr
->view
->flags
.realized
) {
638 paintTextField(tPtr
);
645 WMGetTextFieldFont(WMTextField
*tPtr
)
652 didResizeTextField(W_ViewDelegate
*self
, WMView
*view
)
654 WMTextField
*tPtr
= (WMTextField
*)view
->self
;
657 WMAX((tPtr
->view
->size
.height
- WMFontHeight(tPtr
->font
))/2, 1);
659 tPtr
->usableWidth
= tPtr
->view
->size
.width
- 2*tPtr
->offsetWidth
+ 2;
664 makeHiddenString(int length
)
666 char *data
= wmalloc(length
+1);
668 memset(data
, '*', length
);
676 paintCursor(TextField
*tPtr
)
679 WMScreen
*screen
= tPtr
->view
->screen
;
683 if (tPtr
->flags
.secure
)
684 text
= makeHiddenString(strlen(tPtr
->text
));
688 cx
= WMWidthOfString(tPtr
->font
, &(text
[tPtr
->viewPosition
]),
689 tPtr
->cursorPosition
-tPtr
->viewPosition
);
691 switch (tPtr
->flags
.alignment
) {
693 textWidth
= WMWidthOfString(tPtr
->font
, text
, tPtr
->textLen
);
694 if (textWidth
< tPtr
->usableWidth
)
695 cx
+= tPtr
->offsetWidth
+ tPtr
->usableWidth
- textWidth
+ 1;
697 cx
+= tPtr
->offsetWidth
+ 1;
700 cx
+= tPtr
->offsetWidth
+ 1;
705 textWidth
= WMWidthOfString(tPtr
->font
, text
, tPtr
->textLen
);
706 if (textWidth
< tPtr
->usableWidth
)
707 cx
+= tPtr
->offsetWidth
+ (tPtr
->usableWidth
-textWidth
)/2;
709 cx
+= tPtr
->offsetWidth
;
713 XDrawRectangle(screen->display, tPtr->view->window, screen->xorGC,
714 cx, tPtr->offsetWidth, 1,
715 tPtr->view->size.height - 2*tPtr->offsetWidth - 1);
716 printf("%d %d\n",cx,tPtr->cursorPosition);
718 XDrawLine(screen
->display
, tPtr
->view
->window
, screen
->xorGC
,
719 cx
, tPtr
->offsetWidth
, cx
,
720 tPtr
->view
->size
.height
- tPtr
->offsetWidth
- 1);
722 if (tPtr
->flags
.secure
)
729 drawRelief(WMView
*view
, Bool beveled
)
731 WMScreen
*scr
= view
->screen
;
732 Display
*dpy
= scr
->display
;
736 int width
= view
->size
.width
;
737 int height
= view
->size
.height
;
739 dgc
= WMColorGC(scr
->darkGray
);
742 XDrawRectangle(dpy
, view
->window
, dgc
, 0, 0, width
-1, height
-1);
746 wgc
= WMColorGC(scr
->white
);
747 lgc
= WMColorGC(scr
->gray
);
750 XDrawLine(dpy
, view
->window
, dgc
, 0, 0, width
-1, 0);
751 XDrawLine(dpy
, view
->window
, dgc
, 0, 1, width
-2, 1);
753 XDrawLine(dpy
, view
->window
, dgc
, 0, 0, 0, height
-2);
754 XDrawLine(dpy
, view
->window
, dgc
, 1, 0, 1, height
-3);
757 XDrawLine(dpy
, view
->window
, wgc
, 0, height
-1, width
-1, height
-1);
758 XDrawLine(dpy
, view
->window
, lgc
, 1, height
-2, width
-2, height
-2);
760 XDrawLine(dpy
, view
->window
, wgc
, width
-1, 0, width
-1, height
-1);
761 XDrawLine(dpy
, view
->window
, lgc
, width
-2, 1, width
-2, height
-3);
766 paintTextField(TextField
*tPtr
)
768 W_Screen
*screen
= tPtr
->view
->screen
;
769 W_View
*view
= tPtr
->view
;
779 if (!view
->flags
.realized
|| !view
->flags
.mapped
)
782 if (!tPtr
->flags
.bordered
) {
788 if (tPtr
->flags
.secure
) {
789 text
= makeHiddenString(strlen(tPtr
->text
));
794 totalWidth
= tPtr
->view
->size
.width
- 2*bd
;
796 drawbuffer
= XCreatePixmap(screen
->display
, view
->window
,
797 view
->size
.width
, view
->size
.height
, screen
->depth
);
798 XFillRectangle(screen
->display
, drawbuffer
, WMColorGC(screen
->white
),
799 0,0, view
->size
.width
,view
->size
.height
);
800 /* this is quite dirty */
801 viewbuffer
.screen
= view
->screen
;
802 viewbuffer
.size
= view
->size
;
803 viewbuffer
.window
= drawbuffer
;
806 if (tPtr
->textLen
> 0) {
807 tw
= WMWidthOfString(tPtr
->font
, &(text
[tPtr
->viewPosition
]),
808 tPtr
->textLen
- tPtr
->viewPosition
);
810 th
= WMFontHeight(tPtr
->font
);
812 ty
= tPtr
->offsetWidth
;
813 switch (tPtr
->flags
.alignment
) {
815 tx
= tPtr
->offsetWidth
+ 1;
816 if (tw
< tPtr
->usableWidth
)
817 XFillRectangle(screen
->display
, drawbuffer
,
818 WMColorGC(screen
->white
),
819 bd
+tw
,bd
, totalWidth
-tw
,view
->size
.height
-2*bd
);
823 tx
= tPtr
->offsetWidth
+ (tPtr
->usableWidth
- tw
) / 2;
824 if (tw
< tPtr
->usableWidth
)
825 XClearArea(screen
->display
, view
->window
, bd
, bd
,
826 totalWidth
, view
->size
.height
-2*bd
, False
);
831 tx
= tPtr
->offsetWidth
+ tPtr
->usableWidth
- tw
- 1;
832 if (tw
< tPtr
->usableWidth
)
833 XClearArea(screen
->display
, view
->window
, bd
, bd
,
834 totalWidth
-tw
, view
->size
.height
-2*bd
, False
);
838 if (!tPtr
->flags
.enabled
)
839 WMSetColorInGC(screen
->darkGray
, screen
->textFieldGC
);
841 WMDrawImageString(screen
, drawbuffer
, screen
->textFieldGC
,
843 &(text
[tPtr
->viewPosition
]),
844 tPtr
->textLen
- tPtr
->viewPosition
);
846 if (tPtr
->selection
.count
) {
849 count
= tPtr
->selection
.count
< 0
850 ? tPtr
->selection
.position
+ tPtr
->selection
.count
851 : tPtr
->selection
.position
;
852 count2
= abs(tPtr
->selection
.count
);
853 if (count
< tPtr
->viewPosition
) {
854 count2
= abs(count2
- abs(tPtr
->viewPosition
- count
));
855 count
= tPtr
->viewPosition
;
859 rx
= tPtr
->offsetWidth
+ 1 + WMWidthOfString(tPtr
->font
,text
,count
)
860 - WMWidthOfString(tPtr
->font
,text
,tPtr
->viewPosition
);
862 XSetBackground(screen
->display
, screen
->textFieldGC
,
863 screen
->gray
->color
.pixel
);
865 WMDrawImageString(screen
, drawbuffer
, screen
->textFieldGC
,
866 tPtr
->font
, rx
, ty
, &(text
[count
]),
869 XSetBackground(screen
->display
, screen
->textFieldGC
,
870 screen
->white
->color
.pixel
);
873 if (!tPtr
->flags
.enabled
)
874 WMSetColorInGC(screen
->black
, screen
->textFieldGC
);
876 XFillRectangle(screen
->display
, drawbuffer
,
877 WMColorGC(screen
->white
),
878 bd
,bd
, totalWidth
,view
->size
.height
-2*bd
);
882 if (tPtr
->flags
.bordered
) {
883 drawRelief(&viewbuffer
, tPtr
->flags
.beveled
);
886 if (tPtr
->flags
.secure
)
888 XCopyArea(screen
->display
, drawbuffer
, view
->window
,
889 screen
->copyGC
, 0,0, view
->size
.width
,
890 view
->size
.height
,0,0);
891 XFreePixmap(screen
->display
, drawbuffer
);
894 if (tPtr
->flags
.focused
&& tPtr
->flags
.enabled
&& tPtr
->flags
.cursorOn
) {
902 blinkCursor(void *data
)
904 TextField
*tPtr
= (TextField
*)data
;
906 if (tPtr
->flags
.cursorOn
) {
907 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY
, blinkCursor
,
910 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
, blinkCursor
,
914 tPtr
->flags
.cursorOn
= !tPtr
->flags
.cursorOn
;
920 handleEvents(XEvent
*event
, void *data
)
922 TextField
*tPtr
= (TextField
*)data
;
924 CHECK_CLASS(data
, WC_TextField
);
927 switch (event
->type
) {
929 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr
->view
))!=tPtr
->view
)
931 tPtr
->flags
.focused
= 1;
933 if (!tPtr
->timerID
) {
934 tPtr
->timerID
= WMAddTimerHandler(CURSOR_BLINK_ON_DELAY
,
938 paintTextField(tPtr
);
940 NOTIFY(tPtr
, didBeginEditing
, WMTextDidBeginEditingNotification
, NULL
);
942 tPtr
->flags
.notIllegalMovement
= 0;
946 tPtr
->flags
.focused
= 0;
949 WMDeleteTimerHandler(tPtr
->timerID
);
950 tPtr
->timerID
= NULL
;
953 paintTextField(tPtr
);
954 if (!tPtr
->flags
.notIllegalMovement
) {
955 NOTIFY(tPtr
, didEndEditing
, WMTextDidEndEditingNotification
,
956 (void*)WMIllegalTextMovement
);
961 if (event
->xexpose
.count
!=0)
963 paintTextField(tPtr
);
967 destroyTextField(tPtr
);
974 handleTextFieldKeyPress(TextField
*tPtr
, XEvent
*event
)
978 char *textEvent
= NULL
;
980 int count
, refresh
= 0;
981 int control_pressed
= 0;
982 int cancelSelection
= 1;
984 /*printf("(%d,%d) -> ", tPtr->selection.position, tPtr->selection.count);*/
985 if (((XKeyEvent
*) event
)->state
& WM_EMACSKEYMASK
)
988 count
= XLookupString(&event
->xkey
, buffer
, 63, &ksym
, NULL
);
989 buffer
[count
] = '\0';
993 #ifdef XK_ISO_Left_Tab
994 case XK_ISO_Left_Tab
:
996 if (event
->xkey
.state
& ShiftMask
) {
997 if (tPtr
->view
->prevFocusChain
) {
998 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr
->view
),
999 tPtr
->view
->prevFocusChain
);
1000 tPtr
->flags
.notIllegalMovement
= 1;
1002 data
= (void*)WMBacktabTextMovement
;
1004 if (tPtr
->view
->nextFocusChain
) {
1005 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr
->view
),
1006 tPtr
->view
->nextFocusChain
);
1007 tPtr
->flags
.notIllegalMovement
= 1;
1009 data
= (void*)WMTabTextMovement
;
1011 textEvent
= WMTextDidEndEditingNotification
;
1015 data
= (void*)WMReturnTextMovement
;
1016 textEvent
= WMTextDidEndEditingNotification
;
1019 case WM_EMACSKEY_LEFT
:
1020 if (!control_pressed
) {
1027 if (tPtr
->cursorPosition
> 0) {
1029 if (event
->xkey
.state
& ControlMask
) {
1030 int i
= tPtr
->cursorPosition
- 1;
1032 while (i
> 0 && tPtr
->text
[i
] != ' ') i
--;
1033 while (i
> 0 && tPtr
->text
[i
] == ' ') i
--;
1035 tPtr
->cursorPosition
= (i
> 0) ? i
+ 1 : 0;
1037 tPtr
->cursorPosition
--;
1039 if (tPtr
->cursorPosition
< tPtr
->viewPosition
) {
1040 tPtr
->viewPosition
= tPtr
->cursorPosition
;
1045 if (event
->xkey
.state
& ShiftMask
)
1046 cancelSelection
= 0;
1049 case WM_EMACSKEY_RIGHT
:
1050 if (!control_pressed
) {
1057 if (tPtr
->cursorPosition
< tPtr
->textLen
) {
1059 if (event
->xkey
.state
& ControlMask
) {
1060 int i
= tPtr
->cursorPosition
;
1062 while (tPtr
->text
[i
] && tPtr
->text
[i
] != ' ') i
++;
1063 while (tPtr
->text
[i
] == ' ') i
++;
1065 tPtr
->cursorPosition
= i
;
1067 tPtr
->cursorPosition
++;
1069 while (WMWidthOfString(tPtr
->font
,
1070 &(tPtr
->text
[tPtr
->viewPosition
]),
1071 tPtr
->cursorPosition
-tPtr
->viewPosition
)
1072 > tPtr
->usableWidth
) {
1073 tPtr
->viewPosition
++;
1079 if (event
->xkey
.state
& ShiftMask
)
1080 cancelSelection
= 0;
1083 case WM_EMACSKEY_HOME
:
1084 if (!control_pressed
) {
1091 if (tPtr
->cursorPosition
> 0) {
1093 tPtr
->cursorPosition
= 0;
1094 if (tPtr
->viewPosition
> 0) {
1095 tPtr
->viewPosition
= 0;
1100 if (event
->xkey
.state
& ShiftMask
)
1101 cancelSelection
= 0;
1104 case WM_EMACSKEY_END
:
1105 if (!control_pressed
) {
1112 if (tPtr
->cursorPosition
< tPtr
->textLen
) {
1114 tPtr
->cursorPosition
= tPtr
->textLen
;
1115 tPtr
->viewPosition
= 0;
1116 while (WMWidthOfString(tPtr
->font
,
1117 &(tPtr
->text
[tPtr
->viewPosition
]),
1118 tPtr
->textLen
-tPtr
->viewPosition
)
1119 > tPtr
->usableWidth
) {
1120 tPtr
->viewPosition
++;
1126 if (event
->xkey
.state
& ShiftMask
)
1127 cancelSelection
= 0;
1130 case WM_EMACSKEY_BS
:
1131 if (!control_pressed
) {
1135 if (tPtr
->selection
.count
) {
1136 WMDeleteTextFieldRange(tPtr
, tPtr
->selection
);
1137 data
= (void*)WMDeleteTextEvent
;
1138 textEvent
= WMTextDidChangeNotification
;
1139 } else if (tPtr
->cursorPosition
> 0) {
1141 range
.position
= tPtr
->cursorPosition
- 1;
1143 WMDeleteTextFieldRange(tPtr
, range
);
1144 data
= (void*)WMDeleteTextEvent
;
1145 textEvent
= WMTextDidChangeNotification
;
1149 case WM_EMACSKEY_DEL
:
1150 if (!control_pressed
) {
1157 if (tPtr
->selection
.count
) {
1158 WMDeleteTextFieldRange(tPtr
, tPtr
->selection
);
1159 data
= (void*)WMDeleteTextEvent
;
1160 textEvent
= WMTextDidChangeNotification
;
1161 } else if (tPtr
->cursorPosition
< tPtr
->textLen
) {
1163 range
.position
= tPtr
->cursorPosition
;
1165 WMDeleteTextFieldRange(tPtr
, range
);
1166 data
= (void*)WMDeleteTextEvent
;
1167 textEvent
= WMTextDidChangeNotification
;
1173 if (count
> 0 && isprint(buffer
[0])) {
1174 if (tPtr
->selection
.count
)
1175 WMDeleteTextFieldRange(tPtr
, tPtr
->selection
);
1176 WMInsertTextFieldText(tPtr
, buffer
, tPtr
->cursorPosition
);
1177 data
= (void*)WMInsertTextEvent
;
1178 textEvent
= WMTextDidChangeNotification
;
1180 /* should we rather break and goto cancel selection below? -Dan */
1186 if (!cancelSelection
) {
1187 if (tPtr
->selection
.count
!= tPtr
->cursorPosition
- tPtr
->selection
.position
) {
1188 WMNotification
*notif
;
1190 tPtr
->selection
.count
= tPtr
->cursorPosition
- tPtr
->selection
.position
;
1192 XSetSelectionOwner(tPtr
->view
->screen
->display
,
1193 XA_PRIMARY
, tPtr
->view
->window
,
1194 event
->xbutton
.time
);
1195 notif
= WMCreateNotification("_lostOwnership", NULL
, tPtr
);
1196 WMPostNotification(notif
);
1197 WMReleaseNotification(notif
);
1202 if (tPtr
->selection
.count
) {
1203 tPtr
->selection
.count
= 0;
1206 tPtr
->selection
.position
= tPtr
->cursorPosition
;
1209 /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/
1212 WMNotification
*notif
= WMCreateNotification(textEvent
, tPtr
, data
);
1214 if (tPtr
->delegate
) {
1215 if (textEvent
==WMTextDidBeginEditingNotification
&&
1216 tPtr
->delegate
->didBeginEditing
)
1217 (*tPtr
->delegate
->didBeginEditing
)(tPtr
->delegate
, notif
);
1218 else if (textEvent
==WMTextDidEndEditingNotification
&&
1219 tPtr
->delegate
->didEndEditing
)
1220 (*tPtr
->delegate
->didEndEditing
)(tPtr
->delegate
, notif
);
1221 else if (textEvent
==WMTextDidChangeNotification
&&
1222 tPtr
->delegate
->didChange
)
1223 (*tPtr
->delegate
->didChange
)(tPtr
->delegate
, notif
);
1226 WMPostNotification(notif
);
1227 WMReleaseNotification(notif
);
1231 paintTextField(tPtr
);
1233 /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/
1238 pointToCursorPosition(TextField
*tPtr
, int x
)
1243 if (tPtr
->flags
.bordered
)
1246 a
= tPtr
->viewPosition
;
1247 b
= tPtr
->viewPosition
+ tPtr
->textLen
;
1248 if (WMWidthOfString(tPtr
->font
, &(tPtr
->text
[tPtr
->viewPosition
]),
1249 tPtr
->textLen
- tPtr
->viewPosition
) < x
)
1250 return tPtr
->textLen
;
1252 while (a
< b
&& b
-a
>1) {
1254 tw
= WMWidthOfString(tPtr
->font
, &(tPtr
->text
[tPtr
->viewPosition
]),
1255 mid
- tPtr
->viewPosition
);
1268 handleTextFieldActionEvents(XEvent
*event
, void *data
)
1270 TextField
*tPtr
= (TextField
*)data
;
1271 static int move
= 0;
1272 static Time lastButtonReleasedEvent
= 0;
1274 CHECK_CLASS(data
, WC_TextField
);
1276 switch (event
->type
) {
1278 if (tPtr
->flags
.enabled
&& tPtr
->flags
.focused
) {
1279 handleTextFieldKeyPress(tPtr
, event
);
1280 XGrabPointer(WMScreenDisplay(W_VIEW(tPtr
)->screen
),
1281 W_VIEW(tPtr
)->window
, False
,
1282 PointerMotionMask
|ButtonPressMask
|ButtonReleaseMask
,
1283 GrabModeAsync
, GrabModeAsync
, None
,
1284 W_VIEW(tPtr
)->screen
->invisibleCursor
,
1286 tPtr
->flags
.pointerGrabbed
= 1;
1292 if (tPtr
->flags
.pointerGrabbed
) {
1293 tPtr
->flags
.pointerGrabbed
= 0;
1294 XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr
)->screen
), CurrentTime
);
1297 if (tPtr
->flags
.enabled
&& (event
->xmotion
.state
& Button1Mask
)) {
1299 if (tPtr
->viewPosition
< tPtr
->textLen
&& event
->xmotion
.x
>
1300 tPtr
->usableWidth
) {
1301 if (WMWidthOfString(tPtr
->font
,
1302 &(tPtr
->text
[tPtr
->viewPosition
]),
1303 tPtr
->cursorPosition
-tPtr
->viewPosition
)
1304 > tPtr
->usableWidth
) {
1305 tPtr
->viewPosition
++;
1307 } else if (tPtr
->viewPosition
> 0 && event
->xmotion
.x
< 0) {
1309 tPtr
->viewPosition
--;
1312 /*if (!tPtr->selection.count) {
1313 tPtr->selection.position = tPtr->cursorPosition;
1316 tPtr
->cursorPosition
=
1317 pointToCursorPosition(tPtr
, event
->xmotion
.x
);
1319 tPtr
->selection
.count
= tPtr
->cursorPosition
- tPtr
->selection
.position
;
1320 /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count);*/
1323 printf("notify %d %d\n",event->xmotion.x,tPtr->usableWidth);
1327 paintTextField(tPtr
);
1331 XSetSelectionOwner(tPtr
->view
->screen
->display
,
1332 XA_PRIMARY
, tPtr
->view
->window
, event
->xmotion
.time
);
1334 WMNotification
*notif
= WMCreateNotification("_lostOwnership",
1336 WMPostNotification(notif
);
1337 WMReleaseNotification(notif
);
1343 if (tPtr
->flags
.pointerGrabbed
) {
1344 tPtr
->flags
.pointerGrabbed
= 0;
1345 XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr
)->screen
), CurrentTime
);
1350 switch (tPtr
->flags
.alignment
) {
1353 textWidth
= WMWidthOfString(tPtr
->font
, tPtr
->text
, tPtr
->textLen
);
1354 if (tPtr
->flags
.enabled
&& !tPtr
->flags
.focused
) {
1355 WMSetFocusToWidget(tPtr
);
1356 } else if (tPtr
->flags
.focused
) {
1357 tPtr
->selection
.position
= tPtr
->cursorPosition
;
1358 tPtr
->selection
.count
= 0;
1360 if(textWidth
< tPtr
->usableWidth
){
1361 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1362 event
->xbutton
.x
- tPtr
->usableWidth
1365 else tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1368 tPtr->cursorPosition = pointToCursorPosition(tPtr,
1370 tPtr->cursorPosition += tPtr->usableWidth - textWidth;
1373 tPtr->cursorPosition = pointToCursorPosition(tPtr,
1376 paintTextField(tPtr
);
1380 if (tPtr
->flags
.enabled
&& !tPtr
->flags
.focused
) {
1381 WMSetFocusToWidget(tPtr
);
1382 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1384 paintTextField(tPtr
);
1385 } else if (tPtr
->flags
.focused
) {
1386 tPtr
->cursorPosition
= pointToCursorPosition(tPtr
,
1388 tPtr
->selection
.position
= tPtr
->cursorPosition
;
1389 tPtr
->selection
.count
= 0;
1390 paintTextField(tPtr
);
1392 if (event
->xbutton
.button
== Button2
&& tPtr
->flags
.enabled
) {
1395 text
= W_GetTextSelection(tPtr
->view
->screen
, XA_PRIMARY
);
1398 text
= W_GetTextSelection(tPtr
->view
->screen
,
1399 tPtr
->view
->screen
->clipboardAtom
);
1402 text
= W_GetTextSelection(tPtr
->view
->screen
,
1406 WMInsertTextFieldText(tPtr
, text
, tPtr
->cursorPosition
);
1408 NOTIFY(tPtr
, didChange
, WMTextDidChangeNotification
,
1409 (void*)WMInsertTextEvent
);
1417 if (tPtr
->flags
.pointerGrabbed
) {
1418 tPtr
->flags
.pointerGrabbed
= 0;
1419 XUngrabPointer(WMScreenDisplay(W_VIEW(tPtr
)->screen
), CurrentTime
);
1424 if (event
->xbutton
.time
- lastButtonReleasedEvent
1425 <= WINGsConfiguration
.doubleClickDelay
) {
1426 tPtr
->selection
.position
= 0;
1427 tPtr
->selection
.count
= tPtr
->textLen
;
1428 paintTextField(tPtr
);
1429 XSetSelectionOwner(tPtr
->view
->screen
->display
,
1430 XA_PRIMARY
, tPtr
->view
->window
, event
->xbutton
.time
);
1432 WMNotification
*notif
= WMCreateNotification("_lostOwnership",
1434 WMPostNotification(notif
);
1435 WMReleaseNotification(notif
);
1438 lastButtonReleasedEvent
= event
->xbutton
.time
;
1446 destroyTextField(TextField
*tPtr
)
1450 WMDeleteTimerHandler(tPtr
->timerID
);
1453 WMReleaseFont(tPtr
->font
);
1454 WMDeleteSelectionHandler(tPtr
, XA_PRIMARY
);
1455 WMRemoveNotificationObserver(tPtr
);