menu.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 }