1 /*
2 * vbi-gui -- motif videotext browser
3 *
4 * (c) 2002 Gerd Knorr <kraxel@bytesex.org>
5 */
6
7 #include "config.h"
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <pthread.h>
16 #include <iconv.h>
17 #include <langinfo.h>
18 #include <sys/types.h>
19 #include <sys/time.h>
20 #include <sys/ioctl.h>
21
22 #include <X11/Xlib.h>
23 #include <X11/Xatom.h>
24 #include <X11/Intrinsic.h>
25 #include <X11/keysym.h>
26 #include <Xm/Xm.h>
27 #include <Xm/Form.h>
28 #include <Xm/Label.h>
29 #include <Xm/RowColumn.h>
30 #include <Xm/CascadeB.h>
31 #include <Xm/PushB.h>
32 #include <Xm/DrawingA.h>
33 #include <Xm/Protocols.h>
34 #include <Xm/Separator.h>
35 #include <Xm/SelectioB.h>
36 #include <Xm/TransferP.h>
37 #include <Xm/DragIcon.h>
38 #include <Xm/FileSB.h>
39
40 #include "RegEdit.h"
41 #include "atoms.h"
42 #include "list.h"
43 #include "vbi-data.h"
44 #include "vbi-x11.h"
45 #include "vbi-gui.h"
46
47 #include "channel.h"
48
49 static int tt_debug = 1;
50 static int tt_windows = 0;
51
52 struct vbi_selection {
53 struct list_head list;
54 Atom atom;
55 struct vbi_page pg;
56 struct vbi_rect rect;
57 Pixmap pix;
58 };
59
60 static void vbi_new_cb(Widget, XtPointer, XtPointer);
61 static void vbi_goto_cb(Widget, XtPointer, XtPointer);
62 static void vbi_subpage_menu(struct vbi_window *vw);
63 static void selection_pri(struct vbi_window *vw);
64 static void selection_dnd_start(struct vbi_window *vw, XEvent *event);
65
66 /* --------------------------------------------------------------------- */
67
68 static void
69 vbi_fix_head(struct vbi_window *vw, struct vbi_char *ch)
70 {
71 int showno,showsub,red,i;
72
73 showno = vw->pg.pgno;
74 showsub = vw->pg.subno;
75 red = 0;
76 if (0 == showno) {
77 showno = vw->pgno;
78 showsub = 0;
79 red = 1;
80 }
81 if (vw->newpage) {
82 showno = vw->newpage;
83 showsub = 0;
84 red = 1;
85 }
86
87 for (i = 1; i <= 6; i++)
88 ch[i].unicode = ' ';
89 if (showno >= 0x100)
90 ch[1].unicode = '' + ((showno >> 8) & 0xf);
91 if (showno >= 0x10)
92 ch[2].unicode = '' + ((showno >> 4) & 0xf);
93 if (showno >= 0x1)
94 ch[3].unicode = '' + ((showno >> 0) & 0xf);
95 if (showsub) {
96 ch[4].unicode = '/';
97 ch[5].unicode = '' + ((showsub >> 4) & 0xf);
98 ch[6].unicode = '' + ((showsub >> 0) & 0xf);
99 }
100 if (red) {
101 ch[1].foreground = VBI_RED;
102 ch[2].foreground = VBI_RED;
103 ch[3].foreground = VBI_RED;
104 }
105 }
106
107 static void
108 vbi_check_rectangle(struct vbi_rect *rect)
109 {
110 int h;
111
112 if (rect->x1 > rect->x2)
113 h = rect->x1, rect->x1 = rect->x2, rect->x2 = h;
114 if (rect->y1 > rect->y2)
115 h = rect->y1, rect->y1 = rect->y2, rect->y2 = h;
116
117 if (rect->x1 < 0) rect->x1 = 0;
118 if (rect->x2 < 0) rect->x2 = 0;
119 if (rect->y1 < 0) rect->y1 = 0;
120 if (rect->y2 < 0) rect->y2 = 0;
121
122 if (rect->x1 > 41) rect->x1 = 41;
123 if (rect->x2 > 41) rect->x2 = 41;
124 if (rect->y1 > 25) rect->y1 = 25;
125 if (rect->y2 > 25) rect->y2 = 25;
126 }
127
128 static void
129 vbi_mark_rectangle(struct vbi_window *vw)
130 {
131 struct vbi_rect rect;
132 XGCValues values;
133 int x,y,w,h;
134
135 rect = vw->s;
136 vbi_check_rectangle(&rect);
137 x = vw->w * (rect.x1);
138 w = vw->w * (rect.x2 - rect.x1);
139 y = vw->h * (rect.y1);
140 h = vw->h * (rect.y2 - rect.y1);
141 values.function = GXxor;
142 values.foreground = ~0;
143 XChangeGC(XtDisplay(vw->tt),vw->gc,GCFunction|GCForeground,&values);
144 XFillRectangle(XtDisplay(vw->tt),XtWindow(vw->tt),vw->gc,
145 x,y,w,h);
146 }
147
148 static void
149 vbi_render_page(struct vbi_window *vw)
150 {
151 struct vbi_char *ch;
152 int y;
153
154 vbi_fix_head(vw,vw->pg.text);
155 for (y = 0; y < 25; y++) {
156 ch = vw->pg.text + 41*y;
157 vbi_render_line(vw,XtWindow(vw->tt),ch,y,0,0,41);
158 }
159 if ((vw->s.x1 || vw->s.x2) &&
160 (vw->s.y1 || vw->s.y2))
161 vbi_mark_rectangle(vw);
162 }
163
164 static void
165 vbi_render_head(struct vbi_window *vw, int pgno, int subno)
166 {
167 vbi_page pg;
168
169 memset(&pg,0,sizeof(pg));
170 vbi_fetch_vt_page(vw->vbi->dec,&pg,pgno,subno,
171 VBI_WST_LEVEL_1p5,1,0);
172 vbi_fix_head(vw,pg.text);
173 vbi_render_line(vw,XtWindow(vw->tt),pg.text,0,0,0,41);
174 }
175
176 static void
177 vbi_newdata(struct vbi_event *ev, void *user)
178 {
179 struct vbi_window *vw = user;
180
181 switch (ev->type) {
182 case VBI_EVENT_TTX_PAGE:
183 if (vw->pgno == ev->ev.ttx_page.pgno) {
184 if (vw->subno == ev->ev.ttx_page.subno ||
185 vw->subno == VBI_ANY_SUBNO) {
186 vbi_fetch_vt_page(vw->vbi->dec,&vw->pg,vw->pgno,vw->subno,
187 VBI_WST_LEVEL_1p5,25,1);
188 vbi_render_page(vw);
189 }
190 vbi_subpage_menu(vw);
191 } else {
192 vbi_render_head(vw,
193 ev->ev.ttx_page.pgno,
194 ev->ev.ttx_page.subno);
195 }
196 break;
197 case VBI_EVENT_NETWORK:
198 XtVaSetValues(vw->shell,XtNtitle,ev->ev.network.name,NULL);
199 break;
200 }
201 }
202
203 /* --------------------------------------------------------------------- */
204 /* GUI handling */
205
206 static void
207 vbi_subpage_menu(struct vbi_window *vw)
208 {
209 WidgetList children,list;
210 Cardinal nchildren;
211 Widget push;
212 vbi_page pg;
213 char page[8];
214 unsigned int i;
215
216 /* delete children */
217 XtVaGetValues(vw->submenu,XtNchildren,&children,
218 XtNnumChildren,&nchildren,NULL);
219 if (0 != nchildren) {
220 list = malloc(sizeof(Widget*)*nchildren);
221 memcpy(list,children,sizeof(Widget*)*nchildren);
222 for (i = 0; i < nchildren; i++)
223 XtDestroyWidget(list[i]);
224 free(list);
225 }
226
227 /* rebuild menu */
228 push = XtVaCreateManagedWidget("s00",xmPushButtonWidgetClass,
229 vw->submenu,NULL);
230 XtAddCallback(push,XmNactivateCallback,vbi_goto_cb,vw);
231 XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,
232 vw->submenu,NULL);
233 if (vw->pg.pgno && vw->pg.subno) {
234 XtVaSetValues(vw->subbtn,XtNsensitive,True,NULL);
235 for (i = 0; i < VBI_MAX_SUBPAGES; i++) {
236 if (!vbi_fetch_vt_page(vw->vbi->dec,&pg,vw->pg.pgno,i,
237 VBI_WST_LEVEL_1,0,0))
238 continue;
239 sprintf(page,"s%02x",i);
240 push = XtVaCreateManagedWidget(page,xmPushButtonWidgetClass,
241 vw->submenu,NULL);
242 XtAddCallback(push,XmNactivateCallback,vbi_goto_cb,vw);
243 }
244 } else {
245 XtVaSetValues(vw->subbtn,XtNsensitive,False,NULL);
246 }
247 }
248
249 static void
250 vbi_setpage(struct vbi_window *vw, int pgno, int subno)
251 {
252 vw->pgno = pgno;
253 vw->subno = subno;
254 vw->newpage = 0;
255 memset(&vw->pg,0,sizeof(struct vbi_page));
256 vbi_fetch_vt_page(vw->vbi->dec,&vw->pg,vw->pgno,vw->subno,
257 VBI_WST_LEVEL_1p5,25,1);
258 if (XtWindow(vw->tt))
259 vbi_render_page(vw);
260 vbi_subpage_menu(vw);
261 }
262
263 static void
264 vbi_expose_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
265 {
266 XmDrawingAreaCallbackStruct *cd = call_data;
267 struct vbi_window *vw = clientdata;
268
269 if (cd->event->xexpose.count > 0)
270 return;
271 vbi_render_page(vw);
272 }
273
274 static void
275 vbi_destroy_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
276 {
277 struct vbi_window *vw = clientdata;
278
279 vbi_event_handler_unregister(vw->vbi->dec,vbi_newdata,vw);
280 vbi_render_free_font(widget,vw);
281 XFreeGC(XtDisplay(widget),vw->gc);
282 free(vw);
283 tt_windows--;
284 if (0 == tt_windows)
285 exit(0);
286 }
287
288 static void
289 vbi_close_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
290 {
291 struct vbi_window *vw = clientdata;
292 XtDestroyWidget(vw->shell);
293 }
294
295 static void
296 vbi_new_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
297 {
298 struct vbi_window *vw = clientdata;
299 Widget shell;
300
301 shell = XtVaAppCreateShell("mtt","mtt",applicationShellWidgetClass,
302 XtDisplay(widget),NULL);
303 vbi_create_widgets(shell,vw->vbi);
304 XtRealizeWidget(shell);
305 }
306
307 static void
308 vbi_font_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
309 {
310 struct vbi_window *vw = clientdata;
311 char *name = XtName(widget);
312 vbi_render_set_font(widget, vw, name);
313 XtVaSetValues(vw->tt, XmNwidth,vw->w*41, XmNheight,vw->h*25, NULL);
314 XClearWindow(XtDisplay(vw->tt),XtWindow(vw->tt));
315 }
316
317 static void
318 vbi_goto_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
319 {
320 struct vbi_window *vw = clientdata;
321 int pgno,subno;
322 char *name;
323
324 pgno = vw->pg.pgno;
325 subno = vw->pg.subno;
326 name = XtName(widget);
327 if (0 == strcmp(name,"prev")) {
328 pgno = vbi_calc_page(vw->pgno,-1);
329 subno = VBI_ANY_SUBNO;
330 } else if (0 == strcmp(name,"next")) {
331 pgno = vbi_calc_page(vw->pgno,+1);
332 subno = VBI_ANY_SUBNO;
333 } else if (1 == sscanf(name,"s%x",&subno)) {
334 /* nothing */
335 } else {
336 sscanf(name,"%x",&pgno);
337 subno = VBI_ANY_SUBNO;
338 }
339 if (0 == subno)
340 subno = VBI_ANY_SUBNO;
341 vbi_setpage(vw,pgno,subno);
342 }
343
344 static int
345 vbi_findpage(struct vbi_page *pg, int px, int py)
346 {
347 int newpage = 0;
348 int x;
349
350 if (py == 24) {
351 /* navigation line */
352 int i = (pg->text[py*41+px].foreground & 7) -1;
353 if (i >= 6)
354 i = 0;
355 newpage = pg->nav_link[i].pgno;
356 } else if (px <= 40 && py <= 23) {
357 if (pg->text[py*41+px].unicode >= '' &&
358 pg->text[py*41+px].unicode <= '9') {
359 /* look for a 3-digit string ... */
360 x = px; newpage = 0;
361 while (pg->text[py*41+x].unicode >= '' &&
362 pg->text[py*41+x].unicode <= '9' &&
363 x > 0) {
364 x--;
365 }
366 x++;
367 while (pg->text[py*41+x].unicode >= '' &&
368 pg->text[py*41+x].unicode <= '9' &&
369 x < 40) {
370 newpage = newpage*16 + pg->text[py*41+x].unicode - '';
371 x++;
372 }
373
374 } else if (pg->text[py*41+px].unicode == '>') {
375 /* next page */
376 newpage = vbi_calc_page(pg->pgno,+1);
377
378 } else if (pg->text[py*41+px].unicode == '<') {
379 /* prev page */
380 newpage = vbi_calc_page(pg->pgno,-1);
381 }
382 }
383
384 if (newpage < 0x100 || newpage >= 0x999)
385 return 0;
386 return newpage;
387 }
388
389 static void
390 vbi_kbd_eh(Widget widget, XtPointer clientdata, XEvent *event, Boolean *cont)
391 {
392 struct vbi_window *vw = clientdata;
393 KeySym sym;
394 int digit,subno;
395
396 switch (event->type) {
397 case KeyPress:
398 sym = XKeycodeToKeysym(XtDisplay(widget),event->xkey.keycode,0);
399 digit = -1;
400 switch (sym) {
401 case XK_0:
402 case XK_KP_Insert:
403 digit = 0;
404 break;
405 case XK_1:
406 case XK_KP_End:
407 digit = 1;
408 break;
409 case XK_2:
410 case XK_KP_Down:
411 digit = 2;
412 break;
413 case XK_3:
414 case XK_KP_Next:
415 digit = 3;
416 break;
417 case XK_4:
418 case XK_KP_Left:
419 digit = 4;
420 break;
421 case XK_5:
422 case XK_KP_Begin:
423 digit = 5;
424 break;
425 case XK_6:
426 case XK_KP_Right:
427 digit = 6;
428 break;
429 case XK_7:
430 case XK_KP_Home:
431 digit = 7;
432 break;
433 case XK_8:
434 case XK_KP_Up:
435 digit = 8;
436 break;
437 case XK_9:
438 case XK_KP_Prior:
439 digit = 9;
440 break;
441 case XK_space:
442 case XK_l:
443 vbi_setpage(vw,vbi_calc_page(vw->pgno,+1),VBI_ANY_SUBNO);
444 break;
445 case XK_BackSpace:
446 case XK_h:
447 vbi_setpage(vw,vbi_calc_page(vw->pgno,-1),VBI_ANY_SUBNO);
448 break;
449 case XK_k:
450 subno = (vw->subno != VBI_ANY_SUBNO) ? vw->subno : vw->pg.subno;
451 subno = vbi_calc_subpage(vw->vbi->dec,vw->pgno,subno,+1);
452 vbi_setpage(vw,vw->pgno,subno);
453 break;
454 case XK_j:
455 subno = (vw->subno != VBI_ANY_SUBNO) ? vw->subno : vw->pg.subno;
456 subno = vbi_calc_subpage(vw->vbi->dec,vw->pgno,subno,-1);
457 vbi_setpage(vw,vw->pgno,subno);
458 break;
459 }
460 if (-1 != digit) {
461 vw->newpage *= 16;
462 vw->newpage += digit;
463 if (vw->newpage >= 0x100)
464 vbi_setpage(vw,vw->newpage,VBI_ANY_SUBNO);
465 }
466 break;
467 }
468 }
469
470 static void
471 vbi_mouse_eh(Widget widget, XtPointer clientdata, XEvent *event, Boolean *cont)
472 {
473 struct vbi_window *vw = clientdata;
474 int px,py,newpage;
475
476 switch (event->type) {
477 case ButtonPress:
478 switch (event->xbutton.button) {
479 case 1: /* left mouse button */
480 px = event->xbutton.x / vw->w;
481 py = event->xbutton.y / vw->h;
482 vw->s.x1 = vw->s.x2 = px;
483 vw->s.y1 = vw->s.y2 = py;
484 vw->down = event->xbutton.time;
485 break;
486 case 2: /* middle button */
487 selection_dnd_start(vw,event);
488 break;
489 }
490 break;
491 case MotionNotify:
492 if (event->xmotion.state & Button1Mask) {
493 vw->s.x2 = event->xbutton.x / vw->w +1;
494 vw->s.y2 = event->xbutton.y / vw->h +1;
495 vbi_render_page(vw);
496 }
497 break;
498 case ButtonRelease:
499 switch (event->xbutton.button) {
500 case 1: /* left mouse button */
501 px = event->xbutton.x / vw->w;
502 py = event->xbutton.y / vw->h;
503 if (abs(vw->s.x1 - px) < 2 && abs(vw->s.y1 - py) < 2 &&
504 event->xbutton.time - vw->down < 500) {
505 /* mouse click */
506 vw->s.x1 = vw->s.x2 = 0;
507 vw->s.y1 = vw->s.y2 = 0;
508 newpage = vbi_findpage(&vw->pg,px,py);
509 if (0 != newpage)
510 vbi_setpage(vw,newpage,VBI_ANY_SUBNO);
511 else
512 vbi_render_page(vw);
513 } else {
514 /* marked region */
515 vw->s.x2 = px +1;
516 vw->s.y2 = py +1;
517 vbi_render_page(vw);
518 selection_pri(vw);
519 }
520 break;
521 case 4: /* wheel up */
522 newpage = vbi_calc_page(vw->pgno,-1);
523 vbi_setpage(vw,newpage,VBI_ANY_SUBNO);
524 break;
525 case 5: /* wheel down */
526 newpage = vbi_calc_page(vw->pgno,+1);
527 vbi_setpage(vw,newpage,VBI_ANY_SUBNO);
528 break;
529 }
530 break;
531 }
532 }
533
534 /* --------------------------------------------------------------------- */
535 /* export data */
536
537 static void
538 export_do_save_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
539 {
540 static struct vbi_rect rect = {
541 x1: 0,
542 x2: 41,
543 y1: 0,
544 y2: 25,
545 };
546 XmFileSelectionBoxCallbackStruct *cb = call_data;
547 struct vbi_window *vw = clientdata;
548 char *filename, *data;
549 int len,fh;
550
551 if (cb->reason == XmCR_OK) {
552 filename = XmStringUnparse(cb->value,NULL,
553 XmMULTIBYTE_TEXT,XmMULTIBYTE_TEXT,
554 NULL,0,0);
555 data = malloc(25*41*8);
556 len = vbi_export_txt(data,vw->charset,25*41*8,&vw->pg,&rect,
557 VBI_NOCOLOR);
558 fh = open(filename,O_WRONLY | O_CREAT, 0666);
559 if (-1 == fh) {
560 fprintf(stderr,"open %s: %s\n",filename,strerror(errno));
561 } else {
562 ftruncate(fh,0);
563 write(fh,data,len);
564 close(fh);
565 }
566 free(data);
567 }
568 XtUnmanageChild(widget);
569 }
570
571 static void
572 export_charset_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
573 {
574 struct vbi_window *vw = clientdata;
575 vw->charset = XtName(widget);
576 }
577
578 static void
579 export_save_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
580 {
581 struct vbi_window *vw = clientdata;
582 Widget help,text,menu,option,push;
583 Arg args[2];
584
585 if (NULL == vw->savebox) {
586 vw->savebox = XmCreateFileSelectionDialog(vw->shell,"save",NULL,0);
587 help = XmFileSelectionBoxGetChild(vw->savebox,XmDIALOG_HELP_BUTTON);
588 text = XmFileSelectionBoxGetChild(vw->savebox,XmDIALOG_TEXT);
589 XtUnmanageChild(help);
590
591 menu = XmCreatePulldownMenu(vw->savebox,"formatM",NULL,0);
592 XtSetArg(args[0],XmNsubMenuId,menu);
593 option = XmCreateOptionMenu(vw->savebox,"format",args,1);
594 XtManageChild(option);
595
596 vw->charset = nl_langinfo(CODESET);
597 push = XtVaCreateManagedWidget(vw->charset,xmPushButtonWidgetClass,
598 menu, NULL);
599 XtAddCallback(push,XmNactivateCallback,export_charset_cb,vw);
600 if (0 != strcasecmp(vw->charset,"UTF-8")) {
601 push = XtVaCreateManagedWidget("UTF-8",
602 xmPushButtonWidgetClass,menu,NULL);
603 XtAddCallback(push,XmNactivateCallback,export_charset_cb,vw);
604 }
605 if (0 != strcasecmp(vw->charset,"ISO-8859-1")) {
606 push = XtVaCreateManagedWidget("ISO-8859-1",
607 xmPushButtonWidgetClass,menu,NULL);
608 XtAddCallback(push,XmNactivateCallback,export_charset_cb,vw);
609 }
610 if (0 != strcasecmp(vw->charset,"US-ASCII")) {
611 push = XtVaCreateManagedWidget("US-ASCII",
612 xmPushButtonWidgetClass,menu,NULL);
613 XtAddCallback(push,XmNactivateCallback,export_charset_cb,vw);
614 }
615 XtAddCallback(vw->savebox,XmNokCallback,export_do_save_cb,vw);
616 XtAddCallback(vw->savebox,XmNcancelCallback,export_do_save_cb,vw);
617 }
618 XtManageChild(vw->savebox);
619 }
620
621 /* --------------------------------------------------------------------- */
622 /* selection handling (cut+paste, drag'n'drop) */
623
624 static struct vbi_selection*
625 selection_find(struct vbi_window *vw, Atom selection)
626 {
627 struct list_head *item;
628 struct vbi_selection *sel;
629
630 list_for_each(item,&vw->selections) {
631 sel = list_entry(item, struct vbi_selection, list);
632 if (sel->atom == selection)
633 return sel;
634 }
635 return NULL;
636 }
637
638 static void
639 selection_fini(struct vbi_window *vw, Atom selection)
640 {
641 struct vbi_selection *sel;
642
643 sel = selection_find(vw,selection);
644 if (NULL == sel)
645 return;
646 if (sel->pix)
647 XFreePixmap(XtDisplay(vw->tt),sel->pix);
648
649 list_del(&sel->list);
650 free(sel);
651 }
652
653 static void
654 selection_init(struct vbi_window *vw, Atom selection)
655 {
656 struct vbi_selection *sel;
657
658 selection_fini(vw,selection);
659 sel = malloc(sizeof(*sel));
660 memset(sel,0,sizeof(*sel));
661 list_add_tail(&sel->list,&vw->selections);
662 sel->atom = selection;
663 sel->pg = vw->pg;
664 sel->rect = vw->s;
665 vbi_check_rectangle(&sel->rect);
666 if (0 == sel->rect.x2 && 0 == sel->rect.y2) {
667 sel->rect.x2 = 41;
668 sel->rect.y2 = 25;
669 }
670 }
671
672 static Atom selection_unique_atom(struct vbi_window *vw)
673 {
674 char id_name[32];
675 Atom id;
676 int i;
677
678 for (i = 0;; i++) {
679 sprintf(id_name,"_VBI_DATA_%lX_%d",XtWindow(vw->tt),i);
680 id = XInternAtom(XtDisplay(vw->tt),id_name,False);
681 if (NULL == selection_find(vw,id))
682 break;
683 }
684 return id;
685 }
686
687 static void
688 selection_convert_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
689 {
690 XmConvertCallbackStruct *ccs = call_data;
691 struct vbi_window *vw = clientdata;
692 struct vbi_selection *sel;
693 Display *dpy = XtDisplay(widget);
694 unsigned long *ldata;
695 unsigned char *cdata;
696 Atom *targs;
697 int n;
698
699 if (tt_debug) {
700 char *y = !ccs->type ? NULL : XGetAtomName(dpy,ccs->type);
701 char *t = !ccs->target ? NULL : XGetAtomName(dpy,ccs->target);
702 char *s = !ccs->selection ? NULL : XGetAtomName(dpy,ccs->selection);
703 fprintf(stderr,"tt: target=%s type=%s selection=%s\n",t,y,s);
704 if (y) XFree(y);
705 if (t) XFree(t);
706 if (s) XFree(s);
707 }
708
709 if ((ccs->target == XA_TARGETS) ||
710 (ccs->target == _MOTIF_CLIPBOARD_TARGETS) ||
711 (ccs->target == _MOTIF_DEFERRED_CLIPBOARD_TARGETS) ||
712 (ccs->target == _MOTIF_EXPORT_TARGETS)) {
713 /* query convert capabilities */
714 n = 0;
715 targs = (Atom*)XtMalloc(sizeof(Atom)*32);
716 if (ccs->target != _MOTIF_CLIPBOARD_TARGETS) {
717 targs[n++] = XA_TARGETS;
718 targs[n++] = XA_PIXMAP;
719 targs[n++] = XA_COLORMAP;
720 targs[n++] = XA_FOREGROUND;
721 targs[n++] = XA_BACKGROUND;
722 targs[n++] = MIME_TEXT_UTF_8;
723 targs[n++] = XA_UTF8_STRING;
724 targs[n++] = MIME_TEXT_ISO8859_1;
725 targs[n++] = XA_STRING;
726 }
727 if (ccs->target == _MOTIF_EXPORT_TARGETS) {
728 /* save away drag'n'drop data */
729 selection_init(vw,ccs->selection);
730 }
731 ccs->value = targs;
732 ccs->length = n;
733 ccs->type = XA_ATOM;
734 ccs->format = 32;
735 ccs->status = XmCONVERT_DONE;
736 return;
737
738 } else if (ccs->target == _MOTIF_SNAPSHOT) {
739 /* save away clipboard data */
740 n = 0;
741 targs = (Atom*)XtMalloc(sizeof(Atom));
742 targs[n++] = selection_unique_atom(vw);
743 selection_init(vw,targs[0]);
744 ccs->value = targs;
745 ccs->length = n;
746 ccs->type = XA_ATOM;
747 ccs->format = 32;
748 ccs->status = XmCONVERT_DONE;
749 return;
750 }
751
752 /* find data */
753 sel = selection_find(vw,ccs->selection);
754 if (NULL == sel) {
755 /* shouldn't happen */
756 fprintf(stderr,"tt: oops: selection data not found\n");
757 ccs->status = XmCONVERT_REFUSE;
758 return;
759 }
760
761 if (ccs->target == _MOTIF_LOSE_SELECTION ||
762 ccs->target == XA_DONE) {
763 /* cleanup */
764 selection_fini(vw,ccs->selection);
765 if (XA_PRIMARY == ccs->selection) {
766 /* unmark selection */
767 vw->s.x1 = vw->s.x2 = 0;
768 vw->s.y1 = vw->s.y2 = 0;
769 vbi_render_page(vw);
770 }
771 ccs->value = NULL;
772 ccs->length = 0;
773 ccs->type = XA_INTEGER;
774 ccs->format = 32;
775 ccs->status = XmCONVERT_DONE;
776 return;
777 }
778
779 /* convert data */
780 if (ccs->target == XA_STRING ||
781 ccs->target == MIME_TEXT_ISO8859_1) {
782 cdata = XtMalloc(25*41*8);
783 n = vbi_export_txt(cdata,"ISO8859-1",25*41*8,&sel->pg,&sel->rect,
784 VBI_NOCOLOR);
785 ccs->value = cdata;
786 ccs->length = n;
787 ccs->type = XA_STRING;
788 ccs->format = 8;
789 ccs->status = XmCONVERT_DONE;
790
791 } else if (ccs->target == XA_UTF8_STRING ||
792 ccs->target == MIME_TEXT_UTF_8) {
793 cdata = XtMalloc(25*41*8);
794 n = vbi_export_txt(cdata,"UTF-8",25*41*8,&sel->pg,&sel->rect,
795 VBI_NOCOLOR);
796 ccs->value = cdata;
797 ccs->length = n;
798 ccs->type = XA_STRING;
799 ccs->format = 8;
800 ccs->status = XmCONVERT_DONE;
801
802 } else if (ccs->target == XA_BACKGROUND ||
803 ccs->target == XA_FOREGROUND ||
804 ccs->target == XA_COLORMAP) {
805 n = 0;
806 ldata = (Atom*)XtMalloc(sizeof(Atom)*8);
807 if (ccs->target == XA_BACKGROUND) {
808 ldata[n++] = WhitePixelOfScreen(XtScreen(widget));
809 ccs->type = XA_PIXEL;
810 }
811 if (ccs->target == XA_FOREGROUND) {
812 ldata[n++] = BlackPixelOfScreen(XtScreen(widget));
813 ccs->type = XA_PIXEL;
814 }
815 if (ccs->target == XA_COLORMAP) {
816 ldata[n++] = DefaultColormapOfScreen(XtScreen(widget));
817 ccs->type = XA_COLORMAP;
818 }
819 ccs->value = ldata;
820 ccs->length = n;
821 ccs->format = 32;
822 ccs->status = XmCONVERT_DONE;
823
824 } else if (ccs->target == XA_PIXMAP) {
825 /* xfer pixmap */
826 if (!sel->pix)
827 sel->pix = vbi_export_pixmap(vw,&sel->pg,&sel->rect);
828 if (tt_debug)
829 fprintf(stderr,"tt: pixmap id is 0x%lx\n",sel->pix);
830 ldata = (Pixmap*)XtMalloc(sizeof(Pixmap));
831 ldata[0] = sel->pix;
832 ccs->value = ldata;
833 ccs->length = 1;
834 ccs->type = XA_DRAWABLE;
835 ccs->format = 32;
836 ccs->status = XmCONVERT_DONE;
837
838 } else {
839 /* shouldn't happen */
840 fprintf(stderr,"tt: oops: target not found\n");
841 ccs->status = XmCONVERT_REFUSE;
842 }
843 }
844
845 static void
846 selection_pri(struct vbi_window *vw)
847 {
848 if (tt_debug)
849 fprintf(stderr,"tt: primary\n");
850
851 selection_init(vw,XA_PRIMARY);
852 XmePrimarySource(vw->tt,XtLastTimestampProcessed(XtDisplay(vw->tt)));
853 }
854
855 static void
856 selection_clip_cb(Widget widget, XtPointer clientdata, XtPointer call_data)
857 {
858 struct vbi_window *vw = clientdata;
859
860 if (tt_debug)
861 fprintf(stderr,"tt: clipboard [copy]\n");
862
863 XmeClipboardSource(vw->tt,XmCOPY,
864 XtLastTimestampProcessed(XtDisplay(vw->tt)));
865 }
866
867 static void
868 selection_dnd_done(Widget widget, XtPointer clientdata, XtPointer call_data)
869 {
870 struct vbi_window *vw = clientdata;
871
872 if (tt_debug)
873 fprintf(stderr,"tt: dnd done\n");
874 selection_fini(vw,_MOTIF_DROP);
875 }
876
877 static void
878 selection_dnd_start(struct vbi_window *vw, XEvent *event)
879 {
880 Widget drag;
881 Arg args[4];
882 Cardinal n=0;
883
884 if (tt_debug)
885 fprintf(stderr,"tt: dnd start\n");
886 n = 0;
887 XtSetArg(args[n], XmNdragOperations, XmDROP_COPY); n++;
888 drag = XmeDragSource(vw->tt, NULL, event, args, n);
889 XtAddCallback(drag, XmNdragDropFinishCallback, selection_dnd_done, vw);
890 }
891
892 /* --------------------------------------------------------------------- */
893
894 static void vbi_station_cb(Widget widget, XtPointer client, XtPointer call)
895 {
896 struct vbi_state *vbi = client;
897 char *name = XtName(widget);
898 int i;
899
900 for (i = 0; i < count; i++)
901 if (0 == strcmp(channels[i]->name,name))
902 break;
903 if (i == count)
904 return;
905 #if 0
906 fprintf(stderr,"tune: %.3f MHz [channel %s, station %s]\n",
907 channels[i]->freq / 16.0,
908 channels[i]->cname,
909 channels[i]->name);
910 #endif
911
912 #ifdef linux
913 #include "videodev.h"
914 if (-1 == ioctl(vbi->fd,VIDIOCSFREQ,&channels[i]->freq))
915 perror("ioctl VIDIOCSFREQ");
916 #endif
917 /* FIXME: should add some BSD code once libzvbi is ported ... */
918 }
919
920 static void vbi_station_menu(Widget menubar, struct vbi_state *vbi)
921 {
922 struct {
923 char *name;
924 Widget menu;
925 } *sub = NULL;
926 int subs = 0;
927
928 Widget m,menu,push;
929 XmString label;
930 int i,j;
931
932 if (0 == count)
933 return;
934
935 menu = XmCreatePulldownMenu(menubar,"stationM",NULL,0);
936 XtVaCreateManagedWidget("station",xmCascadeButtonWidgetClass,menubar,
937 XmNsubMenuId,menu,NULL);
938
939 for (i = 0; i < count; i++) {
940 #if 0
941 if (channels[i]->key) {
942 if (2 == sscanf(channels[i]->key,
943 "%15[A-Za-z0-9_]+%31[A-Za-z0-9_]",
944 ctrl,key)) {
945 sprintf(accel,"%s<Key>%s",ctrl,key);
946 } else {
947 sprintf(accel,"<Key>%s",channels[i]->key);
948 }
949 } else {
950 accel[0] = 0;
951 }
952 #endif
953
954 m = menu;
955 if (0 != strcmp(channels[i]->group,"main")) {
956 for (j = 0; j < subs; j++)
957 if (0 == strcmp(channels[i]->group,sub[j].name))
958 break;
959 if (j == subs) {
960 subs++;
961 sub = realloc(sub, subs * sizeof(*sub));
962 sub[j].name = channels[i]->group;
963 sub[j].menu = XmCreatePulldownMenu(menu,
964 channels[i]->group,
965 NULL,0);
966 XtVaCreateManagedWidget(channels[i]->group,
967 xmCascadeButtonWidgetClass, menu,
968 XmNsubMenuId, sub[j].menu,
969 NULL);
970 }
971 m = sub[j].menu;
972 }
973
974 label = XmStringGenerate(channels[i]->name, NULL, XmMULTIBYTE_TEXT, NULL);
975 push = XtVaCreateManagedWidget(channels[i]->name,
976 xmPushButtonWidgetClass,m,
977 XmNlabelString,label,
978 NULL);
979 XtAddCallback(push,XmNactivateCallback,vbi_station_cb,vbi);
980 XmStringFree(label);
981 }
982 }
983
984 static int fntcmp(const void *a, const void *b)
985 {
986 char const * const *aa = a;
987 char const * const *bb = b;
988
989 return strcmp(*aa,*bb);
990 }
991
992 static void vbi_xft_font_menu(Widget menu, struct vbi_window *vw)
993 {
994 #ifdef HAVE_XFT
995 FcPattern *pattern;
996 FcObjectSet *oset;
997 FcFontSet *fset;
998 Widget push;
999 XmString label;
1000 char **fonts, *h;
1001 int i;
1002
1003 pattern = FcNameParse(":style=Regular:spacing=100:slant=0:weight=100");
1004 oset = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_SPACING, FC_SLANT,
1005 FC_WEIGHT, NULL);
1006 fset = FcFontList(NULL, pattern, oset);
1007 FcPatternDestroy(pattern);
1008 if (fset) {
1009 XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL);
1010 fonts = malloc(sizeof(char*) * fset->nfont);
1011 for (i = 0; i < fset->nfont; i++)
1012 fonts[i] = FcNameUnparse (fset->fonts[i]);
1013 qsort(fonts,fset->nfont,sizeof(char*),fntcmp);
1014
1015 for (i = 0; i < fset->nfont; i++) {
1016 push = XtVaCreateManagedWidget(fonts[i],xmPushButtonWidgetClass,menu,NULL);
1017 h = strchr(fonts[i],':');
1018 if (h)
1019 *h = 0;
1020 label = XmStringGenerate(fonts[i], NULL, XmMULTIBYTE_TEXT, NULL);
1021 XtVaSetValues(push, XmNlabelString, label, NULL);
1022 XmStringFree(label);
1023
1024 XtAddCallback(push, XmNactivateCallback, vbi_font_cb, vw);
1025 }
1026
1027 for (i = 0; i < fset->nfont; i++)
1028 free(fonts[i]);
1029 free(fonts);
1030 }
1031 #endif
1032 }
1033
1034 /* --------------------------------------------------------------------- */
1035
1036 void vbi_create_widgets(Widget shell, struct vbi_state *vbi)
1037 {
1038 Widget form,menubar,tool,menu,push,tt;
1039 struct vbi_window *vw;
1040 int i;
1041
1042 /* form container */
1043 XtVaSetValues(shell, XmNallowShellResize, True, NULL);
1044 form = XtVaCreateManagedWidget("form", xmFormWidgetClass, shell,
1045 NULL);
1046
1047 /* menu- & toolbar */
1048 menubar = XmCreateMenuBar(form,"bar",NULL,0);
1049 XtManageChild(menubar);
1050 tool = XtVaCreateManagedWidget("tool",xmRowColumnWidgetClass,form,NULL);
1051
1052 /* main view */
1053 tt = XtVaCreateManagedWidget("tt", xmDrawingAreaWidgetClass,form, NULL);
1054 vw = vbi_render_init(shell,tt,vbi);
1055 XtVaSetValues(tt,XmNwidth,vw->w*41,XmNheight,vw->h*25,NULL);
1056 XtAddEventHandler(tt,KeyPressMask,
1057 False,vbi_kbd_eh,vw);
1058 XtAddEventHandler(tt,ButtonPressMask|ButtonReleaseMask|Button1MotionMask,
1059 False,vbi_mouse_eh,vw);
1060 XtAddCallback(tt,XmNexposeCallback,vbi_expose_cb,vw);
1061 XtAddCallback(tt,XmNdestroyCallback,vbi_destroy_cb,vw);
1062 XtAddCallback(tt,XmNconvertCallback,selection_convert_cb,vw);
1063 vbi_event_handler_register(vw->vbi->dec,~0,vbi_newdata,vw);
1064
1065 /* menu -- file */
1066 menu = XmCreatePulldownMenu(menubar,"fileM",NULL,0);
1067 XtVaCreateManagedWidget("file",xmCascadeButtonWidgetClass,menubar,
1068 XmNsubMenuId,menu,NULL);
1069 push = XtVaCreateManagedWidget("new",xmPushButtonWidgetClass,menu,NULL);
1070 XtAddCallback(push,XmNactivateCallback,vbi_new_cb,vw);
1071 push = XtVaCreateManagedWidget("save",xmPushButtonWidgetClass,menu,NULL);
1072 XtAddCallback(push,XmNactivateCallback,export_save_cb,vw);
1073 XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,menu,NULL);
1074 push = XtVaCreateManagedWidget("quit",xmPushButtonWidgetClass,menu,NULL);
1075 XtAddCallback(push,XmNactivateCallback,vbi_close_cb,vw);
1076
1077 /* menu -- edit */
1078 menu = XmCreatePulldownMenu(menubar,"editM",NULL,0);
1079 XtVaCreateManagedWidget("edit",xmCascadeButtonWidgetClass,menubar,
1080 XmNsubMenuId,menu,NULL);
1081 push = XtVaCreateManagedWidget("copy",xmPushButtonWidgetClass,menu,NULL);
1082 XtAddCallback(push,XmNactivateCallback,selection_clip_cb,vw);
1083
1084 /* menu -- go (navigation) */
1085 menu = XmCreatePulldownMenu(menubar,"goM",NULL,0);
1086 XtVaCreateManagedWidget("go",xmCascadeButtonWidgetClass,menubar,
1087 XmNsubMenuId,menu,NULL);
1088 push = XtVaCreateManagedWidget("100",xmPushButtonWidgetClass,menu,NULL);
1089 XtAddCallback(push,XmNactivateCallback,vbi_goto_cb,vw);
1090 push = XtVaCreateManagedWidget("prev",xmPushButtonWidgetClass,menu,NULL);
1091 XtAddCallback(push,XmNactivateCallback,vbi_goto_cb,vw);
1092 push = XtVaCreateManagedWidget("next",xmPushButtonWidgetClass,menu,NULL);
1093 XtAddCallback(push,XmNactivateCallback,vbi_goto_cb,vw);
1094
1095 /* menu -- subpage */
1096 vw->submenu = XmCreatePulldownMenu(menubar,"subpageM",NULL,0);
1097 vw->subbtn = XtVaCreateManagedWidget("subpage",xmCascadeButtonWidgetClass,
1098 menubar,
1099 XmNsubMenuId,vw->submenu,NULL);
1100
1101 /* menu -- stations */
1102 vbi_station_menu(menubar,vbi);
1103
1104 /* menu -- fonts */
1105 menu = XmCreatePulldownMenu(menubar,"fontM",NULL,0);
1106 XtVaCreateManagedWidget("font",xmCascadeButtonWidgetClass,menubar,
1107 XmNsubMenuId,menu,NULL);
1108 for (i = 0; vbi_fonts[i].label != NULL; i++) {
1109 push = XtVaCreateManagedWidget(vbi_fonts[i].label,
1110 xmPushButtonWidgetClass,menu,NULL);
1111 XtAddCallback(push,XmNactivateCallback,vbi_font_cb,vw);
1112 }
1113 vbi_xft_font_menu(menu,vw);
1114
1115 /* toolbar */
1116 push = XtVaCreateManagedWidget("100",xmPushButtonWidgetClass,tool,NULL);
1117 XtAddCallback(push,XmNactivateCallback,vbi_goto_cb,vw);
1118 XtAddEventHandler(push,KeyPressMask,False,vbi_kbd_eh,vw);
1119 push = XtVaCreateManagedWidget("prev",xmPushButtonWidgetClass,tool,NULL);
1120 XtAddCallback(push,XmNactivateCallback,vbi_goto_cb,vw);
1121 XtAddEventHandler(push,KeyPressMask,False,vbi_kbd_eh,vw);
1122 push = XtVaCreateManagedWidget("next",xmPushButtonWidgetClass,tool,NULL);
1123 XtAddCallback(push,XmNactivateCallback,vbi_goto_cb,vw);
1124 XtAddEventHandler(push,KeyPressMask,False,vbi_kbd_eh,vw);
1125 XtVaCreateManagedWidget("sep",xmSeparatorWidgetClass,tool,NULL);
1126 push = XtVaCreateManagedWidget("exit",xmPushButtonWidgetClass,tool,NULL);
1127 XtAddCallback(push,XmNactivateCallback,vbi_close_cb,vw);
1128 XtAddEventHandler(push,KeyPressMask,False,vbi_kbd_eh,vw);
1129
1130 /* shell stuff */
1131 XmdRegisterEditres(shell);
1132 XmAddWMProtocolCallback(shell,WM_DELETE_WINDOW,vbi_close_cb,vw);
1133
1134 /* set start page */
1135 vbi_setpage(vw,0x100,VBI_ANY_SUBNO);
1136 tt_windows++;
1137 }
1138
|
This page was automatically generated by the
LXR engine.
|