#ifndef lint static char sccsid[] = "@(#)SunOSI.c 9.20 88/02/10"; #endif /* * Copyright (c) 1987 by Sun Microsystems, Inc. */ /*- Sun operating system interface routines SunOSI.c, Tue Jul 22 15:12:10 1986 James Gosling, Sun Microsystems */ #include #include #include #include #include #include "PostScript.h" #include "input.h" #include "cscript.h" #include #include #include #include #include #include #include #include #include #ifdef sparc #include #endif #ifdef TemporaryInitHack #undef pr_open #include #include #include #include #include #include #include #include #include #include /* FIXME: XXX Remove references to RepairColorMap */ int vsdev; /* FD of event source (sunwindows window) */ struct scene *CurrentInputScene; /* XXX - AAAAAAARGGGHHHHH! */ static char my_hostname[40]; static u_char sun_red[256], sun_green[256], sun_blue[256]; static void (*sig_TSTP_cache) (); static void (*sig_CONT_cache) (); static void (*sig_IO_cache) (); static void (*sig_VTALRM_cache) (); static void (*sig_WINCH_cache) (); static void sun_win_change(); static void sun_pause(); static void sun_resume(); static void sun_sigio(); static void sun_sigvtalrm(); static void setcolors(); static void remember_colors(); static void sun_set_parent_name(); extern void sun_set_shared_locking_info(); static void set_timeout_alarm(); static void sun_enable_kbd_input(); static void sun_enable_pick_input(); static void sun_disable_pick_input(); static void sun_enter_news_region(); static void sun_exit_news_region(); static short sun_cursor_zone;/* = 16 */ /* * 16 is the width of a normal cursor (16). This is not completely safe but * should work for 90% of the cases. */ static int sun_created_root; static int sun_placeholderfd; static enum kbd_translation { UNENCODED_KEYBOARD, NORMAL_KEYBOARD } sun_current_keyboard; static struct timeval sun_cached_input_timeout; static ttysw_saveparms(); static we_setptyparms(); #endif TemporaryInitHack int news_pid; /* process id of NeWS server */ int raw_keyboard, /* is translation desired? */ raw_mouse; struct body *motion_keyword, *but1_keyword, *but2_keyword, *but3_keyword, *raw_motion_keyword, *raw_but1_keyword, *raw_but2_keyword, *raw_but3_keyword, *up_keyword, *down_keyword; /* * This routine interferrs with load in dload.c. Load currently blocks * SIGCHLD this interaction may need to be fixed someday. */ static reaper() { union wait status; register pid; while ((pid = wait3(&status, WNOHANG, 0)) > 0) if (verbose) fprintf(stderr, "Reaped %d, rv=0%o\n", pid, status.w_retcode); } /* * This is disgusting! It is absolutly essential that we get rid of all the * win_* hacks! */ static startkeyboardandmouse(ee) register struct execution_environment *ee; { extern char *getenv(); register int i; struct screen sc; char *parentname; if (vsdev > 0) return; sig_IO_cache = signal(SIGIO, sun_sigio); sig_WINCH_cache = signal(SIGWINCH, sun_win_change); set_timeout_alarm(); /* See if SunWindows running */ if ((parentname = getenv("WINDOW_PARENT"))) { extern int sun_left, sun_top, sun_width, sun_height; extern char *sun_fb_name; int parentfd; Rect r; char *p2name; int p2fd; Rect r2; struct screen screen; /* Determine screen dimensions */ if ((parentfd = open(parentname, O_RDONLY, 0)) < 0) { fprintf(stderr, "Can't open parent %s\n", parentname); ee->error_code = ioerror_error_code; return; } /* See if parent is on the same screen as sun_fb_name */ win_screenget(parentfd, &screen); if (strcmp(sun_fb_name, screen.scr_fbname) != 0) { close(parentfd); goto NewScreen; } win_getrect(parentfd, &r); /* See if want partial screen capibility */ if (sun_left != 0 || sun_top != 0 || sun_width > 0 || sun_height > 0) { rect_construct(&r, sun_left, sun_top, sun_width, sun_height); /* * See if running under overall by testing for gfx window that * covers the entire screen. */ } else if ((p2name = getenv("WINDOW_GFX"))) { if ((p2fd = open(p2name, O_RDONLY, 0)) < 0) { fprintf(stderr, "Can't open parent %s\n", p2name); ee->error_code = ioerror_error_code; close(parentfd); return; } win_getrect(p2fd, &r2); if (rect_equal(&r, &r2)) { /* Make the gfx window the parent */ close(parentfd); parentfd = p2fd; parentname = p2name; /* Handle stopped server */ sig_TSTP_cache = signal(SIGTSTP, sun_pause); sig_CONT_cache = signal(SIGCONT, sun_resume); } } /* Allocate new window */ if ((vsdev = win_getnewwindow()) < 0) goto NoWin; /* Set window's dimensions */ win_setrect(vsdev, &r); /* Install window as top child of parent */ win_setlink(vsdev, WL_PARENT, win_fdtonumber(parentfd)); win_setlink(vsdev, WL_OLDERSIB, win_getlink(parentfd, WL_TOPCHILD)); /* Set window's colors to match servers */ remember_colors(); setcolors(); /* Make visible */ win_insert(vsdev); close(parentfd); win_setmouseposition(vsdev, r.r_width / 2, r.r_height / 2); cs_movecursor(r.r_width / 2, r.r_height / 2); } else { extern (*RepairColorMap) (); extern char *sun_fb_name; NewScreen: bzero((caddr_t) &sc, sizeof sc); strncpy(sc.scr_fbname, sun_fb_name, SCR_NAMESIZE); { extern char *sun_fb_name; struct pixrect *pr = pr_open(sun_fb_name); if (pr) { if (pr->pr_depth > 1) /* * Set "only use one plane group" flag so SunView on NeWS * programs don't try to use alternate plane groups that * NeWS isn't managing. */ sc.scr_flags |= SCR_8BITCOLORONLY; pr_destroy(pr); } } /* Running alone */ if ((vsdev = win_screennew(&sc)) < 0) goto NoWin; sun_created_root = 1; /* Set window's colors to match servers */ /* Remove references to RepairColorMap */ if (RepairColorMap) /* win_screennew gratuitously trashes the * color map */ (*RepairColorMap) (); remember_colors(); setcolors(); /* * Steal a window for the tool slot allocator & stash its name in the * environment */ if ((sun_placeholderfd = win_getnewwindow()) == -1) { (void) fprintf(stderr, "No window available for placing open windows\n"); perror("PS"); } else { char name[WIN_NAMESIZE]; (void) win_fdtoname(sun_placeholderfd, name); (void) setenv("WMGR_ENV_PLACEHOLDER", name); } } /* Blank out cursor */ zap_cursor(vsdev); /* * Set up name of vsdev in environment so that SunWindows based programs * that are run under NeWS are children of the NeWS window. */ sun_set_parent_name(vsdev); /* Setup tty parameters for all terminal emulators that will start */ { int tty_fd; tty_fd = open("/dev/tty", O_RDWR, 0); if (tty_fd < 0) (void) ttysw_saveparms(2); /* Try stderr */ else { (void) ttysw_saveparms(tty_fd); (void) close(tty_fd); } } /* Set up shared memory locking mechanism */ sun_set_shared_locking_info(vsdev); add_selectable_file(vsdev, 1); if (vsdev > maximum_fd) maximum_fd = vsdev + 1; { /* XXX - this should go in the expressinterest stuff */ struct inputmask im; /* Set kbd mask */ sun_enable_kbd_input(NORMAL_KEYBOARD); /* Set pick mask */ sun_enable_pick_input(); } if (fcntl(vsdev, F_SETFL, O_NDELAY | FASYNC) < 0 || fcntl(vsdev, F_SETFD, 1) < 0) { ee->error_code = ioerror_error_code; return; } sun_enter_news_region(); return; NoWin: fprintf(stderr, "Couldn't get base SunWindow\n"); exit(1); } static void sun_set_parent_name(windowfd) int windowfd; { char name[WIN_NAMESIZE]; /* * Set up name of windowfd in environment so that SunWindows based * programs that are run under NeWS are children of the NeWS window. */ win_fdtoname(windowfd, name); we_setparentwindow(name); } /* Remember the current state of the colormap */ static void remember_colors() { extern char *sun_fb_name; struct pixrect *pr; pr = pr_open(sun_fb_name); pr_getcolormap(pr, 0, 256, sun_red, sun_green, sun_blue); pr_destroy(pr); } /* Set window's colors to match servers */ static void setcolors() { struct colormapseg cms; struct cms_map cmap; /* Init cms to zeros */ bzero((caddr_t) &cms, sizeof(cms)); /* Make window a colormap hog */ cms.cms_addr = 0; cms.cms_size = 256; cmap.cm_red = sun_red; cmap.cm_green = sun_green; cmap.cm_blue = sun_blue; if (!sun_created_root) { /* * Use a non-monochrome colormap segment when there are existing * SunView windows so as to not trash the color state. Colors will * flash when moving between NeWS and SunView, which is better then * trashing existing windows. */ sprintf(cms.cms_name, "NeWS"); } else { /* * Set the monochrome colormap segment to be the colormap hog so as to * reduce the flashing when moving from NeWS to SunView. */ sprintf(cms.cms_name, "monochrome"); } win_setcms(vsdev, &cms, &cmap); } static void sun_win_change(sig, code, scp) int sig, code; struct sigcontext *scp; { /* Just used to kick sched out of select(2) */ if (sig_WINCH_cache != SIG_DFL && sig_WINCH_cache != SIG_IGN) (void) sig_WINCH_cache(sig, code, scp); fcntl(vsdev, F_SETFL, O_NDELAY | FASYNC); } static void sun_pause(sig, code, scp) int sig, code; struct sigcontext *scp; { win_remove(vsdev); if (sig_TSTP_cache != SIG_DFL && sig_TSTP_cache != SIG_IGN) (void) sig_TSTP_cache(sig, code, scp); else kill(getpid(), SIGSTOP); } static void sun_resume(sig, code, scp) int sig, code; struct sigcontext *scp; { win_insert(vsdev); if (sig_CONT_cache != SIG_DFL && sig_CONT_cache != SIG_IGN) (void) sig_CONT_cache(sig, code, scp); } static void sun_sigio(sig, code, scp) int sig, code; struct sigcontext *scp; { extern int io_ready; io_ready = 1; } void make_async(fd) int fd; { register unsigned flags; if (flags = fcntl(fd, F_GETFL) == -1) { perror("getflags"); return; } flags |= FASYNC; if (fcntl(fd, F_SETFL, flags) == -1) perror("setflags"); /* async_files[fd+1] = 1; */ } static void sun_sigvtalrm(sig, code, scp) int sig, code; struct sigcontext *scp; { extern int timeout_ticks, timeout_value; if (--timeout_ticks == 0) { timeout_ticks = timeout_value; if (current_process) current_process->error_code = timeout_error_code; } } static void set_timeout_alarm() { struct itimerval val, oval; sig_VTALRM_cache = signal(SIGVTALRM, sun_sigvtalrm); val.it_interval.tv_sec = 1; val.it_interval.tv_usec = 0; val.it_value.tv_sec = 1; val.it_value.tv_usec = 0; if (setitimer(ITIMER_VIRTUAL, &val, &oval)) { perror("set_timeout_alarm"); } } static fract scene_clipping_matrix[3][2]; static void init_scene_clipping_matrix() { /* {fracti(1), 0, 0, fracti(1), 0, 0} */ register fract *ptr = &scene_clipping_matrix[0][0]; *ptr++ = fracti(1); *ptr++ = 0; *ptr++ = 0; *ptr++ = fracti(1); *ptr++ = 0; *ptr = 0; } /* This routine unacceptably reaches around the CScript interface */ damage_everything(cv) register struct canvas *cv; { if (cv == 0) return; if (!cv->transparent && cv->mapped) cv_extend_damage(cv, cv->outerclip); if (cv->hasopaque) for (cv = cv->topchild; cv; cv = cv->prev) if ((!cv->transparent && cv->mapped) || cv->hasopaque) damage_everything(cv); } void sun_set_scene_clipping(sc, rl_sw_visible) struct scene *sc; struct rectlist *rl_sw_visible; { struct rectlist rl_sw_invisible; /* NeWS window invisible */ struct rectlist rl_clip; /* Root window clipping */ struct rectlist rl_remove; struct rectlist rl_zone; static struct graphics_context *gc; register struct rectnode *rn; register struct rectnode *rn_pr; struct rect r; extern struct rect sun_wl_rect; struct canvas *cv_under_mouse; /* Initialize rectlists */ rl_clip = rl_zone = rl_remove = rl_sw_invisible = rl_null; /* * May clobber the NeWS cursor (the lock removed the SunWindows cursor), * ee below at cv_under_mouse. */ /* Establish new graphics context & reinit the transformation */ if (gc == 0) gc = cs_newcontext(sc->canvases); cs_setmatrix(gc, scene_clipping_matrix); /* Set enable plane if have multiple plane groups */ sun_init_plane_groups(sc->display, rl_sw_visible); /* If completely visible then set single rect */ if (rl_equalrect(&sun_wl_rect, rl_sw_visible)) { r = sun_wl_rect; /* Add rectangle to path */ cs_moveto(gc, r.r_left, r.r_top); cs_rlineto(gc, r.r_width, 0); cs_rlineto(gc, 0, r.r_height); cs_rlineto(gc, -r.r_width, 0); cs_closepath(gc); } else { /* Determine invisible portion of NeWS window */ rl_initwithrect(&sun_wl_rect, &rl_remove); rl_difference(&rl_remove, rl_sw_visible, &rl_sw_invisible); rl_free(&rl_remove); /* Initialize rl_clip */ rl_copy(rl_sw_visible, &rl_clip); /* Cycle through clipping list (invisible portions) */ for (rn = rl_sw_invisible.rl_head; rn; rn = rn->rn_next) { /* * Expand invisible portion of NeSW window to allow for cursor * buffer zone. */ r = rn->rn_rect; rect_marginadjust(&r, sun_cursor_zone); /* Remove this cursor zone from root clipping */ rl_initwithrect(&r, &rl_remove); rl_difference(&rl_clip, &rl_remove, &rl_clip); rl_free(&rl_remove); /* Intersect cursor zone with NeWS window visible */ rl_rectintersection(&r, rl_sw_visible, &rl_zone); /* Clear the border zone with low level rop */ for (rn_pr = rl_zone.rl_head; rn_pr; rn_pr = rn_pr->rn_next) pr_rop(sc->display, rn_pr->rn_rect.r_left, rn_pr->rn_rect.r_top - 1, rn_pr->rn_rect.r_width, rn_pr->rn_rect.r_height + 1, PIX_SRC, 0, 0, 0); rl_free(&rl_zone); } /* Clean up unexplained line at bottom of screen */ pr_rop(sc->display, 0, rect_bottom(&sun_wl_rect) - 1, sun_wl_rect.r_width, 2, PIX_SRC, 0, 0, 0); rl_free(&rl_sw_invisible); /* Try to reduce the number of regions */ rl_coalesce(&rl_clip); /* Cycle through root canvas new clipping list and make path */ for (rn = rl_clip.rl_head; rn; rn = rn->rn_next) { r = rn->rn_rect; /* Add rectangle to path */ cs_moveto(gc, r.r_left, sun_wl_rect.r_height - r.r_top); cs_rlineto(gc, r.r_width, 0); cs_rlineto(gc, 0, -r.r_height); cs_rlineto(gc, -r.r_width, 0); cs_closepath(gc); } rl_free(&rl_clip); } /* We need to reshape the root canvas, but we can't use cs_setcanvasshape(gc, sc->canvases); here because it makes assumptions about the integrity of the screen. Since we can't save anything, doing the reshape by hand is relatively easy. All of this code should really be somewhere in CScript. */ { register struct canvas *cv = sc->canvases; register struct shape *outline; outline = cv_pathtoshape(gc, ~0); if (outline == 0) { /* Reshaping to empty path */ qtalloc(outline, (struct shape *)); outline->refcnt = 1; outline->pos.x = outline->pos.y = 0; outline->size.x = outline->size.y = 0; outline->is_rect = 1; outline->trapset = 0; } cv_invalidate_pixrects(cv); cv_invalidate_clip(cv, 1); cs_newpath(gc); sh_decref(cv->outerclip); cv->outerclip = outline; damage_everything(cv); } /* * Claim that the cursor is down if the cursor collides with new clipped * part of screen. This still leave cursor turds when the cursor is in * the boundary between NeWS and SunWindows. But, that the way it goes * with this hack. */ cv_under_mouse = cs_locatecanvasinscene(CurrentInputScene, cfloorfr(cv_cursor.ri.pos.x), cfloorfr(cv_cursor.ri.pos.y)); if (CanvasUnderMouse && !cv_under_mouse) cv_cursor.up = 0; CheckCrossings(last_event_time); } static setkeyboardtranslation_primitive(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop - 1; register enum kbd_translation desired; if (optop->type != boolean_type) { ee->error_code = typecheck_error_code; return; } desired = optop->value.fixed ? NORMAL_KEYBOARD : UNENCODED_KEYBOARD; if (!setkeyboardtranslation(desired)) { ee->error_code = rangecheck_error_code; return; } raw_keyboard = (desired == UNENCODED_KEYBOARD); ee->optop--; } static setkeyboardtranslation(arg) enum kbd_translation arg; { register int kbd_fd; int current, desired, ret = 1; #ifdef TR_UNTRANS_EVENT if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) return 0; if (ioctl(kbd_fd, KIOCGTRANS, (caddr_t) ¤t)) { ret = 0; goto Return; } switch (current) { case TR_ASCII: if (arg == NORMAL_KEYBOARD) goto Return; desired = TR_NONE; break; case TR_EVENT: if (arg == NORMAL_KEYBOARD) goto Return; desired = TR_UNTRANS_EVENT; break; case TR_NONE: if (arg == UNENCODED_KEYBOARD) goto Return; desired = TR_ASCII; break; case TR_UNTRANS_EVENT: if (arg == UNENCODED_KEYBOARD) goto Return; desired = TR_EVENT; break; default: ret = 0; goto Return; } if (ioctl(kbd_fd, KIOCTRANS, (caddr_t) &desired)) { ret = 0; goto Return; } sun_current_keyboard = arg; switch (desired) { case TR_NONE: break; case TR_ASCII: break; case TR_EVENT: sun_enable_kbd_input(NORMAL_KEYBOARD); break; case TR_UNTRANS_EVENT: sun_enable_kbd_input(UNENCODED_KEYBOARD); break; } Return: close(kbd_fd); return ret; #else return 0; #endif } static void sun_enable_kbd_input(encoding) enum kbd_translation encoding; { struct inputmask im; input_imnull(&im); win_setinputcodebit(&im, KBD_REQUEST); win_setinputcodebit(&im, KBD_USE); win_setinputcodebit(&im, KBD_DONE); im.im_flags = IM_ASCII | IM_META; if (encoding == UNENCODED_KEYBOARD) im.im_flags |= IM_NEGASCII; win_set_kbd_mask(vsdev, &im, NULL, WIN_NULLLINK); } static void sun_enable_pick_input() { struct inputmask im; input_imnull(&im); win_setinputcodebit(&im, LOC_MOVE); win_setinputcodebit(&im, MS_LEFT); win_setinputcodebit(&im, MS_MIDDLE); win_setinputcodebit(&im, MS_RIGHT); /* Include LOC_WINENTER & LOC_WINEXIT for cursor maintainence */ win_setinputcodebit(&im, LOC_WINEXIT); win_setinputcodebit(&im, LOC_WINENTER); im.im_flags = IM_NEGEVENT | IM_INTRANSIT; win_set_pick_mask(vsdev, &im, NULL, WIN_NULLLINK); } /* Called when exit NeWS window */ static void sun_disable_pick_input() { /* * Turns out that we should get mouse motion even when the mouse is over a * SunView application so that NeWS gets awaken when the clipping of the * root canvas changes (just restricting the clipping doesn't generate a * SIGWINCH) [if go back to LOC_WINEXIT & LOC_WINENTER, make sure include * IM_INTRANSIT]. */ sun_enable_pick_input(); } static getkeyboardtranslation(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop - 1; register int kbd_fd; int result; #ifdef KIOCGTRANS if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) { ee->error_code = ioerror_error_code; return; } if (ioctl(kbd_fd, KIOCGTRANS, (caddr_t) &result)) { ee->error_code = ioerror_error_code; return; } close(kbd_fd); switch (result) { case TR_NONE: case TR_UNTRANS_EVENT: result = 0; case TR_ASCII: case TR_EVENT: result = 1; } #else result = 0; #endif set_typed_object(ee->optop, boolean_type); ee->optop->value.fixed = result; ee->optop++; } static keyboardtype(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop - 1; register int kbd_fd; int result; #ifdef KIOCTYPE if ((kbd_fd = open("/dev/kbd", O_RDONLY, 0)) < 0) { ee->error_code = ioerror_error_code; return; } if (ioctl(kbd_fd, KIOCTYPE, (caddr_t) &result)) { ee->error_code = ioerror_error_code; return; } close(kbd_fd); #else result = 0; #endif set_fixed_object(ee->optop, fracti(result)); ee->optop++; } static getmousetranslation(ee) register struct execution_environment *ee; { set_typed_object(ee->optop, boolean_type); ee->optop->value.fixed = !raw_mouse; ee->optop++; } static setmousetranslation(ee) register struct execution_environment *ee; { #ifdef WS_SCALE_MAX_COUNT register struct object *optop = ee->optop - 1; static Ws_scale_list old_scaling, scaling; if (optop->type != boolean_type) { ee->error_code = typecheck_error_code; return; } if (raw_mouse) { if (optop->value.fixed) { scaling = old_scaling; if (win_set_scaling(vsdev, &scaling)) { perror("set mouse parameters"); ee->error_code = typecheck_error_code; return; } raw_mouse = 0; } else { if (win_get_scaling(vsdev, &old_scaling)) { perror("read mouse parameters"); ee->error_code = typecheck_error_code; return; } scaling.scales[0].ceiling = -1; scaling.scales[0].factor = 1; if (win_set_scaling(vsdev, &scaling)) { perror("set mouse parameters"); ee->error_code = typecheck_error_code; return; } raw_mouse = 1; } } ee->optop--; #endif } void setcursorposition(x, y) int x, y; /* integer framebuffer coordinates */ { cs_movecursor(x, y); CheckCrossings(last_event_time); win_setmouseposition(vsdev, x, y); } open_socket(name, inf, outf) char *name; PSFILE **inf, **outf; { register char *p = name; struct sockaddr_in addr; int con = 0; int lis = 0; register fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); char *hostname; long strtol(); bzero((char *)&addr, sizeof(addr)); addr.sin_family = AF_INET; if (*p == 'l') lis++, p++; else if (*p == 'c') con++, p++; if (*p) if ((addr.sin_port = htons((short)strtol(p, &hostname, 10))) == 0) { bad_socket: close(fd); } else { setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 0, 0); if (con) { struct hostent *hp; if (*hostname == '\0') hostname = "localhost"; if (!isalpha(*hostname)) /* skip separator character */ hostname++; hp = gethostbyname(hostname); if (hp == NULL) goto bad_socket; bcopy(hp->h_addr, (char *)&addr.sin_addr, hp->h_length); if (addr.sin_port == 0 || connect(fd, &addr, sizeof addr)) goto bad_socket; if (fcntl(fd, F_SETFL, FNDELAY) == -1) perror("socket fcntl"); *inf = psio_fdopen(fd, "r"); *outf = psio_fdopen(fd, "w"); } else { addr.sin_addr.s_addr = INADDR_ANY; if (bind(fd, &addr, sizeof addr) < 0 || lis && listen(fd, 3) < 0) goto bad_socket; *inf = psio_fdopen(fd, "r"); } } } fract currenttime(tv) struct timeval *tv; { fract ret; struct timeval now; long sec, usec; if (tv == 0) { tv = &now; gettimeofday(tv, 0); } sec = tv->tv_sec - startup_time.tv_sec; usec = tv->tv_usec - startup_time.tv_usec; if (usec < 0) { usec += 1000000; sec -= 1; } ret = sec * ((1 << 16) / 60) /* fraction(sec, 60) */ ; ret += usec / (60000000 >> 16) /* fraction((usec / 1000), 60000) */ ; return (ret); } EventsHaveSelected() { /* Some event has happened */ #define INPBUFSIZE 64 struct inputevent sunevents[INPBUFSIZE]; register struct inputevent *eventp, *limit; register int n, m; if (vsdev < 0) return; if ((n = read(vsdev, sunevents, sizeof sunevents)) < 0) { if (errno != EWOULDBLOCK) { /* XXX - do something creative here! */ return; } } for (eventp = sunevents, limit = sunevents - 1 + n / sizeof sunevents[0]; eventp <= limit; eventp++) { if (eventp < limit && eventp[0].ie_code == LOC_MOVE && eventp[1].ie_code == LOC_MOVE) continue; ProcessInputEvent(eventp); } } static void sun_enter_news_region() { struct timeval tv; win_get_event_timeout(vsdev, &sun_cached_input_timeout); timerclear(&tv); win_set_event_timeout(vsdev, &tv); /* Do fullblown mouse/cursor tracking. Reset colormap for the case * * of running SunView binaries on top of raw NeWS, in which you get * * colormap entry 1 (currently red) messed up. */ sun_enable_pick_input(); cs_cursorenable(); setcolors(); /* If the SunWindows environment is in cursor follows mouse mode, * * then switch translation quickly, before KBD_* events get to us. */ if (sun_kbd_follows_ms() && raw_keyboard) setkeyboardtranslation(UNENCODED_KEYBOARD); fcntl(vsdev, F_SETFL, O_NDELAY | FASYNC); } static void sun_exit_news_region() { win_set_event_timeout(vsdev, &sun_cached_input_timeout); /* Since the mouse is not going to be doing stuff over the NeWS * * window, disable reading of mouse input and adjusting the NeWS * * cursor. If we don't disable mouse input then NeWS will be * * tracking mouse motion even when a SunView application is above * * NeWS, due to the event propagation mechanism of SunWindows. */ sun_disable_pick_input(); cs_cursordown(); cs_cursordisable(); /* Keyboard translation follows same rules as enter */ if (sun_kbd_follows_ms() && raw_keyboard) setkeyboardtranslation(NORMAL_KEYBOARD); } static ProcessInputEvent(se) struct inputevent *se; { register struct body *b; register int code; register enum { unknown, keystroke, motion } class; struct object name; switch (se->ie_code) { case LOC_MOVE: class = motion; set_typed_bodied_object(&name, keyword_type, raw_mouse ? raw_motion_keyword : motion_keyword); break; case MS_LEFT: set_typed_bodied_object(&name, keyword_type, raw_mouse ? raw_but1_keyword : but1_keyword); class = keystroke; break; case MS_MIDDLE: set_typed_bodied_object(&name, keyword_type, raw_mouse ? raw_but2_keyword : but2_keyword); class = keystroke; break; case MS_RIGHT: set_typed_bodied_object(&name, keyword_type, raw_mouse ? raw_but3_keyword : but3_keyword); class = keystroke; break; default: if ((code = se->ie_code) > META_LAST) class = unknown; else { class = keystroke; if (raw_keyboard) code += DEVIDKBD; } set_fixed_object(&name, fracti(code)); break; /* Following SunWindows events mean the cursor (or focus) entered * or left NeWS (in SunView1 compatibility mode). This requires * adjusting keyboard translation, cursor-tracking, input timeouts, * and (eventually) maintaining keyboard state across the transition. * None of these events is interesting to a NeWS client. */ case LOC_WINENTER: sun_enter_news_region(); return; case LOC_WINEXIT: sun_exit_news_region(); return; case KBD_REQUEST: /* ignore; a KBD_USE will follow immediately */ return; case KBD_USE: if (raw_keyboard && sun_current_keyboard != UNENCODED_KEYBOARD) setkeyboardtranslation(UNENCODED_KEYBOARD); return; case KBD_DONE: if (raw_keyboard && sun_current_keyboard != NORMAL_KEYBOARD) { setkeyboardtranslation(NORMAL_KEYBOARD); } return; } b = createevent(); b->body.event.pos.x = fracti(se->ie_locx); b->body.event.pos.y = fracti(se->ie_locy); b->body.event.name = name; b->body.event.time = currenttime(&(se->ie_time)); switch (class) { case keystroke: set_typed_bodied_object(&b->body.event.action, keyword_type, (se->ie_flags & IE_NEGEVENT ? up_keyword : down_keyword)); break; case motion: if (raw_mouse) { static int lastx, lasty; register int newx, newy; newx = se->ie_locx; newy = se->ie_locy; b->body.event.pos.x = cv_cursor.ri.pos.x + fracti(newx - lastx); b->body.event.pos.y = cv_cursor.ri.pos.y + fracti(newy - lasty); lastx = newx; lasty = newy; } else { cs_movecursor(se->ie_locx, se->ie_locy); CheckCrossings(b->body.event.time); } /* FALL THROUGH */ default: clear_object(&(b->body.event.action)); } enqueueEvent(b); } /* Determine if the SunWindows environment is in cursor follows mouse mode */ static sun_kbd_follows_ms() { Firm_event fe; int shifts; win_get_focus_event(vsdev, &fe, &shifts); return (fe.id == LOC_WINENTER); } static getenv_primitive(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; char *res; extern char *getenv(); /* Rely on auto zero */ static char *name; static unsigned int name_size; if (optop[-1].type != string_type) { ee->error_code = typecheck_error_code; return; } if (optop[-1].value.substring.length >= name_size) { if (name) free(name); name_size = optop[-1].value.substring.length + 50; name = (char *) snoopalloc("SunOSI.c", name_size); } bcopy(body_of(optop - 1)->body.string.chars + optop[-1].value.substring.start, name, optop[-1].value.substring.length); name[optop[-1].value.substring.length] = 0; res = getenv(name); if (res == 0) { ee->error_code = undefined_error_code; return; } object_decref(optop - 1); optop[-1] = make_string(strlen(res), res); } static putenv_primitive(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; /* Rely on auto zero */ static char *name; static char *value; static unsigned int name_size; static unsigned int value_size; if (optop[-2].type != string_type || optop[-1].type != string_type) { ee->error_code = typecheck_error_code; return; } if (optop[-2].value.substring.length >= name_size) { if (name) free(name); name_size = optop[-2].value.substring.length + 50; name = (char *) snoopalloc("SunOSI.c", name_size); } if (optop[-1].value.substring.length >= value_size) { if (value) free(value); value_size = optop[-1].value.substring.length + 50; value = (char *) snoopalloc("SunOSI.c", value_size); } bcopy(body_of(optop - 2)->body.string.chars + optop[-2].value.substring.start, name, optop[-2].value.substring.length); name[optop[-2].value.substring.length] = 0; bcopy(body_of(optop - 1)->body.string.chars + optop[-1].value.substring.start, value, optop[-1].value.substring.length); value[optop[-1].value.substring.length] = 0; object_decref(optop - 2); object_decref(optop - 1); ee->optop -= 2; putenv(name, value); } static getsocketlocaladdress(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; char hname[50]; register struct hostent *h; register fd; struct sockaddr_in addr; int namelen; if (optop[-1].type != file_type) { ee->error_code = typecheck_error_code; return; } if (body_of(&optop[-1])->body.file.inbuf == 0) { ee->error_code = invalidaccess_error_code; return; } fd = psio_fileno(body_of(&optop[-1])->body.file.inbuf); namelen = sizeof addr; if (getsockname(fd, &addr, &namelen) < 0) { ee->error_code = invalidaccess_error_code; return; } h = gethostbyname(my_hostname); if (h) sprintf(hname, "%u.%u;%s", *(int *) h->h_addr, addr.sin_port, h->h_name); else sprintf(hname, "%u.%u;localhost", addr.sin_addr.s_addr, addr.sin_port); object_decref(optop - 1); optop[-1] = make_string(strlen(hname), hname); } static getsocketpeername(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; register struct hostent *h; register fd; struct sockaddr_in addr; int namelen; if (optop[-1].type != file_type) { ee->error_code = typecheck_error_code; return; } if (body_of(&optop[-1])->body.file.inbuf == 0) { ee->error_code = invalidaccess_error_code; return; } fd = psio_fileno(body_of(&optop[-1])->body.file.inbuf); namelen = sizeof addr; if (getpeername(fd, &addr, &namelen) < 0 || (h = gethostbyaddr(&addr.sin_addr, sizeof addr.sin_addr, addr.sin_family)) == 0) { ee->error_code = invalidaccess_error_code; return; } object_decref(optop - 1); optop[-1] = make_string(strlen(h->h_name), h->h_name); } static localhostname(ee) register struct execution_environment *ee; { *ee->optop++ = make_string(strlen(my_hostname), my_hostname); } extern char **environ; osi_spawn_process(sp, len) register char *sp; { char combuf[400]; char *args[100]; register char *dp; register char **ap; register cnt; int err = 0; struct itimerval new_t, old_t; cs_cursorup(); for (dp = sp, cnt = len; --cnt >= 0; dp++) switch (*dp) { case '!': case '"': case '$': case '&': case '(': case ')': case '*': case ';': case '<': case '>': case '?': case '[': case '\'': case '\\': case ']': case '`': case '{': case '|': case '}': case '~': cnt = -1; } ap = args; if (cnt == -1) { /* no special characters, don't invoke the * shell */ dp = combuf; while (len > 0 && ap < &args[sizeof args / sizeof args[0] - 1]) { *ap++ = dp; while (dp < combuf + sizeof combuf - 1 && *sp > ' ' && --len >= 0) *dp++ = *sp++; *dp++ = 0; while (*sp <= ' ' && --len >= 0) sp++; } } else { static char *shell; strncpy(combuf, sp, len); combuf[len] = 0; if (shell == 0 && (shell = (char *) getenv("SHELL")) == 0) shell = "/bin/sh"; *ap++ = shell; *ap++ = "-c"; *ap++ = combuf; } *ap++ = 0; timerclear(&new_t.it_value); timerclear(&new_t.it_interval); if (setitimer(ITIMER_VIRTUAL, &new_t, &old_t)) { perror("clear timeout_alarm"); } if (vfork() == 0) { setpgrp(0, getpid()); close(0); open("/dev/null", 2); dup2(0, 1); /* Leave stderr alone so we see errors on the console -deh */ #ifdef notdef dup2(0, 2); #endif execvp(args[0], args, environ); /* * Beware: I'm depending on vfork semantics to propagate the error * code. */ err = 1; _exit(0252); } if (setitimer(ITIMER_VIRTUAL, &old_t, &new_t)) { perror("set_timeout_alarm"); } return err; } #ifndef HAVEPUTENV putenv(name, value) char *name, *value; { register char *p; register len; register char **ap; register char **new; register char *buf; static alloced; len = strlen(name); buf = (char *) snoopalloc("SunOSI.c", len + strlen(value) + 2); sprintf(buf, "%s=%s", name, value); for (ap = environ; *ap; ap++) if (strncmp(*ap, name, len) == 0) { *ap = buf; return; } len = ap - environ; new = (char **) snoopalloc("SunOSI.c", (len + 2) * sizeof(char *)); bcopy(environ, new, len * sizeof(char *)); new[len] = buf; new[len + 1] = 0; if (alloced) free(environ); environ = new; } #endif /* * ttysw_saveparms and we_setptyparms have been copied the suntool libaray: * "@(#)ttysw_stty.c 10.5 86/09/03 Copyr 1983 Sun Micro"; */ /* * Ttysw parameter setting mechanism using given tty settings. */ /* * Determine ttyfd tty settings and cache in environment. */ static ttysw_saveparms(ttyfd) int ttyfd; { int ldisc, localmodes; struct sgttyb mode; struct tchars tchars; struct ltchars ltchars; /* * Get line discipline. */ (void) ioctl(ttyfd, TIOCGETD, &ldisc); /* * Get tty parameters */ (void) ioctl(ttyfd, TIOCGETP, &mode); /* * Get local modes */ (void) ioctl(ttyfd, TIOCLGET, &localmodes); /* * Get terminal characters */ (void) ioctl(ttyfd, TIOCGETC, &tchars); /* * Get local special characters */ (void) ioctl(ttyfd, TIOCGLTC, <chars); /* * Write environment variable */ (void) we_setptyparms(ldisc, localmodes, &mode, &tchars, <chars); } #define WE_TTYPARMS "WINDOW_TTYPARMS" #define WE_TTYPARMSLEN 120 /* * Save tty settings in environment. */ static we_setptyparms(ldisc, localmodes, mode, tchars, ltchars) int ldisc, localmodes; struct sgttyb *mode; struct tchars *tchars; struct ltchars *ltchars; { char str[WE_TTYPARMSLEN]; str[0] = '\0'; /* * %c cannot be used to write the character valued fields because they * often have a value of \0. */ (void) sprintf(str, "%D,%D,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", ldisc, localmodes, mode->sg_ispeed, mode->sg_ospeed, mode->sg_erase, mode->sg_kill, mode->sg_flags, tchars->t_intrc, tchars->t_quitc, tchars->t_startc, tchars->t_stopc, tchars->t_eofc, tchars->t_brkc, ltchars->t_suspc, ltchars->t_dsuspc, ltchars->t_rprntc, ltchars->t_flushc, ltchars->t_werasc, ltchars->t_lnextc); (void) setenv(WE_TTYPARMS, str); } static /* * Enumerate all the directories in the font path and push the names of all * font family files onto the PostScript stack. Font family files are * identified by their extension: .ffam, .ffa or .ff */ enumeratefontdicts(ee) register struct execution_environment *ee; { extern char *cs_fontpath(); register char *p, *s, *d; for (s = cs_fontpath(); *s; s = p + 1) { char buf[300]; DIR *dir; register struct direct *ent; d = buf; p = s; while (*p != ':' && *p) *d++ = *p++; if (d == buf) *d++ = '.'; *d++ = 0; if (dir = opendir(buf)) { while (ent = readdir(dir)) { register n = ent->d_namlen; char fullname[300]; register char *ffs; d = &ent->d_name[n]; while (--n >= 0 && *--d != '.'); if (n < 0 || ent->d_namlen - n < 3 || ent->d_namlen - n > 5) continue; for (ffs = ".ffam"; n < ent->d_namlen; n++) if (*d++ != *ffs++) break; if (n != ent->d_namlen) continue; if (ee->optop >= ee->overflow && grow_stack(ee, 1) < 0) { ee->error_code = stackoverflow_error_code; closedir(dir); return; } sprintf(fullname, "%s/%.*s", buf, ent->d_namlen, ent->d_name); *ee->optop = make_string(strlen(fullname), fullname); ee->optop++; } closedir(dir); } if (*p == 0) return 0; } } /* OSI specific clean executed just before NeWS exits */ restore_keyboard() { register i; char map[256]; if (vsdev < 0) return; setkeyboardtranslation(NORMAL_KEYBOARD); raw_keyboard = 0; for (i = 0; i < 256;) map[i++] = 255, map[i++] = 0; if (CurrentInputScene) pr_putcolormap(CurrentInputScene->display, 0, 256, map, map, map); /* See if other SunWindows on NeWS */ if (sun_created_root && win_getlink(vsdev, WL_TOPCHILD) != WIN_NULLLINK) { /* * Destroy screen sends SIGTERMs to all existing windows and wouldn''t * let any windows install themselves in the window tree. Calling * process of win_screedestroy is spared SIGTERM. */ (void) win_screendestroy(vsdev); } } #ifndef DEBUG static CatastrophicSignalHandler(sig, code, scp) int sig; int code; struct sigcontext *scp; { restore_keyboard(); write(2, "NeWS: unexpected ", 17); switch (sig) { case SIGBUS: write(2, "SIGBUS ", 7); break; case SIGSEGV: write(2, "SIGSEGV ", 8); break; } write(2, "signal received\n", 16); abort(0); exit(1); } #endif initialize_SunOSI() { vsdev = -1; news_pid = getpid(); raw_keyboard = 0; raw_mouse = 0; init_scene_clipping_matrix(); sun_cursor_zone = 16; motion_keyword = get_name("MouseDragged", -1); but1_keyword = get_name("LeftMouseButton", -1); but2_keyword = get_name("MiddleMouseButton", -1); but3_keyword = get_name("RightMouseButton", -1); raw_motion_keyword = get_name("RawMouseDragged", -1); raw_but1_keyword = get_name("RawLeftMouseButton", -1); raw_but2_keyword = get_name("RawMiddleMouseButton", -1); raw_but3_keyword = get_name("RawRightMouseButton", -1); up_keyword = get_name("UpTransition", -1); down_keyword = get_name("DownTransition", -1); define_operator("getkeyboardtranslation", getkeyboardtranslation, 0, 0, 1); define_operator("getmousetranslation", getmousetranslation, 0, 0, 1); define_operator("keyboardtype", keyboardtype, 0, 0, 1); define_operator("setkeyboardtranslation", setkeyboardtranslation_primitive, 0, 1, 0); define_operator("setmousetranslation", setmousetranslation, 0, 1, 0); define_operator("startkeyboardandmouse", startkeyboardandmouse, 0, 0, 0); define_operator("getenv", getenv_primitive, 0, 1, 1); define_operator("putenv", putenv_primitive, 0, 2, 0); define_operator("localhostname", localhostname, 0, 0, 1); define_operator("getsocketpeername", getsocketpeername, 0, 1, 1); define_operator("getsocketlocaladdress", getsocketlocaladdress, 0, 1, 1); define_operator("enumeratefontdicts", enumeratefontdicts, 0, 0, 0); signal(SIGCHLD, reaper); signal(SIGPIPE, SIG_IGN); signal(SIGFPE, SIG_IGN); #ifndef DEBUG signal(SIGBUS, CatastrophicSignalHandler); signal(SIGSEGV, CatastrophicSignalHandler); #endif gethostname(my_hostname, sizeof my_hostname); my_hostname[sizeof my_hostname - 1] = 0; }