URI:
       tmenu.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
       ---
       tmenu.c (7529B)
       ---
            1 /*
            2  * Pop-up menus.
            3  */
            4 
            5 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
            6 #define _SVID_SOURCE 1        /* putenv in glibc */
            7 #define _DEFAULT_SOURCE 1
            8 #include <stdio.h>
            9 #include <signal.h>
           10 #include <unistd.h>
           11 #include <stdlib.h>
           12 #include <string.h>
           13 #include <sys/wait.h>
           14 #include <X11/X.h>
           15 #include <X11/Xlib.h>
           16 #include <X11/Xutil.h>
           17 #include "dat.h"
           18 #include "fns.h"
           19 
           20 Client        *hiddenc[MAXHIDDEN];
           21 
           22 int        numhidden;
           23 
           24 int virt;
           25 int reversehide = 1;
           26 
           27 Client * currents[NUMVIRTUALS] =
           28 {
           29         NULL, NULL, NULL, NULL
           30 };
           31 
           32 char        *b2items[NUMVIRTUALS+1] =
           33 {
           34         "One",
           35         "Two",
           36         "Three",
           37         "Four",
           38         "Five",
           39         "Six",
           40         "Seven",
           41         "Eight",
           42         "Nine",
           43         "Ten",
           44         "Eleven",
           45         "Twelve",
           46         0
           47 };
           48 
           49 Menu b2menu =
           50 {
           51         b2items
           52 };
           53 
           54 char        *b3items[B3FIXED+MAXHIDDEN+1] =
           55 {
           56         "New",
           57         "Reshape",
           58         "Move",
           59         "Delete",
           60         "Hide",
           61         0
           62 };
           63 
           64 enum
           65 {
           66         New,
           67         Reshape,
           68         Move,
           69         Delete,
           70         Hide
           71 };
           72 
           73 Menu        b3menu =
           74 {
           75         b3items
           76 };
           77 
           78 Menu        egg =
           79 {
           80         version
           81 };
           82 
           83 void
           84 button(XButtonEvent *e)
           85 {
           86         int n, shift;
           87         Client *c;
           88         Window dw;
           89         ScreenInfo *s;
           90 
           91         curtime = e->time;
           92         s = getscreen(e->root);
           93         if(s == 0)
           94                 return;
           95         c = getclient(e->window, 0);
           96         if(c){
           97                 if(debug) fprintf(stderr, "but: e x=%d y=%d c x=%d y=%d dx=%d dy=%d BORDR %d\n",
           98                                 e->x, e->y, c->x, c->y, c->dx, c->dy, BORDER);
           99                 if(borderorient(c, e->x, e->y) != BorderUnknown){
          100                         switch (e->button){
          101                         case Button1:
          102                         case Button2:
          103                                 reshape(c, e->button, pull, e);
          104                                 return;
          105                         case Button3:
          106                                 move(c, Button3);
          107                                 return;
          108                         default:
          109                                 return;
          110                         }
          111                 }
          112                 e->x += c->x - BORDER;
          113                 e->y += c->y - BORDER;
          114         } else if(e->window != e->root){
          115                 if(debug) fprintf(stderr, "but no client: e x=%d y=%d\n",
          116                                 e->x, e->y);
          117                 XTranslateCoordinates(dpy, e->window, s->root, e->x, e->y,
          118                                 &e->x, &e->y, &dw);
          119         }
          120         switch (e->button){
          121         case Button1:
          122                 if(c){
          123                         XMapRaised(dpy, c->parent);
          124                         top(c);
          125                         active(c);
          126                 }
          127                 return;
          128         case Button2:
          129                 if(c){
          130                         XMapRaised(dpy, c->parent);
          131                         active(c);
          132                         XAllowEvents (dpy, ReplayPointer, curtime);
          133                 } else if((e->state&(ShiftMask|ControlMask))==(ShiftMask|ControlMask)){
          134                         menuhit(e, &egg);
          135                 } else if(numvirtuals > 1 && (n = menuhit(e, &b2menu)) > -1)
          136                                 button2(n);
          137                 return;
          138         case Button3:
          139                 break;
          140         case Button4:
          141                 /* scroll up changes to previous virtual screen */
          142                 if(!c && e->type == ButtonPress)
          143                         if(numvirtuals > 1 && virt > 0)
          144                                 switch_to(virt - 1);
          145                 return;
          146         case Button5:
          147                 /* scroll down changes to next virtual screen */
          148                 if(!c && e->type == ButtonPress)
          149                         if(numvirtuals > 1 && virt < numvirtuals - 1)
          150                                 switch_to(virt + 1);
          151                 return;
          152         default:
          153                 return;
          154         }
          155 
          156         if(current && current->screen == s)
          157                 cmapnofocus(s);
          158         switch (n = menuhit(e, &b3menu)){
          159         case New:
          160                 spawn(s);
          161                 break;
          162         case Reshape:
          163                 reshape(selectwin(1, 0, s), Button3, sweep, 0);
          164                 break;
          165         case Move:
          166                 move(selectwin(0, 0, s), Button3);
          167                 break;
          168         case Delete:
          169                 shift = 0;
          170                 c = selectwin(1, &shift, s);
          171                 delete(c, shift);
          172                 break;
          173         case Hide:
          174                 hide(selectwin(1, 0, s));
          175                 break;
          176         default:        /* unhide window */
          177                 unhide(n - B3FIXED, 1);
          178                 break;
          179         case -1:        /* nothing */
          180                 break;
          181         }
          182         if(current && current->screen == s)
          183                 cmapfocus(current);
          184 }
          185 
          186 void
          187 spawn(ScreenInfo *s)
          188 {
          189         /*
          190          * ugly dance to cause sweeping for terminals.
          191          * the very next window created will require sweeping.
          192          * hope it's created by the program we're about to
          193          * exec!
          194          */
          195         isNew = 1;
          196         /*
          197          * ugly dance to avoid leaving zombies. Could use SIGCHLD,
          198          * but it's not very portable.
          199          */
          200         if(fork() == 0){
          201                 if(fork() == 0){
          202                         close(ConnectionNumber(dpy));
          203                         if(s->display[0] != '\0')
          204                                 putenv(s->display);
          205                         signal(SIGINT, SIG_DFL);
          206                         signal(SIGTERM, SIG_DFL);
          207                         signal(SIGHUP, SIG_DFL);
          208                         if(termprog != NULL){
          209                                 execl(shell, shell, "-c", termprog, (char*)0);
          210                                 fprintf(stderr, "rio: exec %s", shell);
          211                                 perror(" failed");
          212                         }
          213                         execlp("9term", "9term", scrolling ? "-ws" : "-w", (char*)0);
          214                         execlp("xterm", "xterm", "-ut", (char*)0);
          215                         perror("rio: exec 9term/xterm failed");
          216                         exit(1);
          217                 }
          218                 exit(0);
          219         }
          220         wait((int *) 0);
          221 }
          222 
          223 void
          224 reshape(Client *c, int but, int (*fn)(Client*, int, XButtonEvent *), XButtonEvent *e)
          225 {
          226         int odx, ody;
          227 
          228         if(c == 0)
          229                 return;
          230         odx = c->dx;
          231         ody = c->dy;
          232         if(fn(c, but, e) == 0)
          233                 return;
          234         active(c);
          235         top(c);
          236         XRaiseWindow(dpy, c->parent);
          237         XMoveResizeWindow(dpy, c->parent, c->x-BORDER, c->y-BORDER,
          238                                         c->dx+2*BORDER, c->dy+2*BORDER);
          239         if(c->dx == odx && c->dy == ody)
          240                 sendconfig(c);
          241         else
          242                 XMoveResizeWindow(dpy, c->window, BORDER, BORDER, c->dx, c->dy);
          243 }
          244 
          245 void
          246 move(Client *c, int but)
          247 {
          248         if(c == 0)
          249                 return;
          250         if(drag(c, but) == 0)
          251                 return;
          252         active(c);
          253         top(c);
          254         XRaiseWindow(dpy, c->parent);
          255         XMoveWindow(dpy, c->parent, c->x-BORDER, c->y-BORDER);
          256         sendconfig(c);
          257 }
          258 
          259 void
          260 delete(Client *c, int shift)
          261 {
          262         if(c == 0)
          263                 return;
          264         if((c->proto & Pdelete) && !shift)
          265                 sendcmessage(c->window, wm_protocols, wm_delete, 0, 0);
          266         else
          267                 XKillClient(dpy, c->window);                /* let event clean up */
          268 }
          269 
          270 void
          271 hide(Client *c)
          272 {
          273         if(c == 0 || numhidden == MAXHIDDEN)
          274                 return;
          275         if(hidden(c)){
          276                 fprintf(stderr, "rio: already hidden: %s\n", c->label);
          277                 return;
          278         }
          279         XUnmapWindow(dpy, c->parent);
          280         XUnmapWindow(dpy, c->window);
          281         setstate(c, IconicState);
          282         if(c == current)
          283                 nofocus();
          284         if(reversehide){
          285                 memmove(hiddenc+1, hiddenc, numhidden*sizeof hiddenc[0]);
          286                 memmove(b3items+B3FIXED+1, b3items+B3FIXED, numhidden*sizeof b3items[0]);
          287                 hiddenc[0] = c;
          288                 b3items[B3FIXED] = c->label;
          289         }else{
          290                 hiddenc[numhidden] = c;
          291                 b3items[B3FIXED+numhidden] = c->label;
          292         }
          293         numhidden++;
          294         b3items[B3FIXED+numhidden] = 0;
          295 }
          296 
          297 void
          298 unhide(int n, int map)
          299 {
          300         Client *c;
          301         int i;
          302 
          303         if(n >= numhidden){
          304                 fprintf(stderr, "rio: unhide: n %d numhidden %d\n", n, numhidden);
          305                 return;
          306         }
          307         c = hiddenc[n];
          308         if(!hidden(c)){
          309                 fprintf(stderr, "rio: unhide: not hidden: %s(0x%x)\n",
          310                         c->label, (int)c->window);
          311                 return;
          312         }
          313         c->virt = virt;
          314 
          315         if(map){
          316                 XMapWindow(dpy, c->window);
          317                 XMapRaised(dpy, c->parent);
          318                 setstate(c, NormalState);
          319                 active(c);
          320                 top(c);
          321         }
          322 
          323         numhidden--;
          324         for(i = n; i < numhidden; i++){
          325                 hiddenc[i] = hiddenc[i+1];
          326                 b3items[B3FIXED+i] = b3items[B3FIXED+i+1];
          327         }
          328         b3items[B3FIXED+numhidden] = 0;
          329 }
          330 
          331 void
          332 unhidec(Client *c, int map)
          333 {
          334         int i;
          335 
          336         for(i = 0; i < numhidden; i++)
          337                 if(c == hiddenc[i]){
          338                         unhide(i, map);
          339                         return;
          340                 }
          341         fprintf(stderr, "rio: unhidec: not hidden: %s(0x%x)\n",
          342                 c->label, (int)c->window);
          343 }
          344 
          345 void
          346 renamec(Client *c, char *name)
          347 {
          348         int i;
          349 
          350         if(name == 0)
          351                 name = "???";
          352         c->label = name;
          353         if(!hidden(c))
          354                 return;
          355         for(i = 0; i < numhidden; i++)
          356                 if(c == hiddenc[i]){
          357                         b3items[B3FIXED+i] = name;
          358                         return;
          359                 }
          360 }
          361 
          362 void
          363 button2(int n)
          364 {
          365         switch_to(n);
          366         if(current)
          367                 cmapfocus(current);
          368 }
          369 
          370 void
          371 switch_to_c(int n, Client *c)
          372 {
          373         if(c == 0)
          374                 return;
          375 
          376         if(c->next)
          377                 switch_to_c(n, c->next);
          378 
          379         if(c->parent == DefaultRootWindow(dpy))
          380                 return;
          381 
          382         if(c->virt != virt && c->state == NormalState){
          383                 XUnmapWindow(dpy, c->parent);
          384                 XUnmapWindow(dpy, c->window);
          385                 setstate(c, IconicState);
          386                 if(c == current)
          387                         nofocus();
          388         } else if(c->virt == virt && c->state == IconicState){
          389                 int i;
          390 
          391                 for(i = 0; i < numhidden; i++)
          392                         if(c == hiddenc[i])
          393                                 break;
          394 
          395                 if(i == numhidden){
          396                         XMapWindow(dpy, c->window);
          397                         XMapWindow(dpy, c->parent);
          398                         setstate(c, NormalState);
          399                         if(currents[virt] == c)
          400                                 active(c);
          401                 }
          402         }
          403 }
          404 
          405 void
          406 switch_to(int n)
          407 {
          408         if(n == virt)
          409                 return;
          410         currents[virt] = current;
          411         virt = n;
          412 
          413         /* redundant when called from a menu switch
          414          * but needed for scroll-button switches
          415          */
          416         b2menu.lasthit = n;
          417 
          418         switch_to_c(n, clients);
          419         current = currents[virt];
          420 }
          421 
          422 void
          423 initb2menu(int n)
          424 {
          425         b2items[n] = 0;
          426 }