Blob


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