Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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.