URI:
       tmain.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tmain.c (12860B)
       ---
            1 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
            2 #include <stdio.h>
            3 #include <signal.h>
            4 #include <errno.h>
            5 #include <stdlib.h>
            6 #include <unistd.h>
            7 #include <X11/X.h>
            8 #include <X11/Xos.h>
            9 #include <X11/Xlib.h>
           10 #include <X11/Xutil.h>
           11 #include <X11/Xatom.h>
           12 #ifdef SHAPE
           13 #include <X11/extensions/shape.h>
           14 #endif
           15 #include "dat.h"
           16 #include "fns.h"
           17 #include "patchlevel.h"
           18 
           19 char        *version[] =
           20 {
           21         "rio version 1.0, Copyright (c) 1994-1996 David Hogan, (c) 2004 Russ Cox", 0
           22 };
           23 
           24 Display                 *dpy;
           25 ScreenInfo        *screens;
           26 int                         initting;
           27 XFontStruct         *font;
           28 int                         nostalgia;
           29 char                        **myargv;
           30 char                        *termprog;
           31 char                        *shell;
           32 Bool                        shape;
           33 int                         _border = 4;
           34 int                         _corner = 25;
           35 int                         _inset = 1;
           36 int                         curtime;
           37 int                         debug;
           38 int                         signalled;
           39 int                         scrolling;
           40 int                         num_screens;
           41 int                        solidsweep = 0;
           42 int                        numvirtuals = 0;
           43 int                        ffm = 0;
           44 
           45 Atom                exit_rio;
           46 Atom                restart_rio;
           47 Atom                wm_state;
           48 Atom                wm_change_state;
           49 Atom                wm_protocols;
           50 Atom                wm_delete;
           51 Atom                wm_take_focus;
           52 Atom                wm_lose_focus;
           53 Atom                wm_colormaps;
           54 Atom                _rio_running;
           55 Atom                _rio_hold_mode;
           56 Atom                wm_state_fullscreen;
           57 Atom                wm_state;
           58 
           59 char        *fontlist[] = {
           60         "lucm.latin1.9",
           61         "blit",
           62         "*-lucidatypewriter-bold-*-14-*-75-*",
           63         "*-lucidatypewriter-medium-*-12-*-75-*",
           64         "9x15bold",
           65         "fixed",
           66         "*",
           67         0
           68 };
           69 
           70 void
           71 usage(void)
           72 {
           73         fprintf(stderr, "usage: rio [-grey] [-font fname] [-s] [-term prog] [-version] [-virtuals num] [exit|restart]\n");
           74         exit(1);
           75 }
           76 
           77 int
           78 main(int argc, char *argv[])
           79 {
           80         int i, background, do_exit, do_restart;
           81         char *fname;
           82         int shape_event;
           83 #ifdef SHAPE
           84         int dummy;
           85 #endif
           86 
           87         shape_event = 0;
           88         myargv = argv;                        /* for restart */
           89 
           90         do_exit = do_restart = 0;
           91         background = 0;
           92         font = 0;
           93         fname = 0;
           94         for(i = 1; i < argc; i++)
           95                 if(strcmp(argv[i], "-nostalgia") == 0)
           96                         nostalgia++;
           97                 else if(strcmp(argv[i], "-grey") == 0)
           98                         background = 1;
           99                 else if(strcmp(argv[i], "-debug") == 0)
          100                         debug++;
          101         /*
          102                 else if(strcmp(argv[i], "-ffm") == 0)
          103                         ffm++;
          104         */
          105                 else if(strcmp(argv[i], "-font") == 0 && i+1<argc){
          106                         i++;
          107                         fname = argv[i];
          108                 }
          109                 else if(strcmp(argv[i], "-term") == 0 && i+1<argc)
          110                         termprog = argv[++i];
          111                 else if(strcmp(argv[i], "-virtuals") == 0 && i+1<argc){
          112                         numvirtuals = atoi(argv[++i]);
          113                         if(numvirtuals < 0 || numvirtuals > 12){
          114                                 fprintf(stderr, "rio: wrong number of virtual displays, defaulting to 4\n");
          115                                 numvirtuals = 4;
          116                         }
          117                 } else if(strcmp(argv[i], "-version") == 0){
          118                         fprintf(stderr, "%s", version[0]);
          119                         if(PATCHLEVEL > 0)
          120                                 fprintf(stderr, "; patch level %d", PATCHLEVEL);
          121                         fprintf(stderr, "\n");
          122                         exit(0);
          123                 }
          124                 else if(strcmp(argv[i], "-s") == 0){
          125                         scrolling = 1;
          126                 }
          127                 else if(argv[i][0] == '-')
          128                         usage();
          129                 else
          130                         break;
          131         for(; i < argc; i++)
          132                 if(strcmp(argv[i], "exit") == 0)
          133                         do_exit++;
          134                 else if(strcmp(argv[i], "restart") == 0)
          135                         do_restart++;
          136                 else
          137                         usage();
          138 
          139         if(do_exit && do_restart)
          140                 usage();
          141 
          142         shell = (char *)getenv("SHELL");
          143         if(shell == NULL)
          144                 shell = DEFSHELL;
          145 
          146         dpy = XOpenDisplay("");
          147         if(dpy == 0)
          148                 fatal("can't open display");
          149 
          150         initting = 1;
          151         XSetErrorHandler(handler);
          152         if(signal(SIGTERM, sighandler) == SIG_IGN)
          153                 signal(SIGTERM, SIG_IGN);
          154         if(signal(SIGINT, sighandler) == SIG_IGN)
          155                 signal(SIGINT, SIG_IGN);
          156         if(signal(SIGHUP, sighandler) == SIG_IGN)
          157                 signal(SIGHUP, SIG_IGN);
          158 
          159         exit_rio = XInternAtom(dpy, "9WM_EXIT", False);
          160         restart_rio = XInternAtom(dpy, "9WM_RESTART", False);
          161 
          162         curtime = -1;                /* don't care */
          163         if(do_exit){
          164                 sendcmessage(DefaultRootWindow(dpy), exit_rio, 0L, 1, 1);
          165                 XSync(dpy, False);
          166                 exit(0);
          167         }
          168         if(do_restart){
          169                 sendcmessage(DefaultRootWindow(dpy), restart_rio, 0L, 1, 1);
          170                 XSync(dpy, False);
          171                 exit(0);
          172         }
          173 
          174         if(0) XSynchronize(dpy, True);
          175 
          176         wm_state = XInternAtom(dpy, "WM_STATE", False);
          177         wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
          178         wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
          179         wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
          180         wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
          181         wm_lose_focus = XInternAtom(dpy, "_9WM_LOSE_FOCUS", False);
          182         wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
          183         _rio_running = XInternAtom(dpy, "_9WM_RUNNING", False);
          184         _rio_hold_mode = XInternAtom(dpy, "_9WM_HOLD_MODE", False);
          185         wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
          186         wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
          187 
          188         if(fname != 0)
          189                 if((font = XLoadQueryFont(dpy, fname)) == 0)
          190                         fprintf(stderr, "rio: warning: can't load font %s\n", fname);
          191 
          192         if(font == 0){
          193                 i = 0;
          194                 for(;;){
          195                         fname = fontlist[i++];
          196                         if(fname == 0){
          197                                 fprintf(stderr, "rio: warning: can't find a font\n");
          198                                 break;
          199                         }
          200                         font = XLoadQueryFont(dpy, fname);
          201                         if(font != 0)
          202                                 break;
          203                 }
          204         }
          205         if(nostalgia){
          206                 _border--;
          207                 _inset--;
          208         }
          209 
          210 #ifdef        SHAPE
          211         shape = XShapeQueryExtension(dpy, &shape_event, &dummy);
          212 #endif
          213 
          214         num_screens = ScreenCount(dpy);
          215         screens = (ScreenInfo *)malloc(sizeof(ScreenInfo) * num_screens);
          216 
          217         for(i = 0; i < num_screens; i++)
          218                 initscreen(&screens[i], i, background);
          219 
          220         initb2menu(numvirtuals);
          221 
          222         /* set selection so that 9term knows we're running */
          223         curtime = CurrentTime;
          224         XSetSelectionOwner(dpy, _rio_running, screens[0].menuwin, timestamp());
          225 
          226         XSync(dpy, False);
          227         initting = 0;
          228 
          229         nofocus();
          230 
          231         for(i = 0; i < num_screens; i++)
          232                 scanwins(&screens[i]);
          233 
          234         keysetup();
          235         mainloop(shape_event);
          236         return 0;
          237 }
          238 
          239 void
          240 initscreen(ScreenInfo *s, int i, int background)
          241 {
          242         char *ds, *colon, *dot1;
          243         unsigned long mask;
          244         unsigned long gmask;
          245         XGCValues gv;
          246         XSetWindowAttributes attr;
          247         XVisualInfo xvi;
          248         XSetWindowAttributes attrs;
          249 
          250         s->num = i;
          251         s->root = RootWindow(dpy, i);
          252         s->def_cmap = DefaultColormap(dpy, i);
          253         s->min_cmaps = MinCmapsOfScreen(ScreenOfDisplay(dpy, i));
          254         s->depth = DefaultDepth(dpy, i);
          255 
          256         /*
          257          * Figure out underlying screen format.
          258          */
          259         if(XMatchVisualInfo(dpy, i, 16, TrueColor, &xvi)
          260         || XMatchVisualInfo(dpy, i, 16, DirectColor, &xvi)){
          261                 s->vis = xvi.visual;
          262                 s->depth = 16;
          263         }
          264         else
          265         if(XMatchVisualInfo(dpy, i, 15, TrueColor, &xvi)
          266         || XMatchVisualInfo(dpy, i, 15, DirectColor, &xvi)){
          267                 s->vis = xvi.visual;
          268                 s->depth = 15;
          269         }
          270         else
          271         if(XMatchVisualInfo(dpy, i, 24, TrueColor, &xvi)
          272         || XMatchVisualInfo(dpy, i, 24, DirectColor, &xvi)){
          273                 s->vis = xvi.visual;
          274                 s->depth = 24;
          275         }
          276         else
          277         if(XMatchVisualInfo(dpy, i, 8, PseudoColor, &xvi)
          278         || XMatchVisualInfo(dpy, i, 8, StaticColor, &xvi)){
          279                 s->vis = xvi.visual;
          280                 s->depth = 8;
          281         }
          282         else{
          283                 s->depth = DefaultDepth(dpy, i);
          284                 if(s->depth != 8){
          285                         fprintf(stderr, "can't understand depth %d screen", s->depth);
          286                         exit(1);
          287                 }
          288                 s->vis = DefaultVisual(dpy, i);
          289         }
          290         if(DefaultDepth(dpy, i) != s->depth){
          291                 s->def_cmap = XCreateColormap(dpy, s->root, s->vis, AllocNone);
          292         }
          293 
          294         ds = DisplayString(dpy);
          295         colon = rindex(ds, ':');
          296         if(colon && num_screens > 1){
          297                 strcpy(s->display, "DISPLAY=");
          298                 strcat(s->display, ds);
          299                 colon = s->display + 8 + (colon - ds);        /* use version in buf */
          300                 dot1 = index(colon, '.');        /* first period after colon */
          301                 if(!dot1)
          302                         dot1 = colon + strlen(colon);        /* if not there, append */
          303                 sprintf(dot1, ".%d", i);
          304         }
          305         else
          306                 s->display[0] = '\0';
          307 
          308         s->black = BlackPixel(dpy, i);
          309         s->white = WhitePixel(dpy, i);
          310         s->activeholdborder = colorpixel(dpy, s, s->depth, 0x000099, s->white);
          311         s->inactiveholdborder = colorpixel(dpy, s, s->depth, 0x005DBB, s->black);
          312         s->activeborder = colorpixel(dpy, s, s->depth, 0x55AAAA, s->black);
          313         s->inactiveborder = colorpixel(dpy, s, s->depth, 0x9EEEEE, s->white);
          314         s->red = colorpixel(dpy, s, s->depth, 0xDD0000, s->white);
          315         s->width = WidthOfScreen(ScreenOfDisplay(dpy, i));
          316         s->height = HeightOfScreen(ScreenOfDisplay(dpy, i));
          317         s->bkup[0] = XCreatePixmap(dpy, s->root, 2*s->width, BORDER, DefaultDepth(dpy, i));
          318         s->bkup[1] = XCreatePixmap(dpy, s->root, BORDER, 2*s->height, DefaultDepth(dpy, i));
          319 
          320         gv.foreground = s->black^s->white;
          321         gv.background = s->white;
          322         gv.function = GXxor;
          323         gv.line_width = 0;
          324         gv.subwindow_mode = IncludeInferiors;
          325         gmask = GCForeground | GCBackground | GCFunction | GCLineWidth
          326                 | GCSubwindowMode;
          327         if(font != 0){
          328                 gv.font = font->fid;
          329                 gmask |= GCFont;
          330         }
          331         s->gc = XCreateGC(dpy, s->root, gmask, &gv);
          332 
          333         gv.function = GXcopy;
          334         s->gccopy = XCreateGC(dpy, s->root, gmask, &gv);
          335 
          336         gv.foreground = s->red;
          337         s->gcred = XCreateGC(dpy, s->root, gmask, &gv);
          338 
          339         gv.foreground = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
          340         s->gcsweep = XCreateGC(dpy, s->root, gmask, &gv);
          341 
          342         initcurs(s);
          343 
          344         attr.cursor = s->arrow;
          345         attr.event_mask = SubstructureRedirectMask
          346                 | SubstructureNotifyMask | ColormapChangeMask
          347                 | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask
          348                 | KeyPressMask | EnterWindowMask;
          349         mask = CWCursor|CWEventMask;
          350         XChangeWindowAttributes(dpy, s->root, mask, &attr);
          351         XSync(dpy, False);
          352 
          353         if(background){
          354                 XSetWindowBackgroundPixmap(dpy, s->root, s->root_pixmap);
          355                 XClearWindow(dpy, s->root);
          356         } else
          357                 system("xsetroot -solid grey30");
          358 
          359         attrs.border_pixel =  colorpixel(dpy, s, s->depth, 0x88CC88, s->black);
          360         attrs.background_pixel =  colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
          361         attrs.colormap = s->def_cmap;
          362 
          363         s->menuwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 2,
          364                                                 s->depth,
          365                                                 CopyFromParent,
          366                                                 s->vis,
          367                                                 CWBackPixel | CWBorderPixel | CWColormap,
          368                                                 &attrs
          369                                                 );
          370 
          371 
          372         gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
          373         s->gcmenubg = XCreateGC(dpy, s->menuwin, gmask, &gv);
          374 
          375         gv.foreground = colorpixel(dpy, s, s->depth, 0x448844, s->black);
          376         s->gcmenubgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
          377 
          378         gv.foreground = s->black;
          379         gv.background = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
          380         s->gcmenufg = XCreateGC(dpy, s->menuwin, gmask, &gv);
          381 
          382         gv.foreground = colorpixel(dpy, s, s->depth, 0xE9FFE9, s->white);
          383         gv.background = colorpixel(dpy, s, s->depth, 0x448844, s->black);
          384         s->gcmenufgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
          385 
          386         attrs.border_pixel =  s->red;
          387         attrs.background_pixel =  colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
          388         attrs.colormap = s->def_cmap;
          389         s->sweepwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 4,
          390                                                 s->depth,
          391                                                 CopyFromParent,
          392                                                 s->vis,
          393                                                 CWBackPixel | CWBorderPixel | CWColormap,
          394                                                 &attrs
          395                                                 );
          396 }
          397 
          398 ScreenInfo*
          399 getscreen(Window w)
          400 {
          401         int i;
          402 
          403         for(i = 0; i < num_screens; i++)
          404                 if(screens[i].root == w)
          405                         return &screens[i];
          406 
          407         return 0;
          408 }
          409 
          410 Time
          411 timestamp(void)
          412 {
          413         XEvent ev;
          414 
          415         if(curtime == CurrentTime){
          416                 XChangeProperty(dpy, screens[0].root, _rio_running, _rio_running, 8,
          417                                 PropModeAppend, (unsigned char *)"", 0);
          418                 XMaskEvent(dpy, PropertyChangeMask, &ev);
          419                 curtime = ev.xproperty.time;
          420         }
          421         return curtime;
          422 }
          423 
          424 void
          425 sendcmessage(Window w, Atom a, long x, int isroot, int usemask)
          426 {
          427         XEvent ev;
          428         int status;
          429         long mask;
          430 
          431         memset(&ev, 0, sizeof(ev));
          432         ev.xclient.type = ClientMessage;
          433         ev.xclient.window = w;
          434         ev.xclient.message_type = a;
          435         ev.xclient.format = 32;
          436         ev.xclient.data.l[0] = x;
          437         ev.xclient.data.l[1] = timestamp();
          438         mask = 0;
          439         if(usemask){
          440                 mask |= KeyPressMask;        /* seems to be necessary */
          441                 if(isroot)
          442                         mask |= SubstructureRedirectMask;                /* magic! */
          443                 else
          444                         mask |= ExposureMask;        /* not really correct but so be it */
          445         }
          446         status = XSendEvent(dpy, w, False, mask, &ev);
          447         if(status == 0)
          448                 fprintf(stderr, "rio: sendcmessage failed\n");
          449 }
          450 
          451 void
          452 sendconfig(Client *c)
          453 {
          454         XConfigureEvent ce;
          455 
          456         ce.type = ConfigureNotify;
          457         ce.event = c->window;
          458         ce.window = c->window;
          459         ce.x = c->x;
          460         ce.y = c->y;
          461         ce.width = c->dx;
          462         ce.height = c->dy;
          463         ce.border_width = c->border;
          464         ce.above = None;
          465         ce.override_redirect = 0;
          466         XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent*)&ce);
          467 }
          468 
          469 void
          470 sighandler(void)
          471 {
          472         signalled = 1;
          473 }
          474 
          475 void
          476 getevent(XEvent *e)
          477 {
          478         int fd;
          479         fd_set rfds;
          480         struct timeval t;
          481 
          482         if(!signalled){
          483                 if(QLength(dpy) > 0){
          484                         XNextEvent(dpy, e);
          485                         return;
          486                 }
          487                 fd = ConnectionNumber(dpy);
          488                 FD_ZERO(&rfds);
          489                 FD_SET(fd, &rfds);
          490                 t.tv_sec = t.tv_usec = 0;
          491                 if(select(fd+1, &rfds, NULL, NULL, &t) == 1){
          492                         XNextEvent(dpy, e);
          493                         return;
          494                 }
          495                 XFlush(dpy);
          496                 FD_SET(fd, &rfds);
          497                 if(select(fd+1, &rfds, NULL, NULL, NULL) == 1){
          498                         XNextEvent(dpy, e);
          499                         return;
          500                 }
          501                 if(errno != EINTR || !signalled){
          502                         perror("rio: select failed");
          503                         exit(1);
          504                 }
          505         }
          506         fprintf(stderr, "rio: exiting on signal\n");
          507         cleanup();
          508         exit(1);
          509 }
          510 
          511 void
          512 cleanup(void)
          513 {
          514         Client *c, *cc[2], *next;
          515         XWindowChanges wc;
          516         int i;
          517 
          518         /* order of un-reparenting determines final stacking order... */
          519         cc[0] = cc[1] = 0;
          520         for(c = clients; c; c = next){
          521                 next = c->next;
          522                 i = normal(c);
          523                 c->next = cc[i];
          524                 cc[i] = c;
          525         }
          526 
          527         for(i = 0; i < 2; i++){
          528                 for(c = cc[i]; c; c = c->next){
          529                         if(!withdrawn(c)){
          530                                 XReparentWindow(dpy, c->window, c->screen->root,
          531                                                 c->x, c->y);
          532                         }
          533                         wc.border_width = c->border;
          534                         XConfigureWindow(dpy, c->window, CWBorderWidth, &wc);
          535                 }
          536         }
          537 
          538         XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, timestamp());
          539         for(i = 0; i < num_screens; i++)
          540                 cmapnofocus(&screens[i]);
          541         XCloseDisplay(dpy);
          542 }