plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }