Blob


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