#include #include #include #include #include #include #include #include #include #include "xlocale.h" #include "MsgShellP.h" #include "parse.h" static void ClassInitialize(void); static void Initialize(Widget, Widget, ArgList args, Cardinal * num); static void Destroy(Widget); static void Resize(Widget); static void Realize(Widget, XtValueMask*, XSetWindowAttributes *); static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *); static void Exposure(Widget widget, XEvent *ev, Region region); /* private */ static void DeleteInputWin(MsgShellWidget msw); static void SetInputWin(MsgShellWidget msw); static void InputHandler(XtPointer cl, int *fdp, XtInputId *id); static void OutputHandler(XtPointer cl, int *fdp, XtInputId *id); static void TimerHandler(XtPointer cl, XtIntervalId *id); static void MsgShellDestroy(Widget w, XEvent *ev, String *p, Cardinal *n); static void MsgShellDragStart(Widget w, XEvent *ev, String *p, Cardinal *n); static void MsgShellDrag(Widget w, XEvent *ev, String *p, Cardinal *n); static void MsgShellGetURL(Widget w, XEvent *ev, String *p, Cardinal *n); #define offset(field) XtOffsetOf(MsgShellRec, msg.field) /* resouces */ static XtResource resources[] = { {XtNfileid, XtCFileid, XtRInt, sizeof(int), offset(fd), XtRImmediate, (XtPointer)-1}, {XtNfileidout, XtCFileid, XtRInt, sizeof(int), offset(fdout), XtRImmediate, (XtPointer)-1}, {XtNfile, XtCFile, XtRString, sizeof(String), offset(filename), XtRImmediate, (String)NULL}, {XtNdiffxpos, XtCDiffpos, XtRInt, sizeof(int), offset(dx), XtRImmediate, (XtPointer)0}, {XtNdiffypos, XtCDiffpos, XtRInt, sizeof(int), offset(dy), XtRImmediate, (XtPointer)0}, {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor), offset(cursor), XtRString, (XtPointer)"FONT cursor 68 cursor 69"}, {XtNhrefcursor, XtCCursor, XtRCursor, sizeof(Cursor), offset(href_cursor), XtRString,(XtPointer)"FONT cursor 60 cursor 61"}, {XtNhukidasi, XtCHukidasi, XtRBoolean, sizeof(Boolean), offset(hukidasi), XtRImmediate, (XtPointer)True}, }; static XtActionsRec actions[] = { {"msgshell_destroy", MsgShellDestroy}, {"msgshell_dragstart", MsgShellDragStart}, {"msgshell_drag", MsgShellDrag}, {"msgshell_geturl", MsgShellGetURL} }; static char translations[] = "WM_PROTOCOLS: msgshell_destroy()\n" ": msgshell_geturl(0)\n" ": msgshell_geturl(1)\n" ": msgshell_dragstart()\n" ": msgshell_drag()\n"; MsgShellClassRec msgShellClassRec = { { /* superclass */ (WidgetClass) (&topLevelShellClassRec), /* class_name */ "MsgShell", /* size */ sizeof(MsgShellRec), /* class_initialize */ ClassInitialize, /* class_part_initialize */ NULL, /* Class init'ed */ FALSE, /* initialize */ Initialize, /* initialize_hook */ NULL, /* realize */ Realize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* resource_count */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ FALSE, /* visible_interest */ FALSE, /* destroy */ Destroy, /* resize */ Resize, /* expose */ Exposure, /* set_values */ SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* intrinsics version */ XtVersion, /* callback offsets */ NULL, /* tm_table */ translations, /* query_geometry */ NULL, /* display_accelerator */ NULL, /* extension */ NULL },{ /* geometry_manager */ XtInheritGeometryManager, /* change_managed */ XtInheritChangeManaged, /* insert_child */ XtInheritInsertChild, /* delete_child */ XtInheritDeleteChild, /* extension */ NULL },{ /* extension */ NULL },{ /* extension */ NULL },{ /* extension */ NULL },{ /* extension */ NULL },{ /* extension */ NULL, /* fontinfotables */ } }; WidgetClass msgShellWidgetClass = (WidgetClass)&msgShellClassRec; #define FILENAME (msw->msg.filename) #define MSGWIN (msw->msg.msgwin) #define FRAME (msw->msg.frame) #define FILEDESC (msw->msg.fd) #define FILEDESCO (msw->msg.fdout) #define TIMERID (msw->msg.timer_id) #define INPUTID (msw->msg.input_id) #define OUTPUTID (msw->msg.output_id) #define MSGLIST (msw->msg.msglist) #define CURSOR (msw->msg.cursor) #define HREFCURSOR (msw->msg.href_cursor) #define INPUTWINDOWS (msw->msg.inputwindows) #define INPUTWINDOWS_NUM (msw->msg.inputwindows_num) #define CLICKX (msw->msg.click_x) #define CLICKY (msw->msg.click_y) #define DX (msw->msg.dx) #define DY (msw->msg.dy) #define HUKIDASI (msw->msg.hukidasi) #define FNL (msw->msg.fnl) #define FNLFIXED (msw->msg.fnl_fixed) #define OLDFILENAME (old->msg.filename) #define OLDMSGWIN (old->msg.msgwin) #define OLDFRAME (old->msg.frame) #define OLDFILEDESC (old->msg.fd) #define OLDTIMERID (old->msg.timer_id) #define OLDINPUTID (old->msg.input_id) static Boolean XtQuarkCvt(Display *dpy, XrmValue *args, Cardinal *num, XrmValue *from, XrmValue *to, XtPointer *converter_data) { XrmQuark *ret = (XrmQuark*)to->addr; if (from->addr == NULL) *ret = None; else *ret = XrmStringToQuark((String)from->addr); return TRUE; } static void ClassInitialize(void) { XtSetTypeConverter(XtRString, XtRQuark, XtQuarkCvt, NULL, 0, XtCacheNone, NULL); } static XtResource font_resources[] = { {"foundry", "Foundry", XtRQuark, sizeof(XrmQuark), XtOffsetOf(FontName, foundry), XtRImmediate, (XtPointer)None}, {"name", "Name", XtRQuark, sizeof(XrmQuark), XtOffsetOf(FontName, name), XtRImmediate, (XtPointer)None}, {"point", "Point", XtRInt, sizeof(int), XtOffsetOf(FontName, base_point), XtRImmediate, (XPointer)120} }; static struct fontres { wchar_t head; char *name; } font_resdat[] = { { HEAD_ISO8859_1, "iso8859-1" }, { HEAD_JISX0208, "jisx0208" }, { HEAD_JISX0201, "jisx0201" }, { HEAD_JIS_ROMAN, "jisx0201" }, { HEAD_JISX0212, "jisx0212" }, { HEAD_ISO8859_2, "iso8859-2" }, { HEAD_ISO8859_3, "iso8859-3" }, { HEAD_ISO8859_4, "iso8859-4" }, { HEAD_ISO8859_5, "iso8859-5" }, { HEAD_ISO8859_6, "iso8859-6" }, { HEAD_ISO8859_7, "iso8859-7" }, { HEAD_ISO8859_8, "iso8859-8" }, { HEAD_ISO8859_9, "iso8859-9" }, { HEAD_KSC5601, "ksc5601" }, { 0x62310000, "viscii1_1" }, { 0x62540000, "tis620_2529" }, { HEAD_GB2312, "gb2312" }, { HEAD_CNS11643_1, "cns11643_1" }, { HEAD_CNS11643_2, "cns11643_2" }, { HEAD_UNICODE, "unicode1_1" } }; static void Initialize(Widget req, Widget new, ArgList args, Cardinal * num) { MsgShellWidget msw = (MsgShellWidget)new; MSGWIN = NULL; FRAME = NULL; TIMERID = 0; INPUTID = 0; OUTPUTID = 0; MSGLIST = NULL; CLICKX = CLICKY = 0; INPUTWINDOWS = NULL; INPUTWINDOWS_NUM = 0; /* make fontname list */ FNL = NULL; FNLFIXED = NULL; { int i; FontName *p, *q; for (i=0;ihead = q->head = font_resdat[i].head; sprintf(buf, "font_%s", font_resdat[i].name); XtGetSubresources(new, p, buf, "Font", font_resources, XtNumber(font_resources), NULL, 0); sprintf(buf, "fixed_%s", font_resdat[i].name); XtGetSubresources(new, q, buf, "Fixed", font_resources, XtNumber(font_resources), NULL, 0); /* add to list */ p->next = FNL; FNL = p; q->next = FNLFIXED; FNLFIXED = q; } } } static void DeleteInputWin(MsgShellWidget msw) { int i; if (INPUTWINDOWS) { for (i=0;i< INPUTWINDOWS_NUM;i++) XDestroyWindow(XtDisplay((Widget)msw), INPUTWINDOWS[i]); free(INPUTWINDOWS); INPUTWINDOWS = NULL; INPUTWINDOWS_NUM = 0; } } static void SetInputWin(MsgShellWidget msw) { int n = 0; HTMLObj *p = FRAME->disp_start; Display *dpy = XtDisplay((Widget)msw); Window win = XtWindow((Widget)msw); DeleteInputWin(msw); while (p != FRAME->disp_end) { if (p->link) n++; p = p->next; } if (n > 0) { p = FRAME->disp_start; if ((INPUTWINDOWS = malloc(sizeof(*INPUTWINDOWS) * n))) { Window *w = INPUTWINDOWS; XSetWindowAttributes attr; attr.cursor = HREFCURSOR; while (p != FRAME->disp_end) { if (p->link) { int x1 = p->x + p->lbearing - FRAME->scr_x + FRAME->off_x; int y1 = p->y - p->ascent - FRAME->scr_y + FRAME->off_y; *w = XCreateWindow(dpy, win, x1, y1, p->width, p->height, 0, 0, InputOnly, CopyFromParent, CWCursor, &attr); XMapWindow(dpy, *w++); } p = p->next; } } } } static void CloseHandler(XtPointer cl, int *fdp, XtInputId *id) { int len; char buf[100]; if ((len = read(*fdp, buf, sizeof(buf))) < 0) { perror("CLoseHandler"); XtRemoveInput(*id); close(*fdp); } else if (len == 0) { XtRemoveInput(*id); close(*fdp); } } static void MyClose(Widget widget, int fd) { struct stat sb; if (fstat(fd, &sb) < 0) { perror("MsgShell MyCLose"); close(fd); } else { if (S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) XtAppAddInput(XtWidgetToApplicationContext(widget), fd, (XtPointer)XtInputReadMask, CloseHandler, NULL); else close(fd); } } static void Destroy(Widget widget) { MsgShellWidget msw = (MsgShellWidget)widget; if (TIMERID) XtRemoveTimeOut(TIMERID); if (INPUTID) XtRemoveInput(INPUTID); if (OUTPUTID) XtRemoveInput(OUTPUTID); if (MSGWIN) msgwin_delete(MSGWIN); if (FRAME) frame_delete(FRAME); DeleteInputWin(msw); msgpacketlist_delete(MSGLIST); if (FILEDESC >= 0) MyClose(widget, FILEDESC); if (FILEDESCO >= 0) close(FILEDESCO); if (FILENAME) free(FILENAME); fontnamelist_delete(FNL); fontnamelist_delete(FNLFIXED); } static void Resize(Widget widget) { MsgShellWidget msw = (MsgShellWidget)widget; if (XtIsRealized(widget) && MSGWIN != NULL && (MSGWIN->w != msw->core.width || MSGWIN->h != msw->core.height)) { if (TIMERID) XtRemoveTimeOut(TIMERID); TIMERID = 0; msgwin_reattach(MSGWIN); frame_resize(FRAME, MSGWIN->clip_w, MSGWIN->clip_h, MSGWIN->off_x, MSGWIN->off_y); MSGWIN->shaped = 0; msgwin_setpos(MSGWIN, MSGWIN->o_xpos, MSGWIN->o_ypos, DX, DY, 1); #if 0 XtMoveWidget(widget, MSGWIN->xpos, MSGWIN->ypos); #endif if (FILEDESC >= 0 && INPUTID == None) { INPUTID = XtAppAddInput(XtWidgetToApplicationContext(widget), FILEDESC, (XtPointer)XtInputReadMask, InputHandler, (XtPointer)widget); } } } static void StartDrawing(MsgShellWidget msw) { if (FILEDESC >= 0 || (FILENAME != NULL && (FILEDESC = open(FILENAME, O_RDONLY, 0)) >= 0)) { frame_open(FRAME, FILEDESC, FILENAME); /* start drawing */ INPUTID = XtAppAddInput(XtWidgetToApplicationContext((Widget)msw), FILEDESC, (XtPointer)XtInputReadMask, InputHandler, (XtPointer)msw); } else fprintf(stderr, "can't open file...\n"); } static void Realize(Widget widget, XtValueMask *value_mask, XSetWindowAttributes *attr) { Display *dpy; Window win; MsgShellWidget msw = (MsgShellWidget)widget; XtRealizeProc realize; realize = msgShellWidgetClass->core_class.superclass->core_class.realize; (*realize)(widget, value_mask, attr); dpy = XtDisplay(widget); win = XtWindow(widget); XDefineCursor(dpy, win, CURSOR); { Atom a[2]; a[0] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); a[1] = XInternAtom(dpy, "WM_SAVEYOURSELF", False); XSetWMProtocols(dpy, win, a, 2); } MSGWIN = msgwin_new(); if (!HUKIDASI) MSGWIN->lx = MSGWIN->ly = 0; msgwin_attach_win(MSGWIN, dpy, win); msgwin_setpos(MSGWIN, widget->core.x, widget->core.y, DX, DY, 1); XtMoveWidget(widget, MSGWIN->xpos, MSGWIN->ypos); FRAME = frame_new(dpy, win, text_get_fftl(dpy), FNL, FNLFIXED, MSGWIN->clip_w, MSGWIN->clip_h, MSGWIN->off_x, MSGWIN->off_y); /* set_coding_system("Shift_JIS"); */ set_coding_system("ISO-2022-JP"); StartDrawing(msw); } static Boolean SetValues(Widget cur, Widget req, Widget new, ArgList args, Cardinal *num_args) { MsgShellWidget old = (MsgShellWidget)cur; MsgShellWidget msw = (MsgShellWidget)new; Boolean redisplay = FALSE; if (OLDFILEDESC != FILEDESC || (FILEDESC == -1 && OLDFILENAME != FILENAME)) { if (OLDTIMERID) XtRemoveTimeOut(OLDTIMERID); TIMERID = 0; if (OLDINPUTID) XtRemoveInput(OLDINPUTID); INPUTID = 0; if (OLDFILEDESC >= 0) MyClose(cur, OLDFILEDESC); if (XtIsRealized(cur)) { StartDrawing(msw); redisplay = TRUE; } } if (OLDFILENAME != FILENAME) { if (OLDFILENAME) free(OLDFILENAME); if (FILENAME) FILENAME = strdup(FILENAME); } return redisplay; } static void Exposure(Widget widget, XEvent *ev, Region region) { MsgShellWidget msw = (MsgShellWidget)widget; if (FRAME) frame_expose_region(FRAME, region); } static u_int timer_go(Frame *f) { TimerDatList list = f->images; HTMLImageObj *io; int ret; TimerDat *p; u_int interval; if (list != NULL ) { if ((p = list->next) != NULL) { retry: io = ((HTMLObj*)(p->data))->data; interval = io->anim->point->interval; ret = animate_go(io->anim); frame_disp_obj(f,p->data); list->next = p->next; if (ret) { if (interval == 0) /* XXX */ interval = 10; mytimer_reentry(list, p->data, p, interval); } else mytimer_delete(p); if ((p = list->next)) { if (list->next->interval == 0) goto retry; return list->next->interval; } } } return 0; } static void InputHandler(XtPointer cl, int *fdp, XtInputId *id) { MsgShellWidget msw = cl; HTMLObj *obj; u_int interval; if (FRAME != NULL && FILEDESC == *fdp) { frame_parse(FRAME); if (FRAME->body) { obj = FRAME->body; while (obj->next != FRAME->body) { obj = obj->next; frame_disp_obj(FRAME, obj); } } if (FRAME->eof) { /* end of input */ XtRemoveInput(INPUTID); INPUTID = None; #if 0 close(FILEDESC); FILEDESC = -1; #endif frame_check_area(FRAME); SetInputWin(msw); /* start animated gif */ if (TIMERID == 0 && (interval = timer_go(FRAME)) > 0) TIMERID = XtAppAddTimeOut(XtWidgetToApplicationContext(cl), interval, TimerHandler, cl); } } } static void OutputHandler(XtPointer cl, int *fdp, XtInputId *id) { MsgShellWidget msw = cl; int len; MsgPacket *m = MSGLIST; if ((len = write(*fdp, m->p, m->len)) < 0) { perror("OutputHandler"); MSGLIST = MSGLIST->next; msgpacket_delete(m); } else { m->p = (char*)(m->p) + len; m->len -= len; if (m->len <= 0) { MSGLIST = MSGLIST->next; msgpacket_delete(m); } } if (!MSGLIST) XtRemoveInput(OUTPUTID); OUTPUTID = 0; } /* timer handler for animated gif */ static void TimerHandler(XtPointer cl, XtIntervalId *id) { MsgShellWidget msw = cl; u_int interval; if ((interval = timer_go(FRAME)) > 0) TIMERID = XtAppAddTimeOut(XtWidgetToApplicationContext(cl), interval, TimerHandler, cl); } static void MsgShellDestroy(Widget w, XEvent *ev, String *p, Cardinal *n) { Display *dpy = XtDisplay(w); if (ev->xclient.data.l[0] ==XInternAtom(dpy, "WM_DELETE_WINDOW", False) || ev->xclient.data.l[0] ==XInternAtom(dpy, "WM_SAVE_YOURSELF", False) ) { XtDestroyWidget(w); } } static void MsgShellDragStart(Widget w, XEvent *ev, String *p, Cardinal *n) { MsgShellWidget msw = (MsgShellWidget)w; CLICKX = ev->xbutton.x; CLICKY = ev->xbutton.y; } static void MsgShellDrag(Widget w, XEvent *ev, String *p, Cardinal *n) { MsgShellWidget msw = (MsgShellWidget)w; frame_scroll(FRAME, CLICKX - ev->xmotion.x, CLICKY - ev->xmotion.y); SetInputWin(msw); CLICKX = ev->xmotion.x; CLICKY = ev->xmotion.y; } static void MsgShellGetURL(Widget w, XEvent *ev, String *p, Cardinal *n) { MsgShellWidget msw = (MsgShellWidget)w; HTMLHrefInfo *href; int mode = 0; if (*n == 1) mode = atoi(p[0]); href = frame_get_url(FRAME, ev->xbutton.x, ev->xbutton.y); if (href) { if (FILEDESCO >= 0) { char *s; int len; if ((s = malloc(len = (sizeof("url:")-1 + strlen(href->url)+2+2))) != NULL){ MsgPacket *p; sprintf(s, "url:%d:%s\n", mode, href->url); #if 0 fprintf(stderr, "%d:%s", len-1, s); #endif p = msgpacket_new(s, len-1); if (MSGLIST == NULL) MSGLIST = p; else { MsgPacket *q = MSGLIST; while (q->next != NULL) q = q->next; q->next = p; } if (!OUTPUTID) OUTPUTID = XtAppAddInput(XtWidgetToApplicationContext(w), FILEDESCO, (XtPointer)XtInputWriteMask, OutputHandler, (XtPointer)w); } } } }