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 #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"
20 Client *hiddenc[MAXHIDDEN];
22 int numhidden;
24 int virt;
25 int reversehide = 1;
27 Client * currents[NUMVIRTUALS] =
28 {
29 NULL, NULL, NULL, NULL
30 };
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 };
49 Menu b2menu =
50 {
51 b2items
52 };
54 char *b3items[B3FIXED+MAXHIDDEN+1] =
55 {
56 "New",
57 "Reshape",
58 "Move",
59 "Delete",
60 "Hide",
61 0
62 };
64 enum
65 {
66 New,
67 Reshape,
68 Move,
69 Delete,
70 Hide
71 };
73 Menu b3menu =
74 {
75 b3items
76 };
78 Menu egg =
79 {
80 version
81 };
83 void
84 button(XButtonEvent *e)
85 {
86 int n, shift;
87 Client *c;
88 Window dw;
89 ScreenInfo *s;
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;
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);
120 switch (e->button){
121 case Button1:
122 if(c){
123 XMapRaised(dpy, c->parent);
124 top(c);
125 active(c);
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;
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;
182 if(current && current->screen == s)
183 cmapfocus(current);
186 void
187 spawn(ScreenInfo *s)
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");
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);
218 exit(0);
220 wait((int *) 0);
223 void
224 reshape(Client *c, int but, int (*fn)(Client*, int, XButtonEvent *), XButtonEvent *e)
226 int odx, ody;
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);
245 void
246 move(Client *c, int but)
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);
259 void
260 delete(Client *c, int shift)
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 */
270 void
271 hide(Client *c)
273 if(c == 0 || numhidden == MAXHIDDEN)
274 return;
275 if(hidden(c)){
276 fprintf(stderr, "rio: already hidden: %s\n", c->label);
277 return;
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;
293 numhidden++;
294 b3items[B3FIXED+numhidden] = 0;
297 void
298 unhide(int n, int map)
300 Client *c;
301 int i;
303 if(n >= numhidden){
304 fprintf(stderr, "rio: unhide: n %d numhidden %d\n", n, numhidden);
305 return;
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;
313 c->virt = virt;
315 if(map){
316 XMapWindow(dpy, c->window);
317 XMapRaised(dpy, c->parent);
318 setstate(c, NormalState);
319 active(c);
320 top(c);
323 numhidden--;
324 for(i = n; i < numhidden; i++){
325 hiddenc[i] = hiddenc[i+1];
326 b3items[B3FIXED+i] = b3items[B3FIXED+i+1];
328 b3items[B3FIXED+numhidden] = 0;
331 void
332 unhidec(Client *c, int map)
334 int i;
336 for(i = 0; i < numhidden; i++)
337 if(c == hiddenc[i]){
338 unhide(i, map);
339 return;
341 fprintf(stderr, "rio: unhidec: not hidden: %s(0x%x)\n",
342 c->label, (int)c->window);
345 void
346 renamec(Client *c, char *name)
348 int i;
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;
362 void
363 button2(int n)
365 switch_to(n);
366 if(current)
367 cmapfocus(current);
370 void
371 switch_to_c(int n, Client *c)
373 if(c == 0)
374 return;
376 if(c->next)
377 switch_to_c(n, c->next);
379 if(c->parent == DefaultRootWindow(dpy))
380 return;
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;
391 for(i = 0; i < numhidden; i++)
392 if(c == hiddenc[i])
393 break;
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);
405 void
406 switch_to(int n)
408 if(n == virt)
409 return;
410 currents[virt] = current;
411 virt = n;
413 /* redundant when called from a menu switch
414 * but needed for scroll-button switches
415 */
416 b2menu.lasthit = n;
418 switch_to_c(n, clients);
419 current = currents[virt];
422 void
423 initb2menu(int n)
425 b2items[n] = 0;