Add history to some dialog boxes
[wmaker-crm.git] / WINGs / wtextfield.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001
9d2e6ef9 scottc1998-09-29 22:36:29 +00002#include "WINGsP.h"
882b9a8e kojima2001-07-23 20:31:32 +00003#include "wconfig.h"
9d2e6ef9 scottc1998-09-29 22:36:29 +00004
5#include <X11/keysym.h>
6#include <X11/Xatom.h>
7
8#include <ctype.h>
9
10#define CURSOR_BLINK_ON_DELAY 600
11#define CURSOR_BLINK_OFF_DELAY 300
12
9d2e6ef9 scottc1998-09-29 22:36:29 +000013char *WMTextDidChangeNotification = "WMTextDidChangeNotification";
14char *WMTextDidBeginEditingNotification = "WMTextDidBeginEditingNotification";
15char *WMTextDidEndEditingNotification = "WMTextDidEndEditingNotification";
16
9d2e6ef9 scottc1998-09-29 22:36:29 +000017typedef struct W_TextField {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020018 W_Class widgetClass;
19 W_View *view;
9d2e6ef9 scottc1998-09-29 22:36:29 +000020
e7495baf dan1999-02-17 11:06:40 +000021#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020022 struct W_TextField *nextField; /* next textfield in the chain */
23 struct W_TextField *prevField;
e7495baf dan1999-02-17 11:06:40 +000024#endif
9d2e6ef9 scottc1998-09-29 22:36:29 +000025
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020026 char *text;
27 int textLen; /* size of text */
28 int bufferSize; /* memory allocated for text */
9d2e6ef9 scottc1998-09-29 22:36:29 +000029
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020030 int viewPosition; /* position of text being shown */
9d2e6ef9 scottc1998-09-29 22:36:29 +000031
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020032 int cursorPosition; /* position of the insertion cursor */
9d2e6ef9 scottc1998-09-29 22:36:29 +000033
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020034 short usableWidth;
35 short offsetWidth; /* offset of text from border */
9d2e6ef9 scottc1998-09-29 22:36:29 +000036
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020037 WMRange selection;
0261c326 dan1999-01-06 15:22:33 +000038
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020039 WMFont *font;
e7495baf dan1999-02-17 11:06:40 +000040
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020041 WMTextFieldDelegate *delegate;
dd2d71fc kojima1999-05-15 17:38:05 +000042
9d2e6ef9 scottc1998-09-29 22:36:29 +000043#if 0
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020044 WMHandlerID timerID; /* for cursor blinking */
9d2e6ef9 scottc1998-09-29 22:36:29 +000045#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020046 struct {
47 WMAlignment alignment:2;
9d2e6ef9 scottc1998-09-29 22:36:29 +000048
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020049 unsigned int bordered:1;
e7495baf dan1999-02-17 11:06:40 +000050
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020051 unsigned int beveled:1;
e7495baf dan1999-02-17 11:06:40 +000052
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020053 unsigned int enabled:1;
e7495baf dan1999-02-17 11:06:40 +000054
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020055 unsigned int focused:1;
9d2e6ef9 scottc1998-09-29 22:36:29 +000056
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020057 unsigned int cursorOn:1;
e7495baf dan1999-02-17 11:06:40 +000058
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020059 unsigned int secure:1; /* password entry style */
9d2e6ef9 scottc1998-09-29 22:36:29 +000060
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020061 unsigned int pointerGrabbed:1;
7e8bff90 dan2001-03-23 02:26:15 +000062
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020063 unsigned int ownsSelection:1;
7e8bff90 dan2001-03-23 02:26:15 +000064
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020065 unsigned int waitingSelection:1; /* requested selection, but
66 * didnt get yet */
e50b7e9c kojima1999-04-28 23:50:52 +000067
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020068 unsigned int notIllegalMovement:1;
69 } flags;
9d2e6ef9 scottc1998-09-29 22:36:29 +000070} TextField;
71
bc4de88d dan2006-04-25 23:52:43 +000072#define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
6830b057 dan2004-10-12 21:28:27 +000073 if ((T)->delegate && (T)->delegate->C)\
74 (*(T)->delegate->C)((T)->delegate,notif);\
75 WMPostNotification(notif);\
76 WMReleaseNotification(notif);}
dd2d71fc kojima1999-05-15 17:38:05 +000077
9d2e6ef9 scottc1998-09-29 22:36:29 +000078#define MIN_TEXT_BUFFER 2
79#define TEXT_BUFFER_INCR 8
80
9d2e6ef9 scottc1998-09-29 22:36:29 +000081#define WM_EMACSKEYMASK ControlMask
82
83#define WM_EMACSKEY_LEFT XK_b
84#define WM_EMACSKEY_RIGHT XK_f
85#define WM_EMACSKEY_HOME XK_a
86#define WM_EMACSKEY_END XK_e
87#define WM_EMACSKEY_BS XK_h
88#define WM_EMACSKEY_DEL XK_d
89
9d2e6ef9 scottc1998-09-29 22:36:29 +000090#define DEFAULT_WIDTH 60
91#define DEFAULT_HEIGHT 20
92#define DEFAULT_BORDERED True
93#define DEFAULT_ALIGNMENT WALeft
94
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020095static void destroyTextField(TextField * tPtr);
96static void paintTextField(TextField * tPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000097
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020098static void handleEvents(XEvent * event, void *data);
99static void handleTextFieldActionEvents(XEvent * event, void *data);
5e4625da kojima1999-05-29 21:41:25 +0000100static void didResizeTextField();
9d2e6ef9 scottc1998-09-29 22:36:29 +0000101
5e4625da kojima1999-05-29 21:41:25 +0000102struct W_ViewDelegate _TextFieldViewDelegate = {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200103 NULL,
104 NULL,
105 didResizeTextField,
106 NULL,
107 NULL
9d2e6ef9 scottc1998-09-29 22:36:29 +0000108};
109
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200110static void lostSelection(WMView * view, Atom selection, void *cdata);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000111
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200112static WMData *requestHandler(WMView * view, Atom selection, Atom target, void *cdata, Atom * type);
60a247f2 kojima2000-04-03 03:10:20 +0000113
114static WMSelectionProcs selectionHandler = {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200115 requestHandler,
116 lostSelection,
117 NULL
60a247f2 kojima2000-04-03 03:10:20 +0000118};
119
bc4de88d dan2006-04-25 23:52:43 +0000120#define TEXT_WIDTH(tPtr, start) (WMWidthOfString((tPtr)->font, \
121 &((tPtr)->text[(start)]), (tPtr)->textLen - (start)))
9d2e6ef9 scottc1998-09-29 22:36:29 +0000122
e7495baf dan1999-02-17 11:06:40 +0000123#define TEXT_WIDTH2(tPtr, start, end) (WMWidthOfString((tPtr)->font, \
bc4de88d dan2006-04-25 23:52:43 +0000124 &((tPtr)->text[(start)]), (end) - (start)))
125
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200126static INLINE int oneUTF8CharBackward(char *str, int len)
bc4de88d dan2006-04-25 23:52:43 +0000127{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200128 unsigned char *ustr = (unsigned char *)str;
129 int pos = 0;
bc4de88d dan2006-04-25 23:52:43 +0000130
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200131 while (len-- > 0 && ustr[--pos] >= 0x80 && ustr[pos] <= 0xbf) ;
132 return pos;
bc4de88d dan2006-04-25 23:52:43 +0000133}
134
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200135static INLINE int oneUTF8CharForward(char *str, int len)
bc4de88d dan2006-04-25 23:52:43 +0000136{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200137 unsigned char *ustr = (unsigned char *)str;
138 int pos = 0;
bc4de88d dan2006-04-25 23:52:43 +0000139
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200140 while (len-- > 0 && ustr[++pos] >= 0x80 && ustr[pos] <= 0xbf) ;
141 return pos;
bc4de88d dan2006-04-25 23:52:43 +0000142}
143
bc4de88d dan2006-04-25 23:52:43 +0000144// find the beginning of the UTF8 char pointed by str
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200145static INLINE int seekUTF8CharStart(char *str, int len)
bc4de88d dan2006-04-25 23:52:43 +0000146{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200147 unsigned char *ustr = (unsigned char *)str;
148 int pos = 0;
bc4de88d dan2006-04-25 23:52:43 +0000149
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200150 while (len-- > 0 && ustr[pos] >= 0x80 && ustr[pos] <= 0xbf)
151 --pos;
152 return pos;
bc4de88d dan2006-04-25 23:52:43 +0000153}
9d2e6ef9 scottc1998-09-29 22:36:29 +0000154
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200155static void normalizeRange(TextField * tPtr, WMRange * range)
dbdb44a4 kojima1999-10-02 20:24:41 +0000156{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200157 if (range->position < 0 && range->count < 0)
158 range->count = 0;
159
160 if (range->count == 0) {
161 /*range->position = 0; why is this? */
162 return;
163 }
164
165 /* (1,-2) ~> (0,1) ; (1,-1) ~> (0,1) ; (2,-1) ~> (1,1) */
166 if (range->count < 0) { /* && range->position >= 0 */
167 if (range->position + range->count < 0) {
168 range->count = range->position;
169 range->position = 0;
170 } else {
171 range->count = -range->count;
172 range->position -= range->count;
173 }
174 /* (-2,1) ~> (0,0) ; (-1,1) ~> (0,0) ; (-1,2) ~> (0,1) */
175 } else if (range->position < 0) { /* && range->count > 0 */
176 if (range->position + range->count < 0) {
177 range->position = range->count = 0;
178 } else {
179 range->count += range->position;
180 range->position = 0;
181 }
182 }
183
184 if (range->position + range->count > tPtr->textLen)
185 range->count = tPtr->textLen - range->position;
dbdb44a4 kojima1999-10-02 20:24:41 +0000186}
187
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200188static void memmv(char *dest, char *src, int size)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000189{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200190 int i;
191
192 if (dest > src) {
193 for (i = size - 1; i >= 0; i--) {
194 dest[i] = src[i];
195 }
196 } else if (dest < src) {
197 for (i = 0; i < size; i++) {
198 dest[i] = src[i];
199 }
200 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000201}
202
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200203static int incrToFit(TextField * tPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000204{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200205 int vp = tPtr->viewPosition;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000206
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200207 while (TEXT_WIDTH(tPtr, tPtr->viewPosition) > tPtr->usableWidth) {
208 tPtr->viewPosition += oneUTF8CharForward(&tPtr->text[tPtr->viewPosition],
209 tPtr->textLen - tPtr->viewPosition);
210 }
211 return vp != tPtr->viewPosition;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000212}
213
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200214static int incrToFit2(TextField * tPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000215{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200216 int vp = tPtr->viewPosition;
bc4de88d dan2006-04-25 23:52:43 +0000217
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200218 while (TEXT_WIDTH2(tPtr, tPtr->viewPosition, tPtr->cursorPosition)
219 >= tPtr->usableWidth)
220 tPtr->viewPosition += oneUTF8CharForward(&tPtr->text[tPtr->viewPosition],
221 tPtr->cursorPosition - tPtr->viewPosition);
222 return vp != tPtr->viewPosition;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000223}
224
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200225static void decrToFit(TextField * tPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000226{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200227 int vp = tPtr->viewPosition;
bc4de88d dan2006-04-25 23:52:43 +0000228
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200229 while (vp > 0 && (vp += oneUTF8CharBackward(&tPtr->text[vp], vp),
230 TEXT_WIDTH(tPtr, vp)) < tPtr->usableWidth) {
231 tPtr->viewPosition = vp;
232 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000233}
234
235#undef TEXT_WIDTH
236#undef TEXT_WIDTH2
237
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200238static WMData *requestHandler(WMView * view, Atom selection, Atom target, void *cdata, Atom * type)
bedc2238 kojima1999-05-16 07:00:01 +0000239{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200240 TextField *tPtr = view->self;
241 int count;
242 Display *dpy = tPtr->view->screen->display;
243 Atom _TARGETS;
244 Atom TEXT = XInternAtom(dpy, "TEXT", False);
245 Atom COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", False);
246 WMData *data;
60a247f2 kojima2000-04-03 03:10:20 +0000247
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200248 count = tPtr->selection.count < 0
249 ? tPtr->selection.position + tPtr->selection.count : tPtr->selection.position;
7f6c4d1a id1999-05-16 01:27:03 +0000250
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200251 if (target == XA_STRING || target == TEXT || target == COMPOUND_TEXT) {
6830b057 dan2004-10-12 21:28:27 +0000252
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200253 data = WMCreateDataWithBytes(&(tPtr->text[count]), abs(tPtr->selection.count));
254 WMSetDataFormat(data, 8);
255 *type = target;
6830b057 dan2004-10-12 21:28:27 +0000256
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200257 return data;
258 }
6830b057 dan2004-10-12 21:28:27 +0000259
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200260 _TARGETS = XInternAtom(dpy, "TARGETS", False);
261 if (target == _TARGETS) {
262 Atom *ptr;
7f6c4d1a id1999-05-16 01:27:03 +0000263
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200264 ptr = wmalloc(4 * sizeof(Atom));
265 ptr[0] = _TARGETS;
266 ptr[1] = XA_STRING;
267 ptr[2] = TEXT;
268 ptr[3] = COMPOUND_TEXT;
6830b057 dan2004-10-12 21:28:27 +0000269
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200270 data = WMCreateDataWithBytes(ptr, 4 * 4);
271 WMSetDataFormat(data, 32);
6830b057 dan2004-10-12 21:28:27 +0000272
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200273 *type = target;
274 return data;
275 }
60a247f2 kojima2000-04-03 03:10:20 +0000276
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200277 return NULL;
7f6c4d1a id1999-05-16 01:27:03 +0000278
279}
280
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200281static void lostSelection(WMView * view, Atom selection, void *cdata)
7f6c4d1a id1999-05-16 01:27:03 +0000282{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200283 TextField *tPtr = (WMTextField *) view->self;
284
285 if (tPtr->flags.ownsSelection) {
286 WMDeleteSelectionHandler(view, selection, CurrentTime);
287 tPtr->flags.ownsSelection = 0;
288 }
289 if (tPtr->selection.count != 0) {
290 tPtr->selection.count = 0;
291 paintTextField(tPtr);
292 }
7f6c4d1a id1999-05-16 01:27:03 +0000293}
294
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200295static void selectionNotification(void *observerData, WMNotification * notification)
17c4c23f id1999-05-29 01:57:30 +0000296{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200297 WMView *observerView = (WMView *) observerData;
298 WMView *newOwnerView = (WMView *) WMGetNotificationClientData(notification);
299
300 if (observerView != newOwnerView) {
301 /*
302 //if (tPtr->flags.ownsSelection)
303 // WMDeleteSelectionHandler(observerView, XA_PRIMARY, CurrentTime);
304 */
305 lostSelection(observerView, XA_PRIMARY, NULL);
306 }
17c4c23f id1999-05-29 01:57:30 +0000307}
9d2e6ef9 scottc1998-09-29 22:36:29 +0000308
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200309static void realizeObserver(void *self, WMNotification * not)
ca616755 dan2004-10-28 04:17:18 +0000310{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200311 W_CreateIC(((TextField *) self)->view);
ca616755 dan2004-10-28 04:17:18 +0000312}
313
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200314WMTextField *WMCreateTextField(WMWidget * parent)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000315{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200316 TextField *tPtr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000317
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200318 tPtr = wmalloc(sizeof(TextField));
319 memset(tPtr, 0, sizeof(TextField));
9d2e6ef9 scottc1998-09-29 22:36:29 +0000320
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200321 tPtr->widgetClass = WC_TextField;
6830b057 dan2004-10-12 21:28:27 +0000322
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200323 tPtr->view = W_CreateView(W_VIEW(parent));
324 if (!tPtr->view) {
325 wfree(tPtr);
326 return NULL;
327 }
328 tPtr->view->self = tPtr;
5e4625da kojima1999-05-29 21:41:25 +0000329
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200330 tPtr->view->delegate = &_TextFieldViewDelegate;
5e4625da kojima1999-05-29 21:41:25 +0000331
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200332 tPtr->view->attribFlags |= CWCursor;
333 tPtr->view->attribs.cursor = tPtr->view->screen->textCursor;
6830b057 dan2004-10-12 21:28:27 +0000334
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200335 W_SetViewBackgroundColor(tPtr->view, tPtr->view->screen->white);
6830b057 dan2004-10-12 21:28:27 +0000336
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200337 tPtr->text = wmalloc(MIN_TEXT_BUFFER);
338 tPtr->text[0] = 0;
339 tPtr->textLen = 0;
340 tPtr->bufferSize = MIN_TEXT_BUFFER;
e7495baf dan1999-02-17 11:06:40 +0000341
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200342 tPtr->flags.enabled = 1;
6830b057 dan2004-10-12 21:28:27 +0000343
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200344 WMCreateEventHandler(tPtr->view, ExposureMask | StructureNotifyMask | FocusChangeMask, handleEvents, tPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000345
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200346 tPtr->font = WMRetainFont(tPtr->view->screen->normalFont);
e7495baf dan1999-02-17 11:06:40 +0000347
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200348 tPtr->flags.bordered = DEFAULT_BORDERED;
349 tPtr->flags.beveled = True;
350 tPtr->flags.alignment = DEFAULT_ALIGNMENT;
351 tPtr->offsetWidth = WMAX((tPtr->view->size.height - WMFontHeight(tPtr->font)) / 2, 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000352
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200353 W_ResizeView(tPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
5e4625da kojima1999-05-29 21:41:25 +0000354
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200355 WMCreateEventHandler(tPtr->view, EnterWindowMask | LeaveWindowMask
356 | ButtonReleaseMask | ButtonPressMask | KeyPressMask | Button1MotionMask,
357 handleTextFieldActionEvents, tPtr);
9b63a77d dan2002-01-07 06:11:34 +0000358
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200359 WMAddNotificationObserver(selectionNotification, tPtr->view,
360 WMSelectionOwnerDidChangeNotification, (void *)XA_PRIMARY);
7f6c4d1a id1999-05-16 01:27:03 +0000361
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200362 WMAddNotificationObserver(realizeObserver, tPtr, WMViewRealizedNotification, tPtr->view);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000363
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200364 tPtr->flags.cursorOn = 1;
e7495baf dan1999-02-17 11:06:40 +0000365
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200366 return tPtr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000367}
368
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200369void WMSetTextFieldDelegate(WMTextField * tPtr, WMTextFieldDelegate * delegate)
dd2d71fc kojima1999-05-15 17:38:05 +0000370{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200371 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000372
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200373 tPtr->delegate = delegate;
dd2d71fc kojima1999-05-15 17:38:05 +0000374}
375
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200376WMTextFieldDelegate *WMGetTextFieldDelegate(WMTextField * tPtr)
75091798 dan2002-04-03 00:51:36 +0000377{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200378 CHECK_CLASS(tPtr, WC_TextField);
75091798 dan2002-04-03 00:51:36 +0000379
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200380 return tPtr->delegate;
75091798 dan2002-04-03 00:51:36 +0000381}
382
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200383void WMInsertTextFieldText(WMTextField * tPtr, char *text, int position)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000384{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200385 int len;
386
387 CHECK_CLASS(tPtr, WC_TextField);
388
389 if (!text)
390 return;
391
392 len = strlen(text);
393
394 /* check if buffer will hold the text */
395 if (len + tPtr->textLen >= tPtr->bufferSize) {
396 tPtr->bufferSize = tPtr->textLen + len + TEXT_BUFFER_INCR;
397 tPtr->text = wrealloc(tPtr->text, tPtr->bufferSize);
398 }
399
400 if (position < 0 || position >= tPtr->textLen) {
401 /* append the text at the end */
402 strcat(tPtr->text, text);
403 tPtr->textLen += len;
404 tPtr->cursorPosition += len;
405 incrToFit(tPtr);
406 } else {
407 /* insert text at position */
408 memmv(&(tPtr->text[position + len]), &(tPtr->text[position]), tPtr->textLen - position + 1);
409
410 memcpy(&(tPtr->text[position]), text, len);
411
412 tPtr->textLen += len;
413 if (position >= tPtr->cursorPosition) {
414 tPtr->cursorPosition += len;
415 incrToFit2(tPtr);
416 } else {
417 incrToFit(tPtr);
418 }
419 }
420
421 paintTextField(tPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000422}
423
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200424void WMDeleteTextFieldRange(WMTextField * tPtr, WMRange range)
55d51e54 dan1999-05-16 00:45:34 +0000425{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200426 CHECK_CLASS(tPtr, WC_TextField);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000427
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200428 normalizeRange(tPtr, &range);
dbdb44a4 kojima1999-10-02 20:24:41 +0000429
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200430 if (!range.count)
431 return;
6830b057 dan2004-10-12 21:28:27 +0000432
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200433 memmv(&(tPtr->text[range.position]), &(tPtr->text[range.position + range.count]),
434 tPtr->textLen - (range.position + range.count) + 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000435
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200436 /* better than nothing ;) */
437 if (tPtr->cursorPosition > range.position)
438 tPtr->viewPosition += oneUTF8CharBackward(&tPtr->text[tPtr->viewPosition], tPtr->viewPosition);
439 tPtr->textLen -= range.count;
440 tPtr->cursorPosition = range.position;
6830b057 dan2004-10-12 21:28:27 +0000441
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200442 decrToFit(tPtr);
23aac1a8 kojima1999-05-16 00:15:03 +0000443
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200444 paintTextField(tPtr);
931a37b1 dan1999-01-29 08:11:17 +0000445}
416e3a82 dan1999-01-25 19:06:50 +0000446
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200447char *WMGetTextFieldText(WMTextField * tPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000448{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200449 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000450
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200451 return wstrdup(tPtr->text);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000452}
453
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200454void WMSetTextFieldText(WMTextField * tPtr, char *text)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000455{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200456 CHECK_CLASS(tPtr, WC_TextField);
457
458 if ((text && strcmp(tPtr->text, text) == 0) || (!text && tPtr->textLen == 0))
459 return;
460
461 if (text == NULL) {
462 tPtr->text[0] = 0;
463 tPtr->textLen = 0;
464 } else {
465 tPtr->textLen = strlen(text);
466
467 if (tPtr->textLen >= tPtr->bufferSize) {
468 tPtr->bufferSize = tPtr->textLen + TEXT_BUFFER_INCR;
469 tPtr->text = wrealloc(tPtr->text, tPtr->bufferSize);
470 }
471 strcpy(tPtr->text, text);
472 }
473
474 tPtr->cursorPosition = tPtr->selection.position = tPtr->textLen;
475 tPtr->viewPosition = 0;
476 tPtr->selection.count = 0;
477
478 if (tPtr->view->flags.realized)
479 paintTextField(tPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000480}
481
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200482void WMSetTextFieldAlignment(WMTextField * tPtr, WMAlignment alignment)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000483{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200484 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000485
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200486 tPtr->flags.alignment = alignment;
6830b057 dan2004-10-12 21:28:27 +0000487
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200488 if (alignment != WALeft) {
489 wwarning("only left alignment is supported in textfields");
490 return;
491 }
6830b057 dan2004-10-12 21:28:27 +0000492
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200493 if (tPtr->view->flags.realized) {
494 paintTextField(tPtr);
495 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000496}
497
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200498void WMSetTextFieldBordered(WMTextField * tPtr, Bool bordered)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000499{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200500 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000501
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200502 tPtr->flags.bordered = bordered;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000503
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200504 if (tPtr->view->flags.realized) {
505 paintTextField(tPtr);
506 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000507}
508
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200509void WMSetTextFieldBeveled(WMTextField * tPtr, Bool flag)
e7495baf dan1999-02-17 11:06:40 +0000510{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200511 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000512
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200513 tPtr->flags.beveled = ((flag == 0) ? 0 : 1);
e7495baf dan1999-02-17 11:06:40 +0000514
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200515 if (tPtr->view->flags.realized) {
516 paintTextField(tPtr);
517 }
e7495baf dan1999-02-17 11:06:40 +0000518}
519
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200520void WMSetTextFieldSecure(WMTextField * tPtr, Bool flag)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000521{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200522 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000523
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200524 tPtr->flags.secure = ((flag == 0) ? 0 : 1);
6830b057 dan2004-10-12 21:28:27 +0000525
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200526 if (tPtr->view->flags.realized) {
527 paintTextField(tPtr);
528 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000529}
530
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200531Bool WMGetTextFieldEditable(WMTextField * tPtr)
e7495baf dan1999-02-17 11:06:40 +0000532{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200533 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000534
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200535 return tPtr->flags.enabled;
e7495baf dan1999-02-17 11:06:40 +0000536}
537
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200538void WMSetTextFieldEditable(WMTextField * tPtr, Bool flag)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000539{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200540 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000541
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200542 tPtr->flags.enabled = ((flag == 0) ? 0 : 1);
6830b057 dan2004-10-12 21:28:27 +0000543
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200544 if (tPtr->view->flags.realized) {
545 paintTextField(tPtr);
546 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000547}
548
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200549void WMSelectTextFieldRange(WMTextField * tPtr, WMRange range)
931a37b1 dan1999-01-29 08:11:17 +0000550{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200551 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000552
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200553 if (tPtr->flags.enabled) {
554 normalizeRange(tPtr, &range);
931a37b1 dan1999-01-29 08:11:17 +0000555
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200556 tPtr->selection = range;
931a37b1 dan1999-01-29 08:11:17 +0000557
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200558 tPtr->cursorPosition = range.position + range.count;
6dd37d59 dan1999-10-22 23:39:39 +0000559
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200560 if (tPtr->view->flags.realized) {
561 paintTextField(tPtr);
562 }
563 }
931a37b1 dan1999-01-29 08:11:17 +0000564}
565
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200566void WMSetTextFieldCursorPosition(WMTextField * tPtr, unsigned int position)
931a37b1 dan1999-01-29 08:11:17 +0000567{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200568 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000569
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200570 if (tPtr->flags.enabled) {
571 if (position > tPtr->textLen)
572 position = tPtr->textLen;
931a37b1 dan1999-01-29 08:11:17 +0000573
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200574 tPtr->cursorPosition = position;
575 if (tPtr->view->flags.realized) {
576 paintTextField(tPtr);
577 }
578 }
931a37b1 dan1999-01-29 08:11:17 +0000579}
580
05720d97
AV
Alexey Voinov2007-08-14 15:15:37 +0400581unsigned WMGetTextFieldCursorPosition(WMTextField *tPtr)
582{
583 CHECK_CLASS(tPtr, WC_TextField);
584
585 return tPtr->cursorPosition;
586}
587
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200588void WMSetTextFieldNextTextField(WMTextField * tPtr, WMTextField * next)
e7495baf dan1999-02-17 11:06:40 +0000589{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200590 CHECK_CLASS(tPtr, WC_TextField);
591 if (next == NULL) {
592 if (tPtr->view->nextFocusChain)
593 tPtr->view->nextFocusChain->prevFocusChain = NULL;
594 tPtr->view->nextFocusChain = NULL;
595 return;
596 }
597
598 CHECK_CLASS(next, WC_TextField);
599
600 if (tPtr->view->nextFocusChain)
601 tPtr->view->nextFocusChain->prevFocusChain = NULL;
602 if (next->view->prevFocusChain)
603 next->view->prevFocusChain->nextFocusChain = NULL;
604
605 tPtr->view->nextFocusChain = next->view;
606 next->view->prevFocusChain = tPtr->view;
e7495baf dan1999-02-17 11:06:40 +0000607}
608
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200609void WMSetTextFieldPrevTextField(WMTextField * tPtr, WMTextField * prev)
e7495baf dan1999-02-17 11:06:40 +0000610{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200611 CHECK_CLASS(tPtr, WC_TextField);
612 if (prev == NULL) {
613 if (tPtr->view->prevFocusChain)
614 tPtr->view->prevFocusChain->nextFocusChain = NULL;
615 tPtr->view->prevFocusChain = NULL;
616 return;
617 }
618
619 CHECK_CLASS(prev, WC_TextField);
620
621 if (tPtr->view->prevFocusChain)
622 tPtr->view->prevFocusChain->nextFocusChain = NULL;
623 if (prev->view->nextFocusChain)
624 prev->view->nextFocusChain->prevFocusChain = NULL;
625
626 tPtr->view->prevFocusChain = prev->view;
627 prev->view->nextFocusChain = tPtr->view;
e7495baf dan1999-02-17 11:06:40 +0000628}
629
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200630void WMSetTextFieldFont(WMTextField * tPtr, WMFont * font)
e7df5ed4 kojima1999-09-18 22:57:19 +0000631{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200632 CHECK_CLASS(tPtr, WC_TextField);
6830b057 dan2004-10-12 21:28:27 +0000633
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200634 if (tPtr->font)
635 WMReleaseFont(tPtr->font);
636 tPtr->font = WMRetainFont(font);
6830b057 dan2004-10-12 21:28:27 +0000637
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200638 tPtr->offsetWidth = WMAX((tPtr->view->size.height - WMFontHeight(tPtr->font)) / 2, 1);
e7df5ed4 kojima1999-09-18 22:57:19 +0000639
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200640 if (tPtr->view->flags.realized) {
641 paintTextField(tPtr);
642 }
e7df5ed4 kojima1999-09-18 22:57:19 +0000643}
644
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200645WMFont *WMGetTextFieldFont(WMTextField * tPtr)
d5fbe62d kojima1999-09-22 02:09:42 +0000646{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200647 return tPtr->font;
d5fbe62d kojima1999-09-22 02:09:42 +0000648}
649
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200650static void didResizeTextField(W_ViewDelegate * self, WMView * view)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000651{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200652 WMTextField *tPtr = (WMTextField *) view->self;
e7495baf dan1999-02-17 11:06:40 +0000653
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200654 tPtr->offsetWidth = WMAX((tPtr->view->size.height - WMFontHeight(tPtr->font)) / 2, 1);
e7495baf dan1999-02-17 11:06:40 +0000655
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200656 tPtr->usableWidth = tPtr->view->size.width - 2 * tPtr->offsetWidth /*+ 2 */ ;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000657}
658
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200659static char *makeHiddenString(int length)
76827c72 dan1999-04-27 02:46:55 +0000660{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200661 char *data = wmalloc(length + 1);
76827c72 dan1999-04-27 02:46:55 +0000662
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200663 memset(data, '*', length);
664 data[length] = '\0';
5e4625da kojima1999-05-29 21:41:25 +0000665
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200666 return data;
76827c72 dan1999-04-27 02:46:55 +0000667}
668
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200669static void paintCursor(TextField * tPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000670{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200671 int cx;
672 WMScreen *screen = tPtr->view->screen;
673 int textWidth;
674 char *text;
675
676 if (tPtr->flags.secure)
677 text = makeHiddenString(strlen(tPtr->text));
678 else
679 text = tPtr->text;
680
681 cx = WMWidthOfString(tPtr->font, &(text[tPtr->viewPosition]), tPtr->cursorPosition - tPtr->viewPosition);
682
683 switch (tPtr->flags.alignment) {
684 case WARight:
685 textWidth = WMWidthOfString(tPtr->font, text, tPtr->textLen);
686 if (textWidth < tPtr->usableWidth)
687 cx += tPtr->offsetWidth + tPtr->usableWidth - textWidth + 1;
688 else
689 cx += tPtr->offsetWidth + 1;
690 break;
691 case WALeft:
692 cx += tPtr->offsetWidth + 1;
693 break;
694 case WAJustified:
695 /* not supported */
696 case WACenter:
697 textWidth = WMWidthOfString(tPtr->font, text, tPtr->textLen);
698 if (textWidth < tPtr->usableWidth)
699 cx += tPtr->offsetWidth + (tPtr->usableWidth - textWidth) / 2;
700 else
701 cx += tPtr->offsetWidth;
702 break;
703 }
704 /*
705 XDrawRectangle(screen->display, tPtr->view->window, screen->xorGC,
706 cx, tPtr->offsetWidth, 1,
707 tPtr->view->size.height - 2*tPtr->offsetWidth - 1);
708 printf("%d %d\n",cx,tPtr->cursorPosition);
709 */
710
711 XDrawLine(screen->display, tPtr->view->window, screen->xorGC,
712 cx, tPtr->offsetWidth, cx, tPtr->view->size.height - tPtr->offsetWidth - 1);
713
714 W_SetPreeditPositon(tPtr->view, cx, 0);
715
716 if (tPtr->flags.secure) {
717 wfree(text);
718 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000719}
720
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200721static void drawRelief(WMView * view, Bool beveled)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000722{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200723 WMScreen *scr = view->screen;
724 Display *dpy = scr->display;
725 GC wgc;
726 GC lgc;
727 GC dgc;
728 int width = view->size.width;
729 int height = view->size.height;
6830b057 dan2004-10-12 21:28:27 +0000730
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200731 dgc = WMColorGC(scr->darkGray);
e7495baf dan1999-02-17 11:06:40 +0000732
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200733 if (!beveled) {
734 XDrawRectangle(dpy, view->window, dgc, 0, 0, width - 1, height - 1);
e7495baf dan1999-02-17 11:06:40 +0000735
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200736 return;
737 }
738 wgc = WMColorGC(scr->white);
739 lgc = WMColorGC(scr->gray);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000740
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200741 /* top left */
742 XDrawLine(dpy, view->window, dgc, 0, 0, width - 1, 0);
743 XDrawLine(dpy, view->window, dgc, 0, 1, width - 2, 1);
6830b057 dan2004-10-12 21:28:27 +0000744
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200745 XDrawLine(dpy, view->window, dgc, 0, 0, 0, height - 2);
746 XDrawLine(dpy, view->window, dgc, 1, 0, 1, height - 3);
6830b057 dan2004-10-12 21:28:27 +0000747
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200748 /* bottom right */
749 XDrawLine(dpy, view->window, wgc, 0, height - 1, width - 1, height - 1);
750 XDrawLine(dpy, view->window, lgc, 1, height - 2, width - 2, height - 2);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000751
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200752 XDrawLine(dpy, view->window, wgc, width - 1, 0, width - 1, height - 1);
753 XDrawLine(dpy, view->window, lgc, width - 2, 1, width - 2, height - 3);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000754}
755
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200756static void paintTextField(TextField * tPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000757{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200758 W_Screen *screen = tPtr->view->screen;
759 W_View *view = tPtr->view;
760 W_View viewbuffer;
761 int tx, ty, tw, th;
762 int rx;
763 int bd;
764 int totalWidth;
765 char *text;
766 Pixmap drawbuffer;
767 WMColor *color;
768
769 if (!view->flags.realized || !view->flags.mapped)
770 return;
771
772 if (!tPtr->flags.bordered) {
773 bd = 0;
774 } else {
775 bd = 2;
776 }
777
778 if (tPtr->flags.secure) {
779 text = makeHiddenString(strlen(tPtr->text));
780 } else {
781 text = tPtr->text;
782 }
783
784 totalWidth = tPtr->view->size.width - 2 * bd;
785
786 drawbuffer = XCreatePixmap(screen->display, view->window,
787 view->size.width, view->size.height, screen->depth);
788 XFillRectangle(screen->display, drawbuffer, WMColorGC(screen->white),
789 0, 0, view->size.width, view->size.height);
790 /* this is quite dirty */
791 viewbuffer.screen = view->screen;
792 viewbuffer.size = view->size;
793 viewbuffer.window = drawbuffer;
794
795 if (tPtr->textLen > 0) {
796 tw = WMWidthOfString(tPtr->font, &(text[tPtr->viewPosition]), tPtr->textLen - tPtr->viewPosition);
797
798 th = WMFontHeight(tPtr->font);
799
800 ty = tPtr->offsetWidth;
801 switch (tPtr->flags.alignment) {
802 case WALeft:
803 tx = tPtr->offsetWidth + 1;
804 if (tw < tPtr->usableWidth)
805 XFillRectangle(screen->display, drawbuffer,
806 WMColorGC(screen->white),
807 bd + tw, bd, totalWidth - tw, view->size.height - 2 * bd);
808 break;
809
810 case WACenter:
811 tx = tPtr->offsetWidth + (tPtr->usableWidth - tw) / 2;
812 if (tw < tPtr->usableWidth)
813 XClearArea(screen->display, view->window, bd, bd,
814 totalWidth, view->size.height - 2 * bd, False);
815 break;
816
817 default:
818 case WARight:
819 tx = tPtr->offsetWidth + tPtr->usableWidth - tw - 1;
820 if (tw < tPtr->usableWidth)
821 XClearArea(screen->display, view->window, bd, bd,
822 totalWidth - tw, view->size.height - 2 * bd, False);
823 break;
824 }
825
826 color = tPtr->flags.enabled ? screen->black : screen->darkGray;
827
828 WMDrawImageString(screen, drawbuffer, color, screen->white,
829 tPtr->font, tx, ty, &(text[tPtr->viewPosition]),
830 tPtr->textLen - tPtr->viewPosition);
831
832 if (tPtr->selection.count) {
833 int count, count2;
834
835 count = tPtr->selection.count < 0
836 ? tPtr->selection.position + tPtr->selection.count : tPtr->selection.position;
837 count2 = abs(tPtr->selection.count);
838 if (count < tPtr->viewPosition) {
839 count2 = abs(count2 - abs(tPtr->viewPosition - count));
840 count = tPtr->viewPosition;
841 }
842
843 rx = tPtr->offsetWidth + 1 + WMWidthOfString(tPtr->font, text, count)
844 - WMWidthOfString(tPtr->font, text, tPtr->viewPosition);
845
846 WMDrawImageString(screen, drawbuffer, color, screen->gray,
847 tPtr->font, rx, ty, &(text[count]), count2);
848 }
849 } else {
850 XFillRectangle(screen->display, drawbuffer, WMColorGC(screen->white),
851 bd, bd, totalWidth, view->size.height - 2 * bd);
852 }
853
854 /* draw relief */
855 if (tPtr->flags.bordered) {
856 drawRelief(&viewbuffer, tPtr->flags.beveled);
857 }
858
859 if (tPtr->flags.secure)
860 wfree(text);
861 XCopyArea(screen->display, drawbuffer, view->window,
862 screen->copyGC, 0, 0, view->size.width, view->size.height, 0, 0);
863 XFreePixmap(screen->display, drawbuffer);
864
865 /* draw cursor */
866 if (tPtr->flags.focused && tPtr->flags.enabled && tPtr->flags.cursorOn) {
867 paintCursor(tPtr);
868 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000869}
870
9d2e6ef9 scottc1998-09-29 22:36:29 +0000871#if 0
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200872static void blinkCursor(void *data)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000873{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200874 TextField *tPtr = (TextField *) data;
875
876 if (tPtr->flags.cursorOn) {
877 tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_OFF_DELAY, blinkCursor, data);
878 } else {
879 tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_ON_DELAY, blinkCursor, data);
880 }
881 paintCursor(tPtr);
882 tPtr->flags.cursorOn = !tPtr->flags.cursorOn;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000883}
884#endif
885
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200886static void handleEvents(XEvent * event, void *data)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000887{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200888 TextField *tPtr = (TextField *) data;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000889
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200890 CHECK_CLASS(data, WC_TextField);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000891
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200892 switch (event->type) {
893 case FocusIn:
894 W_FocusIC(tPtr->view);
895 if (W_FocusedViewOfToplevel(W_TopLevelOfView(tPtr->view)) != tPtr->view)
896 return;
897 tPtr->flags.focused = 1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000898#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200899 if (!tPtr->timerID) {
900 tPtr->timerID = WMAddTimerHandler(CURSOR_BLINK_ON_DELAY, blinkCursor, tPtr);
901 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000902#endif
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200903 paintTextField(tPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000904
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200905 NOTIFY(tPtr, didBeginEditing, WMTextDidBeginEditingNotification, NULL);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000906
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200907 tPtr->flags.notIllegalMovement = 0;
908 break;
dd2d71fc kojima1999-05-15 17:38:05 +0000909
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200910 case FocusOut:
911 W_UnFocusIC(tPtr->view);
912 tPtr->flags.focused = 0;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000913#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200914 if (tPtr->timerID)
915 WMDeleteTimerHandler(tPtr->timerID);
916 tPtr->timerID = NULL;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000917#endif
918
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200919 paintTextField(tPtr);
920 if (!tPtr->flags.notIllegalMovement) {
921 NOTIFY(tPtr, didEndEditing, WMTextDidEndEditingNotification,
922 (void *)WMIllegalTextMovement);
923 }
924 break;
925
926 case Expose:
927 if (event->xexpose.count != 0)
928 break;
929 paintTextField(tPtr);
930 break;
931
932 case DestroyNotify:
933 destroyTextField(tPtr);
934 break;
935 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000936}
937
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200938static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000939{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200940 char buffer[64];
941 KeySym ksym;
942 char *textEvent = NULL;
943 void *data = NULL;
944 int count, refresh = 0;
945 int control_pressed = 0;
946 int cancelSelection = 1;
947 Bool shifted, controled, modified;
948 Bool relay = True;
949
950 /*printf("(%d,%d) -> ", tPtr->selection.position, tPtr->selection.count); */
951 if (((XKeyEvent *) event)->state & WM_EMACSKEYMASK)
952 control_pressed = 1;
953
954 shifted = (event->xkey.state & ShiftMask ? True : False);
955 controled = (event->xkey.state & ControlMask ? True : False);
956 modified = shifted || controled;
957
958 count = W_LookupString(tPtr->view, &event->xkey, buffer, 63, &ksym, NULL);
959 //count = XLookupString(&event->xkey, buffer, 63, &ksym, NULL);
960 buffer[count] = '\0';
961
962 switch (ksym) {
963 case XK_Tab:
b9c1aba4 dan1999-06-04 20:13:40 +0000964#ifdef XK_ISO_Left_Tab
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200965 case XK_ISO_Left_Tab:
b9c1aba4 dan1999-06-04 20:13:40 +0000966#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200967 if (!controled) {
968 if (shifted) {
969 if (tPtr->view->prevFocusChain) {
970 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
971 tPtr->view->prevFocusChain);
972 tPtr->flags.notIllegalMovement = 1;
973 }
974 data = (void *)WMBacktabTextMovement;
975 } else {
976 if (tPtr->view->nextFocusChain) {
977 W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
978 tPtr->view->nextFocusChain);
979 tPtr->flags.notIllegalMovement = 1;
980 }
981 data = (void *)WMTabTextMovement;
982 }
983 textEvent = WMTextDidEndEditingNotification;
984
985 cancelSelection = 0;
986
987 relay = False;
988 }
989 break;
990
991 case XK_Escape:
992 if (!modified) {
993 data = (void *)WMEscapeTextMovement;
994 textEvent = WMTextDidEndEditingNotification;
995
996 relay = False;
997 }
998 break;
999
1000 case XK_Return:
1001 if (!modified) {
1002 data = (void *)WMReturnTextMovement;
1003 textEvent = WMTextDidEndEditingNotification;
1004
1005 relay = False;
1006 }
1007 break;
1008
1009 case WM_EMACSKEY_LEFT:
1010 if (!control_pressed)
1011 goto normal_key;
1012 else
1013 controled = False;
97e20d94 dan2002-03-14 22:20:25 +00001014
052ab01c kojima1999-09-16 02:55:56 +00001015#ifdef XK_KP_Left
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001016 case XK_KP_Left:
052ab01c kojima1999-09-16 02:55:56 +00001017#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001018 case XK_Left:
1019 if (tPtr->cursorPosition > 0) {
1020 int i;
1021 paintCursor(tPtr);
1022
1023 i = tPtr->cursorPosition;
1024 i += oneUTF8CharBackward(&tPtr->text[i], i);
1025 if (controled) {
1026 while (i > 0 && tPtr->text[i] != ' ')
1027 i--;
1028 while (i > 0 && tPtr->text[i] == ' ')
1029 i--;
1030
1031 tPtr->cursorPosition = (i > 0) ? i + 1 : 0;
1032 } else
1033 tPtr->cursorPosition = i;
1034
1035 if (tPtr->cursorPosition < tPtr->viewPosition) {
1036 tPtr->viewPosition = tPtr->cursorPosition;
1037 refresh = 1;
1038 } else
1039 paintCursor(tPtr);
1040 }
1041 if (shifted)
1042 cancelSelection = 0;
1043
1044 relay = False;
1045
1046 break;
1047
1048 case WM_EMACSKEY_RIGHT:
1049 if (!control_pressed)
1050 goto normal_key;
1051 else
1052 controled = False;
882b9a8e kojima2001-07-23 20:31:32 +00001053
052ab01c kojima1999-09-16 02:55:56 +00001054#ifdef XK_KP_Right
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001055 case XK_KP_Right:
052ab01c kojima1999-09-16 02:55:56 +00001056#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001057 case XK_Right:
1058 if (tPtr->cursorPosition < tPtr->textLen) {
1059 int i;
1060 paintCursor(tPtr);
1061
1062 i = tPtr->cursorPosition;
1063 if (controled) {
1064 while (tPtr->text[i] && tPtr->text[i] != ' ')
1065 i++;
1066 while (tPtr->text[i] == ' ')
1067 i++;
1068 } else {
1069 i += oneUTF8CharForward(&tPtr->text[i], tPtr->textLen - i);
1070 }
1071 tPtr->cursorPosition = i;
1072
1073 refresh = incrToFit2(tPtr);
1074
1075 if (!refresh)
1076 paintCursor(tPtr);
1077 }
1078 if (shifted)
1079 cancelSelection = 0;
1080
1081 relay = False;
1082
1083 break;
1084
1085 case WM_EMACSKEY_HOME:
1086 if (!control_pressed)
1087 goto normal_key;
1088 else
1089 controled = False;
97e20d94 dan2002-03-14 22:20:25 +00001090
052ab01c kojima1999-09-16 02:55:56 +00001091#ifdef XK_KP_Home
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001092 case XK_KP_Home:
052ab01c kojima1999-09-16 02:55:56 +00001093#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001094 case XK_Home:
1095 if (!controled) {
1096 if (tPtr->cursorPosition > 0) {
1097 paintCursor(tPtr);
1098 tPtr->cursorPosition = 0;
1099 if (tPtr->viewPosition > 0) {
1100 tPtr->viewPosition = 0;
1101 refresh = 1;
1102 } else
1103 paintCursor(tPtr);
1104 }
1105 if (shifted)
1106 cancelSelection = 0;
1107
1108 relay = False;
1109 }
1110 break;
1111
1112 case WM_EMACSKEY_END:
1113 if (!control_pressed)
1114 goto normal_key;
1115 else
1116 controled = False;
97e20d94 dan2002-03-14 22:20:25 +00001117
052ab01c kojima1999-09-16 02:55:56 +00001118#ifdef XK_KP_End
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001119 case XK_KP_End:
052ab01c kojima1999-09-16 02:55:56 +00001120#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001121 case XK_End:
1122 if (!controled) {
1123 if (tPtr->cursorPosition < tPtr->textLen) {
1124 paintCursor(tPtr);
1125 tPtr->cursorPosition = tPtr->textLen;
1126 tPtr->viewPosition = 0;
1127
1128 refresh = incrToFit(tPtr);
1129
1130 if (!refresh)
1131 paintCursor(tPtr);
1132 }
1133 if (shifted)
1134 cancelSelection = 0;
1135
1136 relay = False;
1137 }
1138 break;
1139
1140 case WM_EMACSKEY_BS:
1141 if (!control_pressed)
1142 goto normal_key;
1143 else
1144 modified = False;
1145
1146 case XK_BackSpace:
1147 if (!modified) {
1148 if (tPtr->selection.count) {
1149 WMDeleteTextFieldRange(tPtr, tPtr->selection);
1150 data = (void *)WMDeleteTextEvent;
1151 textEvent = WMTextDidChangeNotification;
1152 } else if (tPtr->cursorPosition > 0) {
1153 int i = oneUTF8CharBackward(&tPtr->text[tPtr->cursorPosition],
1154 tPtr->cursorPosition);
1155 WMRange range;
1156 range.position = tPtr->cursorPosition + i;
1157 range.count = -i;
1158 WMDeleteTextFieldRange(tPtr, range);
1159 data = (void *)WMDeleteTextEvent;
1160 textEvent = WMTextDidChangeNotification;
1161 }
1162
1163 relay = False;
1164 }
1165 break;
1166
1167 case WM_EMACSKEY_DEL:
1168 if (!control_pressed)
1169 goto normal_key;
1170 else
1171 modified = False;
97e20d94 dan2002-03-14 22:20:25 +00001172
052ab01c kojima1999-09-16 02:55:56 +00001173#ifdef XK_KP_Delete
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001174 case XK_KP_Delete:
052ab01c kojima1999-09-16 02:55:56 +00001175#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001176 case XK_Delete:
1177 if (!modified) {
1178 if (tPtr->selection.count) {
1179 WMDeleteTextFieldRange(tPtr, tPtr->selection);
1180 data = (void *)WMDeleteTextEvent;
1181 textEvent = WMTextDidChangeNotification;
1182 } else if (tPtr->cursorPosition < tPtr->textLen) {
1183 WMRange range;
1184 range.position = tPtr->cursorPosition;
1185 range.count = oneUTF8CharForward(&tPtr->text[tPtr->cursorPosition],
1186 tPtr->textLen - tPtr->cursorPosition);
1187 WMDeleteTextFieldRange(tPtr, range);
1188 data = (void *)WMDeleteTextEvent;
1189 textEvent = WMTextDidChangeNotification;
1190 }
1191
1192 relay = False;
1193 }
1194 break;
1195
1196 normal_key:
1197 default:
1198 if (!controled) {
1199 if (count > 0 && !iscntrl(buffer[0])) {
1200 if (tPtr->selection.count)
1201 WMDeleteTextFieldRange(tPtr, tPtr->selection);
1202 WMInsertTextFieldText(tPtr, buffer, tPtr->cursorPosition);
1203 data = (void *)WMInsertTextEvent;
1204 textEvent = WMTextDidChangeNotification;
1205
1206 relay = False;
1207 }
1208 }
1209 break;
1210 }
1211
1212 if (relay) {
1213 WMRelayToNextResponder(W_VIEW(tPtr), event);
1214 return;
1215 }
1216
1217 /* Do not allow text selection in secure text fields */
1218 if (cancelSelection || tPtr->flags.secure) {
1219 lostSelection(tPtr->view, XA_PRIMARY, NULL);
1220
1221 if (tPtr->selection.count) {
1222 tPtr->selection.count = 0;
1223 refresh = 1;
1224 }
1225 tPtr->selection.position = tPtr->cursorPosition;
1226 } else {
1227 if (tPtr->selection.count != tPtr->cursorPosition - tPtr->selection.position) {
1228
1229 tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position;
1230
1231 refresh = 1;
1232 }
1233 }
1234
1235 /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count); */
1236
1237 if (textEvent) {
1238 WMNotification *notif = WMCreateNotification(textEvent, tPtr, data);
1239
1240 if (tPtr->delegate) {
1241 if (textEvent == WMTextDidBeginEditingNotification && tPtr->delegate->didBeginEditing)
1242 (*tPtr->delegate->didBeginEditing) (tPtr->delegate, notif);
1243
1244 else if (textEvent == WMTextDidEndEditingNotification && tPtr->delegate->didEndEditing)
1245 (*tPtr->delegate->didEndEditing) (tPtr->delegate, notif);
1246
1247 else if (textEvent == WMTextDidChangeNotification && tPtr->delegate->didChange)
1248 (*tPtr->delegate->didChange) (tPtr->delegate, notif);
1249 }
1250
1251 WMPostNotification(notif);
1252 WMReleaseNotification(notif);
1253 }
1254
1255 if (refresh)
1256 paintTextField(tPtr);
1257
1258 /*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count); */
9d2e6ef9 scottc1998-09-29 22:36:29 +00001259}
1260
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001261static int pointToCursorPosition(TextField * tPtr, int x)
9d2e6ef9 scottc1998-09-29 22:36:29 +00001262{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001263 int a, b, pos, prev, tw;
1264
1265 if (tPtr->flags.bordered)
1266 x -= 2;
1267
1268 if (WMWidthOfString(tPtr->font, &(tPtr->text[tPtr->viewPosition]),
1269 tPtr->textLen - tPtr->viewPosition) <= x)
1270 return tPtr->textLen;
1271
1272 a = tPtr->viewPosition;
1273 b = tPtr->textLen;
1274
1275 /* we halve the text until we get into a 10 byte vicinity of x */
1276 while (b - a > 10) {
1277 pos = (a + b) / 2;
1278 pos += seekUTF8CharStart(&tPtr->text[pos], pos - a);
1279 tw = WMWidthOfString(tPtr->font, &(tPtr->text[tPtr->viewPosition]), pos - tPtr->viewPosition);
1280 if (tw > x) {
1281 b = pos;
1282 } else if (tw < x) {
1283 a = pos;
1284 } else {
1285 return pos;
1286 }
1287 }
1288
1289 /* at this point x can be positioned on any glyph between 'a' and 'b-1'
1290 * inclusive, with the exception of the left border of the 'a' glyph and
1291 * the right border or the 'b-1' glyph
1292 *
1293 * ( <--- range for x's position ---> )
1294 * a a+1 .......................... b-1 b
1295 */
1296 pos = prev = a;
1297 while (pos <= b) {
1298 tw = WMWidthOfString(tPtr->font, &(tPtr->text[tPtr->viewPosition]), pos - tPtr->viewPosition);
1299 if (tw > x) {
1300 return prev;
1301 } else if (pos == b) {
1302 break;
1303 }
1304 prev = pos;
1305 pos += oneUTF8CharForward(&tPtr->text[pos], b - pos);
1306 }
1307
1308 return b;
9d2e6ef9 scottc1998-09-29 22:36:29 +00001309}
1310
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001311static void pasteText(WMView * view, Atom selection, Atom target, Time timestamp, void *cdata, WMData * data)
60a247f2 kojima2000-04-03 03:10:20 +00001312{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001313 TextField *tPtr = (TextField *) view->self;
1314 char *str;
60a247f2 kojima2000-04-03 03:10:20 +00001315
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001316 tPtr->flags.waitingSelection = 0;
60a247f2 kojima2000-04-03 03:10:20 +00001317
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001318 if (data != NULL) {
1319 str = (char *)WMDataBytes(data);
1320
1321 WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition);
1322 NOTIFY(tPtr, didChange, WMTextDidChangeNotification, (void *)WMInsertTextEvent);
1323 } else {
1324 int n;
1325
1326 str = XFetchBuffer(tPtr->view->screen->display, &n, 0);
1327
1328 if (str != NULL) {
1329 str[n] = 0;
1330 WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition);
1331 XFree(str);
1332 NOTIFY(tPtr, didChange, WMTextDidChangeNotification, (void *)WMInsertTextEvent);
1333 }
1334 }
9d2e6ef9 scottc1998-09-29 22:36:29 +00001335}
1336
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001337static void handleTextFieldActionEvents(XEvent * event, void *data)
1338{
1339 TextField *tPtr = (TextField *) data;
1340 static int move = 0;
1341 static Time lastButtonReleasedEvent = 0;
1342 static Time lastButtonReleasedEvent2 = 0;
1343 Display *dpy = event->xany.display;
1344
1345 CHECK_CLASS(data, WC_TextField);
1346
1347 switch (event->type) {
1348 case KeyPress:
1349 if (tPtr->flags.waitingSelection) {
1350 return;
1351 }
1352 if (tPtr->flags.enabled && tPtr->flags.focused) {
1353 handleTextFieldKeyPress(tPtr, event);
1354 XDefineCursor(dpy, W_VIEW(tPtr)->window, W_VIEW(tPtr)->screen->invisibleCursor);
1355 tPtr->flags.pointerGrabbed = 1;
1356 }
1357 break;
1358
1359 case MotionNotify:
1360
1361 if (tPtr->flags.pointerGrabbed) {
1362 tPtr->flags.pointerGrabbed = 0;
1363 XDefineCursor(dpy, W_VIEW(tPtr)->window, W_VIEW(tPtr)->screen->textCursor);
1364 }
1365 if (tPtr->flags.waitingSelection) {
1366 return;
1367 }
1368
1369 if (tPtr->flags.enabled && (event->xmotion.state & Button1Mask)) {
1370
1371 if (tPtr->viewPosition < tPtr->textLen && event->xmotion.x > tPtr->usableWidth) {
1372 if (WMWidthOfString(tPtr->font,
1373 &(tPtr->text[tPtr->viewPosition]),
1374 tPtr->cursorPosition - tPtr->viewPosition)
1375 > tPtr->usableWidth) {
1376 tPtr->viewPosition += oneUTF8CharForward(&tPtr->text[tPtr->viewPosition],
1377 tPtr->textLen -
1378 tPtr->viewPosition);
1379 }
1380 } else if (tPtr->viewPosition > 0 && event->xmotion.x < 0) {
1381 paintCursor(tPtr);
1382 tPtr->viewPosition += oneUTF8CharBackward(&tPtr->text[tPtr->viewPosition],
1383 tPtr->viewPosition);
1384 }
1385
1386 tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xmotion.x);
1387
1388 /* Do not allow text selection in secure textfields */
1389 if (tPtr->flags.secure) {
1390 tPtr->selection.position = tPtr->cursorPosition;
1391 }
1392
1393 tPtr->selection.count = tPtr->cursorPosition - tPtr->selection.position;
1394
1395 paintCursor(tPtr);
1396 paintTextField(tPtr);
1397
1398 }
1399 break;
1400
1401 case ButtonPress:
1402 if (tPtr->flags.pointerGrabbed) {
1403 tPtr->flags.pointerGrabbed = 0;
1404 XDefineCursor(dpy, W_VIEW(tPtr)->window, W_VIEW(tPtr)->screen->textCursor);
1405 break;
1406 }
1407
1408 if (tPtr->flags.waitingSelection) {
1409 break;
1410 }
1411
1412 move = 1;
1413 switch (tPtr->flags.alignment) {
1414 int textWidth;
1415 case WARight:
1416 textWidth = WMWidthOfString(tPtr->font, tPtr->text, tPtr->textLen);
1417 if (tPtr->flags.enabled && !tPtr->flags.focused) {
1418 WMSetFocusToWidget(tPtr);
1419 }
1420 if (tPtr->flags.focused) {
1421 tPtr->selection.position = tPtr->cursorPosition;
1422 tPtr->selection.count = 0;
1423 }
1424 if (textWidth < tPtr->usableWidth) {
1425 tPtr->cursorPosition = pointToCursorPosition(tPtr,
1426 event->xbutton.x - tPtr->usableWidth
1427 + textWidth);
1428 } else
1429 tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xbutton.x);
1430
1431 paintTextField(tPtr);
1432 break;
1433
1434 case WALeft:
1435 if (tPtr->flags.enabled && !tPtr->flags.focused) {
1436 WMSetFocusToWidget(tPtr);
1437 }
1438 if (tPtr->flags.focused && event->xbutton.button == Button1) {
1439 tPtr->cursorPosition = pointToCursorPosition(tPtr, event->xbutton.x);
1440 tPtr->selection.position = tPtr->cursorPosition;
1441 tPtr->selection.count = 0;
1442 paintTextField(tPtr);
1443 }
1444 if (event->xbutton.button == Button2 && tPtr->flags.enabled) {
1445 char *text;
1446 int n;
1447
1448 if (!WMRequestSelection(tPtr->view, XA_PRIMARY, XA_STRING,
1449 event->xbutton.time, pasteText, NULL)) {
1450 text = XFetchBuffer(tPtr->view->screen->display, &n, 0);
1451
1452 if (text) {
1453 text[n] = 0;
1454 WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition);
1455 XFree(text);
1456 NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
1457 (void *)WMInsertTextEvent);
1458 }
1459 } else {
1460 tPtr->flags.waitingSelection = 1;
1461 }
1462 }
1463 break;
1464 default:
1465 break;
1466 }
1467 break;
1468
1469 case ButtonRelease:
1470 if (tPtr->flags.pointerGrabbed) {
1471 tPtr->flags.pointerGrabbed = 0;
1472 XDefineCursor(dpy, W_VIEW(tPtr)->window, W_VIEW(tPtr)->screen->textCursor);
1473 }
1474 if (tPtr->flags.waitingSelection) {
1475 break;
1476 }
1477
1478 if (!tPtr->flags.secure && tPtr->selection.count != 0) {
1479 int start, count;
1480 XRotateBuffers(dpy, 1);
1481
1482 count = abs(tPtr->selection.count);
1483 if (tPtr->selection.count < 0)
1484 start = tPtr->selection.position - count;
1485 else
1486 start = tPtr->selection.position;
1487
1488 XStoreBuffer(dpy, &tPtr->text[start], count, 0);
1489 }
1490
1491 move = 0;
1492
1493 if (!tPtr->flags.secure &&
1494 event->xbutton.time - lastButtonReleasedEvent <= WINGsConfiguration.doubleClickDelay) {
1495
1496 if (event->xbutton.time - lastButtonReleasedEvent2 <=
1497 2 * WINGsConfiguration.doubleClickDelay) {
1498 tPtr->selection.position = 0;
1499 tPtr->selection.count = tPtr->textLen;
1500 } else {
1501 int pos, cnt;
1502 char *txt;
1503 pos = tPtr->selection.position;
1504 cnt = tPtr->selection.count;
1505 txt = tPtr->text;
1506 while (pos >= 0) {
1507 if (txt[pos] == ' ' || txt[pos] == '\t')
1508 break;
1509 pos--;
1510 }
1511 pos++;
1512
1513 while (pos + cnt < tPtr->textLen) {
1514 if (txt[pos + cnt] == ' ' || txt[pos + cnt] == '\t')
1515 break;
1516 cnt++;
1517 }
1518 tPtr->selection.position = pos;
1519 tPtr->selection.count = cnt;
1520 }
1521 paintTextField(tPtr);
1522
1523 if (!tPtr->flags.ownsSelection) {
1524 tPtr->flags.ownsSelection =
1525 WMCreateSelectionHandler(tPtr->view,
1526 XA_PRIMARY,
1527 event->xbutton.time, &selectionHandler, NULL);
1528 }
1529 } else if (!tPtr->flags.secure && tPtr->selection.count != 0 && !tPtr->flags.ownsSelection) {
1530 tPtr->flags.ownsSelection =
1531 WMCreateSelectionHandler(tPtr->view,
1532 XA_PRIMARY, event->xbutton.time, &selectionHandler, NULL);
1533 }
1534
1535 lastButtonReleasedEvent2 = lastButtonReleasedEvent;
1536 lastButtonReleasedEvent = event->xbutton.time;
1537
1538 break;
1539 }
1540}
9d2e6ef9 scottc1998-09-29 22:36:29 +00001541
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001542static void destroyTextField(TextField * tPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +00001543{
1544#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001545 if (tPtr->timerID)
1546 WMDeleteTimerHandler(tPtr->timerID);
9d2e6ef9 scottc1998-09-29 22:36:29 +00001547#endif
e7495baf dan1999-02-17 11:06:40 +00001548
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001549 W_DestroyIC(tPtr->view);
ca616755 dan2004-10-28 04:17:18 +00001550
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001551 WMReleaseFont(tPtr->font);
1552 /*// use lostSelection() instead of WMDeleteSelectionHandler here? */
1553 WMDeleteSelectionHandler(tPtr->view, XA_PRIMARY, CurrentTime);
1554 WMRemoveNotificationObserver(tPtr);
e7495baf dan1999-02-17 11:06:40 +00001555
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001556 if (tPtr->text)
1557 wfree(tPtr->text);
9d2e6ef9 scottc1998-09-29 22:36:29 +00001558
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001559 wfree(tPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +00001560}