Annotation of researchv9/X11/src/X.V11R1/server/ddx/sun/sunMouse.c, revision 1.1.1.1

1.1       root        1: /*-
                      2:  * sunMouse.c --
                      3:  *     Functions for playing cat and mouse... sorry.
                      4:  *
                      5:  * Copyright (c) 1987 by the Regents of the University of California
                      6:  *
                      7:  * Permission to use, copy, modify, and distribute this
                      8:  * software and its documentation for any purpose and without
                      9:  * fee is hereby granted, provided that the above copyright
                     10:  * notice appear in all copies.  The University of California
                     11:  * makes no representations about the suitability of this
                     12:  * software for any purpose.  It is provided "as is" without
                     13:  * express or implied warranty.
                     14:  *
                     15:  *
                     16:  */
                     17: 
                     18: /************************************************************
                     19: Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA.
                     20: 
                     21:                     All Rights Reserved
                     22: 
                     23: Permission  to  use,  copy,  modify,  and  distribute   this
                     24: software  and  its documentation for any purpose and without
                     25: fee is hereby granted, provided that the above copyright no-
                     26: tice  appear  in all copies and that both that copyright no-
                     27: tice and this permission notice appear in  supporting  docu-
                     28: mentation,  and  that the names of Sun or MIT not be used in
                     29: advertising or publicity pertaining to distribution  of  the
                     30: software  without specific prior written permission. Sun and
                     31: M.I.T. make no representations about the suitability of this
                     32: software for any purpose. It is provided "as is" without any
                     33: express or implied warranty.
                     34: 
                     35: SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
                     36: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
                     37: NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
                     38: ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
                     39: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
                     40: PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
                     41: OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
                     42: THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     43: 
                     44: ********************************************************/
                     45: 
                     46: #ifndef        lint
                     47: static char sccsid[] = "%W %G Copyright 1987 Sun Micro";
                     48: #endif
                     49: 
                     50: #define NEED_EVENTS
                     51: #include    "sun.h"
                     52: 
                     53: typedef struct {
                     54:     int            bmask;          /* Current button state */
                     55:     Bool    mouseMoved;            /* Mouse has moved */
                     56: } SunMsPrivRec, *SunMsPrivPtr;
                     57: 
                     58: static void            sunMouseCtrl();
                     59: static int             sunMouseGetMotionEvents();
                     60: static Firm_event      *sunMouseGetEvents();
                     61: static void            sunMouseProcessEvent();
                     62: static void            sunMouseDoneEvents();
                     63: 
                     64: static SunMsPrivRec    sunMousePriv;
                     65: static PtrPrivRec      sysMousePriv = {
                     66:     -1,                                /* Descriptor to device */
                     67:     sunMouseGetEvents,         /* Function to read events */
                     68:     sunMouseProcessEvent,      /* Function to process an event */
                     69:     sunMouseDoneEvents,                /* When all the events have been */
                     70:                                /* handled, this function will be */
                     71:                                /* called. */
                     72:     0,                         /* Current X coordinate of pointer */
                     73:     0,                         /* Current Y coordinate */
                     74:     NULL,                      /* Screen pointer is on */
                     75:     (pointer)&sunMousePriv,    /* Field private to device */
                     76: };
                     77: 
                     78: /*-
                     79:  *-----------------------------------------------------------------------
                     80:  * sunMouseProc --
                     81:  *     Handle the initialization, etc. of a mouse
                     82:  *
                     83:  * Results:
                     84:  *     none.
                     85:  *
                     86:  * Side Effects:
                     87:  *
                     88:  * Note:
                     89:  *     When using sunwindows, all input comes off a single fd, stored in the
                     90:  *     global windowFd.  Therefore, only one device should be enabled and
                     91:  *     disabled, even though the application still sees both mouse and
                     92:  *     keyboard.  We have arbitrarily chosen to enable and disable windowFd
                     93:  *     in the keyboard routine sunKbdProc rather than in sunMouseProc.
                     94:  *
                     95:  *-----------------------------------------------------------------------
                     96:  */
                     97: int
                     98: sunMouseProc (pMouse, what)
                     99:     DevicePtr    pMouse;       /* Mouse to play with */
                    100:     int                  what;         /* What to do with it */
                    101: {
                    102:     register int  fd;
                    103:     int                  format;
                    104:     static int   oformat;
                    105:     BYTE         map[4];
                    106: 
                    107:     switch (what) {
                    108:        case DEVICE_INIT:
                    109:            if (pMouse != LookupPointerDevice()) {
                    110:                ErrorF ("Cannot open non-system mouse");        
                    111:                return (!Success);
                    112:            }
                    113: 
                    114:            if (! sunUseSunWindows()) {
                    115:                if (sysMousePriv.fd >= 0) {
                    116:                    fd = sysMousePriv.fd;
                    117:                } else {
                    118:                    fd = open ("/dev/mouse", O_RDWR, 0);
                    119:                    if (fd < 0) {
                    120:                        Error ("Opening /dev/mouse");
                    121:                        return (!Success);
                    122:                    }
                    123:                    if (fcntl (fd, F_SETFL, (FNDELAY|FASYNC)) < 0
                    124:                        || fcntl(fd, F_SETOWN, getpid()) < 0) {
                    125:                            perror("sunMouseProc");
                    126:                            ErrorF("Can't set up mouse on fd %d\n", fd);
                    127:                        }
                    128:                    
                    129:                    sysMousePriv.fd = fd;
                    130:                }
                    131:            }
                    132: 
                    133:            sysMousePriv.pScreen = &screenInfo.screen[0];
                    134:            sysMousePriv.x = sysMousePriv.pScreen->width / 2;
                    135:            sysMousePriv.y = sysMousePriv.pScreen->height / 2;
                    136: 
                    137:            sunMousePriv.bmask = 0;
                    138:            sunMousePriv.mouseMoved = FALSE;
                    139: 
                    140:            pMouse->devicePrivate = (pointer) &sysMousePriv;
                    141:            pMouse->on = FALSE;
                    142:            map[1] = 1;
                    143:            map[2] = 2;
                    144:            map[3] = 3;
                    145:            InitPointerDeviceStruct(
                    146:                pMouse, map, 3, sunMouseGetMotionEvents, sunMouseCtrl);
                    147:            break;
                    148: 
                    149:        case DEVICE_ON:
                    150:            if (! sunUseSunWindows()) {
                    151:                if (ioctl (((PtrPrivPtr)pMouse->devicePrivate)->fd,
                    152:                        VUIDGFORMAT, &oformat) < 0) {
                    153:                    Error ("VUIDGFORMAT");
                    154:                    return(!Success);
                    155:                }
                    156:                format = VUID_FIRM_EVENT;
                    157:                if (ioctl (((PtrPrivPtr)pMouse->devicePrivate)->fd,
                    158:                        VUIDSFORMAT, &format) < 0) {
                    159:                    Error ("VUIDSFORMAT");
                    160:                    return(!Success);
                    161:                }
                    162:                AddEnabledDevice (((PtrPrivPtr)pMouse->devicePrivate)->fd);
                    163:            }
                    164: 
                    165:            pMouse->on = TRUE;
                    166:            break;
                    167: 
                    168:        case DEVICE_CLOSE:
                    169:            if (! sunUseSunWindows()) {
                    170:                if (ioctl (((PtrPrivPtr)pMouse->devicePrivate)->fd,
                    171:                        VUIDSFORMAT, &oformat) < 0) {
                    172:                    Error ("VUIDSFORMAT");
                    173:                }
                    174:            }
                    175:            break;
                    176: 
                    177:        case DEVICE_OFF:
                    178:            pMouse->on = FALSE;
                    179:            if (! sunUseSunWindows()) {
                    180:                RemoveEnabledDevice (((PtrPrivPtr)pMouse->devicePrivate)->fd);
                    181:            }
                    182:            break;
                    183:     }
                    184:     return (Success);
                    185: }
                    186:            
                    187: /*-
                    188:  *-----------------------------------------------------------------------
                    189:  * sunMouseCtrl --
                    190:  *     Alter the control parameters for the mouse. Since acceleration
                    191:  *     etc. is done from the PtrCtrl record in the mouse's device record,
                    192:  *     there's nothing to do here.
                    193:  *
                    194:  * Results:
                    195:  *     None.
                    196:  *
                    197:  * Side Effects:
                    198:  *     None.
                    199:  *
                    200:  *-----------------------------------------------------------------------
                    201:  */
                    202: static void
                    203: sunMouseCtrl (pMouse)
                    204:     DevicePtr    pMouse;
                    205: {
                    206: }
                    207: 
                    208: /*-
                    209:  *-----------------------------------------------------------------------
                    210:  * sunMouseGetMotionEvents --
                    211:  *     Return the (number of) motion events in the "motion history
                    212:  *     buffer" (snicker) between the given times.
                    213:  *
                    214:  * Results:
                    215:  *     The number of events stuffed.
                    216:  *
                    217:  * Side Effects:
                    218:  *     The relevant xTimecoord's are stuffed in the passed memory.
                    219:  *
                    220:  *-----------------------------------------------------------------------
                    221:  */
                    222: static int
                    223: sunMouseGetMotionEvents (buff, start, stop)
                    224:     CARD32 start, stop;
                    225:     xTimecoord *buff;
                    226: {
                    227:     return 0;
                    228: }
                    229: 
                    230: /*-
                    231:  *-----------------------------------------------------------------------
                    232:  * sunMouseGetEvents --
                    233:  *     Return the events waiting in the wings for the given mouse.
                    234:  *
                    235:  * Results:
                    236:  *     A pointer to an array of Firm_events or (Firm_event *)0 if no events
                    237:  *     The number of events contained in the array.
                    238:  *
                    239:  * Side Effects:
                    240:  *     None.
                    241:  *-----------------------------------------------------------------------
                    242:  */
                    243: static Firm_event *
                    244: sunMouseGetEvents (pMouse, pNumEvents)
                    245:     DevicePtr    pMouse;           /* Mouse to read */
                    246:     int                  *pNumEvents;      /* Place to return number of events */
                    247: {
                    248:     int                  nBytes;           /* number of bytes of events available. */
                    249:     register PtrPrivPtr          pPriv;
                    250:     static Firm_event  evBuf[MAXEVENTS];   /* Buffer for Firm_events */
                    251: 
                    252:     pPriv = (PtrPrivPtr) pMouse->devicePrivate;
                    253: 
                    254:     nBytes = read (pPriv->fd, evBuf, sizeof(evBuf));
                    255: 
                    256:     if (nBytes < 0) {
                    257:        if (errno == EWOULDBLOCK) {
                    258:            *pNumEvents = 0;
                    259:        } else {
                    260:            Error ("Reading mouse");
                    261:            FatalError ("Could not read from mouse");
                    262:        }
                    263:     } else {
                    264:        *pNumEvents = nBytes / sizeof (Firm_event);
                    265:     }
                    266:     return (evBuf);
                    267: }
                    268: 
                    269: 
                    270: /*-
                    271:  *-----------------------------------------------------------------------
                    272:  * MouseAccelerate --
                    273:  *     Given a delta and a mouse, return the acceleration of the delta.
                    274:  *
                    275:  * Results:
                    276:  *     The corrected delta
                    277:  *
                    278:  * Side Effects:
                    279:  *     None.
                    280:  *
                    281:  *-----------------------------------------------------------------------
                    282:  */
                    283: static short
                    284: MouseAccelerate (pMouse, delta)
                    285:     DevicePtr    pMouse;
                    286:     int                  delta;
                    287: {
                    288:     register int  sgn = sign(delta);
                    289:     register PtrCtrl *pCtrl;
                    290: 
                    291:     delta = abs(delta);
                    292:     pCtrl = &((DeviceIntPtr) pMouse)->u.ptr.ctrl;
                    293: 
                    294:     if (delta > pCtrl->threshold) {
                    295:        return ((short) (sgn * (pCtrl->threshold +
                    296:                                ((delta - pCtrl->threshold) * pCtrl->num) /
                    297:                                pCtrl->den)));
                    298:     } else {
                    299:        return ((short) (sgn * delta));
                    300:     }
                    301: }
                    302: 
                    303: /*-
                    304:  *-----------------------------------------------------------------------
                    305:  * sunMouseProcessEvent --
                    306:  *     Given a Firm_event for a mouse, pass it off the the dix layer
                    307:  *     properly converted...
                    308:  *
                    309:  * Results:
                    310:  *     None.
                    311:  *
                    312:  * Side Effects:
                    313:  *     The cursor may be redrawn...? devPrivate/x/y will be altered.
                    314:  *
                    315:  *-----------------------------------------------------------------------
                    316:  */
                    317: static void
                    318: sunMouseProcessEvent (pMouse, fe)
                    319:     DevicePtr    pMouse;       /* Mouse from which the event came */
                    320:     Firm_event   *fe;          /* Event to process */
                    321: {
                    322:     int      index;            /* screen index */
                    323:     xEvent             xE;
                    324:     register PtrPrivPtr        pPriv;  /* Private data for pointer */
                    325:     register SunMsPrivPtr pSunPriv; /* Private data for mouse */
                    326:     register int       bmask;  /* Temporary button mask */
                    327: 
                    328:     pPriv = (PtrPrivPtr)pMouse->devicePrivate;
                    329:     pSunPriv = (SunMsPrivPtr) pPriv->devPrivate;
                    330: 
                    331:     xE.u.keyButtonPointer.time = TVTOMILLI(fe->time);
                    332: 
                    333:     switch (fe->id) {
                    334:        case MS_LEFT:
                    335:        case MS_MIDDLE:
                    336:        case MS_RIGHT:
                    337:            /*
                    338:             * A button changed state. Sometimes we will get two events
                    339:             * for a single state change. Should we get a button event which
                    340:             * reflects the current state of affairs, that event is discarded.
                    341:             *
                    342:             * Mouse buttons start at 1.
                    343:             */
                    344:            xE.u.u.detail = (fe->id - MS_LEFT) + 1;
                    345:            bmask = 1 << xE.u.u.detail;
                    346:            if (fe->value == VKEY_UP) {
                    347:                if (pSunPriv->bmask & bmask) {
                    348:                    xE.u.u.type = ButtonRelease;
                    349:                    pSunPriv->bmask &= ~bmask;
                    350:                } else {
                    351:                    return;
                    352:                }
                    353:            } else {
                    354:                if ((pSunPriv->bmask & bmask) == 0) {
                    355:                    xE.u.u.type = ButtonPress;
                    356:                    pSunPriv->bmask |= bmask;
                    357:                } else {
                    358:                    return;
                    359:                }
                    360:            }
                    361:            /*
                    362:             * If the mouse has moved, we must update any interested client
                    363:             * as well as DIX before sending a button event along.
                    364:             */
                    365:            if (pSunPriv->mouseMoved) {
                    366:                sunMouseDoneEvents (pMouse, FALSE);
                    367:            }
                    368:        
                    369:            break;
                    370:        case LOC_X_DELTA:
                    371:            /*
                    372:             * When we detect a change in the mouse coordinates, we call
                    373:             * the cursor module to move the cursor. It has the option of
                    374:             * simply removing the cursor or just shifting it a bit.
                    375:             * If it is removed, DIX will restore it before we goes to sleep...
                    376:             *
                    377:             * What should be done if it goes off the screen? Move to another
                    378:             * screen? For now, we just force the pointer to stay on the
                    379:             * screen...
                    380:             */
                    381:            pPriv->x += MouseAccelerate (pMouse, fe->value);
                    382: 
                    383:             /*
                    384:              * Active Zaphod implementation:
                    385:              *    increment or decrement the current screen
                    386:              *    if the x is to the right or the left of
                    387:              *    the current screen.
                    388:              */
                    389:             if (screenInfo.numScreens > 1 &&
                    390:                 (pPriv->x > pPriv->pScreen->width ||
                    391:                  pPriv->x < 0)) {
                    392:                 sunRemoveCursor();
                    393:                 /* disable color plane if it's current */
                    394:                 index = pPriv->pScreen->myNum;
                    395:                 (*sunFbs[index].EnterLeave) (pPriv->pScreen, 1);
                    396:                 if (pPriv->x < 0) { 
                    397:                      if (pPriv->pScreen->myNum != 0)
                    398:                         (pPriv->pScreen)--;
                    399:                      else
                    400:                          pPriv->pScreen = &screenInfo.screen[screenInfo.numScreens -1];
                    401:  
                    402:                      pPriv->x += pPriv->pScreen->width;
                    403:                 }
                    404:                 else {
                    405:                     pPriv->x -= pPriv->pScreen->width;
                    406: 
                    407:                     if (pPriv->pScreen->myNum != screenInfo.numScreens -1)
                    408:                         (pPriv->pScreen)++;
                    409:                     else
                    410:                          pPriv->pScreen = &screenInfo.screen[0];
                    411:                 }
                    412: 
                    413:                 index = pPriv->pScreen->myNum;
                    414:                 /* enable color plane if new current screen */
                    415:                 (*sunFbs[index].EnterLeave) (pPriv->pScreen, 0);
                    416:             }
                    417: 
                    418:            if (!sunConstrainXY (&pPriv->x, &pPriv->y)) {
                    419:                return;
                    420:            }
                    421: 
                    422:             NewCurrentScreen (pPriv->pScreen, pPriv->x, pPriv->y);
                    423: 
                    424: #ifdef SUN_ALL_MOTION
                    425:            xE.u.u.type = MotionNotify;
                    426:            sunMoveCursor (pPriv->pScreen, pPriv->x, pPriv->y);
                    427:            break;
                    428: #else
                    429:            ((SunMsPrivPtr)pPriv->devPrivate)->mouseMoved = TRUE;
                    430:            return;
                    431: #endif
                    432:        case LOC_Y_DELTA:
                    433:            /*
                    434:             * For some reason, motion up generates a positive y delta
                    435:             * and motion down a negative delta, so we must subtract
                    436:             * here instead of add...
                    437:             */
                    438:            pPriv->y -= MouseAccelerate (pMouse, fe->value);
                    439:            if (!sunConstrainXY (&pPriv->x, &pPriv->y)) {
                    440:                return;
                    441:            }
                    442: #ifdef SUN_ALL_MOTION
                    443:            xE.u.u.type = MotionNotify;
                    444:            sunMoveCursor (pPriv->pScreen, pPriv->x, pPriv->y);
                    445:            break;
                    446: #else
                    447:            ((SunMsPrivPtr)pPriv->devPrivate)->mouseMoved = TRUE;
                    448:            return;
                    449: #endif SUN_ALL_MOTION
                    450:        default:
                    451:            FatalError ("sunMouseProcessEvent: unrecognized id\n");
                    452:            break;
                    453:     }
                    454: 
                    455:     xE.u.keyButtonPointer.rootX = pPriv->x;
                    456:     xE.u.keyButtonPointer.rootY = pPriv->y;
                    457: 
                    458:     (* pMouse->processInputProc) (&xE, pMouse);
                    459: }
                    460: 
                    461: /*-
                    462:  *-----------------------------------------------------------------------
                    463:  * sunMouseDoneEvents --
                    464:  *     Finish off any mouse motions we haven't done yet. (At the moment
                    465:  *     this code is unused since we never save mouse motions as I'm
                    466:  *     unsure of the effect of getting a keystroke at a given [x,y] w/o
                    467:  *     having gotten a motion event to that [x,y])
                    468:  *
                    469:  * Results:
                    470:  *     None.
                    471:  *
                    472:  * Side Effects:
                    473:  *     A MotionNotify event may be generated.
                    474:  *
                    475:  *-----------------------------------------------------------------------
                    476:  */
                    477: /*ARGSUSED*/
                    478: static void
                    479: sunMouseDoneEvents (pMouse,final)
                    480:     DevicePtr    pMouse;
                    481:     Bool         final;
                    482: {
                    483:     PtrPrivPtr   pPriv;
                    484:     SunMsPrivPtr  pSunPriv;
                    485:     xEvent       xE;
                    486: 
                    487:     pPriv = (PtrPrivPtr) pMouse->devicePrivate;
                    488:     pSunPriv = (SunMsPrivPtr) pPriv->devPrivate;
                    489: 
                    490:     if (pSunPriv->mouseMoved) {
                    491:        sunMoveCursor (pPriv->pScreen, pPriv->x, pPriv->y);
                    492:        xE.u.keyButtonPointer.rootX = pPriv->x;
                    493:        xE.u.keyButtonPointer.rootY = pPriv->y;
                    494:        xE.u.keyButtonPointer.time = lastEventTime;
                    495:        xE.u.u.type = MotionNotify;
                    496:        (* pMouse->processInputProc) (&xE, pMouse);
                    497:        pSunPriv->mouseMoved = FALSE;
                    498:     }
                    499: }
                    500: 
                    501: #ifdef SUN_WINDOWS
                    502: 
                    503: /*
                    504:  * Process a sunwindows mouse event.  The possible events are
                    505:  *   LOC_MOVE
                    506:  *   MS_LEFT
                    507:  *   MS_MIDDLE
                    508:  *   MS_RIGHT
                    509:  */
                    510: 
                    511: void
                    512: sunMouseProcessEventSunWin(pMouse,se)
                    513:     DeviceRec *pMouse;
                    514:     register struct inputevent *se;
                    515: {   
                    516:     xEvent                     xE;
                    517:     register int               bmask;  /* Temporary button mask */
                    518:     register PtrPrivPtr                pPriv;  /* Private data for pointer */
                    519:     register SunMsPrivPtr      pSunPriv; /* Private data for mouse */
                    520: 
                    521:     pPriv = (PtrPrivPtr)pMouse->devicePrivate;
                    522:     pSunPriv = (SunMsPrivPtr) pPriv->devPrivate;
                    523: 
                    524:     xE.u.keyButtonPointer.time = TVTOMILLI(event_time(se));
                    525: 
                    526:     switch (event_id(se)) {
                    527:         case MS_LEFT:
                    528:         case MS_MIDDLE:
                    529:         case MS_RIGHT:
                    530:            /*
                    531:             * A button changed state. Sometimes we will get two events
                    532:             * for a single state change. Should we get a button event which
                    533:             * reflects the current state of affairs, that event is discarded.
                    534:             *
                    535:             * Mouse buttons start at 1.
                    536:             */
                    537:            xE.u.u.detail = (event_id(se) - MS_LEFT) + 1;
                    538:            bmask = 1 << xE.u.u.detail;
                    539:            if (win_inputnegevent(se)) {
                    540:                if (pSunPriv->bmask & bmask) {
                    541:                    xE.u.u.type = ButtonRelease;
                    542:                    pSunPriv->bmask &= ~bmask;
                    543:                } else {
                    544:                    return;
                    545:                }
                    546:            } else {
                    547:                if ((pSunPriv->bmask & bmask) == 0) {
                    548:                    xE.u.u.type = ButtonPress;
                    549:                    pSunPriv->bmask |= bmask;
                    550:                } else {
                    551:                    return;
                    552:                }
                    553:            }
                    554:            break;
                    555:         case LOC_MOVE:
                    556:            xE.u.u.type = MotionNotify;
                    557:            xE.u.u.detail = 0;
                    558:            pPriv->x = event_x(se);
                    559:            pPriv->y = event_y(se);
                    560:            if (!sunConstrainXY (&pPriv->x, &pPriv->y)) {
                    561:                return;
                    562:            }
                    563:            sunMoveCursor (pPriv->pScreen, pPriv->x, pPriv->y);
                    564:            if ((pPriv->x != event_x(se)) || (pPriv->y != event_y(se))) {
                    565:                /*
                    566:                 * We constrained the pointer motion.  Tell the pointer
                    567:                 * where it really needs to be.
                    568:                 */
                    569:                win_setmouseposition(windowFd, pPriv->x, pPriv->y);
                    570:            }
                    571:            break;
                    572:        default:
                    573:            FatalError ("sunMouseProcessEventSunWin: unrecognized id\n");
                    574:            break;
                    575:     }
                    576: 
                    577:     xE.u.keyButtonPointer.rootX = event_x(se);
                    578:     xE.u.keyButtonPointer.rootY = event_y(se);
                    579: 
                    580:     (* pMouse->processInputProc) (&xE, pMouse);
                    581: 
                    582: }
                    583: #endif SUN_WINDOWS

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.