Introduction
Introduction Statistics Contact Development Disclaimer Help
gwin.c - sam - An updated version of the sam text editor.
git clone git://vernunftzentrum.de/sam.git
Log
Files
Refs
LICENSE
---
gwin.c (13612B)
---
1 /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */
2 #include <u.h>
3 #include <libg.h>
4 #include <stdio.h>
5 #include <X11/IntrinsicP.h>
6 #include <X11/StringDefs.h>
7 #include <X11/Xatom.h>
8 #include <X11/XKBlib.h>
9 #include <X11/keysym.h>
10
11 #include "GwinP.h"
12 #include "libgint.h"
13
14 const char *clipatom = "PRIMARY";
15
16 /* Forward declarations */
17 static void Realize(Widget, XtValueMask *, XSetWindowAttributes *);
18 static void Resize(Widget);
19 static void Redraw(Widget, XEvent *, Region);
20 static void Mappingaction(Widget, XEvent *, String *, Cardinal*);
21 static void Keyaction(Widget, XEvent *, String *, Cardinal*);
22 static void Mouseaction(Widget, XEvent *, String *, Cardinal*);
23 static String SelectSwap(Widget, String);
24
25 /* Data */
26
27 #define Offset(field) XtOffsetOf(GwinRec, gwin.field)
28
29 static XtResource resources[] = {
30 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
31 Offset(foreground), XtRString, (XtPointer)XtDefaultForeground},
32 {XtNscrollForwardR, XtCScrollForwardR, XtRBoolean, sizeof(Boolean),
33 Offset(forwardr), XtRImmediate, (XtPointer)true},
34 {XtNreshaped, XtCReshaped, XtRFunction, sizeof(Reshapefunc),
35 Offset(reshaped), XtRFunction, (XtPointer) NULL},
36 {XtNgotchar, XtCGotchar, XtRFunction, sizeof(Charfunc),
37 Offset(gotchar), XtRFunction, (XtPointer) NULL},
38 {XtNgotmouse, XtCGotmouse, XtRFunction, sizeof(Mousefunc),
39 Offset(gotmouse), XtRFunction, (XtPointer) NULL},
40 {XtNselection, XtCSelection, XtRString, sizeof(String),
41 Offset(selection), XtRString, (XtPointer) NULL},
42 };
43 #undef Offset
44
45 static XtActionsRec actions[] = {
46 {"key", Keyaction},
47 {"mouse", Mouseaction},
48 {"mapping", Mappingaction}
49 };
50
51 static char tms[] =
52 "<Key> : key() \n\
53 <Motion> : mouse() \n\
54 <BtnDown> : mouse() \n\
55 <BtnUp> : mouse() \n\
56 <Mapping> : mapping() \n";
57
58 /* Class record declaration */
59
60 GwinClassRec gwinClassRec = {
61 /* Core class part */
62 {
63 /* superclass */ (WidgetClass)&widgetClassRec,
64 /* class_name */ "Gwin",
65 /* widget_size */ sizeof(GwinRec),
66 /* class_initialize */ NULL,
67 /* class_part_initialize*/ NULL,
68 /* class_inited */ false,
69 /* initialize */ NULL,
70 /* initialize_hook */ NULL,
71 /* realize */ Realize,
72 /* actions */ actions,
73 /* num_actions */ XtNumber(actions),
74 /* resources */ resources,
75 /* num_resources */ XtNumber(resources),
76 /* xrm_class */ NULLQUARK,
77 /* compress_motion */ true,
78 /* compress_exposure */ XtExposeCompressMultiple,
79 /* compress_enterleave*/ true,
80 /* visible_interest */ false,
81 /* destroy */ NULL,
82 /* resize */ Resize,
83 /* expose */ Redraw,
84 /* set_values */ NULL,
85 /* set_values_hook */ NULL,
86 /* set_values_almost */ XtInheritSetValuesAlmost,
87 /* get_values_hook */ NULL,
88 /* accept_focus */ XtInheritAcceptFocus,
89 /* version */ XtVersion,
90 /* callback_offsets */ NULL,
91 /* tm_table */ tms,
92 /* query_geometry */ XtInheritQueryGeometry,
93 /* display_accelerator */ NULL,
94 /* extension */ NULL
95 },
96 /* Gwin class part */
97 {
98 /* select_swap */ SelectSwap,
99 }
100 };
101
102 /* Class record pointer */
103 WidgetClass gwinWidgetClass = (WidgetClass) &gwinClassRec;
104
105 static XModifierKeymap *modmap;
106 static int keypermod;
107 extern XIC xic;
108 extern XIM xim;
109
110 static void
111 Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attrs)
112 {
113 *valueMask |= CWBackingStore;
114 attrs->backing_store = Always;
115
116 XtCreateWindow(w, InputOutput, (Visual *)0, *valueMask, attrs);
117 XtSetKeyboardFocus(w->core.parent, w);
118 if ((modmap = XGetModifierMapping(XtDisplay(w))))
119 keypermod = modmap->max_keypermod;
120
121 Resize(w);
122
123 xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNoth…
124 XNClientWindow, XtWindow(w), XNFocusWindow, XtWindow…
125 if (!xic){
126 fprintf(stderr, "could not create input context\n");
127 exit(EXIT_FAILURE);
128 }
129 }
130
131 static void
132 Resize(Widget w)
133 {
134 if(XtIsRealized(w))
135 (*(XtClass(w)->core_class.expose))(w, (XEvent *)NULL, (Region)NU…
136 }
137
138 static void
139 Redraw(Widget w, XEvent *e, Region r)
140 {
141 Reshapefunc f;
142
143 f = ((GwinWidget)w)->gwin.reshaped;
144 if(f)
145 (*f)(w->core.x, w->core.y,
146 w->core.x+w->core.width, w->core.y+w->core.height);
147 }
148
149 static void
150 Mappingaction(Widget w, XEvent *e, String *p, Cardinal *np)
151 {
152 if (modmap)
153 XFreeModifiermap(modmap);
154 modmap = XGetModifierMapping(e->xany.display);
155 if (modmap)
156 keypermod = modmap->max_keypermod;
157 }
158
159 typedef struct Unikeysym Unikeysym;
160 struct Unikeysym{
161 KeySym keysym;
162 uint16_t value;
163 };
164
165 Unikeysym unikeysyms[] ={
166 #include "unikeysyms.h"
167 {0, 0}
168 };
169
170 uint16_t
171 keysymtoshort(KeySym k)
172 {
173 for (Unikeysym *ks = unikeysyms; ks->keysym != 0; ks++){
174 if (k == ks->keysym)
175 return ks->value;
176 }
177
178 return k;
179 }
180
181 typedef struct Keymapping Keymapping;
182 struct Keymapping{
183 Keymapping *next;
184 int m;
185 KeySym s;
186 int k;
187 int c;
188 char a[];
189 };
190
191 static Keymapping *keymappings = NULL;
192
193 int
194 installbinding(int m, KeySym s, int k, int c, const char *a)
195 {
196 if (m < 0 || s == NoSymbol || k < 0 || c < 0)
197 return -1;
198
199 a = a ? a : "";
200 Keymapping *km = calloc(1, sizeof(Keymapping) + strlen(a) + 1);
201 if (!km)
202 return -1;
203
204 km->m = m;
205 km->s = s;
206 km->k = k;
207 km->c = c;
208 strcpy(km->a, a);
209 km->next = keymappings;
210 keymappings = km;
211
212 return 0;
213 }
214
215 int
216 removebinding(int m, KeySym s)
217 {
218 if (m < 0 || s == NoSymbol)
219 return -1;
220
221 for (Keymapping *km = keymappings; km; km = km->next){
222 if (km->m == m && km->s == s)
223 km->c = Cdefault;
224 }
225
226 return 0;
227 }
228
229 void
230 freebindings(void)
231 {
232 Keymapping *m = keymappings;
233 while (m){
234 Keymapping *n = m->next;
235 free(m);
236 m = n;
237 }
238 }
239
240 static void
241 Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
242 {
243 extern XIC xic;
244 int kind = Kraw;
245
246 int c, len, minmod;
247 KeySym k, mk;
248 Charfunc f;
249 Modifiers md;
250 Status s;
251 wchar_t buf[32] = {0};
252
253 c = 0;
254 len = 0;
255
256 /* Translate the keycode into a key symbol. */
257 if(e->xany.type != KeyPress)
258 return;
259
260 len = XwcLookupString(xic, &e->xkey, buf, 32, &k, &s);
261 if (IsModifierKey(k))
262 return;
263
264 /* Check to see if it's a specially-handled key first. */
265 for (Keymapping *m = keymappings; m; m = m->next){
266 KeySym u = NoSymbol;
267 KeySym l = NoSymbol;
268 XConvertCase(k, &l, &u);
269
270 /* Note that magic bit manipulation here - we want to check that…
271 * modifiers that are specified for the binding are all pressed,…
272 * we allow other modifiers to be as well. This is because when …
273 * is on, it's always added to the modifier mask.
274 */
275 if (l == m->s || m->s == XK_VoidSymbol){
276 if (m->m == 0 || (m->m & ~e->xkey.state) == 0){
277 switch (m->c){
278 case Cnone:
279 return;
280
281 case Cdefault:
282 continue;
283
284 default:
285 f = ((GwinWidget)w)->gwin.gotchar;
286 if (f)
287 (*f)(m->c, m->k, Tcurrent, 0, 0, m->a);
288 return;
289 }
290 }
291 }
292 }
293
294 c = keysymtoshort(k);
295 f = ((GwinWidget)w)->gwin.gotchar;
296 if(f && c)
297 (*f)(c? c : buf[0], kind, Tcurrent, 0, 0, NULL);
298 }
299
300 typedef struct Chordmapping Chordmapping;
301 struct Chordmapping{
302 Chordmapping *next;
303 int s1;
304 int s2;
305 int c;
306 int t;
307 const char *a;
308 };
309
310 static Chordmapping *chordmap = NULL;
311
312 int
313 installchord(int s1, int s2, int c, int t, const char *a)
314 {
315 if (s1 < 0 || s2 < 0 || c < 0 || (t != Tmouse && t != Tcurrent))
316 return -1;
317
318 Chordmapping *m = calloc(1, sizeof(Chordmapping));
319 if (!m)
320 return -1;
321
322 m->s1 = s1;
323 m->s2 = s2;
324 m->c = c;
325 m->t = t;
326 m->a = a;
327
328 m->next = chordmap;
329 chordmap = m;
330 return 0;
331 }
332
333 int
334 removechord(int s1, int s2)
335 {
336 if (s1 < 0 || s2 < 0)
337 return -1;
338
339 for (Chordmapping *m = chordmap; m; m = m->next){
340 if (m->s1 == s1 && m->s2 == s2)
341 m->c = Cdefault;
342 }
343
344 return 0;
345 }
346
347 void
348 freechords(void)
349 {
350 Chordmapping *m = chordmap;
351 while (m){
352 Chordmapping *n = m->next;
353 free(m);
354 m = n;
355 }
356 }
357
358 static void
359 Mouseaction(Widget w, XEvent *e, String *p, Cardinal *np)
360 {
361 int s = 0;
362 int ps = 0; /* the previous state */
363 int ob = 0;
364 static bool chording = false;
365 Charfunc kf;
366
367 XButtonEvent *be = (XButtonEvent *)e;
368 XMotionEvent *me = (XMotionEvent *)e;
369 Gwinmouse m;
370 Mousefunc f;
371
372 switch(e->type){
373 case ButtonPress:
374 m.xy.x = be->x;
375 m.xy.y = be->y;
376 m.msec = be->time;
377 ps = s = be->state;
378 switch(be->button){
379 case 1: s |= Button1Mask; break;
380 case 2: s |= Button2Mask; break;
381 case 3: s |= Button3Mask; break;
382 case 4: s |= Button4Mask; break;
383 case 5: s |= Button5Mask; break;
384 }
385 break;
386 case ButtonRelease:
387 m.xy.x = be->x;
388 m.xy.y = be->y;
389 m.msec = be->time;
390 ps = s = be->state;
391 switch(be->button){
392 case 1: s &= ~Button1Mask; break;
393 case 2: s &= ~Button2Mask; break;
394 case 3: s &= ~Button3Mask; break;
395 case 4: s &= ~Button4Mask; break;
396 case 5: s &= ~Button5Mask; break;
397 }
398 break;
399 case MotionNotify:
400 ps = s = me->state;
401 m.xy.x = me->x;
402 m.xy.y = me->y;
403 m.msec = me->time;
404 break;
405 default:
406 return;
407 }
408
409 m.buttons = 0;
410
411 if(ps & Button1Mask) ob |= 1;
412 if(ps & Button2Mask) ob |= 2;
413 if(ps & Button3Mask) ob |= (s & ShiftMask) ? 2 : 4;
414 if(ps & Button4Mask) ob |= 8;
415 if(ps & Button5Mask) ob |= 16;
416
417 if(s & Button1Mask) m.buttons |= 1;
418 if(s & Button2Mask) m.buttons |= 2;
419 if(s & Button3Mask) m.buttons |= (s & ShiftMask) ? 2 : 4;
420 if(s & Button4Mask) m.buttons |= 8;
421 if(s & Button5Mask) m.buttons |= 16;
422
423 if (!m.buttons)
424 chording = false;
425
426 /* Check to see if it's a chord first. */
427 for (Chordmapping *cm = chordmap; cm; cm = cm->next){
428 if (ob == cm->s1 && m.buttons == cm->s2){
429 switch (cm->c){
430 case Cdefault:
431 continue;
432
433 case Cnone:
434 break;
435
436 default:
437 kf = ((GwinWidget)w)->gwin.gotchar;
438 if (kf)
439 (*kf)(cm->c, Kcommand, cm->t, m.xy.x, m.xy.y, NU…
440
441 m.buttons = 0;
442 chording = true;
443 break;
444 }
445 }
446 }
447
448 if (chording)
449 m.buttons = 0;
450
451 f = ((GwinWidget)w)->gwin.gotmouse;
452 if(f)
453 (*f)(&m);
454 }
455
456 static void
457 SelCallback(Widget w, XtPointer cldata, Atom *sel, Atom *seltype,
458 XtPointer val, uint64_t *len, int *fmt)
459 {
460 GwinWidget gw = (GwinWidget)w;
461 XTextProperty p = {0};
462 char *ls[2] = {(char *)val, NULL};
463
464 if (*seltype == 0){
465 if (gw->gwin.selection == NULL)
466 gw->gwin.selection = strdup("");
467 return;
468 }
469
470 if(gw->gwin.selection){
471 XtFree(gw->gwin.selection);
472 gw->gwin.selection = NULL;
473 }
474
475 if(*seltype != XInternAtom(_dpy, "UTF8_STRING", 0))
476 return;
477
478 if (XmbTextListToTextProperty(_dpy, ls, 1, XUTF8StringStyle, &p) != …
479 return;
480
481 gw->gwin.selection = strdup(p.value);
482 XtFree(val);
483 XFree(p.value);
484 }
485
486 static Boolean
487 SendSel(Widget w, Atom *sel, Atom *target, Atom *rtype, XtPointer *ans,
488 uint64_t *anslen, int *ansfmt)
489 {
490 GwinWidget gw = (GwinWidget)w;
491 XTextProperty p = {0};
492 char *ls[2] = {NULL, NULL};
493
494 if (*target == XA_STRING){
495 ls[0] = gw->gwin.selection? gw->gwin.selection : "";
496 if (XmbTextListToTextProperty(_dpy, ls, 1, XUTF8StringStyle, &p)…
497 return false;
498
499 *rtype = p.encoding;
500 *ans = (XtPointer) XtNewString(p.value);
501 *anslen = p.nitems;
502 *ansfmt = p.format;
503 XFree(p.value);
504 return true;
505 }
506
507 return false;
508 }
509
510 static String
511 SelectSwap(Widget w, String s)
512 {
513 GwinWidget gw;
514 String ans;
515
516 gw = (GwinWidget)w;
517 if(gw->gwin.selection){
518 XtFree(gw->gwin.selection);
519 gw->gwin.selection = NULL;
520 }
521 XtGetSelectionValue(w, XInternAtom(_dpy, clipatom, 0), XInternAtom(_…
522 XtLastTimestampProcessed(XtDisplay(w)));
523
524 while(gw->gwin.selection == NULL)
525 XtAppProcessEvent(XtWidgetToApplicationContext(w) , XtIMAll);
526 ans = gw->gwin.selection;
527 gw->gwin.selection = XtMalloc(strlen(s)+1);
528 strcpy(gw->gwin.selection, s);
529
530 XtOwnSelection(w, XInternAtom(_dpy, clipatom, 0), XtLastTimestampPro…
531 SendSel, NULL, NULL);
532
533 return ans;
534 }
535
536 /* The returned answer should be free()ed when no longer needed */
537 String
538 GwinSelectionSwap(Widget w, String s)
539 {
540 XtCheckSubclass(w, gwinWidgetClass, NULL);
541 return (*((GwinWidgetClass) XtClass(w))->gwin_class.select_swap)(w, …
542 }
You are viewing proxied material from vernunftzentrum.de. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.