1
by Tommi Virtanen
Import upstream version 1.00 |
1 |
// Menu.cxx
|
2 |
||
3 |
#include "config.h" |
|
4 |
#include "Frame.H" |
|
5 |
#if DESKTOPS
|
|
6 |
#include "Desktop.H" |
|
7 |
#endif
|
|
8 |
#include <FL/Fl_Box.H> |
|
9 |
#include <FL/Fl_Return_Button.H> |
|
10 |
#include <FL/Fl_Input.H> |
|
11 |
#include <FL/Fl_Menu_Item.H> |
|
12 |
#include <FL/fl_draw.H> |
|
13 |
#include <stdio.h> |
|
14 |
#include <stdlib.h> |
|
15 |
#include <string.h> |
|
16 |
#include <ctype.h> |
|
17 |
#include "FrameWindow.H" |
|
18 |
||
19 |
#include <sys/types.h> |
|
20 |
#include <dirent.h> |
|
21 |
#include <sys/stat.h> |
|
22 |
||
23 |
// it is possible for the window to be deleted or withdrawn while
|
|
24 |
// the menu is up. This will detect that case (with reasonable
|
|
25 |
// reliability):
|
|
26 |
static int |
|
27 |
window_deleted(Frame* c) |
|
28 |
{
|
|
29 |
return c->state() != NORMAL |
|
30 |
&& c->state() != ICONIC |
|
31 |
&& c->state() != OTHER_DESKTOP; |
|
32 |
}
|
|
33 |
||
34 |
static void |
|
35 |
frame_callback(Fl_Widget*, void*d) |
|
36 |
{
|
|
37 |
Frame* c = (Frame*)d; |
|
38 |
if (window_deleted(c)) return; |
|
39 |
c->raise(); |
|
40 |
c->activate(2); |
|
41 |
}
|
|
42 |
||
43 |
#if DESKTOPS
|
|
44 |
// raise it but also put it on the current desktop:
|
|
45 |
static void |
|
46 |
move_frame_callback(Fl_Widget*, void*d) |
|
47 |
{
|
|
48 |
Frame* c = (Frame*)d; |
|
49 |
if (window_deleted(c)) return; |
|
50 |
c->desktop(Desktop::current()); |
|
51 |
c->raise(); |
|
52 |
c->activate(2); |
|
53 |
}
|
|
54 |
#endif
|
|
55 |
||
56 |
#define SCREEN_DX 1 // offset to corner of contents area |
|
57 |
#define SCREEN_W (MENU_ICON_W-2) // size of area to draw contents in |
|
58 |
#define SCREEN_H (MENU_ICON_H-2) // size of area to draw contents in |
|
59 |
||
60 |
#define MAX_NESTING_DEPTH 32
|
|
61 |
||
62 |
extern Fl_Window* Root; |
|
63 |
||
64 |
static void |
|
65 |
frame_label_draw(const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) |
|
66 |
{
|
|
67 |
Frame* f = (Frame*)(o->value); |
|
68 |
if (window_deleted(f)) return; |
|
69 |
fl_draw_box(FL_THIN_DOWN_BOX, X, Y, MENU_ICON_W, MENU_ICON_H, FL_GRAY); |
|
70 |
for (Frame* c = Frame::first; c; c = c->next) { |
|
71 |
if (c->state() != UNMAPPED && (c==f || c->is_transient_for(f))) { |
|
72 |
int x = ((c->x()-Root->x())*SCREEN_W+Root->w()/2)/Root->w(); |
|
73 |
int w = (c->w()*SCREEN_W+Root->w()-1)/Root->w(); |
|
74 |
if (w > SCREEN_W) w = SCREEN_W; |
|
75 |
if (w < 3) w = 3; |
|
76 |
if (x+w > SCREEN_W) x = SCREEN_W-w; |
|
77 |
if (x < 0) x = 0; |
|
78 |
int y = ((c->y()-Root->y())*SCREEN_H+Root->h()/2)/Root->h(); |
|
79 |
int h = (c->h()*SCREEN_H+Root->h()-1)/Root->h(); |
|
80 |
if (h > SCREEN_H) h = SCREEN_H; |
|
81 |
if (h < 3) h = 3; |
|
82 |
if (y+h > SCREEN_H) y = SCREEN_H-h; |
|
83 |
if (y < 0) y = 0; |
|
84 |
fl_color(FL_BLACK); |
|
85 |
if (c->state() == ICONIC) |
|
86 |
fl_rect(X+x+SCREEN_DX, Y+y+SCREEN_DX, w, h); |
|
87 |
else
|
|
88 |
fl_rectf(X+x+SCREEN_DX, Y+y+SCREEN_DX, w, h); |
|
89 |
}
|
|
90 |
}
|
|
91 |
fl_font(o->font, o->size); |
|
92 |
fl_color((Fl_Color)o->color); |
|
93 |
const char* l = f->label(); if (!l) l = "unnamed"; |
|
94 |
fl_draw(l, X+MENU_ICON_W+3, Y, W-MENU_ICON_W-3, H, align); |
|
95 |
}
|
|
96 |
||
97 |
static void |
|
98 |
frame_label_measure(const Fl_Label* o, int& W, int& H) |
|
99 |
{
|
|
100 |
Frame* f = (Frame*)(o->value); |
|
101 |
if (window_deleted(f)) {W = MENU_ICON_W+3; H = MENU_ICON_H; return;} |
|
102 |
const char* l = f->label(); if (!l) l = "unnamed"; |
|
103 |
fl_font(o->font, o->size); |
|
104 |
fl_measure(l, W, H); |
|
105 |
W += MENU_ICON_W+3; |
|
106 |
if (W > MAX_MENU_WIDTH) W = MAX_MENU_WIDTH; |
|
107 |
if (H < MENU_ICON_H) H = MENU_ICON_H; |
|
108 |
}
|
|
109 |
||
110 |
// This labeltype is used for non-frame items so the text can line
|
|
111 |
// up with the icons:
|
|
112 |
||
113 |
static void |
|
114 |
label_draw(const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) |
|
115 |
{
|
|
116 |
fl_font(o->font, o->size); |
|
117 |
fl_color((Fl_Color)o->color); |
|
118 |
fl_draw(o->value, X+MENU_ICON_W+3, Y, W-MENU_ICON_W-3, H, align); |
|
119 |
}
|
|
120 |
||
121 |
static void |
|
122 |
label_measure(const Fl_Label* o, int& W, int& H) |
|
123 |
{
|
|
124 |
fl_font(o->font, o->size); |
|
125 |
fl_measure(o->value, W, H); |
|
126 |
W += MENU_ICON_W+3; |
|
127 |
if (W > MAX_MENU_WIDTH) W = MAX_MENU_WIDTH; |
|
128 |
if (H < MENU_ICON_H) H = MENU_ICON_H; |
|
129 |
}
|
|
130 |
||
131 |
#define FRAME_LABEL FL_FREE_LABELTYPE
|
|
132 |
#define TEXT_LABEL Fl_Labeltype(FL_FREE_LABELTYPE+1)
|
|
133 |
||
134 |
////////////////////////////////////////////////////////////////
|
|
135 |
||
136 |
static void |
|
137 |
cancel_cb(Fl_Widget* w, void*) |
|
138 |
{
|
|
139 |
w->window()->hide(); |
|
140 |
}
|
|
141 |
||
142 |
#if DESKTOPS
|
|
143 |
||
144 |
static void |
|
145 |
desktop_cb(Fl_Widget*, void* v) |
|
146 |
{
|
|
147 |
Desktop::current((Desktop*)v); |
|
148 |
}
|
|
149 |
||
150 |
static void |
|
151 |
delete_desktop_cb(Fl_Widget*, void* v) |
|
152 |
{
|
|
153 |
delete (Desktop*)v; |
|
154 |
}
|
|
155 |
||
156 |
#if ASK_FOR_NEW_DESKTOP_NAME
|
|
157 |
||
158 |
static Fl_Input* new_desktop_input; |
|
159 |
||
160 |
static void |
|
161 |
new_desktop_ok_cb(Fl_Widget* w, void*) |
|
162 |
{
|
|
163 |
w->window()->hide(); |
|
164 |
Desktop::current(new Desktop(new_desktop_input->value(), Desktop::available_number())); |
|
165 |
}
|
|
166 |
||
167 |
static void |
|
168 |
new_desktop_cb(Fl_Widget*, void*) |
|
169 |
{
|
|
170 |
if (!new_desktop_input) { |
|
171 |
FrameWindow* w = new FrameWindow(190,90); |
|
172 |
new_desktop_input = new Fl_Input(10,30,170,25,"New desktop name:"); |
|
173 |
new_desktop_input->align(FL_ALIGN_TOP_LEFT); |
|
174 |
new_desktop_input->labelfont(FL_BOLD); |
|
175 |
Fl_Return_Button* b = new Fl_Return_Button(100,60,80,20,"OK"); |
|
176 |
b->callback(new_desktop_ok_cb); |
|
177 |
Fl_Button* b2 = new Fl_Button(10,60,80,20,"Cancel"); |
|
178 |
b2->callback(cancel_cb); |
|
179 |
w->set_non_modal(); |
|
180 |
w->end(); |
|
181 |
}
|
|
182 |
char buf[120]; |
|
183 |
sprintf(buf, "Desktop %d", Desktop::available_number()); |
|
184 |
new_desktop_input->value(buf); |
|
185 |
new_desktop_input->window()->hotspot(new_desktop_input); |
|
186 |
new_desktop_input->window()->show(); |
|
187 |
}
|
|
188 |
||
189 |
#else // !ASK_FOR_NEW_DESKTOP_NAME |
|
190 |
||
191 |
static void |
|
192 |
new_desktop_cb(Fl_Widget*, void*) |
|
193 |
{
|
|
194 |
char buf[120]; |
|
195 |
int i = Desktop::available_number(); |
|
196 |
sprintf(buf, "Desktop %d", i); |
|
197 |
Desktop::current(new Desktop(buf, i)); |
|
198 |
}
|
|
199 |
||
200 |
#endif
|
|
201 |
||
202 |
#endif
|
|
203 |
////////////////////////////////////////////////////////////////
|
|
204 |
||
205 |
static void |
|
206 |
exit_cb(Fl_Widget*, void*) |
|
207 |
{
|
|
208 |
Frame::save_protocol(); |
|
209 |
exit(0); |
|
210 |
}
|
|
211 |
||
212 |
static void |
|
213 |
logout_cb(Fl_Widget*, void*) |
|
214 |
{
|
|
215 |
static FrameWindow* w; |
|
216 |
if (!w) { |
|
217 |
w = new FrameWindow(190,90); |
|
218 |
Fl_Box* l = new Fl_Box(0, 0, 190, 60, "Really log out?"); |
|
219 |
l->labelfont(FL_BOLD); |
|
220 |
Fl_Return_Button* b = new Fl_Return_Button(100,60,80,20,"OK"); |
|
221 |
b->callback(exit_cb); |
|
222 |
Fl_Button* b2 = new Fl_Button(10,60,80,20,"Cancel"); |
|
223 |
b2->callback(cancel_cb); |
|
224 |
w->set_non_modal(); |
|
225 |
w->end(); |
|
226 |
}
|
|
227 |
w->hotspot(w); |
|
228 |
w->show(); |
|
229 |
}
|
|
230 |
||
231 |
////////////////////////////////////////////////////////////////
|
|
232 |
||
233 |
#include <unistd.h> |
|
234 |
#include <sys/wait.h> |
|
235 |
#include <errno.h> |
|
236 |
||
237 |
#if XTERM_MENU_ITEM || WMX_MENU_ITEMS
|
|
238 |
||
239 |
static const char* xtermname = "xterm"; |
|
240 |
||
241 |
static void |
|
242 |
spawn_cb(Fl_Widget*, void*n) |
|
243 |
{
|
|
244 |
char* name = (char*)n; |
|
245 |
// strange code thieved from 9wm to avoid leaving zombies
|
|
246 |
if (fork() == 0) { |
|
247 |
if (fork() == 0) { |
|
248 |
close(ConnectionNumber(fl_display)); |
|
249 |
if (name == xtermname) execlp(name, name, "-ut", 0); |
|
250 |
else execl(name, name, 0); |
|
251 |
fprintf(stderr, "flwm: can't run %s, %s\n", name, strerror(errno)); |
|
252 |
XBell(fl_display, 70); |
|
253 |
exit(1); |
|
254 |
}
|
|
255 |
exit(0); |
|
256 |
}
|
|
257 |
wait((int *) 0); |
|
258 |
}
|
|
259 |
||
260 |
#endif
|
|
261 |
||
262 |
static Fl_Menu_Item other_menu_items[] = { |
|
263 |
#if XTERM_MENU_ITEM
|
|
264 |
{"New xterm", 0, spawn_cb, (void*)xtermname, 0, 0, 0, MENU_FONT_SIZE}, |
|
265 |
#endif
|
|
266 |
#if DESKTOPS
|
|
267 |
{"New desktop", 0, new_desktop_cb, 0, 0, 0, 0, MENU_FONT_SIZE}, |
|
268 |
#endif
|
|
269 |
{"Logout", 0, logout_cb, 0, 0, 0, 0, MENU_FONT_SIZE}, |
|
270 |
{0}}; |
|
271 |
#define num_other_items (sizeof(other_menu_items)/sizeof(Fl_Menu_Item))
|
|
272 |
||
273 |
// use this to fill in a menu location:
|
|
274 |
static void |
|
275 |
init(Fl_Menu_Item& m, const char* data) |
|
276 |
{
|
|
277 |
#ifdef HAVE_STYLES
|
|
278 |
m.style = 0; |
|
279 |
#endif
|
|
280 |
m.label(data); |
|
281 |
m.flags = 0; |
|
282 |
m.labeltype(FL_NORMAL_LABEL); |
|
283 |
m.shortcut(0); |
|
284 |
m.labelfont(MENU_FONT_SLOT); |
|
285 |
m.labelsize(MENU_FONT_SIZE); |
|
286 |
m.labelcolor(FL_BLACK); |
|
287 |
}
|
|
288 |
||
289 |
#if WMX_MENU_ITEMS
|
|
290 |
||
291 |
// wmxlist is an array of char* pointers (for efficient sorting purposes),
|
|
292 |
// which are stored in wmxbuffer (for memory efficiency and to avoid
|
|
293 |
// freeing and fragmentation)
|
|
294 |
static char** wmxlist = NULL; |
|
295 |
static int wmxlistsize = 0; |
|
296 |
// wmx commands are read from ~/.wmx,
|
|
297 |
// they are stored null-separated here:
|
|
298 |
static char* wmxbuffer = NULL; |
|
299 |
static int wmxbufsize = 0; |
|
300 |
static int num_wmx = 0; |
|
301 |
static time_t wmx_time = 0; |
|
302 |
static int wmx_pathlen = 0; |
|
303 |
||
304 |
static int |
|
305 |
scan_wmx_dir (char *path, int bufindex, int nest) |
|
306 |
{
|
|
307 |
DIR* dir = opendir(path); |
|
308 |
struct stat st; |
|
309 |
int pathlen = strlen (path); |
|
310 |
if (dir) { |
|
311 |
struct dirent* ent; |
|
312 |
while ((ent=readdir(dir))) { |
|
313 |
if (ent->d_name[0] == '.') |
|
314 |
continue; |
|
315 |
strcpy(path+pathlen, ent->d_name); |
|
316 |
if (stat(path, &st) < 0) continue; |
|
317 |
int len = pathlen+strlen(ent->d_name); |
|
318 |
// worst-case alloc needs
|
|
319 |
if (bufindex+len+nest+1 > wmxbufsize) |
|
320 |
wmxbuffer = (char*)realloc(wmxbuffer, (wmxbufsize+=1024)); |
|
321 |
for (int i=0; i<nest; i++) |
|
322 |
wmxbuffer[bufindex++] = '/'; // extra slash marks menu titles |
|
323 |
if (S_ISDIR(st.st_mode) && (st.st_mode & 0555) && nest<MAX_NESTING_DEPTH){ |
|
324 |
strcpy(wmxbuffer+bufindex, path); |
|
325 |
bufindex += len+1; |
|
326 |
strcat(path, "/"); |
|
327 |
bufindex = scan_wmx_dir (path, bufindex, nest+1); |
|
328 |
num_wmx++; |
|
329 |
} else if (S_ISREG(st.st_mode) && (st.st_mode & 0111)) { |
|
330 |
// make sure it exists and is an executable file:
|
|
331 |
strcpy(wmxbuffer+bufindex, path); |
|
332 |
bufindex += len+1; |
|
333 |
num_wmx++; |
|
334 |
}
|
|
335 |
}
|
|
336 |
closedir(dir); |
|
337 |
}
|
|
338 |
return bufindex; |
|
339 |
}
|
|
340 |
||
341 |
// comparison for qsort
|
|
342 |
// We keep submenus together by noting that they're proper superstrings
|
|
343 |
static int |
|
344 |
wmxCompare(const void *A, const void *B) |
|
345 |
{
|
|
346 |
char *pA, *pB; |
|
347 |
pA = *(char **)A; |
|
348 |
pB = *(char **)B; |
|
349 |
||
350 |
pA += strspn(pA, "/"); |
|
351 |
pB += strspn(pB, "/"); |
|
352 |
||
353 |
// caseless compare
|
|
354 |
while (*pA && *pB) { |
|
355 |
if (toupper(*pA) > toupper(*pB)) |
|
356 |
return(1); |
|
357 |
if (toupper(*pA) < toupper(*pB)) |
|
358 |
return(-1); |
|
359 |
pA++; |
|
360 |
pB++; |
|
361 |
}
|
|
362 |
if (*pA) |
|
363 |
return(1); |
|
364 |
if (*pB) |
|
365 |
return(-1); |
|
366 |
return(0); |
|
367 |
}
|
|
368 |
||
369 |
static void |
|
370 |
load_wmx() |
|
371 |
{
|
|
372 |
const char* home=getenv("HOME"); if (!home) home = "."; |
|
373 |
char path[1024]; |
|
374 |
strcpy(path, home); |
|
375 |
if (path[strlen(path)-1] != '/') strcat(path, "/"); |
|
376 |
strcat(path, ".wmx/"); |
|
2
by Tommi Virtanen
Added xutils to Build-Deps. Closes: #87825. |
377 |
struct stat st; |
378 |
if (stat(path, &st) < 0) { |
|
4
by Bill Allombert
* Rebuild with current g++/libfltk1.1. Closes: #328174. |
379 |
strcpy(path, "/var/lib/flwm/wmx/"); |
2
by Tommi Virtanen
Added xutils to Build-Deps. Closes: #87825. |
380 |
if (stat(path, &st) < 0) return; |
381 |
}
|
|
1
by Tommi Virtanen
Import upstream version 1.00 |
382 |
if (st.st_mtime == wmx_time) return; |
383 |
wmx_time = st.st_mtime; |
|
384 |
num_wmx = 0; |
|
385 |
wmx_pathlen = strlen(path); |
|
386 |
scan_wmx_dir(path, 0, 0); |
|
387 |
||
388 |
// Build wmxlist
|
|
389 |
if (num_wmx > wmxlistsize) { |
|
390 |
if (wmxlist) |
|
391 |
delete [] wmxlist; |
|
392 |
wmxlist = new char *[num_wmx]; |
|
393 |
wmxlistsize = num_wmx; |
|
394 |
}
|
|
395 |
for (int i=0; i<num_wmx; i++) { |
|
396 |
char* cmd = wmxbuffer; |
|
397 |
||
398 |
for (int j = 0; j < num_wmx; j++) { |
|
399 |
wmxlist[j] = cmd; |
|
400 |
cmd += strlen(cmd)+1; |
|
401 |
}
|
|
402 |
}
|
|
403 |
||
404 |
qsort(wmxlist, num_wmx, sizeof(char *), wmxCompare); |
|
405 |
}
|
|
406 |
||
407 |
#endif
|
|
408 |
||
409 |
////////////////////////////////////////////////////////////////
|
|
410 |
||
411 |
int exit_flag; // set by the -x switch |
|
412 |
||
413 |
static int is_active_frame(Frame* c) { |
|
414 |
for (Frame* a = Frame::activeFrame(); a; a = a->transient_for()) |
|
415 |
if (a == c) return 1; |
|
416 |
return 0; |
|
417 |
}
|
|
418 |
||
419 |
void
|
|
420 |
ShowTabMenu(int tab) |
|
421 |
{
|
|
422 |
||
423 |
static char beenhere; |
|
424 |
if (!beenhere) { |
|
425 |
beenhere = 1; |
|
426 |
Fl::set_labeltype(FRAME_LABEL, frame_label_draw, frame_label_measure); |
|
427 |
Fl::set_labeltype(TEXT_LABEL, label_draw, label_measure); |
|
428 |
if (exit_flag) { |
|
429 |
Fl_Menu_Item* m = other_menu_items+num_other_items-2; |
|
430 |
m->label("Exit"); |
|
431 |
m->callback(exit_cb); |
|
432 |
}
|
|
433 |
}
|
|
434 |
||
435 |
static Fl_Menu_Item* menu = 0; |
|
436 |
static int arraysize = 0; |
|
437 |
||
438 |
#if DESKTOPS
|
|
439 |
int one_desktop = !Desktop::first->next; |
|
440 |
#endif
|
|
441 |
||
442 |
// count up how many items are on the menu:
|
|
443 |
||
444 |
int n = num_other_items; |
|
445 |
#if WMX_MENU_ITEMS
|
|
446 |
load_wmx(); |
|
447 |
if (num_wmx) { |
|
448 |
n -= 1; // delete "new xterm" |
|
449 |
// add wmx items
|
|
450 |
int level = 0; |
|
451 |
for (int i=0; i<num_wmx; i++) { |
|
452 |
int nextlev = (i==num_wmx-1)?0:strspn(wmxlist[i+1], "/")-1; |
|
453 |
if (nextlev < level) { |
|
454 |
n += level-nextlev; |
|
455 |
level = nextlev; |
|
456 |
} else if (nextlev > level) |
|
457 |
level++; |
|
458 |
n++; |
|
459 |
}
|
|
460 |
}
|
|
461 |
#endif
|
|
462 |
||
463 |
#if DESKTOPS
|
|
464 |
// count number of items per desktop in these variables:
|
|
465 |
int numsticky = 0; |
|
466 |
Desktop* d; |
|
467 |
for (d = Desktop::first; d; d = d->next) d->junk = 0; |
|
468 |
#endif
|
|
469 |
||
470 |
// every frame contributes 1 item:
|
|
471 |
Frame* c; |
|
472 |
for (c = Frame::first; c; c = c->next) { |
|
473 |
if (c->state() == UNMAPPED || c->transient_for()) continue; |
|
474 |
#if DESKTOPS
|
|
475 |
if (!c->desktop()) { |
|
476 |
numsticky++; |
|
477 |
} else { |
|
478 |
c->desktop()->junk++; |
|
479 |
}
|
|
480 |
#endif
|
|
481 |
n++; |
|
482 |
}
|
|
483 |
||
484 |
#if DESKTOPS
|
|
485 |
if (!one_desktop) { |
|
486 |
// add the sticky "desktop":
|
|
487 |
n += 2; if (!numsticky) n++; |
|
488 |
if (Desktop::current()) { |
|
489 |
n += numsticky; |
|
490 |
Desktop::current()->junk += numsticky; |
|
491 |
}
|
|
492 |
// every desktop contributes menu title, null terminator,
|
|
493 |
// and possible delete:
|
|
494 |
for (d = Desktop::first; d; d = d->next) { |
|
495 |
n += 2; if (!d->junk) n++; |
|
496 |
}
|
|
497 |
}
|
|
498 |
#endif
|
|
499 |
||
500 |
if (n > arraysize) { |
|
501 |
delete[] menu; |
|
502 |
menu = new Fl_Menu_Item[arraysize = n]; |
|
503 |
}
|
|
504 |
||
505 |
// build the menu:
|
|
506 |
n = 0; |
|
507 |
const Fl_Menu_Item* preset = 0; |
|
508 |
const Fl_Menu_Item* first_on_desk = 0; |
|
509 |
#if DESKTOPS
|
|
510 |
if (one_desktop) { |
|
511 |
#endif
|
|
512 |
for (c = Frame::first; c; c = c->next) { |
|
513 |
if (c->state() == UNMAPPED || c->transient_for()) continue; |
|
514 |
init(menu[n],(char*)c); |
|
515 |
menu[n].labeltype(FRAME_LABEL); |
|
516 |
menu[n].callback(frame_callback, c); |
|
517 |
if (is_active_frame(c)) preset = menu+n; |
|
518 |
n++; |
|
519 |
}
|
|
520 |
if (n > 0) first_on_desk = menu; |
|
521 |
#if DESKTOPS
|
|
522 |
} else for (d = Desktop::first; ; d = d->next) { |
|
523 |
// this loop adds the "sticky" desktop last, when d==0
|
|
524 |
if (d == Desktop::current()) preset = menu+n; |
|
525 |
init(menu[n], d ? d->name() : "Sticky"); |
|
526 |
menu[n].callback(desktop_cb, d); |
|
527 |
menu[n].flags = FL_SUBMENU; |
|
528 |
n++; |
|
529 |
if (d && !d->junk) { |
|
530 |
init(menu[n],"delete this desktop"); |
|
531 |
menu[n].callback(delete_desktop_cb, d); |
|
532 |
n++; |
|
533 |
} else if (!d && !numsticky) { |
|
534 |
init(menu[n],"(empty)"); |
|
535 |
menu[n].callback_ = 0; |
|
536 |
menu[n].deactivate(); |
|
537 |
n++; |
|
538 |
} else { |
|
539 |
if (d == Desktop::current()) first_on_desk = menu+n; |
|
540 |
for (c = Frame::first; c; c = c->next) { |
|
541 |
if (c->state() == UNMAPPED || c->transient_for()) continue; |
|
542 |
if (c->desktop() == d || !c->desktop() && d == Desktop::current()) { |
|
543 |
init(menu[n],(char*)c); |
|
544 |
menu[n].labeltype(FRAME_LABEL); |
|
545 |
menu[n].callback(d == Desktop::current() ? |
|
546 |
frame_callback : move_frame_callback, c); |
|
547 |
if (d == Desktop::current() && is_active_frame(c)) preset = menu+n; |
|
548 |
n++; |
|
549 |
}
|
|
550 |
}
|
|
551 |
}
|
|
552 |
menu[n].label(0); n++; // terminator for submenu |
|
553 |
if (!d) break; |
|
554 |
}
|
|
555 |
#endif
|
|
556 |
||
557 |
// For ALT+Tab, move the selection forward or backward:
|
|
558 |
if (tab > 0 && first_on_desk) { |
|
559 |
if (!preset) |
|
560 |
preset = first_on_desk; |
|
561 |
else { |
|
562 |
preset++; |
|
563 |
if (!preset->label() || preset->callback_ != frame_callback) |
|
564 |
preset = first_on_desk; |
|
565 |
}
|
|
566 |
} else if (tab < 0 && first_on_desk) { |
|
567 |
if (preset && preset != first_on_desk) |
|
568 |
preset--; |
|
569 |
else { |
|
570 |
// go to end of menu
|
|
571 |
preset = first_on_desk; |
|
572 |
while (preset[1].label() && preset[1].callback_ == frame_callback) |
|
573 |
preset++; |
|
574 |
}
|
|
575 |
}
|
|
576 |
||
577 |
#if WMX_MENU_ITEMS
|
|
578 |
// put wmx-style commands above that:
|
|
579 |
if (num_wmx > 0) { |
|
580 |
char* cmd; |
|
581 |
int pathlen[MAX_NESTING_DEPTH]; |
|
582 |
int level = 0; |
|
583 |
pathlen[0] = wmx_pathlen; |
|
584 |
for (int i = 0; i < num_wmx; i++) { |
|
585 |
cmd = wmxlist[i]; |
|
586 |
cmd += strspn(cmd, "/")-1; |
|
587 |
init(menu[n], cmd+pathlen[level]); |
|
588 |
#if DESKTOPS
|
|
589 |
if (one_desktop) |
|
590 |
#endif
|
|
591 |
if (!level) |
|
592 |
menu[n].labeltype(TEXT_LABEL); |
|
593 |
||
594 |
int nextlev = (i==num_wmx-1)?0:strspn(wmxlist[i+1], "/")-1; |
|
595 |
if (nextlev < level) { |
|
596 |
menu[n].callback(spawn_cb, cmd); |
|
597 |
// Close 'em off
|
|
598 |
for (; level>nextlev; level--) |
|
599 |
init(menu[++n], 0); |
|
600 |
} else if (nextlev > level) { |
|
601 |
// This should be made a submenu
|
|
602 |
pathlen[++level] = strlen(cmd)+1; // extra for next trailing / |
|
603 |
menu[n].flags = FL_SUBMENU; |
|
604 |
menu[n].callback((Fl_Callback*)0); |
|
605 |
} else { |
|
606 |
menu[n].callback(spawn_cb, cmd); |
|
607 |
}
|
|
608 |
n++; |
|
609 |
}
|
|
610 |
}
|
|
611 |
||
612 |
// put the fixed menu items at the bottom:
|
|
613 |
#if XTERM_MENU_ITEM
|
|
614 |
if (num_wmx) // if wmx commands, delete the built-in xterm item: |
|
615 |
memcpy(menu+n, other_menu_items+1, sizeof(other_menu_items)-sizeof(Fl_Menu_Item)); |
|
616 |
else
|
|
617 |
#endif
|
|
618 |
#endif
|
|
619 |
memcpy(menu+n, other_menu_items, sizeof(other_menu_items)); |
|
620 |
#if DESKTOPS
|
|
621 |
if (one_desktop) |
|
622 |
#endif
|
|
623 |
// fix the menus items so they are indented to align with window names:
|
|
624 |
while (menu[n].label()) menu[n++].labeltype(TEXT_LABEL); |
|
625 |
||
626 |
const Fl_Menu_Item* picked = |
|
627 |
menu->popup(Fl::event_x(), Fl::event_y(), 0, preset); |
|
628 |
if (picked && picked->callback()) picked->do_callback(0); |
|
629 |
}
|
|
630 |
||
631 |
void ShowMenu() {ShowTabMenu(0);} |