#ifndef lint static char sccsid[] = "@(#)winioctl.c 1.1 94/10/31 SMI"; #endif /* * Copyright (c) 1989 by Sun Microsystems, Inc. */ /* * SunWindows ioctls, see sunwindow/win_ioctl.h. */ #include #include /* for cursor access macros */ #include #include #include /* for mpr support */ #include /* for double buffering support */ #include /* for plane groups */ #include /* for time */ #include #include #ifdef WINDEVDEBUG int winprintall; /* Temp: Debugging message when call winioctl */ int winprintexits; /* Temp: Debugging message when return from winioctl */ int winfilterlockscreen; /* Temp: Don't print debugging messages about WINLOCKSCREEN and WINUNLOCKSCREEN calls */ #endif int winnodisplaylock; /* Temp: Don't actually lock if WINLOCKSCREEN */ /* * Scaling is accomplished by finding the first entry in the following * table whose ceiling >= the current motion, and multiplying that * motion by the corresponding factor. */ Ws_scale ws_scaling[WS_SCALE_MAX_COUNT+1] = { {WS_SCALE_MAX_CEILING, 2} }; extern int MS_DEBUG; extern int ws_button_order; /* current button mapping */ extern void ws_set_dtop_waiting(); extern void dtop_putcolormap(); extern struct window *wt_intersected(); extern int winkill(), wt_positionchanged(), wt_partialrepair(), wt_sizechanged(); extern int winpsnotkill; /* Reach around communication from WINSCREENDESTROY to winkill */ extern struct proc *pfind(); extern bool wt_isindisplaytree(); extern caddr_t dtop_alloccmapdata(); extern void dtop_update_enable(); extern void dtop_choose_dblbuf(); extern void dtop_changedisplay(); extern void dtop_flip_display(); extern void dtop_copy_dblbuffer(); extern Workstation *ws_indev_match_name(); extern Workstation *ws_open(); extern Wsindev *ws_open_indev(); extern int copyin(), copyout(); static int check_crosshair_info(), wt_gettreelayer(); static void wt_copy_layer_node(), wt_count_layer(); static void win_prepare_surface(); static void win_return_cms(); static void win_pick_plane_group(); static void win_initialize_plane_group(); static void win_clear_cursor_plane_groups(); int win_errno; /* Set from calls out of module (same values as errno)*/ int win_exit_seconds = 1000; int print_waiting = TRUE; int print_still_waiting = TRUE; int always_signal = 1; /*ARGSUSED*/ int winioctl(dev, cmd, data, flag) dev_t dev; register caddr_t data; { register struct window *w = winfromdev(dev); register struct desktop *dtop = w->w_desktop; register Workstation *ws = NULL; register int i; int pri; register int error = 0; #ifdef WINSVJ register short win_playrec_sync_flg = 1; /* Flag for syncing type */ #endif extern winnotify_inorder; #define returnerror(e) {error = (e); goto done;} #ifdef WINDEVDEBUG if (winprintall) { if (winfilterlockscreen && (cmd == WINLOCKSCREEN || cmd == WINUNLOCKSCREEN)) {} else printf("winioctl dev: %X, cmd: %X, data: %X [%X,%X,%X...]\n", dev, cmd, data, *(int *)data, *(int *)(data+4), *(int *)(data+8)); } #endif /* Block out timeouts */ pri = spl_timeout(); if (dtop == NULL) { /* * All but the following operations need dtop not NULL because * so much of the code assumes a not NULL dtop. * Note: the list of allowable operations should be expanded. */ switch (cmd) { case WINSCREENNEW: case WINSETLINK: case WINSETRECT: case WINGETRECT: case WINSETSAVEDRECT: case WINGETSAVEDRECT: case WINNEXTFREE: case WINGETBUTTONORDER: case WINSETBUTTONORDER: case WINGETSCALING: case WINSETSCALING: case WINGETUSERFLAGS: case WINSETUSERFLAGS: #ifndef PRE_FLAMINGO case WINGETNOTIFYALL: case WINSETNOTIFYALL: #endif case _IO(g, 100): break; default: returnerror(ESPIPE); } } else { ws = dtop->dt_ws; if (!dtop->shared_info) /* Has happened but don't know why */ returnerror(ESPIPE); dtop->shared_info->waiting++; if (wlok_waitunlocked(&dtop->dt_datalock)) { if (dtop->shared_info) dtop->shared_info->waiting--; goto restart; } dtop->shared_info->waiting--; switch (cmd) { /* * Don't tamper with display lock while locked by another. */ case WINLOCKSCREEN: case WINUNLOCKSCREEN: case WINGRABIO: /* * Any operation that involes double buffering waits * while the display is locked. * */ case WINDBLCURRENT: case WINDBLACCESS: case WINDBLRLSE: case WINDBLFLIP: case WINDBLABSORB: case WINDBLSET: case WINDBLGET: /* * Any operation that might invoke a clipping change while the * display is locked must wait until the lock is released. * An exception to this is if the calling user process is * the same as the original locker. */ case WININSERT: case WINREMOVE: case WINSETRECT: case WINSETOWNER: case WINUNLOCKDATA: case WINSCREENDESTROY: /* * Don't tamper with colormap while display locked by another. */ case WINSETCMS: case WINRELEASEIO: /* * Don't tamper with plane group while display locked * by another. */ case WINSETPLANEGROUP: case WINGETDAMAGEDRL: /* Make sure dt still around if waited before */ if (!(dtop->dt_flags & DTF_PRESENT)) returnerror(EACCES); /* Bump the waiting count and wait for the * display lock to be released, or just * go on through if we have the display lock. * Note that we look at the shared lock only, * since we can't trust the internal wlok after * we sleep. */ dtop->shared_info->waiting++; dtop->display_waiting++; while (win_lock_display_locked(dtop->shared_info) && (dtop->shared_info->display.pid != u.u_procp->p_pid)) if (sleep((caddr_t)dtop->shared_info, LOCKPRI|PCATCH)) { if (dtop->shared_info) dtop->shared_info->waiting--; dtop->display_waiting--; goto restart; } /* Now make sure the internal display lock * is valid. We have to do this here because * we don't know what went on while we were sleeping. */ dtop_validate_shared_lock(dtop, &dtop->dt_displaylock); dtop->shared_info->waiting--; dtop->display_waiting--; } switch (cmd) { /* * Don't tamper with colormap while io rights locked by another. */ case WINSETCMS: case WINSETPLANEGROUP: /* * Don't tamper with io right lock while locked by another. */ case WINGRABIO: case WINRELEASEIO: case WINDBLCURRENT: case WINDBLACCESS: case WINDBLRLSE: case WINDBLFLIP: case WINDBLABSORB: case WINDBLSET: case WINDBLGET: /* * Don't acquire data lock while io rights locked by another. * If we did, one could get into a situation in which the * data lock holder might try to access the screen but be * prevented by the other process having the io lock. Also, * the io lock holder couldn't access the screen because * the data lock is more powerful. Deadlock. */ case WINLOCKDATA: if (ws == NULL) returnerror(ESPIPE); /* Make sure ws still around if waited before */ if (!(ws->ws_flags & WSF_PRESENT)) returnerror(EACCES); ws_set_dtop_waiting(ws, 1); if (wlok_waitunlocked(&ws->ws_iolock)) { ws_set_dtop_waiting(ws, -1); goto restart; } ws_set_dtop_waiting(ws, -1); } /* Make sure ws & dt still around if waited before */ if ((!(dtop->dt_flags & DTF_PRESENT)) || (!(ws->ws_flags & WSF_PRESENT))) returnerror(EACCES); } if (ws == NULL) { /* * Same drill as above, except this time for ws -- avoid * operations that assume it's nonnull. This is a gross hack; * the code leading to this point should have insured that ws * is nonnull, but unfortunately does not always do so. */ switch (cmd) { case WINSETMOUSE: case WINSCREENDESTROY: case WINSETKBD: case WINSETMS: case WINSETINPUTDEV: case WINGETINPUTDEV: case WINGETVUIDVALUE: case WINGETFOCUSEVENT: case WINSETFOCUSEVENT: case WINGETSWALLOWEVENT: case WINSETSWALLOWEVENT: case WINGETKBDFOCUS: case WINSETKBDFOCUS: case WINGETEVENTTIMEOUT: case WINSETEVENTTIMEOUT: case WINUNLOCKEVENT: case WINREFUSEKBDFOCUS: returnerror(ESPIPE); } } switch (cmd) { /* * Display management operations * (placed at beginning for faster access[?] because high frequency). */ case WINLOCKSCREEN: { struct winlock *winlock = (struct winlock *)data; int new_id; if (winnodisplaylock) goto done; new_id = dtop_lockdisplay(dev, &winlock->wl_rect); if (new_id < 0) goto restart; winlock->wl_clipid = new_id; break; } case WINUNLOCKSCREEN: if (winnodisplaylock) goto done; wlok_unlock(&dtop->dt_displaylock); break; case FIONREAD: /* return # of CHARACTERS (not events) immediately available */ win_sharedq_shift(w); if (dtop && w->w_desktop->dt_sharedq_owner == w) { if (dtop->shared_info->shared_eventq.tail >= dtop->shared_info->shared_eventq.head) { *(int *)data = dtop->shared_info->shared_eventq.tail - dtop->shared_info->shared_eventq.head; } else { *(int *)data = dtop->shared_info->shared_eventq.tail + dtop->shared_info->shared_eventq.size - dtop->shared_info->shared_eventq.head; } *(int *)data *= sizeof (struct inputevent); *(int *)data += w->w_input.c_cc; } else *(int *)data = w->w_input.c_cc; break; case FIOASYNC: /* * Note: If ignore FIOASYNC then * need to explicitely ignore it due to way that fcntl is * implemented in ../sys/kern_descrip.c. */ if (*(int *)data) { w->w_flags |= WF_ASYNC; w->w_aproc = u.u_procp; w->w_apid = u.u_procp->p_pid; } else { w->w_flags &= ~WF_ASYNC; w->w_aproc = 0; w->w_apid = 0; } break; case FIONBIO: if (*(int *)data) w->w_flags |= WF_NBIO; else w->w_flags &= ~WF_NBIO; break; /* * Tree operations */ case WINGETLINK: { struct winlink *winlink = (struct winlink *)data; if ((unsigned)winlink->wl_which >= WIN_LINKS) returnerror(EINVAL); wt_windowtonumber(w->w_link[winlink->wl_which], &winlink->wl_link); break; } case WINSETLINK: { struct winlink *winlink = (struct winlink *)data; struct window *windowlink; if ((unsigned)winlink->wl_which >= WIN_LINKS) returnerror(EINVAL); if (wt_numbertowindow(winlink->wl_link, &windowlink) < 0) returnerror(EINVAL); if (w->w_flags & WF_INSTALLED || (windowlink == w)) returnerror(EINVAL); w->w_link[winlink->wl_which] = windowlink; if (winlink->wl_which==WL_PARENT && w->w_link[WL_PARENT]) { w->w_desktop = w->w_link[WL_PARENT]->w_desktop; if (w->w_desktop) { /* Make sure dt still around before reference */ if (!(w->w_desktop->dt_flags & DTF_PRESENT)) returnerror(EACCES); w->w_ws = w->w_desktop->dt_ws; win_pick_plane_group(w->w_desktop, w); } } break; } case WININSERT: if (dtop->dt_flags & DTF_EXITING) { winsignal(w, SIGKILL); returnerror(EACCES); } if ((error = wt_install(w)) != 0) returnerror(error); if (wt_isindisplaytree(w)) dtop_invalidateclipping( dtop, w->w_link[WL_PARENT], &w->w_rect); break; case WINREMOVE: if ((error = dtop_removewin(dtop, w))) returnerror(error); break; case WINNEXTFREE: { struct winlink *winlink = (struct winlink *)data; struct window *win; winlink->wl_link = WIN_NULLLINK; #if NWIN > 0 for (i = 0; win = winfromdev(i); i++) if (!(win->w_flags&WF_OPEN)) { wt_windowtonumber(win, &winlink->wl_link); break; } #endif break; } case WINGETTREELAYER: if (dtop->dt_flags & DTF_EXITING) { winsignal(w, SIGKILL); returnerror(EACCES); } if ((error = wt_gettreelayer(w, (Win_tree_layer *)data))) returnerror(error); break; /* * Mouse cursor operations. */ case WINSETMOUSE: { struct mouseposition *mp = (struct mouseposition *)data; Firm_event fe; int delta; Desktop *dtop_old = ws->ws_loc_dtop; if (!dtop_old) { returnerror(ENOENT); } if (dtop != dtop_old) { void dtop_change_loc_dtop(); dtop_change_loc_dtop(dtop_old, dtop, mp->msp_x+w->w_screenx, mp->msp_y+w->w_screeny); } else { /* * Apply the absolute to the user state. Apply the * difference between the original user state and the * new user state to the real time state. */ delta = mp->msp_x + w->w_screenx - dtop->dt_ut_x; dtop->dt_ut_x = mp->msp_x + w->w_screenx; dtop->dt_rt_x += delta; delta = mp->msp_y + w->w_screeny - dtop->dt_ut_y; dtop->dt_ut_y = mp->msp_y + w->w_screeny; dtop->dt_rt_y += delta; } /* * Update the shared memory mouse x, y */ win_shared_update_mouse_xy(dtop->shared_info, dtop->dt_rt_x, dtop->dt_rt_y); /* * We enqueue a bogus LOC_MOVE at the user time end of * the queue so that LOC_WINENTERs, EXITs and STILLs * are generated. */ if (vq_is_full(&ws->ws_q)) break; if (vq_peek(&ws->ws_q, &fe) == VUID_Q_EMPTY) /* Use the current time */ fe.time = time; /* else use the time at the top of the queue */ fe.id = LOC_MOVE; fe.value = 1; /* Set to one because event has no neg */ fe.pair = 0; fe.pair_type = FE_PAIR_NONE; if (vq_putback(&ws->ws_q, &fe) != VUID_Q_OK) #ifdef WINDEVDEBUG printf("putback error\n"); #else ; #endif /* Update the locator (real time end of queue) */ ws_track_locator(ws); /* Update pick focus if changed */ ws_set_focus(ws, FF_PICK_CHANGE); break; } case WINSETLOCATOR: /* check the validity of the * crosshair info. */ if (error = check_crosshair_info((struct cursor *) data)) returnerror(error); /* and fall through ... */ case WINSETCURSOR: { struct cursor *cursor = (struct cursor *)data; struct pixrect mpr; struct mpr_data mpr_data; short image[CUR_MAXIMAGEWORDS]; int empty; if (error = winio_getusercursor( cursor, &mpr, &mpr_data, image, &empty)) returnerror(error); if (empty) /* * dtop_drawcursor knows 0 depth is nop cursor. */ w->w_cursormpr.pr_depth = 0; else { /* * Now that have reasonable cursor, copy to w. */ /* this if-else will go away when our * kernel is released and the SETLOCATOR * and GETLOCATOR code is removed. */ if (cmd == WINSETCURSOR) { w->w_cursor.cur_xhot = cursor->cur_xhot; w->w_cursor.cur_yhot = cursor->cur_yhot; w->w_cursor.cur_function = cursor->cur_function; w->w_cursor.cur_shape = cursor->cur_shape; w->w_cursor.flags = 0; } else w->w_cursor = *cursor; w->w_cursormpr = mpr; w->w_cursordata = mpr_data; bcopy((caddr_t)image, (caddr_t)w->w_cursorimage, CUR_MAXIMAGEBYTES); /* * Fixup cursor internal pointers. */ winfixupcursor(w); /* * Allocate crosshair cursor pixrect storage * if necessary. */ if (show_horiz_hair(cursor) || show_vert_hair(cursor)) dtop_setup_crosshairs(dtop); } /* * Replace new for old on screen if old was up. * Do it now incase client is counting on cursor state. */ if (dtop->dt_cursorwin == w) { dtop_cursordown(dtop); /* update the shared cusor */ win_shared_update_cursor(dtop); dtop_cursorup(dtop); } break; } case WINGETLOCATOR: case WINGETCURSOR: { struct cursor *cursor = (struct cursor *)data; struct pixrect mpr, *mprsave; struct mpr_data mpr_data, *mpr_datasave; struct pixrectops *mpr_opssave; short image[CUR_MAXIMAGEWORDS], *imagesave; int empty; /* * Get user cursor that will copyout to. */ if (error = winio_getusercursor( cursor, &mpr, &mpr_data, image, &empty)) returnerror(error); if (empty) returnerror(EINVAL); /* * Save the user pointers that are needed as destinations * of copyouts. */ mprsave = cursor->cur_shape; mpr_datasave = (struct mpr_data *)mpr.pr_data; mpr_opssave = mpr.pr_ops; imagesave = mpr_data.md_image; /* * Copy cursor info and fixup data pointer. * (Copyout happens by ioctl mechanism) */ /* this if-else will go away when our * kernel is released and the SETLOCATOR * and GETLOCATOR code is removed. */ if (cmd == WINGETCURSOR) { cursor->cur_xhot = w->w_cursor.cur_xhot; cursor->cur_yhot = w->w_cursor.cur_yhot; cursor->cur_function = w->w_cursor.cur_function; } else *cursor = w->w_cursor; cursor->cur_shape = mprsave; /* * Set pixrect info, fixup pointers and copyout. */ mpr = w->w_cursormpr; mpr.pr_data = (caddr_t)mpr_datasave; mpr.pr_ops = mpr_opssave; if (error = copyout((caddr_t)&mpr, (caddr_t)mprsave, sizeof(struct pixrect))) returnerror(error); /* * Set pixrect info, fixup pointers and copyout. */ mpr_data = w->w_cursordata; mpr_data.md_image = imagesave; if (error = copyout((caddr_t)&mpr_data, (caddr_t)mpr_datasave, sizeof(struct mpr_data))) returnerror(error); /* * Copyout image. */ if (error = copyout((caddr_t)w->w_cursorimage, (caddr_t)imagesave, CUR_MAXIMAGEBYTES)) returnerror(error); break; } case WINFINDINTERSECT: { struct winintersect *winintersect = (struct winintersect *)data; struct window *window; window = wt_intersected(w, winintersect->wi_x + w->w_screenx, winintersect->wi_y + w->w_screeny); wt_windowtonumber(window, &winintersect->wi_link); break; } /* * Geometry operations. */ case WINGETRECT: *(struct rect *)data = w->w_rect; break; case WINSETRECT: { struct rect *rect = (struct rect *)data; bool ilocked = FALSE; struct window *winparent; if (dtop == NULL) { w->w_rect = *rect; break; } if (w==dtop->dt_rootwin) winparent = w; else winparent = w->w_link[WL_PARENT]; if (!win_lock_data_locked(dtop->shared_info)) { if (dtop_lockdata(dev)) goto restart; ilocked = TRUE; } if (wt_isindisplaytree(w)) dtop_invalidateclipping(dtop, winparent, &w->w_rect); if ((w->w_rect.r_width != rect->r_width) || (w->w_rect.r_height != rect->r_height)) w->w_flags |= WF_SIZECHANGED; if ((w->w_rect.r_left != rect->r_left) || (w->w_rect.r_top != rect->r_top)) wt_enumeratechildren(wt_positionchanged, w, (struct rect *)0); w->w_rect = *rect; /* * Let blanket windows pick up parent's new size. */ wt_enumeratechildren(wt_sizechanged, w, (struct rect *)0); if (wt_isindisplaytree(w)) dtop_invalidateclipping(dtop, winparent, &w->w_rect); if (ilocked) wlok_unlock(&dtop->dt_datalock); break; } case WINSETSAVEDRECT: w->w_rectsaved = *(struct rect *)data; break; case WINGETSAVEDRECT: *(struct rect *)data = w->w_rectsaved; break; /* * Misc operations. */ case WINGETUSERFLAGS: *(int *)data = w->w_userflags; break; case WINSETUSERFLAGS: w->w_userflags = *(int *)data; break; case WINGETOWNER: { struct proc *p = pfind(w->w_pid); /* * Return 0 if can't find current owner process * Can't rely on kill(pid, 0) to tell user if processes * exists because will say doesn't exist if, say, owner is root. */ *(int *)data = (p == 0)? 0: w->w_pid; break; } case WINSETOWNER: { int pid = *(int *)data; struct proc *p = pfind(pid); if (p==0) returnerror(EINVAL); w->w_pid = pid; rl_copy(&w->w_rlexposed, &w->w_rlfixup); winsignal(w, SIGWINCH); break; } #ifndef PRE_FLAMINGO case WINGETNOTIFYALL: *(int *)data = (w->w_flags&WF_NOTIFYALLCHANGES) != 0; break; case WINSETNOTIFYALL: if (*(int *)data) w->w_flags |= WF_NOTIFYALLCHANGES; else w->w_flags &= ~WF_NOTIFYALLCHANGES; break; #endif /* * Input control. */ case WINGETINPUTMASK: { struct inputmaskdata *inputmaskdata = (struct inputmaskdata *)data; inputmaskdata->ims_set = w->w_pickmask; wt_windowtonumber(w->w_inputnext, &inputmaskdata->ims_nextwindow); break; } case WINSETINPUTMASK: { struct inputmaskdata *inputmaskdata = (struct inputmaskdata *)data; struct window *windownext; int flushit = 0; if (wt_numbertowindow(inputmaskdata->ims_nextwindow, &windownext) < 0) returnerror(EINVAL); /* * Flush input buffer * Note: For now flush entire queue if any thing in ims_flush */ for (i = 0; i < IM_CODEARRAYSIZE; i++) if (inputmaskdata->ims_flush.im_inputcode[i] != 0) { flushit = 1; break; } if (flushit || inputmaskdata->ims_flush.im_flags) { if (w->w_desktop->dt_sharedq_owner && w->w_desktop->dt_sharedq_owner == w) { w->w_desktop->shared_info->shared_eventq.tail = w->w_desktop->shared_info->shared_eventq.head; } while (getc(&w->w_input) >= 0) continue; } /* * Set new mask */ w->w_pickmask = inputmaskdata->ims_set; w->w_inputnext = windownext; break; } /* * Operations applying globally to a screen. */ case WINLOCKDATA: if (dtop_lockdata(dev)) goto restart; break; case WINCOMPUTECLIPPING: if (!win_lock_data_locked(dtop->shared_info)) returnerror(EINVAL); dtop_computeclipping(dtop, FALSE); break; case WINPARTIALREPAIR: { struct rect *rectok = (struct rect *)data; if (!win_lock_data_locked(dtop->shared_info)) returnerror(EINVAL); wt_enumeratechildren(wt_partialrepair, w, rectok); break; } case WINUNLOCKDATA: wlok_unlock(&dtop->dt_datalock); break; case WINGRABIO: if (ws_lockio(dev)) goto restart; break; case WINRELEASEIO: wlok_unlock(&ws->ws_iolock); break; case WINGETDAMAGEDRL: if (dtop->dt_flags & DTF_MULTI_PLANE_GROUPS && !(w->w_flags & WF_PLANE_GROUP_SET)) /* * Prepare surface for this application because it * doesn't know how to play multiple planes. */ win_prepare_surface(w); /* Fall through */ case WINGETEXPOSEDRL: { struct winclip *winclip = (struct winclip *)data; winclip->wc_clipid = w->w_clippingid; rect_construct(&winclip->wc_screenrect, w->w_screenx, w->w_screeny, w->w_rect.r_width, w->w_rect.r_height); returnerror(wincopyoutrl( cmd == WINGETDAMAGEDRL ? &w->w_rlfixup : &w->w_rlexposed, winclip)); } case WINDONEDAMAGED: { int userclippingid = *((int *)data); if (userclippingid==w->w_clippingid) { rl_free(&w->w_rlfixup); w->w_flags &= ~WF_PREVIOUSDAMAGED; } break; } /* * Colormap sharing mechanism. */ case WINSETCMS: { register struct cmschange *cmschange = (struct cmschange *)data; register struct window *wmatch; struct window *dtop_cmsmatch(); int to_offset; /* * Cmschange->cc_cms.cms_addr describes the destination * within the window's colormap segment. * Always reading from cmschange->cc_map at [0]th slot. */ to_offset = cmschange->cc_cms.cms_addr; cmschange->cc_cms.cms_addr = 0; if (cmschange->cc_cms.cms_size == 0 || (cmschange->cc_map.cm_red == 0 && cmschange->cc_map.cm_green == 0 && cmschange->cc_map.cm_blue == 0)) { /* * Releasing color map segment. */ dtop_cmsfree(dtop, w); /* * If had semantic that color map addr could change like * clipping then could retry allocate any CMSHOGs that * we were not able to allocate in past and notify * window with sigwinch. */ } else { /* * If new and existing cms are same then bypass * allocation phase. */ if ((cmschange->cc_cms.cms_size <= w->w_cms.cms_size)&& (strncmp(cmschange->cc_cms.cms_name, w->w_cms.cms_name, CMS_NAMESIZE) == 0)) { if (w->w_flags & WF_CMSHOG) { goto loadcmshog; } else { goto loadcmsstd; } } /* * Start using a color map segment. */ if ((wmatch = dtop_cmsmatch( dtop, w, &cmschange->cc_cms))) { /* * Using an existing color map segment. * Sanity check: if trying to replace * the current cms with a smaller sized * cms, then return error. */ if (w->w_cms.cms_size > wmatch->w_cms.cms_size) returnerror(EINVAL); w->w_cms = wmatch->w_cms; w->w_cmap = wmatch->w_cmap; w->w_cmapdata = wmatch->w_cmapdata; if (wmatch->w_flags & WF_CMSHOG) { w->w_flags |= WF_CMSHOG; goto loadcmshog; } else { goto loadcmsstd; } } else { /* * Free existing cms if not shared. */ dtop_cmsfree(dtop, w); /* * Try allocating a new color map segment. */ w->w_cms = cmschange->cc_cms; if ((w->w_cms.cms_addr = dtop_cmsalloc(dtop, (long)w->w_cms.cms_size)) != -1) { loadcmsstd: /* * Allocation succeded. Load std map. */ if (error = winioctl_cmapcopy( &w->w_cms, &dtop->dt_cmap, to_offset, &cmschange->cc_cms, &cmschange->cc_map, 0, copyin)) { bzero((caddr_t)&w->w_cms, sizeof (struct colormapseg)); returnerror(error); } dtop_stdizecmap(dtop, &dtop->dt_cmap, w->w_cms.cms_addr, w->w_cms.cms_size); } else { /* * Allocation failed. Make hog. */ w->w_cms.cms_addr = 0; w->w_cmapdata = dtop_alloccmapdata(dtop, &w->w_cmap, w->w_cms.cms_size); if (w->w_cmapdata == 0) { returnerror(ENXIO); } loadcmshog: if (error = winioctl_cmapcopy( &w->w_cms, &w->w_cmap, to_offset, &cmschange->cc_cms, &cmschange->cc_map, 0, copyin)) { cms_freecmapdata(w->w_cmapdata, &w->w_cmap, w->w_cms.cms_size); w->w_cmapdata = 0; bzero((caddr_t)&w->w_cms, sizeof (struct colormapseg)); returnerror(error); } dtop_stdizecmap(dtop, &w->w_cmap, w->w_cms.cms_addr, w->w_cms.cms_size); w->w_flags |= WF_CMSHOG; } } } if (dtop->dt_cursorwin == w) { dtop->dt_flags |= DTF_NEWCMAP; dtop_set_cursor(dtop); } else if (dtop->dt_cursorwin && (strncmp(dtop->dt_cursorwin->w_cms.cms_name, w->w_cms.cms_name, CMS_NAMESIZE) == 0)) { /* Case when w is hog and cms is same as cursor win */ dtop->dt_flags |= DTF_NEWCMAP; dtop_set_cursor(dtop); } else { /* * Update color map with std if not being hogged on * this desktop and change was to the std map. */ if (!(w->w_flags & WF_CMSHOG)) { if (dtop->dt_cursorwin && (dtop->dt_cursorwin->w_flags & WF_CMSHOG)) {} else dtop_putcolormap(dtop, dtop->dt_cmsize, &dtop->dt_cmap); } } win_return_cms(w, &cmschange->cc_cms); break; } case WINGETCMS: { register struct cmschange *cmschange = (struct cmschange *)data; int from_offset; if (cmschange->cc_map.cm_red != 0 && cmschange->cc_map.cm_green != 0 && cmschange->cc_map.cm_blue != 0) { /* * cmschange->cc_cms.cms_size is the count of the * section of the color map wanted. */ if (cmschange->cc_cms.cms_size > w->w_cms.cms_size) returnerror(EINVAL); /* * Cmschange->cc_cms.cms_addr describes the source * within the window's colormap segment. * Always loading into cmschange->cc_map at [0]th slot. */ from_offset = cmschange->cc_cms.cms_addr; cmschange->cc_cms.cms_addr = 0; if (w->w_flags & WF_CMSHOG) error = winioctl_cmapcopy( &cmschange->cc_cms, &cmschange->cc_map, 0, &w->w_cms, &w->w_cmap, from_offset, copyout); else error = winioctl_cmapcopy( &cmschange->cc_cms, &cmschange->cc_map, 0, &w->w_cms, &dtop->dt_cmap, from_offset, copyout); if (error) returnerror(error); } win_return_cms(w, &cmschange->cc_cms); break; } case WINSETPLANEGROUP: { int new_plane_group = *(int *)data; /* Validate plane group */ if (new_plane_group >= DTOP_MAX_PLANE_GROUPS || dtop->dt_plane_groups_available[new_plane_group] == 0) returnerror(EINVAL); if (w->w_plane_group != new_plane_group) { w->w_plane_group = new_plane_group; /* Potentially new colormap usage (hog vs std) */ if (dtop->dt_cursorwin == w) { dtop->dt_flags |= DTF_NEWCMAP; dtop_set_cursor(dtop); } /* * Replace cursor if up because it will be in another * plane group. Do it now incase client is counting * on cursor state. */ if ((dtop->dt_cursorwin == w) && (!(dtop->dt_plane_groups_available[PIXPG_CURSOR]))) { dtop_cursordown(dtop); /* update the shared cusor */ win_shared_update_cursor(dtop); dtop_cursorup(dtop); } } /* Notice that window owner knows about plane groups */ w->w_flags |= WF_PLANE_GROUP_SET; break; } case WINGETPLANEGROUP: *(int *)data = w->w_plane_group; break; case WINGETAVAILPLANEGROUPS: bcopy((caddr_t)dtop->dt_plane_groups_available, (caddr_t)((struct win_plane_groups_available *)data)->plane_groups_available, WIN_MAX_PLANE_GROUPS); break; /* * Screen creation, inquiry and deletion. */ case WINSCREENNEW: { struct usrdesktop *udtop = (struct usrdesktop *)data; register Desktop *dt; dtop = NULL; /* Allocate an unused desktop */ for (dt = desktops; dt < &desktops[ndesktops]; dt++) { if (!dtop && !(dt->dt_flags&DTF_PRESENT)) dtop = dt; if (dt->dt_screen.scr_fbname[0] != '\0' && (strncmp(udtop->udt_scr.scr_fbname, dt->dt_screen.scr_fbname, SCR_NAMESIZE) == 0)) returnerror(EBUSY); } if (!dtop || dtop->dt_rootwin) returnerror(EBUSY); /* Check window that is to become root for cleanliness */ if ((w->w_flags & WF_INSTALLED) || w->w_link[WL_OLDERSIB] || w->w_link[WL_YOUNGERSIB] || wt_badchildren(w)) { returnerror(EINVAL); } /* * Set up w and rootwin now so that dtop_close gets called * if encounter error during opening of dtop. */ dtop->dt_rootwin = w; dtop->dt_exit_seconds = 0; w->w_desktop = dtop; w->w_flags |= WF_ROOTWINDOW; /* Initialize cursor data. */ dtopcursorfixup(&dtop->dt_cursor); /* Copy screen. */ dtop->dt_screen = udtop->udt_scr; /* Open frame buffer. */ if (error = dtop_openfb(dtop, udtop->udt_fbfd)) { returnerror(error); } /* Initialize root windows plane group */ win_pick_plane_group(dtop, w); /* Initialize root window's rect. */ w->w_rect = dtop->dt_screen.scr_rect; /* Set cursor in middle of screen */ dtop->dt_rt_x = dtop->dt_ut_x = dtop->dt_screen.scr_rect.r_left+ (dtop->dt_screen.scr_rect.r_width/2); dtop->dt_rt_y = dtop->dt_ut_y = dtop->dt_screen.scr_rect.r_top+ (dtop->dt_screen.scr_rect.r_height/2); /* * Update the shared memory mouse x, y */ win_shared_update_mouse_xy(dtop->shared_info, dtop->dt_rt_x, dtop->dt_rt_y); /* * Install on desktop so that if input turn on fails then * dtop_close will clean up. */ w->w_flags |= WF_INSTALLED; dtop->dt_flags |= DTF_PRESENT; /* * See if input devices that window wants to use are in service. * If so then use that workstation else open a new one. */ if ((ws = ws_indev_match_name(udtop->udt_scr.scr_kbdname, (Wsindev **)0)) != WORKSTATION_NULL) goto UseWs; if ((ws = ws_indev_match_name(udtop->udt_scr.scr_msname, (Wsindev **)0)) != WORKSTATION_NULL) goto UseWs; /* Open new workstation */ if ((ws = ws_open()) == WORKSTATION_NULL) returnerror(EBUSY); /* Place locator on first dtop */ ws->ws_loc_dtop = dtop; win_shared_update_cursor_active(dtop->shared_info, TRUE); ws->ws_pick_dtop = dtop; /* Initialize restricted plane groups */ if (dtop->dt_screen.scr_flags & SCR_8BITCOLORONLY || dtop->dt_screen.scr_flags & SCR_OVERLAYONLY) dtop_update_enable(dtop, DESKTOP_NULL, 1); UseWs: /* * Install desktop with workstation so that if input open * fails then ws_close will clean up. */ dtop->dt_next = ws->ws_dtop; ws->ws_dtop = dtop; dtop->dt_ws = ws; w->w_ws = ws; /* Invalidate clipping so that SIGWINCH generated */ dtop_invalidateclipping(dtop, w, &w->w_rect); /* Open kbd & ms input devices if not already open */ if ((udtop->udt_scr.scr_kbdname[0] != NULL) && (ws_indev_match_name(udtop->udt_scr.scr_kbdname, (Wsindev **)0) == WORKSTATION_NULL)) { if (ws_open_indev(ws, udtop->udt_scr.scr_kbdname, udtop->udt_kbdfd) == WSINDEV_NULL) returnerror(u.u_error); } if ((udtop->udt_scr.scr_msname[0] != NULL) && (ws_indev_match_name(udtop->udt_scr.scr_msname, (Wsindev **)0) == WORKSTATION_NULL)) { if (ws_open_indev(ws, udtop->udt_scr.scr_msname, udtop->udt_msfd) == WSINDEV_NULL) returnerror(u.u_error); } /* Set focuses and cursor window */ ws_set_focus(ws, FF_PICK_CHANGE); dtop_set_cursor(dtop); break; } case WINSCREENGET: *(struct screen *)data = dtop->dt_screen; break; case WINSCREENDESTROY: { extern int hz; int win_check_destroy(); int wnum; Window *w_probe; /* Don't let any other processes install on dtop */ dtop->dt_flags |= DTF_EXITING; /* Stop reading input if workstation going away */ if ((ws->ws_dtop == dtop) && (dtop->dt_next == DESKTOP_NULL)) ws->ws_flags |= WSF_EXITING; /* Tell everyone, other than the caller, to terminate */ winpsnotkill = u.u_procp->p_pid; wt_enumeratechildren(winkill, dtop->dt_rootwin, (struct rect *)0); winpsnotkill = 0; /* Setup timeout to do wakeup for following wait */ timeout(win_check_destroy, (caddr_t)dtop, hz); /* Wait for all children of root to go away */ while ((dtop->dt_flags & DTF_PRESENT) && (dtop->dt_exit_seconds < win_exit_seconds) && (dtop->dt_rootwin != WINDOW_NULL) && (dtop->dt_rootwin->w_link[WL_OLDESTCHILD] != WINDOW_NULL) && (dtop->dt_rootwin->w_link[WL_YOUNGESTCHILD] != WINDOW_NULL)) { (void) sleep((caddr_t)&dtop->dt_flags, LOCKPRI); if (dtop->dt_exit_seconds > 300 && print_waiting) { printf("Waiting for tools to terminate...\n"); print_waiting = FALSE; } else { if (dtop->dt_exit_seconds > 700 && print_still_waiting) { printf("Still waiting...\n"); print_still_waiting = FALSE; } } } /* Kill processes that wouldn't go away */ if (dtop->dt_flags & DTF_PRESENT) { /* Look for any window that is connected to dtop */ for (wnum = 0; wnum < win_nwindows; wnum++) { w_probe = winbufs[wnum]; if ((w_probe != WINDOW_NULL) && (w_probe->w_flags & WF_OPEN) && (w_probe->w_desktop == dtop) && (w_probe->w_pid != u.u_procp->p_pid)) winsignal(w_probe, SIGKILL); } } /* Calling process is responsible for cleaning self up */ print_waiting = TRUE; print_still_waiting = TRUE; break; } case WINSCREENPOSITIONS: { int *neighbors = (int *)data; struct window *window; for (i = 0; i < SCR_POSITIONS; i++) { if (neighbors[i] == WIN_NULLLINK) { dtop->dt_neighbors[i] = NULL; continue; } if (wt_numbertowindow(neighbors[i], &window) < 0) returnerror(EINVAL); dtop->dt_neighbors[i] = window->w_desktop; } break; } case WINGETSCREENPOSITIONS: { int *neighbors = (int *)data; for (i = 0; i < SCR_POSITIONS; i++) { if (dtop->dt_neighbors[i] == NULL) { neighbors[i] = WIN_NULLLINK; continue; } wt_windowtonumber(dtop->dt_neighbors[i]->dt_rootwin, &neighbors[i]); } break; } case WINSETKBD: { struct usrdesktop *udtop = (struct usrdesktop *)data; /* Open kbd input device if not already open */ if ((udtop->udt_scr.scr_kbdname[0] != NULL) && (ws_indev_match_name(udtop->udt_scr.scr_kbdname, (Wsindev **)0) == WORKSTATION_NULL)) { if (ws_open_indev(ws, udtop->udt_scr.scr_kbdname, udtop->udt_kbdfd) == WSINDEV_NULL) returnerror(u.u_error); } break; } case WINSETMS: { struct usrdesktop *udtop = (struct usrdesktop *)data; /* Open ms input device if not already open */ if ((udtop->udt_scr.scr_msname[0] != NULL) && (ws_indev_match_name(udtop->udt_scr.scr_msname, (Wsindev **)0) == WORKSTATION_NULL)) { if (ws_open_indev(ws, udtop->udt_scr.scr_msname, udtop->udt_msfd) == WSINDEV_NULL) returnerror(u.u_error); } break; } case WINSETINPUTDEV: { struct input_device *ind = (struct input_device *)data; Wsindev *indev; if (ind->id == -1) { /* See if given device in open */ if ((ind->name[0] != NULL) && (ws_indev_match_name(ind->name, &indev) != WORKSTATION_NULL)) { /* Close given device */ (void) ws_close_indev(ws, indev); } } else { /* Open input device if not already open */ if ((ind->name[0] != NULL) && (ws_indev_match_name(ind->name, (Wsindev **)0) == WORKSTATION_NULL)) { if (ws_open_indev(ws, ind->name, ind->id) == WSINDEV_NULL) returnerror(u.u_error); } } break; } case WINGETINPUTDEV: { struct input_device *ind = (struct input_device *)data; int n; Wsindev *indev; if (ind->id == -1) { /* See if given device in open */ if ((ind->name[0] != NULL) && (ws_indev_match_name(ind->name, &indev) != WORKSTATION_NULL)) { returnerror (0); } else { returnerror (ENODEV); } } else { /* Get given numbered device */ for (indev = ws->ws_indev, n = 0; indev != WSINDEV_NULL; indev = indev->wsid_next, n++) { if (n == ind->id) { for (i = 0;i < SCR_NAMESIZE; i++) ind->name[i] = indev->wsid_name[i]; returnerror (0); } } returnerror (ENODEV); } /* NOTREACHED */ } case WINGETKBDMASK: { struct inputmask *im = (struct inputmask *)data; *im = w->w_kbdmask; break; } case WINGETPICKMASK: { struct inputmask *im = (struct inputmask *)data; *im = w->w_pickmask; break; } case WINSETKBDMASK: { struct inputmask *im = (struct inputmask *)data; w->w_kbdmask = *im; w->w_flags |= WF_KBD_MASK_SET; break; } case WINSETPICKMASK: { struct inputmask *im = (struct inputmask *)data; w->w_pickmask = *im; break; } case WINSETNEXTINPUT: { struct window *windownext; if (wt_numbertowindow(*(int *)data, &windownext) < 0) returnerror(EINVAL); w->w_inputnext = windownext; break; } case WINGETNEXTINPUT: wt_windowtonumber(w->w_inputnext, (int *)data); break; case WINGETBUTTONORDER: *(u_int *)data = ws_button_order; break; case WINSETBUTTONORDER: if (*(u_int *)data > 5) { returnerror(EINVAL); } else { ws_button_order = *(u_int *)data; } break; case WINGETSCALING: { register Ws_scale *buffer = (Ws_scale *)data; register Ws_scale *scales = ws_scaling; register int count; for (count = 0; count < WS_SCALE_MAX_COUNT; count++) { *buffer++ = *scales; if (scales->ceiling == WS_SCALE_MAX_CEILING) break; scales++; } break; } case WINSETSCALING: { register Ws_scale *buffer = (Ws_scale *)data; register Ws_scale *scales = ws_scaling; register int count; for (count = 0; count < WS_SCALE_MAX_COUNT; count++) { *scales = *buffer++; if (scales->ceiling == WS_SCALE_MAX_CEILING) break; scales++; } if (count == WS_SCALE_MAX_COUNT) { scales->ceiling = WS_SCALE_MAX_CEILING; scales->factor = 1; } break; } case WINGETVUIDVALUE: { Firm_event *fe = (Firm_event *)data; switch (fe->id) { case LOC_X_ABSOLUTE: fe->value = dtop->dt_ut_x - w->w_screenx; break; case LOC_Y_ABSOLUTE: fe->value = dtop->dt_ut_y - w->w_screeny; break; default: fe->value = vuid_get_value(ws->ws_instate, fe->id); } break; } case WINGETFOCUSEVENT: { Focus_event *foe = ((Focus_event *)data); foe->id = ws->ws_kbd_focus_pt.id; foe->value = ws->ws_kbd_focus_pt.value; foe->shifts = ws->ws_kbd_focus_pt.shifts; break; } case WINSETFOCUSEVENT: { Focus_event *foe = ((Focus_event *)data); ws->ws_kbd_focus_pt.id = foe->id; ws->ws_kbd_focus_pt.value = foe->value; ws->ws_kbd_focus_pt.shifts = foe->shifts; break; } case WINGETSWALLOWEVENT: { Focus_event *foe = ((Focus_event *)data); foe->id = ws->ws_kbd_focus_sw.id; foe->value = ws->ws_kbd_focus_sw.value; foe->shifts = ws->ws_kbd_focus_sw.shifts; break; } case WINSETSWALLOWEVENT: { Focus_event *foe = ((Focus_event *)data); ws->ws_kbd_focus_sw.id = foe->id; ws->ws_kbd_focus_sw.value = foe->value; ws->ws_kbd_focus_sw.shifts = foe->shifts; break; } case WINSETKBDFOCUS: { Window *windowfocus; if (wt_numbertowindow(*(int *)data, &windowfocus) < 0) returnerror(EINVAL); /* Update kbd focus */ if ((ws->ws_kbdfocus_next != windowfocus) && ((ws->ws_kbd_focus_sw.id != LOC_WINENTER) || (ws->ws_kbd_focus_pt.id != LOC_WINENTER))) { ws->ws_kbdfocus_next = windowfocus; ws->ws_flags |= WSF_SWALLOW_FOCUS_EVENT; /* * Send directly unless in middle of focus change * sequence, then will catch the request next * time get to SEND_Q_TOP. */ if (ws->ws_focus_state == SEND_Q_TOP) ws->ws_focus_state = SEND_DIRECT_REQUEST; } break; } case WINGETKBDFOCUS: { int winnumber; wt_windowtonumber(ws->ws_kbdfocus, &winnumber); *(int *)data = winnumber; break; } case WINGETEVENTTIMEOUT: { struct timeval *tv = (struct timeval *)data; *tv = ws->ws_eventtimeout; break; } case WINSETEVENTTIMEOUT: { struct timeval *tv = (struct timeval *)data; ws->ws_eventtimeout = *tv; break; } case WINUNLOCKEVENT: /* * Explicitly check that w is lock holder because some parameter * configurations (ws_eventtimeout == 0,0) cause the event * lock to be very loosely acquired and released. Thus, we * don't want to accidently release another window's lock. */ if ((ws->ws_flags & WSF_LOCKED_EVENT) && (ws->ws_event_consumer == w)) wlok_forceunlock(&ws->ws_eventlock); break; case WINREFUSEKBDFOCUS: /* * Turning off the WSF_KBD_REQUEST_PENDING flag says to * not give ws_kbdfocus_next the kbd focus. */ ws->ws_flags &= ~WSF_KBD_REQUEST_PENDING; break; case WINDBLACCESS: /* * Turnon the WF_DBL_ACCESS flag. If this was the first * Double bufferer, pick background to be PR_DBL_A (arbitrary) */ if ((dtop->dt_flags & DTF_DBLBUFFER ) && !(w->w_flags & WF_DBLBUF_ACCESS)) { w->w_flags |= WF_DBLBUF_ACCESS; if ( dtop->dt_dblcount == 0 ) { dtop->dt_curdbl = w; dtop->shared_info->go_to_kernel = 1; w->w_dbl_rdstate = PW_DBL_BACK; w->w_dbl_wrstate = PW_DBL_BACK; /* * Increment the count only after * taking down the cursor and redrawing it in * the foreground. */ dtop_changedisplay(dtop, PR_DBL_A, PR_DBL_B, TRUE); } else dtop->dt_dblcount++; } break; case WINDBLRLSE: /* * Release the double buffer and if there is any * other double bufferer choose it. */ if (( dtop->dt_flags & DTF_DBLBUFFER ) && (w->w_flags & WF_DBLBUF_ACCESS)) { dtop_copy_dblbuffer(dtop, w); w->w_flags &= ~WF_DBLBUF_ACCESS; w->w_dbl_wrstate = PW_DBL_BOTH; w->w_dbl_rdstate = PW_DBL_BACK; if (--dtop->dt_dblcount == 0) { dtop->shared_info->go_to_kernel = 0; if (pr_dbl_set(dtop->dt_pixrect, PR_DBL_READ, w->w_dbl_rdstate, PR_DBL_WRITE, w->w_dbl_wrstate, 0)) #ifdef WINDEVDEBUG printf("Error in WINDRLSE\n"); #else ; #endif dtop->dt_curdbl = WINDOW_NULL; } else dtop_choose_dblbuf(dtop); } break; case WINDBLFLIP: /* * Flip the display and choose another double bufferer * (dt_curdbl field in the dtop struct) if the cursor is * not in the current bufferer. */ if (dtop->dt_flags & DTF_DBLBUFFER) dtop_flip_display(dtop, w); break; case WINDBLSET: { /* * Set display, write or read control bits. Converts * Values like PW_DBL_FORE, PW_DBL_BACK to PR_DBL_A * or PR_DBL_B. (Allowed only when the window is the current * double bufferer). */ register struct pwset *list = (struct pwset *)data; if (!dtop->dt_dblcount) break; /* Keep track of what the read/write setting is */ if (list->attribute == PR_DBL_WRITE) w->w_dbl_wrstate = list->value; else if (list->attribute == PR_DBL_READ) w->w_dbl_rdstate = list->value; if ((dtop->dt_flags & DTF_DBLBUFFER) && ((w == dtop->dt_curdbl) || (dtop->dt_displaygrabber == w))){ int value; if (list->value == PW_DBL_BOTH) value = PR_DBL_BOTH; else if (list->value == PW_DBL_FORE) value = dtop->dt_dbl_frgnd; else if (list->value == PW_DBL_BACK) value = dtop->dt_dbl_bkgnd; else returnerror(0); if (pr_dbl_set(dtop->dt_pixrect, list->attribute, value, 0)) #ifdef WINDEVDEBUG printf("error in ioctl SET for dbl_set\n"); #else ; #endif } break; } case WINDBLGET: { register struct pwset *list = (struct pwset *)data; if (dtop->dt_flags & DTF_DBLBUFFER ) { if (list->attribute == PR_DBL_AVAIL) list->value = TRUE; else if (list->attribute == PR_DBL_READ ) list->value = w->w_dbl_rdstate; else if (list->attribute == PR_DBL_WRITE) list->value = w->w_dbl_wrstate; else list->value = PW_DBL_ERROR; /* Error ? */ } else list->value = FALSE; break; } case WINDBLCURRENT:{ /* * Returns the rect of the dbl bufferer in relation to the * current pixwin */ register struct rect *rectobj = (struct rect *)data; if (dtop->dt_curdbl && dtop == dtop->dt_curdbl->w_desktop){ rectobj->r_left = dtop->dt_curdbl->w_screenx - w->w_screenx; rectobj->r_top = dtop->dt_curdbl->w_screeny - w->w_screeny; rectobj->r_width = dtop->dt_curdbl->w_rect.r_width; rectobj->r_height = dtop->dt_curdbl->w_rect.r_height; } break; } case WINWIDSET: w->w_wid_dbl_info = *(struct fb_wid_dbl_info *) data; break; case WINWIDGET: *(struct fb_wid_dbl_info *) data = w->w_wid_dbl_info; break; case WINSHAREQUEUE: if (dtop->dt_sharedq_owner) { returnerror(EADDRINUSE); } else if (dtop->shared_info->shared_eventq.size <= 0) { returnerror(0); } else { dtop->dt_sharedq_owner = w; } break; case WINCLEARCURSORPLANES: { register struct rect *rectobj = (struct rect *)data; if ((dtop->dt_plane_groups_available[PIXPG_CURSOR]) && (dtop->dt_plane_groups_available[PIXPG_CURSOR_ENABLE])) { win_clear_cursor_plane_groups(w, rectobj); } break; } /* * Record/playback utilities */ #ifdef WINSVJ case WINSETRECQUE: case WINSETRECORD: case WINREADRECQ: case WINSETPLAYBACK: case WINSETPLAYINTR: case WINSETSYNCPT: error = svjioctl(dev, (int) cmd, data, dtop, ws, pri, error); win_playrec_sync_flg = 0; break; #endif default: returnerror(ENOTTY); /* Note: ?? */ } done: if (always_signal) { /* * Clear go_to_kernel field. */ if (winnotify_inorder) { if (dtop && dtop->shared_info) dtop->shared_info->go_to_kernel = 0; wt_sigwnch_nextwin(); /* notify next window */ } } #ifdef WINSVJ if (((ws != NULL) && (ws->ws_flags&WSF_RECORD_QUEUE)) && (win_playrec_sync_flg)) (void) svjioctl(dev, (int) cmd, data, dtop, ws, pri, error); #endif (void) splx(pri); return (error); restart: u.u_eosys = RESTARTSYS; returnerror(EINTR); } static void win_return_cms(w, cms) register Window *w; struct colormapseg *cms; { *cms = w->w_cms; /* * Adjust addr if window is in the overlay plane. * Note: This is a hack to get around the fact that * we haven't provided a separate colormap allocation * mechanism for each plane group. We are allocating * from a single colormap instead. If this situation * is fixed in a future release then the following * code could be removed. */ if (w->w_plane_group == PIXPG_OVERLAY || (w->w_desktop->dt_flags & DTF_MULTI_PLANE_GROUPS && !(w->w_flags & WF_PLANE_GROUP_SET))) cms->cms_addr = 0; } static void win_pick_plane_group(dtop, w) Desktop *dtop; Window *w; { if (dtop->dt_pixrect) { if (!(w->w_flags & WF_PLANE_GROUP_SET)) { w->w_plane_group = pr_get_plane_group(dtop->dt_pixrect); } } } /*ARGSUSED*/ wt_sizechanged(window, rectnotused) register struct window *window; struct rect *rectnotused; { register struct window *winparent = window->w_link[WL_PARENT]; struct rect rect; /* * Blanket windows should stay the same size as their parents. */ if ((window->w_userflags & WUF_BLANKET) && (winparent)) { /* * Construct rect of what blanket window should be. */ rect_construct(&rect, 0, 0, winparent->w_rect.r_width, winparent->w_rect.r_height); /* * Change only if different. */ if (!rect_equal(&rect, &window->w_rect)) { window->w_rect = rect; window->w_flags |= WF_SIZECHANGED; } } } wincopyoutrl(rl, winclip) register struct rectlist *rl; register struct winclip *winclip; { int bytesneeded; register struct rectnode *rn; struct rectlist rluser; caddr_t ptuser; bytesneeded = sizeof (struct rectlist); for (rn = rl->rl_head; rn; rn = rn->rn_next) bytesneeded += sizeof (struct rectnode); if (bytesneeded > winclip->wc_blockbytes) { winclip->wc_blockbytes = bytesneeded; return (EFBIG); } rluser = *rl; ptuser = (caddr_t)(winclip->wc_block + sizeof (struct rectlist)); if (rl->rl_head != NULL) rluser.rl_head = (struct rectnode *)ptuser; for (rn = rl->rl_head; rn; rn = rn->rn_next) { struct rectnode rnuser; rnuser = *rn; if (rn->rn_next) rnuser.rn_next = (struct rectnode *) (ptuser + sizeof (struct rectnode)); if (copyout((char *)&rnuser, ptuser, sizeof (struct rectnode))) return (EFAULT); if (rn == rl->rl_tail) rluser.rl_tail = (struct rectnode *)ptuser; ptuser += sizeof (struct rectnode); } if (copyout((caddr_t)&rluser, (caddr_t)winclip->wc_block, sizeof (struct rectlist))) return (EFAULT); return (0); } static int check_crosshair_info(cursor) register struct cursor *cursor; { if ((cursor->horiz_hair_thickness < 0) || (cursor->horiz_hair_thickness > CURSOR_MAX_HAIR_THICKNESS)) return (EINVAL); if ((cursor->vert_hair_thickness < 0) || (cursor->vert_hair_thickness > CURSOR_MAX_HAIR_THICKNESS)) return (EINVAL); return (0); } winio_getusercursor(cursor, mpr, mpr_data, image, empty) register struct cursor *cursor; register struct pixrect *mpr; struct mpr_data *mpr_data; short *image; int *empty; { int error, imagesize; *empty = 1; if (!cursor->cur_shape) return (0); if (error = copyin((caddr_t)cursor->cur_shape, (caddr_t)mpr, sizeof(struct pixrect))) return (error); if (!mpr->pr_data) return (0); if (error = copyin((caddr_t)mpr->pr_data, (caddr_t)mpr_data, sizeof(struct mpr_data))) return (error); if (!mpr_data->md_image) return (0); imagesize = mpr_data->md_linebytes * mpr->pr_height; if (imagesize > CUR_MAXIMAGEBYTES) return (E2BIG); bzero((caddr_t) image, CUR_MAXIMAGEBYTES); if (error = copyin((caddr_t)mpr_data->md_image, (caddr_t)image, (u_int) imagesize)) return (error); *empty = 0; return (0); } winioctl_cmapcopy(cmsto, cmapto, offsetto, cmsfrom, cmapfrom, offsetfrom, func) register struct colormapseg *cmsto, *cmsfrom; register struct cms_map *cmapto, *cmapfrom; int (*func)(), offsetto, offsetfrom; { register int firstto = cmsto->cms_addr+offsetto; register int firstfrom = cmsfrom->cms_addr+offsetfrom; register int n; int lastto = firstto+cmsto->cms_size-1; int lastfrom = firstfrom+cmsfrom->cms_size-1; /* * Test to see that source and destination data is consistent with self. */ if (firstto > lastto || firstto < 0 || firstfrom > lastfrom || firstfrom < 0 || !cmapto->cm_red || !cmapto->cm_green || !cmapto->cm_blue || !cmapfrom->cm_red || !cmapfrom->cm_green || !cmapfrom->cm_blue) return (EINVAL); /* * Limit range so that destination not overrun. */ n = ((firstto+cmsfrom->cms_size-1) > lastto) ? lastto-firstto+1 : cmsfrom->cms_size; /* * Move data. */ if ((*func)(&(cmapfrom->cm_red[firstfrom]), &(cmapto->cm_red[firstto]), n) || (*func)(&(cmapfrom->cm_green[firstfrom]), &(cmapto->cm_green[firstto]), n) || (*func)(&(cmapfrom->cm_blue[firstfrom]), &(cmapto->cm_blue[firstto]), n)) return (EFAULT); return (0); } win_check_destroy(data) caddr_t data; { register Desktop *dtop = (Desktop *)data; extern int hz; /* Wakeup destroy even if desktop not present */ wakeup((caddr_t)&dtop->dt_flags); if (dtop->dt_flags & DTF_PRESENT) { dtop->dt_exit_seconds++; timeout(win_check_destroy, (caddr_t)dtop, hz); } } static int wt_gettreelayer(parent, data) register Window *parent; register Win_tree_layer *data; { register Window *w; register Win_enum_node *nodep; register int size; int installed, uninstalled; int w_num; if (parent == WINDOW_NULL) return EINVAL; wt_count_layer(parent, &installed, &uninstalled); size = (installed + uninstalled) * sizeof (struct win_enum_node); if (data->bytecount < size) { data->bytecount -= size; return EFBIG; } else data->bytecount = size; nodep = data->buffer; w = parent->w_link[WL_OLDESTCHILD]; while (w != WINDOW_NULL) { wt_copy_layer_node(w, nodep++); w = w->w_link[WL_YOUNGERSIB]; } for (w_num = 0; w = winfromopendev(w_num); w_num++) { if (w->w_link[WL_PARENT] == parent && !(w->w_flags & WF_INSTALLED)) wt_copy_layer_node(w, nodep++); } return 0; } static void wt_copy_layer_node(w, nodep) register Window *w; register Win_enum_node *nodep; { int w_num; Win_enum_node node; wt_windowtonumber(w, &w_num); node.me = w_num; wt_windowtonumber(w->w_link[WL_PARENT], &w_num); node.parent = w_num; wt_windowtonumber(w->w_link[WL_YOUNGERSIB], &w_num); node.upper_sib = w_num; wt_windowtonumber(w->w_link[WL_OLDESTCHILD], &w_num); node.lowest_kid = w_num; if (w->w_flags & WF_INSTALLED) node.flags = WIN_NODE_INSERTED; else node.flags = 0; if (w->w_userflags & WUF_WMGR1) { /* iconic */ node.icon_rect = w->w_rect; node.open_rect = w->w_rectsaved; } else { /* open */ node.flags |= WIN_NODE_OPEN; node.open_rect = w->w_rect; node.icon_rect = w->w_rectsaved; } (void) copyout((caddr_t)&node, (caddr_t)nodep, sizeof (struct win_enum_node)); } static void wt_count_layer(parent, in, out) register Window *parent; register int *in, *out; { /* register */ int i; register Window *w; *in = 0; *out = 0; for (i = 0; w = winfromopendev(i); i++) { if (w->w_link[WL_PARENT] == parent) { if (w->w_flags & WF_INSTALLED) { *in += 1; } else { *out += 1; } } } } static void win_prepare_surface(w) register Window *w; { register Desktop *dtop = w->w_desktop; /* See if anything to do */ if (rl_empty(&w->w_rlfixup)) /* Assumes no side affects from calling this routine */ return; /* Dont take the cursor down if there are cursor planes */ if ((dtop->dt_cursorwin == w) && (!dtop->dt_plane_groups_available[PIXPG_CURSOR])) dtop_cursordown(dtop); if (dtop->dt_plane_groups_available[PIXPG_OVERLAY_ENABLE]) { /* NOTE: ADD HERE AS NEW ENABLE PLANES BECOME AVAILABLE */ /* Enable black and white overlay enable plane */ win_initialize_plane_group(w, PIXPG_OVERLAY_ENABLE, 1); #ifndef PRE_FLAMINGO /* Disable video if available */ if (dtop->dt_plane_groups_available[PIXPG_VIDEO_ENABLE]) win_initialize_plane_group(w, PIXPG_VIDEO_ENABLE, 0); #endif /* Clear color plane group (for tidiness) */ if (dtop->dt_plane_groups_available[PIXPG_8BIT_COLOR]) win_initialize_plane_group(w, PIXPG_8BIT_COLOR, 0); else if (dtop->dt_plane_groups_available[PIXPG_24BIT_COLOR]) win_initialize_plane_group(w, PIXPG_24BIT_COLOR, 0); } if (dtop->dt_plane_groups_available[PIXPG_CURSOR_ENABLE]) { win_initialize_plane_group(w, PIXPG_CURSOR_ENABLE, 0); /* Color planes for tidines*/ if (dtop->dt_plane_groups_available[PIXPG_8BIT_COLOR]) win_initialize_plane_group(w, PIXPG_8BIT_COLOR, 0); else if (dtop->dt_plane_groups_available[PIXPG_24BIT_COLOR]) win_initialize_plane_group(w, PIXPG_24BIT_COLOR, 0); } if ((dtop->dt_cursorwin == w) && (!(dtop->dt_plane_groups_available[PIXPG_CURSOR]))) dtop_cursordown(dtop); } static void win_initialize_plane_group(w, plane_group, color) Window *w; int plane_group; int color; { int plane_group_save; register struct pixrect *pr = w->w_desktop->dt_pixrect; /* Remember original plane group (the planes should be full) */ plane_group_save = pr_get_plane_group(pr); /* Set plane group */ pr_set_plane_group(pr, plane_group); /* Set planes to enable writing offset, effectively clears */ (void) dtop_rl_rop(pr, -w->w_screenx, -w->w_screeny, &w->w_rlfixup, PIX_COLOR(color)|PIX_SRC|PIX_DONTCLIP, (struct pixrect *)0, 0, 0); /* Reset plane group */ pr_set_plane_group(pr, plane_group_save); } static void win_clear_cursor_plane_groups(w, rect) Window *w; struct rect *rect; { int plane_group_save; register struct pixrect *pr = w->w_desktop->dt_pixrect; /* Remember original plane group (the planes should be full) */ plane_group_save = pr_get_plane_group(pr); pr_set_plane_group(pr, PIXPG_CURSOR_ENABLE); (void) pr_rop(pr, rect->r_left, rect->r_top,rect->r_width, rect->r_height, PIX_CLR|PIX_DONTCLIP, (struct pixrect *)0, 0, 0); pr_set_plane_group(pr, PIXPG_CURSOR); (void) pr_rop(pr, rect->r_left, rect->r_top,rect->r_width, rect->r_height, PIX_CLR|PIX_DONTCLIP, (struct pixrect *)0, 0, 0); /* Reset plane group */ pr_set_plane_group(pr, plane_group_save); }