1 /*
2 * Author: William Chia-Wei Cheng (bill.cheng@acm.org)
3 *
4 * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5 *
6 * This file may be distributed under the terms of the Q Public License
7 * as defined by Trolltech AS of Norway and appearing in the file
8 * LICENSE.QPL included in the packaging of this file.
9 *
10 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * @(#)$Header: /mm2/home/cvs/bc-src/tgif/menu.c,v 1.17 2011/05/16 16:21:58 william Exp $
19 */
20
21 #define _INCLUDE_FROM_MENU_C_
22
23 #include "tgifdefs.h"
24 #include "cmdids.h"
25
26 #include "align.e"
27 #include "box.e"
28 #include "choice.e"
29 #include "cmd.e"
30 #include "color.e"
31 #include "cursor.e"
32 #include "dialog.e"
33 #include "drawing.e"
34 #include "edit.e"
35 #include "exec.e"
36 #include "file.e"
37 #include "font.e"
38 #include "grid.e"
39 #include "help.e"
40 #include "imgproc.e"
41 #include "mainloop.e"
42 #include "mainmenu.e"
43 #include "menu.e"
44 #include "menuinfo.e"
45 #include "move.e"
46 #include "msg.e"
47 #include "names.e"
48 #include "navigate.e"
49 #include "obj.e"
50 #include "page.e"
51 #include "pattern.e"
52 #include "raster.e"
53 #include "rect.e"
54 #include "remote.e"
55 #include "scroll.e"
56 #include "select.e"
57 #include "setup.e"
58 #include "shape.e"
59 #include "special.e"
60 #include "stk.e"
61 #include "strtbl.e"
62 #include "tangram2.e"
63 #include "text.e"
64 #include "util.e"
65 #include "version.e"
66
67 #include "xbm/check.xbm"
68 #include "xbm/submenu.xbm"
69
70 int iconWindowCreated=FALSE;
71 int iconWindowShown=FALSE;
72 int importingIconFile=FALSE;
73
74 int showVersion=FALSE;
75 int activeMenu=INVALID;
76
77 #define SEPARATOR_PADDING 1
78
79 static int separatorHeight=SEPARATOR_PADDING;
80
81 GC textMenuGC=(GC)0;
82 GC rvPixmapMenuGC=(GC)0;
83
84 int menuRowsBeforeScroll=21;
85 int menuColsBeforeScroll=27;
86
87 int maxScrollableMenuWidth=0;
88 int maxScrollableMenuHeight=0;
89
90 int deleteCmdAsCut=FALSE;
91
92 MenuDontSendCommandInfo gstMenuDontSendCommandInfo;
93
94 static int savedZoomScale=0, savedDrawOrigX=0, savedDrawOrigY=0;
95 static int savedZoomedIn=FALSE;
96 static int savedDrawWinW=0, savedDrawWinH=0, savedFileModified=FALSE;
97
98 static struct BBRec excludeMenubarWinBBox;
99 static int excludeMenubarIndex=INVALID;
100
101 static int gnNumMenubarItems=0;
102 static int gnNumMainMenuItems=0;
103 /*
104 * gpMenubarItemInfos[i].menu_str and gpMenubarItemInfos[i].status_str
105 * are raw English strings
106 */
107 static TgMenuItemInfo *gpMenubarItemInfos=NULL;
108 static TgMenuItemInfo *gpMainMenuItemInfos=NULL;
109
110 static int gnMinimalMenubar=TRUE;
111 static int gnAutoWrapMenubar=FALSE;
112
113 static
BuildMenubarInfo()114 void BuildMenubarInfo()
115 {
116 static int nInitialized=FALSE;
117 char *c_ptr=NULL;
118 TgMenuItemInfo *item_info=NULL;
119
120 if (nInitialized) return;
121
122 nInitialized = TRUE;
123
124 gnMinimalMenubar = TRUE;
125 if (((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"MinimalMenubar")) !=
126 NULL) && UtilStrICmp(c_ptr,"false") == 0) {
127 gnMinimalMenubar = FALSE;
128 }
129 gnAutoWrapMenubar = FALSE;
130 if (((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"AutoWrapMenubar")) !=
131 NULL) && UtilStrICmp(c_ptr,"true") == 0) {
132 gnAutoWrapMenubar = TRUE;
133 }
134 /* menubar */
135 gpMenubarItemInfos = (gnMinimalMenubar ? minimalMenubarMenuInfo.items :
136 maximalMenubarMenuInfo.items);
137 gnNumMenubarItems = 0;
138 for (item_info=gpMenubarItemInfos; item_info->menu_str != NULL;
139 item_info++) {
140 gnNumMenubarItems++;
141 }
142 if (!cmdLineTgrm2) {
143 int i=0, j=0;
144 TgMenuItemInfo *pMenubarItemInfos=(TgMenuItemInfo*)malloc(
145 (gnNumMenubarItems+1)*sizeof(TgMenuItemInfo));
146
147 for (i=0; i <= gnNumMenubarItems; i++) {
148 if (gpMenubarItemInfos[i].cmdid != MENU_TANGRAM2) {
149 memcpy(&pMenubarItemInfos[j++], &gpMenubarItemInfos[i],
150 sizeof(TgMenuItemInfo));
151 }
152 }
153 memcpy(&pMenubarItemInfos[j], &gpMenubarItemInfos[i],
154 sizeof(TgMenuItemInfo));
155
156 gpMenubarItemInfos = pMenubarItemInfos;
157 gnNumMenubarItems--;
158 }
159
160 /* main menu */
161 gpMainMenuItemInfos = mainMenuInfo.items;
162 gnNumMainMenuItems = 0;
163 for (item_info=gpMainMenuItemInfos; item_info->menu_str != NULL;
164 item_info++) {
165 gnNumMainMenuItems++;
166 }
167 if (!cmdLineTgrm2) {
168 int i=0, j=0;
169 TgMenuItemInfo *pMainMenuItemInfos=(TgMenuItemInfo*)malloc(
170 (gnNumMainMenuItems+1)*sizeof(TgMenuItemInfo));
171
172 for (i=0; i <= gnNumMainMenuItems; i++) {
173 if (gpMainMenuItemInfos[i].cmdid != MENU_TANGRAM2) {
174 memcpy(&pMainMenuItemInfos[j++], &gpMainMenuItemInfos[i],
175 sizeof(TgMenuItemInfo));
176 }
177 }
178 memcpy(&pMainMenuItemInfos[j], &gpMainMenuItemInfos[i],
179 sizeof(TgMenuItemInfo));
180
181 gpMainMenuItemInfos = pMainMenuItemInfos;
182 gnNumMainMenuItems--;
183 }
184 }
185
186 static
UpdateMenubarItemInfo(x,w,h,MenuX,MenuY,TextBBox)187 void UpdateMenubarItemInfo(x, w, h, MenuX, MenuY, TextBBox)
188 int x, w, h, *MenuX, *MenuY;
189 struct BBRec *TextBBox;
190 {
191 if (MenuX != NULL || MenuY != NULL) {
192 int win_x, win_y, main_win_x, main_win_y;
193 unsigned int win_w, win_h, win_brdr_w, win_d;
194 Window root_win;
195
196 ComputeMainWinXY(&main_win_x, &main_win_y);
197 XGetGeometry(mainDisplay, menubarWindow, &root_win, &win_x,
198 &win_y, &win_w, &win_h, &win_brdr_w, &win_d);
199 if (MenuX != NULL) {
200 *MenuX = main_win_x + win_x + x - 3 -
201 ((menuFontSet==NULL && menuFontPtr==NULL) ? 0 :
202 (menuFontWidth>>1));
203 if (!threeDLook) {
204 *MenuX += 4;
205 }
206 }
207 if (MenuY != NULL) {
208 *MenuY = main_win_y+brdrW+win_y+h+(win_brdr_w<<1)-1;
209 }
210 }
211 if (TextBBox != NULL) {
212 TextBBox->ltx = x-((menuFontSet==NULL && menuFontPtr==NULL) ? 0 :
213 (menuFontWidth>>1));
214 TextBBox->rbx = x+w+((menuFontSet==NULL && menuFontPtr==NULL) ? 0 :
215 menuFontWidth);
216 TextBBox->lty = h-((menuFontSet==NULL && menuFontPtr == NULL) ?
217 initialMenubarWindowH : menuFontHeight);
218 TextBBox->rby = h;
219 }
220 }
221
222 static
WhichMenubarItem(X,Y,MenuX,MenuY,TextBBox)223 int WhichMenubarItem(X, Y, MenuX, MenuY, TextBBox)
224 int X, Y, *MenuX, *MenuY;
225 struct BBRec *TextBBox;
226 {
227 int i, x=0, w=0, h=0, len=0, gap=0, padding=(windowPadding>>1);
228 int min_x=((menuFontSet==NULL && menuFontPtr==NULL) ? 2 : menuFontWidth);
229
230 if (noMenubar ||
231 Y < 0 || Y >= menubarWindowH || X < min_x || X >= menubarWindowW) {
232 return INVALID;
233 }
234 if (menuFontSet != NULL || menuFontPtr != NULL) {
235 x = menuFontWidth;
236 h = menuFontHeight;
237 gap = (x<<1);
238 x += padding;
239 h += padding;
240 for (i=0; i < gnNumMenubarItems; i++) {
241 len = strlen(_(gpMenubarItemInfos[i].menu_str));
242 w = MenuTextWidth(menuFontPtr, _(gpMenubarItemInfos[i].menu_str), len);
243 if ((!noMinWinSize || !gnMinimalMenubar || gnAutoWrapMenubar) &&
244 x+w+padding >= menubarWindowW) {
245 if (Y < h) return INVALID;
246 x = menuFontWidth+padding;
247 h += menuFontHeight+padding;
248 }
249 if (Y < h && X < x+w+gap+padding) {
250 if (!colorDisplay && gpMenubarItemInfos[i].cmdid == MENU_COLOR) {
251 return INVALID;
252 }
253 UpdateMenubarItemInfo(x+padding, w, h, MenuX, MenuY, TextBBox);
254 return i;
255 }
256 x += w+gap+padding;
257 }
258 } else {
259 x = 2;
260 h = initialMenubarWindowH;
261 gap = defaultFontWidth+(defaultFontWidth>>1);
262 x += padding;
263 h += padding;
264 for (i=0; i < gnNumMenubarItems; i++) {
265 len = strlen(_(gpMenubarItemInfos[i].menu_str));
266 w = defaultFontWidth*len;
267 if ((!noMinWinSize || !gnMinimalMenubar || gnAutoWrapMenubar) &&
268 x+w+padding >= menubarWindowW) {
269 if (Y < h) return INVALID;
270 x = 2+padding;
271 h += initialMenubarWindowH+padding;
272 }
273 if (Y < h && X < x+w+gap+padding) {
274 if (!colorDisplay && gpMenubarItemInfos[i].cmdid == MENU_COLOR) {
275 return INVALID;
276 }
277 UpdateMenubarItemInfo(x+padding, w, h, MenuX, MenuY, TextBBox);
278 return i;
279 }
280 x += w+gap+padding;
281 }
282 }
283 return INVALID;
284 }
285
286 static
GetMenubarItemInfo(index,MenuX,MenuY,TextBBox)287 int GetMenubarItemInfo(index, MenuX, MenuY, TextBBox)
288 int index, *MenuX, *MenuY;
289 struct BBRec *TextBBox;
290 {
291 int i, x=0, w=0, h=0, len=0, gap=0, padding=(windowPadding>>1);
292
293 if (menuFontSet != NULL || menuFontPtr != NULL) {
294 x = menuFontWidth;
295 h = menuFontHeight;
296 gap = (x<<1);
297 x += padding;
298 h += padding;
299 for (i=0; i < gnNumMenubarItems; i++) {
300 len = strlen(_(gpMenubarItemInfos[i].menu_str));
301 w = MenuTextWidth(menuFontPtr, _(gpMenubarItemInfos[i].menu_str), len);
302 if ((!noMinWinSize || !gnMinimalMenubar || gnAutoWrapMenubar) &&
303 x+w+padding >= menubarWindowW) {
304 x = menuFontWidth+padding;
305 h += menuFontHeight+padding;
306 }
307 if (i == index) {
308 UpdateMenubarItemInfo(x+padding, w, h, MenuX, MenuY, TextBBox);
309 return i;
310 }
311 x += w+gap+padding;
312 }
313 } else {
314 x = 2;
315 h = initialMenubarWindowH;
316 gap = defaultFontWidth+(defaultFontWidth>>1);
317 x += padding;
318 h += padding;
319 for (i=0; i < gnNumMenubarItems; i++) {
320 len = strlen(_(gpMenubarItemInfos[i].menu_str));
321 w = defaultFontWidth*len;
322 if ((!noMinWinSize || !gnMinimalMenubar || gnAutoWrapMenubar) &&
323 x+w+padding >= menubarWindowW) {
324 x = 2+padding;
325 h += initialMenubarWindowH+padding;
326 }
327 if (i == index) {
328 UpdateMenubarItemInfo(x+padding, w, h, MenuX, MenuY, TextBBox);
329 return i;
330 }
331 x += w+gap+padding;
332 }
333 }
334 return INVALID;
335 }
336
SendCommandToSelf(nCmdId,nIndex)337 void SendCommandToSelf(nCmdId, nIndex)
338 int nCmdId, nIndex;
339 {
340 XClientMessageEvent client_ev;
341
342 memset(&client_ev, 0, sizeof(XClientMessageEvent));
343 client_ev.type = ClientMessage;
344 client_ev.window = mainWindow;
345 client_ev.message_type = executeCmdByIDAtom;
346 client_ev.format = 16;
347 client_ev.data.s[0] = (short)TG_COMMAND;
348 client_ev.data.s[1] = (short)(nCmdId & 0x0ffff);
349 client_ev.data.s[2] = (short)(nIndex & 0x0ffff);
350 XSendEvent(mainDisplay, mainWindow, False, NoEventMask, (XEvent*)&client_ev);
351 }
352
FindMenuItemByCmdId(menu,cmdid)353 TgMenuItem *FindMenuItemByCmdId(menu, cmdid)
354 TgMenu *menu;
355 int cmdid;
356 {
357 int i, num_items=menu->num_items;
358 TgMenuItem *menuitems=menu->menuitems;
359
360 for (i=0; i < num_items; i++) {
361 TgMenuItem *menu_item=(&menuitems[i]);
362
363 if ((menu_item->flags & TGMU_SEPARATOR) == 0) {
364 if (menu_item->cmdid == cmdid) {
365 return menu_item;
366 }
367 }
368 }
369 return NULL;
370 }
371
FindMenuItemByIndex(menu,index)372 TgMenuItem *FindMenuItemByIndex(menu, index)
373 TgMenu *menu;
374 int index;
375 /* skip TGMU_SEPARATOR */
376 {
377 int i, num_items=menu->num_items;
378 TgMenuItem *menuitems=menu->menuitems;
379
380 for (i=0; i < num_items; i++) {
381 TgMenuItem *menu_item=(&menuitems[i]);
382
383 if ((menu_item->flags & TGMU_SEPARATOR) == 0) {
384 if (i == index) {
385 return menu_item;
386 }
387 }
388 }
389 return NULL;
390 }
391
FindMenuItemBySubMenuInfoPtr(menu,submenu_info)392 TgMenuItem *FindMenuItemBySubMenuInfoPtr(menu, submenu_info)
393 TgMenu *menu;
394 TgMenuInfo *submenu_info;
395 {
396 int i, num_items=menu->num_items;
397 TgMenuItem *menuitems=menu->menuitems;
398
399 for (i=0; i < num_items; i++) {
400 TgMenuItem *menu_item=(&menuitems[i]);
401
402 if ((menu_item->flags & TGMU_HAS_SUBMENU) == TGMU_HAS_SUBMENU) {
403 TgMenuItemInfo *create_info=menu_item->submenu_create_info;
404
405 if (create_info->submenu_info == submenu_info) {
406 return menu_item;
407 }
408 }
409 }
410 return NULL;
411 }
412
413 static
TgSetMenuItemCheckOrRadioById(menu,cmdid,checked,mask)414 int TgSetMenuItemCheckOrRadioById(menu, cmdid, checked, mask)
415 TgMenu *menu;
416 int cmdid, checked, mask;
417 {
418 TgMenuItem stMenuItem;
419 TgMenuItem *menu_item=NULL;
420
421 if (menu == NULL) return FALSE;
422
423 if ((menu_item=FindMenuItemByCmdId(menu, cmdid)) == NULL) {
424 return FALSE;
425 }
426 memset(&stMenuItem, 0, sizeof(TgMenuItem));
427 stMenuItem.checked = checked;
428 if (!TgSetMenuItemInfo(menu_item, mask, &stMenuItem)) {
429 return FALSE;
430 }
431 return TRUE;
432 }
433
TgSetMenuItemCheckById(menu,cmdid,checked)434 int TgSetMenuItemCheckById(menu, cmdid, checked)
435 TgMenu *menu;
436 int cmdid, checked;
437 {
438 return TgSetMenuItemCheckOrRadioById(menu, cmdid, checked, TGMU_MASK_CHECK);
439 }
440
TgSetMenuItemRadioById(menu,cmdid,checked)441 int TgSetMenuItemRadioById(menu, cmdid, checked)
442 TgMenu *menu;
443 int cmdid, checked;
444 {
445 return TgSetMenuItemCheckOrRadioById(menu, cmdid, checked, TGMU_MASK_RADIO);
446 }
447
TgIsMenuItemChecked(menu,index)448 int TgIsMenuItemChecked(menu, index)
449 TgMenu *menu;
450 int index;
451 {
452 TgMenuItem *menuitems=menu->menuitems;
453
454 if (index >= 0 && index < menu->num_items) {
455 int flags=(menuitems[index].flags);
456
457 return (menuitems[index].checked &&
458 (flags & TGMU_HAS_CHECK) == TGMU_HAS_CHECK);
459 }
460 return FALSE;
461 }
462
TgIsMenuItemRadio(menu,index)463 int TgIsMenuItemRadio(menu, index)
464 TgMenu *menu;
465 int index;
466 {
467 TgMenuItem *menuitems=menu->menuitems;
468
469 if (index >= 0 && index < menu->num_items) {
470 int flags=(menuitems[index].flags);
471
472 return (menuitems[index].checked &&
473 (flags & TGMU_HAS_RADIO) == TGMU_HAS_RADIO);
474 }
475 return FALSE;
476 }
477
TgIsMenuItemEnabled(menu,index)478 int TgIsMenuItemEnabled(menu, index)
479 TgMenu *menu;
480 int index;
481 {
482 TgMenuItem *menuitems=menu->menuitems;
483
484 if (index >= 0 && index < menu->num_items) {
485 int flags=(menuitems[index].flags);
486
487 return ((flags & TGMU_DISABLED) != TGMU_DISABLED);
488 }
489 return FALSE;
490 }
491
TgEnableMenuItemById(menu,cmdid,enabled)492 int TgEnableMenuItemById(menu, cmdid, enabled)
493 TgMenu *menu;
494 int cmdid, enabled;
495 {
496 TgMenuItem *menu_item=NULL;
497
498 if (menu == NULL) return FALSE;
499
500 if ((menu_item=FindMenuItemByCmdId(menu, cmdid)) == NULL) {
501 return FALSE;
502 }
503 if (enabled) {
504 menu_item->flags &= (~TGMU_DISABLED);
505 } else {
506 menu_item->flags |= TGMU_DISABLED;
507 }
508 return TRUE;
509 }
510
TgEnableMenuItemByIndex(menu,index,enabled)511 int TgEnableMenuItemByIndex(menu, index, enabled)
512 TgMenu *menu;
513 int index, enabled;
514 {
515 TgMenuItem *menu_item=NULL;
516
517 if (menu == NULL) return FALSE;
518
519 if ((menu_item=FindMenuItemByIndex(menu, index)) == NULL) {
520 return FALSE;
521 }
522 if (enabled) {
523 menu_item->flags &= (~TGMU_DISABLED);
524 } else {
525 menu_item->flags |= TGMU_DISABLED;
526 }
527 return TRUE;
528 }
529
TgEnableMenuItemBySubMenuInfoPtr(menu,submenu_info,enabled)530 int TgEnableMenuItemBySubMenuInfoPtr(menu, submenu_info, enabled)
531 TgMenu *menu;
532 TgMenuInfo *submenu_info;
533 int enabled;
534 {
535 TgMenuItem *menu_item=NULL;
536
537 if (menu == NULL) return FALSE;
538
539 if ((menu_item=FindMenuItemBySubMenuInfoPtr(menu, submenu_info)) == NULL) {
540 return FALSE;
541 }
542 if (enabled) {
543 menu_item->flags &= (~TGMU_DISABLED);
544 } else {
545 menu_item->flags |= TGMU_DISABLED;
546 }
547 return TRUE;
548 }
549
TgClearThreeDButton(dpy,win,gc,bbox,linewidth)550 void TgClearThreeDButton(dpy, win, gc, bbox, linewidth)
551 Display *dpy;
552 Window win;
553 GC gc;
554 struct BBRec *bbox;
555 int linewidth;
556 {
557 int x=bbox->ltx, y=bbox->lty, w=bbox->rbx-bbox->ltx, h=bbox->rby-bbox->lty;
558
559 XSetForeground(dpy, gc, myLtGryPixel);
560 if (linewidth == 1) {
561 XDrawLine(dpy, win, gc, x, y+h-1, x+w-1, y+h-1);
562 XDrawLine(dpy, win, gc, x+w-1, y+h-1, x+w-1, y);
563 XDrawLine(dpy, win, gc, x, y+h-2, x, y);
564 XDrawLine(dpy, win, gc, x, y, x+w-2, y);
565 } else if (linewidth >= 2) {
566 XDrawLine(dpy, win, gc, x, y+h-1, x+w-1, y+h-1);
567 XDrawLine(dpy, win, gc, x+w-1, y+h-1, x+w-1, y);
568 XDrawLine(dpy, win, gc, x+1, y+h-2, x+w-2, y+h-2);
569 XDrawLine(dpy, win, gc, x+w-2, y+h-2, x+w-2, y+1);
570 XDrawLine(dpy, win, gc, x+1, y+h-3, x+1, y+1);
571 XDrawLine(dpy, win, gc, x+1, y+1, x+w-3, y+1);
572 XDrawLine(dpy, win, gc, x, y+h-2, x, y);
573 XDrawLine(dpy, win, gc, x, y, x+w-2, y);
574 }
575 }
576
TgDrawThreeDButton(dpy,win,gc,bbox,state,linewidth,button)577 void TgDrawThreeDButton(dpy, win, gc, bbox, state, linewidth, button)
578 Display *dpy;
579 Window win;
580 GC gc;
581 struct BBRec *bbox;
582 int state, linewidth, button; /* button is TRUE if the item is a button */
583 {
584 int x=bbox->ltx, y=bbox->lty, w=bbox->rbx-bbox->ltx, h=bbox->rby-bbox->lty;
585 int pixels[4];
586
587 memset(pixels, 0, 4*sizeof(int));
588 switch (state) {
589 case TGBS_NORMAL: return;
590 case TGBS_RAISED:
591 if (linewidth == 1) {
592 pixels[0] = myDkGryPixel; /* inner lower right */
593 pixels[1] = myBlackPixel; /* outer lower right */
594 pixels[2] = myLtGryPixel; /* inner upper left */
595 pixels[3] = myWhitePixel; /* outer upper left */
596 } else {
597 pixels[0] = myBlackPixel; /* outer lower right */
598 pixels[1] = myDkGryPixel; /* inner lower right */
599 if (button) {
600 pixels[2] = myLtGryPixel; /* inner upper left */
601 pixels[3] = myWhitePixel; /* outer upper left */
602 } else {
603 pixels[2] = myWhitePixel; /* inner upper left */
604 pixels[3] = myLtGryPixel; /* outer upper left */
605 }
606 }
607 break;
608 case TGBS_LOWRED:
609 if (linewidth == 1) {
610 if (button) {
611 pixels[0] = myDkGryPixel; /* outer lower right */
612 pixels[1] = myBlackPixel; /* inner lower right */ /* useless here */
613 pixels[2] = myWhitePixel; /* inner upper left */ /* useless here */
614 pixels[3] = myLtGryPixel; /* outer upper left */
615 } else {
616 pixels[0] = myWhitePixel; /* outer lower right */
617 pixels[1] = myLtGryPixel; /* inner lower right */ /* useless here */
618 pixels[2] = myBlackPixel; /* inner upper left */ /* useless here */
619 pixels[3] = myDkGryPixel; /* outer upper left */
620 }
621 } else {
622 if (button) {
623 pixels[0] = myLtGryPixel; /* outer lower right */
624 pixels[1] = myWhitePixel; /* inner lower right */
625 pixels[2] = myDkGryPixel; /* inner upper left */
626 pixels[3] = myBlackPixel; /* outer upper left */
627 } else {
628 pixels[0] = myWhitePixel; /* outer lower right */
629 pixels[1] = myLtGryPixel; /* inner lower right */
630 pixels[2] = myBlackPixel; /* inner upper left */
631 pixels[3] = myDkGryPixel; /* outer upper left */
632 }
633 }
634 break;
635 case TGBS_GRAYED: return;
636 }
637 if (linewidth == 1) {
638 XSetForeground(dpy, gc, pixels[0]);
639 XDrawLine(dpy, win, gc, x, y+h-1, x+w-1, y+h-1);
640 XDrawLine(dpy, win, gc, x+w-1, y+h-1, x+w-1, y);
641 XSetForeground(dpy, gc, pixels[3]);
642 XDrawLine(dpy, win, gc, x, y+h-2, x, y);
643 XDrawLine(dpy, win, gc, x, y, x+w-2, y);
644 } else if (linewidth >= 2) {
645 XSetForeground(dpy, gc, pixels[0]);
646 XDrawLine(dpy, win, gc, x, y+h-1, x+w-1, y+h-1);
647 XDrawLine(dpy, win, gc, x+w-1, y+h-1, x+w-1, y);
648 XSetForeground(dpy, gc, pixels[1]);
649 XDrawLine(dpy, win, gc, x+1, y+h-2, x+w-2, y+h-2);
650 XDrawLine(dpy, win, gc, x+w-2, y+h-2, x+w-2, y+1);
651 XSetForeground(dpy, gc, pixels[2]);
652 XDrawLine(dpy, win, gc, x+1, y+h-3, x+1, y+1);
653 XDrawLine(dpy, win, gc, x+1, y+1, x+w-3, y+1);
654 XSetForeground(dpy, gc, pixels[3]);
655 XDrawLine(dpy, win, gc, x, y+h-2, x, y);
656 XDrawLine(dpy, win, gc, x, y, x+w-2, y);
657 }
658 }
659
TgDrawStipple(dpy,win,gc,stipple,x,y,w,h,fg_pixel,bg_pixel,fill_style)660 void TgDrawStipple(dpy, win, gc, stipple, x, y, w, h, fg_pixel, bg_pixel,
661 fill_style)
662 Display *dpy;
663 Window win;
664 GC gc;
665 Pixmap stipple;
666 int x, y, w, h, fg_pixel, bg_pixel, fill_style;
667 {
668 XGCValues values;
669
670 values.foreground = fg_pixel;
671 values.background = bg_pixel;
672 values.fill_style = fill_style;
673 values.stipple = stipple;
674 values.ts_x_origin = x;
675 values.ts_y_origin = y;
676 XChangeGC(dpy, gc,
677 GCForeground | GCBackground | GCFillStyle | GCStipple |
678 GCTileStipXOrigin | GCTileStipYOrigin, &values);
679 XFillRectangle(dpy, win, gc, values.ts_x_origin, values.ts_y_origin, w, h);
680 values.fill_style = FillSolid;
681 values.ts_x_origin = 0;
682 values.ts_y_origin = 0;
683 XChangeGC(dpy, gc,
684 GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin, &values);
685 }
686
TgDraw2DGrayedPixmap(dpy,win,bitmap,x,y,w,h,fg_pixel,bg_pixel)687 void TgDraw2DGrayedPixmap(dpy, win, bitmap, x, y, w, h, fg_pixel, bg_pixel)
688 Display *dpy;
689 Window win;
690 Pixmap bitmap;
691 int x, y, w, h, fg_pixel, bg_pixel;
692 {
693 XGCValues values;
694 GC gc=NULL;
695
696 if (threeDLook) {
697 /* not meant for threeDLook */
698 return;
699 }
700 values.foreground = fg_pixel;
701 values.background = bg_pixel;
702 values.function = GXcopy;
703 values.fill_style = FillStippled;
704 values.stipple = patPixmap[SCROLLPAT];
705 values.ts_x_origin = x;
706 values.ts_y_origin = y;
707 values.clip_mask = bitmap;
708 values.clip_x_origin = x;
709 values.clip_y_origin = y;
710 gc = XCreateGC(dpy, win,
711 GCForeground | GCBackground | GCFunction | GCFillStyle |
712 GCStipple | GCTileStipXOrigin | GCTileStipYOrigin |
713 GCClipMask | GCClipXOrigin | GCClipYOrigin, &values);
714 if (gc != NULL) {
715 XFillRectangle(dpy, win, gc, x, y, w, h);
716 XFreeGC(mainDisplay, gc);
717 }
718 }
719
720 static struct BBRec gstMenubarWinBBox;
721
722 static
SetMenubarWinBBox()723 void SetMenubarWinBBox()
724 {
725 unsigned int win_w, win_h, win_brdr_w, win_d;
726 int win_x, win_y, main_win_x, main_win_y;
727 Window root_win=None;
728
729 ComputeMainWinXY(&main_win_x, &main_win_y);
730 XGetGeometry(mainDisplay, menubarWindow, &root_win, &win_x, &win_y,
731 &win_w, &win_h, &win_brdr_w, &win_d);
732 gstMenubarWinBBox.ltx = main_win_x + win_x;
733 gstMenubarWinBBox.lty = main_win_y + win_y;
734 gstMenubarWinBBox.rbx = gstMenubarWinBBox.ltx + win_w;
735 gstMenubarWinBBox.rby = gstMenubarWinBBox.lty + win_h;
736 }
737
738 static
SetParentMenuWinBBox(menu)739 void SetParentMenuWinBBox(menu)
740 TgMenu *menu;
741 {
742 memcpy(&gstMenubarWinBBox, &menu->parent_menu->bbox, sizeof(struct BBRec));
743 }
744
745 static
AdjMenuGeometry(menu,pn_orig_x,pn_orig_y,pn_min_pin,pn_max_pin)746 void AdjMenuGeometry(menu, pn_orig_x, pn_orig_y, pn_min_pin, pn_max_pin)
747 TgMenu *menu;
748 int *pn_orig_x, *pn_orig_y, *pn_min_pin, *pn_max_pin;
749 {
750 int dsp_w=DisplayWidth(mainDisplay, mainScreen);
751 int dsp_h=DisplayHeight(mainDisplay, mainScreen);
752 int orig_x=menu->bbox.ltx, orig_y=menu->bbox.lty;
753 int menu_w=menu->bbox.rbx-orig_x+((menu->padding)<<1);
754 int menu_h=menu->bbox.rby-orig_y+((menu->padding)<<1);
755 int min_pin=0, max_pin=0, dx=0, dy=0;
756 TgMenu *parent_menu=menu->parent_menu;
757
758 if (menu->scroll_start > 0) {
759 switch (menu->type) {
760 case TGMUTYPE_TEXT:
761 menu_w += scrollBarW + menu->padding;
762 menu_h = maxScrollableMenuHeight;
763 break;
764 case TGMUTYPE_COLOR:
765 case TGMUTYPE_BITMAP:
766 menu_w = maxScrollableMenuWidth;
767 menu_h += scrollBarW + menu->padding;
768 break;
769 }
770 }
771 if (orig_x+menu_w >= dsp_w-1-((menu->brdr_w)<<1)) {
772 orig_x = dsp_w - 1 - menu_w + ((menu->padding)<<1);
773 if (parent_menu != NULL) {
774 orig_x = parent_menu->bbox.ltx - 1 - menu_w + ((menu->padding)<<1);
775 }
776 }
777 if (orig_y+menu_h >= dsp_h-1-((menu->brdr_w)<<1)) {
778 orig_y = dsp_h - 1 - menu_h + ((menu->padding)<<1);
779 }
780 if (parent_menu != NULL) {
781 if (orig_x < parent_menu->bbox.ltx-((menu->brdr_w)<<1)) {
782 min_pin = orig_x - mainMenuPinDistance;
783 } else {
784 min_pin = parent_menu->bbox.ltx - ((menu->brdr_w)<<1) -
785 mainMenuPinDistance;
786 }
787 if (orig_x+menu_w+((menu->brdr_w)<<2) >=
788 parent_menu->bbox.rbx+((menu->brdr_w)<<1)) {
789 max_pin = orig_x + menu_w + ((menu->brdr_w)<<2) + mainMenuPinDistance;
790 } else {
791 max_pin = parent_menu->bbox.rbx + ((menu->brdr_w)<<1) +
792 mainMenuPinDistance;
793 }
794 } else {
795 min_pin = orig_x - mainMenuPinDistance;
796 max_pin = orig_x + menu_w + ((menu->brdr_w)<<2) + mainMenuPinDistance;
797 }
798 dx = orig_x - menu->bbox.ltx;
799 dy = orig_y - menu->bbox.lty;
800 menu->bbox.ltx += dx; menu->bbox.lty += dy;
801 menu->bbox.rbx += dx; menu->bbox.rby += dy;
802 *pn_orig_x = orig_x;
803 *pn_orig_y = orig_y;
804 *pn_min_pin = min_pin;
805 *pn_max_pin = max_pin;
806 }
807
808 static
TgDrawTextMenuItem(menu,menu_item)809 void TgDrawTextMenuItem(menu, menu_item)
810 TgMenu *menu;
811 TgMenuItem *menu_item;
812 {
813 int x=0, baseline=0, y_offset=0;
814 int item_w=(menu_item->bbox.rbx-menu_item->bbox.ltx);
815 int item_h=(menu_item->bbox.rby-menu_item->bbox.lty);
816 int flags=menu_item->flags; /* TGMU_* */
817 int state=menu_item->state; /* TGBS* */
818 int checked=menu_item->checked;
819 int multicolor=((flags & TGMU_MULTICOLOR)==TGMU_MULTICOLOR);
820 int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
821 int fg_pixels[4], bg_pixels[4];
822 XGCValues values;
823
824 memset(fg_pixels, 0, 4*sizeof(int));
825 memset(bg_pixels, 0, 4*sizeof(int));
826 if (menu->scroll_start > 0 && menu->first_index > 0) {
827 y_offset = (menu->first_index *
828 (((menuFontSet==NULL && menuFontPtr == NULL) ?
829 initialMenubarWindowH : menuFontHeight) + 1));
830 }
831 if (multicolor) {
832 fg_pixels[TGBS_NORMAL] = menu_item->multicolor_pixel;
833 bg_pixels[TGBS_NORMAL] = bg_pixel;
834 fg_pixels[TGBS_GRAYED] = myDkGryPixel;
835 bg_pixels[TGBS_GRAYED] = bg_pixel;
836 /* use reversed video */
837 fg_pixels[TGBS_RAISED] = myBgPixel;
838 bg_pixels[TGBS_RAISED] = menu_item->multicolor_pixel;
839 } else {
840 fg_pixels[TGBS_NORMAL] = myFgPixel;
841 bg_pixels[TGBS_NORMAL] = bg_pixel;
842 fg_pixels[TGBS_GRAYED] = myDkGryPixel;
843 bg_pixels[TGBS_GRAYED] = bg_pixel;
844 /* use reversed video */
845 fg_pixels[TGBS_RAISED] = myBgPixel;
846 bg_pixels[TGBS_RAISED] = myFgPixel;
847 }
848 if (flags & TGMU_DISABLED) state = TGBS_GRAYED;
849
850 switch (state) {
851 case TGBS_NORMAL: /* not selected */
852 case TGBS_GRAYED: /* disabled */
853 case TGBS_RAISED: /* selected */
854 break;
855 case TGBS_LOWRED: /* not valid for a text menu item state */ return;
856 }
857 XSetForeground(mainDisplay, textMenuGC, bg_pixels[state]);
858 XFillRectangle(mainDisplay, menu->window, textMenuGC,
859 menu_item->bbox.ltx, menu_item->bbox.lty-y_offset,
860 item_w+WINDOW_PADDING-windowPadding, item_h+(threeDLook?0:1));
861 if ((flags & TGMU_SEPARATOR) == TGMU_SEPARATOR) {
862 if (threeDLook) {
863 XSetForeground(mainDisplay, textMenuGC, myDkGryPixel);
864 XDrawLine(mainDisplay, menu->window, textMenuGC,
865 menu_item->bbox.ltx, menu_item->bbox.lty-y_offset,
866 item_w, menu_item->bbox.lty-y_offset);
867 XSetForeground(mainDisplay, textMenuGC, myWhitePixel);
868 XDrawLine(mainDisplay, menu->window, textMenuGC,
869 menu_item->bbox.ltx, menu_item->bbox.lty+1-y_offset,
870 item_w, menu_item->bbox.lty+1-y_offset);
871 } else {
872 XSetForeground(mainDisplay, textMenuGC, myFgPixel);
873 XDrawLine(mainDisplay, menu->window, textMenuGC,
874 menu_item->bbox.ltx, menu_item->bbox.lty+1-y_offset,
875 item_w+1, menu_item->bbox.lty+1-y_offset);
876 }
877 return;
878 }
879 baseline = menu_item->bbox.lty - y_offset +
880 ((menuFontSet==NULL && menuFontPtr==NULL) ?
881 defaultFontAsc : menuFontAsc);
882 x = menu->check_start;
883 if ((flags & (TGMU_HAS_CHECK|TGMU_HAS_RADIO)) != 0 && checked) {
884 int dy=((item_h-check_height)>>1);
885
886 values.foreground = fg_pixels[state];
887 values.background = bg_pixels[state];
888 values.fill_style = FillStippled;
889 values.stipple = None;
890 if ((flags & TGMU_HAS_CHECK) == TGMU_HAS_CHECK) {
891 values.stipple = checkBitmap;
892 } else if ((flags & TGMU_HAS_RADIO) == TGMU_HAS_RADIO) {
893 values.stipple = radioBitmap;
894 }
895 if (values.stipple != None) {
896 values.ts_x_origin = x;
897 values.ts_y_origin = menu_item->bbox.lty+dy-y_offset;
898 XChangeGC(mainDisplay, textMenuGC,
899 GCForeground | GCBackground | GCFillStyle | GCStipple |
900 GCTileStipXOrigin | GCTileStipYOrigin, &values);
901 XFillRectangle(mainDisplay, menu->window, textMenuGC,
902 values.ts_x_origin, values.ts_y_origin,
903 check_width, check_height);
904 values.fill_style = FillSolid;
905 values.ts_x_origin = 0;
906 values.ts_y_origin = 0;
907 XChangeGC(mainDisplay, textMenuGC,
908 GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin, &values);
909 }
910 }
911 x = menu->str_start;
912 if (threeDLook) {
913 if (state == TGBS_GRAYED) {
914 XSetForeground(mainDisplay, textMenuGC, myWhitePixel);
915 DrawMenuString(mainDisplay, menu->window, textMenuGC, x+1,
916 baseline+1, _(menu_item->menu_str),
917 strlen(_(menu_item->menu_str)));
918 }
919 XSetForeground(mainDisplay, textMenuGC, fg_pixels[state]);
920 DrawMenuString(mainDisplay, menu->window, textMenuGC, x,
921 baseline, _(menu_item->menu_str), strlen(_(menu_item->menu_str)));
922 } else {
923 if (state == TGBS_GRAYED) {
924 DrawMenuString(mainDisplay, menu->window, revGrayGC, x, baseline,
925 _(menu_item->menu_str), strlen(_(menu_item->menu_str)));
926 } else {
927 XSetForeground(mainDisplay, textMenuGC, fg_pixels[state]);
928 DrawMenuString(mainDisplay, menu->window, textMenuGC, x, baseline,
929 _(menu_item->menu_str), strlen(_(menu_item->menu_str)));
930 }
931 }
932 if ((flags & TGMU_HAS_SHORTCUT) == TGMU_HAS_SHORTCUT) {
933 x = menu->shortcut_start;
934 if (state == TGBS_GRAYED) {
935 XSetForeground(mainDisplay, textMenuGC, myWhitePixel);
936 DrawMenuString(mainDisplay, menu->window, textMenuGC, x+1,
937 baseline+1, menu_item->detail.shortcut_str,
938 strlen(menu_item->detail.shortcut_str));
939 }
940 XSetForeground(mainDisplay, textMenuGC, fg_pixels[state]);
941 DrawMenuString(mainDisplay, menu->window, textMenuGC, x, baseline,
942 menu_item->detail.shortcut_str,
943 strlen(menu_item->detail.shortcut_str));
944 }
945 if ((flags & TGMU_HAS_SUBMENU) == TGMU_HAS_SUBMENU) {
946 int dy=((item_h-check_height)>>1);
947
948 x = menu->arrow_start;
949
950 values.foreground = fg_pixels[state];
951 values.background = bg_pixels[state];
952 values.fill_style = FillStippled;
953 if (!threeDLook && state == TGBS_GRAYED) {
954 values.stipple = graySubmenuBitmap;
955 } else {
956 values.stipple = submenuBitmap;
957 }
958 values.ts_x_origin = x;
959 values.ts_y_origin = menu_item->bbox.lty+dy-y_offset;
960 XChangeGC(mainDisplay, textMenuGC,
961 GCForeground | GCBackground | GCFillStyle | GCStipple |
962 GCTileStipXOrigin | GCTileStipYOrigin, &values);
963 XFillRectangle(mainDisplay, menu->window, textMenuGC,
964 values.ts_x_origin, values.ts_y_origin,
965 check_width, check_height);
966 values.fill_style = FillSolid;
967 values.ts_x_origin = 0;
968 values.ts_y_origin = 0;
969 XChangeGC(mainDisplay, textMenuGC,
970 GCFillStyle | GCTileStipXOrigin | GCTileStipYOrigin, &values);
971 }
972 }
973
974 static
TgDrawBitmapOrColorMenuItem(menu,menu_item)975 void TgDrawBitmapOrColorMenuItem(menu, menu_item)
976 TgMenu *menu;
977 TgMenuItem *menu_item;
978 {
979 int item_x=menu_item->bbox.ltx, item_y=menu_item->bbox.lty, x_offset=0;
980 int item_w=menu_item->bbox.rbx-item_x, item_h=menu_item->bbox.rby-item_y;
981 int flags=menu_item->flags; /* TGMU_* */
982 int state=menu_item->state; /* TGBS* */
983 int checked=menu_item->checked, color_menu=(menu->type==TGMUTYPE_COLOR);
984 int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel), color_pixel=INVALID;
985 Pixmap bitmap=None;
986
987 if (menu->scroll_start > 0 && menu->first_index > 0) {
988 x_offset = ((menu->image_w+(windowPadding<<1)) * menu->first_index);
989 }
990 if (color_menu) {
991 color_pixel = (*(int*)(menu_item->menu_str));
992 } else {
993 bitmap = (*(Pixmap*)(menu_item->menu_str));
994 }
995 if (state == TGBS_NORMAL && checked) state = TGBS_LOWRED;
996 if (flags & TGMU_DISABLED) state = TGBS_GRAYED;
997
998 switch (state) {
999 case TGBS_NORMAL: /* not selected */
1000 case TGBS_RAISED: /* selected, i.e., mouse overed */
1001 case TGBS_LOWRED: /* checked but not selected */
1002 case TGBS_GRAYED: /* not valid for a bitmap menu item state */
1003 break;
1004 }
1005 XSetForeground(mainDisplay, textMenuGC, bg_pixel);
1006 XFillRectangle(mainDisplay, menu->window, textMenuGC,
1007 menu_item->bbox.ltx-x_offset, menu_item->bbox.lty, item_w, item_h);
1008 if ((flags & TGMU_SEPARATOR) == TGMU_SEPARATOR) {
1009 return;
1010 }
1011 if (threeDLook) {
1012 if (x_offset != 0) {
1013 OffsetBBox(&menu_item->bbox, -x_offset, 0, &menu_item->bbox);
1014 TgDrawThreeDButton(mainDisplay, menu->window, textMenuGC,
1015 &menu_item->bbox, state, 2, TRUE);
1016 OffsetBBox(&menu_item->bbox, +x_offset, 0, &menu_item->bbox);
1017 } else {
1018 TgDrawThreeDButton(mainDisplay, menu->window, textMenuGC,
1019 &menu_item->bbox, state, 2, TRUE);
1020 }
1021 if (color_menu) {
1022 TgDrawStipple(mainDisplay, menu->window, textMenuGC,
1023 patPixmap[SOLIDPAT], item_x+menu->padding-x_offset,
1024 item_y+menu->padding, menu->image_w, menu->image_h, color_pixel,
1025 bg_pixel, FillSolid);
1026 } else {
1027 if (state == TGBS_GRAYED) {
1028 TgDrawStipple(mainDisplay, menu->window, textMenuGC, bitmap,
1029 item_x+menu->padding-x_offset+1, item_y+menu->padding+1,
1030 menu->image_w, menu->image_h, myWhitePixel, bg_pixel,
1031 FillStippled);
1032 TgDrawStipple(mainDisplay, menu->window, textMenuGC, bitmap,
1033 item_x+menu->padding-x_offset, item_y+menu->padding,
1034 menu->image_w, menu->image_h, myDkGryPixel, bg_pixel,
1035 FillStippled);
1036 } else {
1037 TgDrawStipple(mainDisplay, menu->window, textMenuGC, bitmap,
1038 item_x+menu->padding-x_offset, item_y+menu->padding,
1039 menu->image_w, menu->image_h, myFgPixel, bg_pixel,
1040 FillStippled);
1041 }
1042 }
1043 } else if (color_menu) {
1044 XSetForeground(mainDisplay, textMenuGC, color_pixel);
1045 XFillRectangle(mainDisplay, menu->window, textMenuGC,
1046 item_x+menu->padding-x_offset, item_y+menu->padding,
1047 menu->image_w, menu->image_h);
1048 } else {
1049 if (state == TGBS_NORMAL) {
1050 XSetStipple(mainDisplay, rasterGC, bitmap);
1051 XFillRectangle(mainDisplay, menu->window, rasterGC,
1052 item_x+menu->padding-x_offset, item_y+menu->padding,
1053 menu->image_w, menu->image_h);
1054 } else if (state == TGBS_GRAYED) {
1055 TgDraw2DGrayedPixmap(mainDisplay, menu->window, bitmap,
1056 item_x+menu->padding-x_offset, item_y+menu->padding,
1057 menu->image_w, menu->image_h, myFgPixel, myBgPixel);
1058 } else {
1059 XSetForeground(mainDisplay, textMenuGC, myFgPixel);
1060 XFillRectangle(mainDisplay, menu->window, textMenuGC,
1061 item_x+menu->padding-x_offset, item_y+menu->padding,
1062 menu->image_w, menu->image_h);
1063 XSetStipple(mainDisplay, rvPixmapMenuGC, bitmap);
1064 XFillRectangle(mainDisplay, menu->window, rvPixmapMenuGC,
1065 item_x+menu->padding-x_offset, item_y+menu->padding,
1066 menu->image_w, menu->image_h);
1067 }
1068 }
1069 }
1070
TgDrawMenuItem(menu,menu_item)1071 void TgDrawMenuItem(menu, menu_item)
1072 TgMenu *menu;
1073 TgMenuItem *menu_item;
1074 {
1075 switch (menu->type) {
1076 case TGMUTYPE_TEXT:
1077 TgDrawTextMenuItem(menu, menu_item);
1078 break;
1079 case TGMUTYPE_COLOR:
1080 case TGMUTYPE_BITMAP:
1081 TgDrawBitmapOrColorMenuItem(menu, menu_item);
1082 break;
1083 }
1084 }
1085
TgDrawEntireMenu(menu)1086 void TgDrawEntireMenu(menu)
1087 TgMenu *menu;
1088 {
1089 int i, num_items=menu->num_items;
1090 TgMenuItem *menuitems=menu->menuitems;
1091
1092 XClearWindow(mainDisplay, menu->window);
1093 if (menu->scroll_start > 0) {
1094 int min_index=0, max_index=0;
1095
1096 if (menu->type == TGMUTYPE_COLOR || menu->type == TGMUTYPE_BITMAP) {
1097 min_index = menu->first_index*menu->num_rows;
1098 max_index = (menu->first_index+menuColsBeforeScroll)*menu->num_rows;
1099 }
1100 for (i=0; i < num_items; i++) {
1101 switch (menu->type) {
1102 case TGMUTYPE_TEXT:
1103 if (i >= menu->first_index &&
1104 i < menu->first_index+menuRowsBeforeScroll) {
1105 TgDrawMenuItem(menu, &menuitems[i]);
1106 }
1107 break;
1108 case TGMUTYPE_COLOR:
1109 case TGMUTYPE_BITMAP:
1110 if (i >= min_index && i < max_index) {
1111 TgDrawMenuItem(menu, &menuitems[i]);
1112 }
1113 break;
1114 }
1115 }
1116 } else {
1117 for (i=0; i < num_items; i++) {
1118 TgDrawMenuItem(menu, &menuitems[i]);
1119 }
1120 }
1121 if (threeDLook) {
1122 struct BBRec bbox;
1123
1124 bbox.ltx = 0;
1125 bbox.lty = 0;
1126 if (menu->scroll_start > 0) {
1127 double start_frac=(double)0;
1128
1129 switch (menu->type) {
1130 case TGMUTYPE_TEXT:
1131 start_frac = (double)((double)(menu->first_index) /
1132 (double)(num_items));
1133 bbox.rbx = menu->scroll_start+(windowPadding<<1);
1134 bbox.rby = maxScrollableMenuHeight;
1135 TgDrawThreeDButton(mainDisplay, menu->window, textMenuGC, &bbox,
1136 TGBS_RAISED, 2, FALSE);
1137 TgDrawScrollBar(mainDisplay, menu->window, VERT_SCROLLBAR,
1138 bbox.rbx+(windowPadding>>1), (windowPadding>>1), scrollBarW,
1139 maxScrollableMenuHeight-windowPadding, start_frac,
1140 menuRowsBeforeScroll, num_items);
1141 bbox.ltx = bbox.rbx;
1142 bbox.lty = 0;
1143 bbox.rbx = bbox.ltx+scrollBarW+windowPadding;
1144 bbox.rby = maxScrollableMenuHeight;
1145 TgDrawThreeDButton(mainDisplay, menu->window, textMenuGC, &bbox,
1146 TGBS_RAISED, 1, FALSE);
1147 break;
1148 case TGMUTYPE_COLOR:
1149 case TGMUTYPE_BITMAP:
1150 start_frac = (double)((double)(menu->first_index) /
1151 (double)(menu->num_cols));
1152 bbox.rbx = maxScrollableMenuWidth;
1153 bbox.rby = menu->scroll_start+(windowPadding<<1);
1154 TgDrawThreeDButton(mainDisplay, menu->window, textMenuGC, &bbox,
1155 TGBS_RAISED, 2, FALSE);
1156 TgDrawScrollBar(mainDisplay, menu->window, HORI_SCROLLBAR,
1157 (windowPadding>>1), bbox.rby+(windowPadding>>1),
1158 maxScrollableMenuWidth-windowPadding, scrollBarW, start_frac,
1159 menuColsBeforeScroll, menu->num_cols);
1160 bbox.ltx = 0;
1161 bbox.lty = bbox.rby;
1162 bbox.rbx = maxScrollableMenuWidth;
1163 bbox.rby = bbox.lty+scrollBarW+windowPadding;
1164 TgDrawThreeDButton(mainDisplay, menu->window, textMenuGC, &bbox,
1165 TGBS_LOWRED, 1, TRUE);
1166 break;
1167 }
1168 } else {
1169 bbox.rbx = menu->bbox.rbx-menu->bbox.ltx+(windowPadding<<1);
1170 bbox.rby = menu->bbox.rby-menu->bbox.lty+(windowPadding<<1);
1171 TgDrawThreeDButton(mainDisplay, menu->window, textMenuGC, &bbox,
1172 TGBS_RAISED, 2, FALSE);
1173 }
1174 } else if (menu->scroll_start > 0) {
1175 double start_frac=(double)0;
1176
1177 switch (menu->type) {
1178 case TGMUTYPE_TEXT:
1179 start_frac = (double)((double)(menu->first_index)/(double)(num_items));
1180 TgDrawScrollBar(mainDisplay, menu->window, VERT_SCROLLBAR,
1181 menu->scroll_start, 0, scrollBarW, maxScrollableMenuHeight,
1182 start_frac, menuRowsBeforeScroll, num_items);
1183 MyBox(menu->window, textMenuGC, menu->scroll_start, 0,
1184 menu->scroll_start+scrollBarW, maxScrollableMenuHeight);
1185 break;
1186 case TGMUTYPE_COLOR:
1187 case TGMUTYPE_BITMAP:
1188 start_frac = (double)((double)(menu->first_index) /
1189 (double)(menu->num_cols));
1190 TgDrawScrollBar(mainDisplay, menu->window, HORI_SCROLLBAR,
1191 0, menu->scroll_start, maxScrollableMenuWidth, scrollBarW,
1192 start_frac, menuColsBeforeScroll, menu->num_cols);
1193 MyBox(menu->window, textMenuGC, 0, menu->scroll_start,
1194 maxScrollableMenuWidth, menu->scroll_start+scrollBarW);
1195 break;
1196 }
1197 }
1198 }
1199
TgWhichMenuIndex(menu,x,y,must_be_in_menu)1200 int TgWhichMenuIndex(menu, x, y, must_be_in_menu)
1201 TgMenu *menu;
1202 int x, y, must_be_in_menu;
1203 /*
1204 * Returns INVALID if clicked outside of the menu.
1205 * Returns -2 if clicked on a separator.
1206 * Returns -3 if clicked on scrollbar.
1207 * Otherwise, returned a menu index.
1208 */
1209 {
1210 int i=0, num_items=menu->num_items;
1211 int first_index=0, max_index_plus_1=num_items, x_offset=0, y_offset=0;
1212
1213 if (must_be_in_menu) {
1214 if (!(x >= 0 && x < menu->bbox.rbx-menu->bbox.ltx &&
1215 y >= 0 && y < menu->bbox.rby-menu->bbox.lty)) {
1216 return INVALID;
1217 }
1218 }
1219 switch (menu->type) {
1220 case TGMUTYPE_TEXT:
1221 if (menu->scroll_start > 0) {
1222 if (x >= menu->scroll_start+windowPadding) {
1223 return (-3);
1224 }
1225 first_index = menu->first_index;
1226 max_index_plus_1 = menu->first_index+menuRowsBeforeScroll;
1227 if (first_index > 0) {
1228 y_offset = (first_index *
1229 (((menuFontSet==NULL && menuFontPtr == NULL) ?
1230 initialMenubarWindowH : menuFontHeight) + 1));
1231 }
1232 }
1233 for (i=first_index; i < max_index_plus_1; i++) {
1234 TgMenuItem *menu_item=(&menu->menuitems[i]);
1235
1236 if (y >= menu_item->bbox.lty-y_offset &&
1237 y < menu_item->bbox.rby+1-y_offset) {
1238 if (menu_item->flags & TGMU_SEPARATOR) {
1239 return (-2);
1240 }
1241 return i;
1242 }
1243 }
1244 break;
1245 case TGMUTYPE_COLOR:
1246 case TGMUTYPE_BITMAP:
1247 if (menu->scroll_start > 0) {
1248 if (y >= menu->scroll_start+windowPadding) {
1249 return (-3);
1250 }
1251 first_index = (menu->first_index*menu->num_rows);
1252 max_index_plus_1 =
1253 (menu->first_index+menuColsBeforeScroll)*menu->num_rows;
1254 if (first_index > 0) {
1255 x_offset = ((menu->image_w+(windowPadding<<1)) * menu->first_index);
1256 }
1257 }
1258 for (i=first_index; i < num_items; i++) {
1259 TgMenuItem *menu_item=(&menu->menuitems[i]);
1260
1261 if ((x >= menu_item->bbox.ltx-x_offset &&
1262 x < menu_item->bbox.rbx+1-x_offset) &&
1263 (y >= menu_item->bbox.lty && y < menu_item->bbox.rby+1)) {
1264 if (menu_item->flags & TGMU_SEPARATOR) {
1265 return (-2);
1266 }
1267 return i;
1268 }
1269 if (i+1 == max_index_plus_1) break;
1270 }
1271 break;
1272 }
1273 return INVALID;
1274 }
1275
1276 static int gnUncheckWhenMoused=FALSE;
1277
1278 static
TgPointInAnAncestorMenu(menu,root_x,root_y)1279 int TgPointInAnAncestorMenu(menu, root_x, root_y)
1280 TgMenu *menu;
1281 int root_x, root_y;
1282 {
1283 if (menu == NULL) return FALSE;
1284
1285 if (PointInBBox(root_x, root_y, menu->bbox)) return TRUE;
1286
1287 return TgPointInAnAncestorMenu(menu->parent_menu, root_x, root_y);
1288 }
1289
1290 static
TgPointInParentMenuSelectedItem(parent_menu)1291 int TgPointInParentMenuSelectedItem(parent_menu)
1292 TgMenu *parent_menu;
1293 {
1294 Window root_win=None, child_win=None;
1295 unsigned int status;
1296 int parent_root_x, parent_root_y, x=0, y=0;
1297
1298 XQueryPointer(mainDisplay, parent_menu->window, &root_win,
1299 &child_win, &parent_root_x, &parent_root_y, &x, &y, &status);
1300 return (TgWhichMenuIndex(parent_menu, x, y, FALSE) ==
1301 parent_menu->selected_index);
1302 }
1303
TgCreatePopUpSubMenu(menu,selected_index)1304 TgMenu *TgCreatePopUpSubMenu(menu, selected_index)
1305 TgMenu *menu;
1306 int selected_index;
1307 {
1308 TgMenu *submenu=NULL;
1309 TgMenuItem *menuitems=menu->menuitems;
1310 TgMenuItemInfo *create_info=menuitems[selected_index].submenu_create_info;
1311
1312 if (create_info == NULL) return NULL;
1313
1314 if (create_info->submenu_info->create_proc == TgCreateMenuFromMenuInfo) {
1315 submenu = menuitems[selected_index].detail.submenu =
1316 (create_info->submenu_info->create_proc)(menu, 0, 0,
1317 create_info->submenu_info, FALSE);
1318 } else {
1319 /*
1320 * if the creation procedure is not the default TgCreateMenuFromMenuInfo,
1321 * the status_str_xlated will be ignored
1322 */
1323 submenu = menuitems[selected_index].detail.submenu =
1324 (create_info->submenu_info->create_proc)(menu, 0, 0,
1325 create_info->submenu_info, INVALID);
1326 }
1327 return submenu;
1328 }
1329
TgPopUpSubMenu(menu,win_x,win_y)1330 int TgPopUpSubMenu(menu, win_x, win_y)
1331 TgMenu *menu;
1332 int win_x, win_y;
1333 {
1334 int rc=INVALID, new_selected=menu->selected_index;
1335 TgMenuItem *menuitems=menu->menuitems;
1336 TgMenu *submenu=menuitems[new_selected].detail.submenu;
1337 int menu_w=menu->bbox.rbx-menu->bbox.ltx+((menu->padding)<<1);
1338 int i, x=0, y=0, dx=0, dy=0;
1339 int saved_active_menu=INVALID, need_to_restore_active_menu=FALSE;
1340
1341 submenu->parent_menu = menu;
1342 submenu->disallow_pinning = ((menuitems[new_selected].flags &
1343 TGMU_SUBMENU_PINNABLE) == 0);
1344 if ((menuitems[new_selected].flags &
1345 TGMU_SUBMENU_PINNABLE) == TGMU_SUBMENU_PINNABLE &&
1346 menuitems[new_selected].cmdid != INVALID) {
1347 saved_active_menu = activeMenu;
1348 activeMenu = menuitems[new_selected].cmdid;
1349 need_to_restore_active_menu = TRUE;
1350 }
1351 x = menu_w+win_x-((menu->padding)<<1);
1352 y = menuitems[new_selected].bbox.lty+win_y-menu->padding;
1353 dx = x-submenu->bbox.ltx;
1354 dy = y-submenu->bbox.lty;
1355 submenu->bbox.ltx += dx; submenu->bbox.lty += dy;
1356 submenu->bbox.rbx += dx; submenu->bbox.rby += dy;
1357 for (i=0; i < submenu->num_items; i++) {
1358 submenu->menuitems[i].state = TGBS_NORMAL;
1359 }
1360 if (submenu->refresh_proc != NULL) {
1361 (submenu->refresh_proc)(submenu);
1362 }
1363 rc = TgMenuLoop(submenu);
1364
1365 if (need_to_restore_active_menu) {
1366 activeMenu = saved_active_menu;
1367 }
1368 return rc;
1369 }
1370
1371 static
ScrollItemCallback(pv_userdata)1372 int ScrollItemCallback(pv_userdata)
1373 void *pv_userdata;
1374 /* returns TRUE to cancel scrolling */
1375 {
1376 TgMenu *menu=((TgMenu*)pv_userdata);
1377 int v_scroll=TRUE;
1378
1379 switch (menu->type) {
1380 case TGMUTYPE_TEXT: v_scroll = TRUE; break;
1381 case TGMUTYPE_COLOR: v_scroll = FALSE; break;
1382 case TGMUTYPE_BITMAP: v_scroll = FALSE; break;
1383 }
1384 if (menu->can_scroll == SCRL_UP || menu->can_scroll == SCRL_LF) {
1385 /* can_scroll temporary used as scroll_dir */
1386 if (menu->first_index == 0) return FALSE;
1387 menu->first_index--;
1388 } else if (v_scroll) {
1389 if (menu->num_items <= menuRowsBeforeScroll ||
1390 menu->first_index+menuRowsBeforeScroll == menu->num_items) {
1391 return FALSE;
1392 }
1393 menu->first_index++;
1394 } else {
1395 if (menu->num_cols <= menuColsBeforeScroll ||
1396 menu->first_index+menuColsBeforeScroll == menu->num_cols) {
1397 return FALSE;
1398 }
1399 menu->first_index++;
1400 }
1401 TgDrawEntireMenu(menu);
1402 XSync(mainDisplay, False);
1403
1404 return FALSE;
1405 }
1406
1407 static
ScrollPageCallback(pv_userdata)1408 int ScrollPageCallback(pv_userdata)
1409 void *pv_userdata;
1410 /* returns TRUE to cancel scrolling */
1411 {
1412 TgMenu *menu=((TgMenu*)pv_userdata);
1413 int v_scroll=TRUE;
1414
1415 switch (menu->type) {
1416 case TGMUTYPE_TEXT: v_scroll = TRUE; break;
1417 case TGMUTYPE_COLOR: v_scroll = FALSE; break;
1418 case TGMUTYPE_BITMAP: v_scroll = FALSE; break;
1419 }
1420 if (menu->can_scroll == SCRL_UP || menu->can_scroll == SCRL_LF) {
1421 /* can_scroll temporary used as scroll_dir */
1422 if (menu->first_index == 0) return FALSE;
1423 menu->first_index -= menuRowsBeforeScroll;
1424 if (menu->first_index < 0) menu->first_index = 0;
1425 } else if (v_scroll) {
1426 if (menu->num_items <= menuRowsBeforeScroll ||
1427 menu->first_index+menuRowsBeforeScroll == menu->num_items) {
1428 return FALSE;
1429 }
1430 menu->first_index += menuRowsBeforeScroll;
1431 if (menu->first_index+menuRowsBeforeScroll >= menu->num_items) {
1432 menu->first_index = menu->num_items-menuRowsBeforeScroll;
1433 }
1434 } else {
1435 if (menu->num_cols <= menuColsBeforeScroll ||
1436 menu->first_index+menuColsBeforeScroll == menu->num_cols) {
1437 return FALSE;
1438 }
1439 menu->first_index += menuColsBeforeScroll;
1440 if (menu->first_index+menuColsBeforeScroll >= menu->num_cols) {
1441 menu->first_index = menu->num_cols-menuColsBeforeScroll;
1442 }
1443 }
1444 TgDrawEntireMenu(menu);
1445 XSync(mainDisplay, False);
1446
1447 return FALSE;
1448 }
1449
1450 static
DoScrollMenu(menu,scroll_page,scroll_dir,pbbox)1451 int DoScrollMenu(menu, scroll_page, scroll_dir, pbbox)
1452 TgMenu *menu;
1453 int scroll_page, scroll_dir;
1454 struct BBRec *pbbox;
1455 {
1456 int v_scroll=TRUE;
1457 ScrollBtnCallbackInfo sbci;
1458
1459 /*
1460 * temporary use can_scroll for scroll_dir
1461 * menu->can_scroll must be restored to TRUE before returning
1462 */
1463 menu->can_scroll = scroll_dir;
1464 memset(&sbci, 0, sizeof(ScrollBtnCallbackInfo));
1465
1466 switch (menu->type) {
1467 case TGMUTYPE_TEXT: v_scroll = TRUE; break;
1468 case TGMUTYPE_COLOR: v_scroll = FALSE; break;
1469 case TGMUTYPE_BITMAP: v_scroll = FALSE; break;
1470 }
1471 if (scroll_page) {
1472 sbci.ms = 200;
1473 sbci.pv_userdata = menu;
1474 sbci.pf_scroll_btn_callback = ScrollPageCallback;
1475 if (TgPressButtonLoop(mainDisplay, menu->window, NULL, &sbci)) {
1476 if (scroll_dir == SCRL_UP || scroll_dir == SCRL_LF) {
1477 if (menu->first_index == 0) {
1478 menu->can_scroll = TRUE;
1479 return TRUE;
1480 }
1481 menu->first_index -= menuRowsBeforeScroll;
1482 if (menu->first_index < 0) menu->first_index = 0;
1483 } else if (v_scroll) {
1484 if (menu->num_items <= menuRowsBeforeScroll ||
1485 menu->first_index+menuRowsBeforeScroll == menu->num_items) {
1486 menu->can_scroll = TRUE;
1487 return TRUE;
1488 }
1489 menu->first_index += menuRowsBeforeScroll;
1490 if (menu->first_index+menuRowsBeforeScroll >= menu->num_items) {
1491 menu->first_index = menu->num_items-menuRowsBeforeScroll;
1492 }
1493 } else {
1494 if (menu->num_cols <= menuColsBeforeScroll ||
1495 menu->first_index+menuColsBeforeScroll == menu->num_cols) {
1496 menu->can_scroll = TRUE;
1497 return TRUE;
1498 }
1499 menu->first_index += menuColsBeforeScroll;
1500 if (menu->first_index+menuColsBeforeScroll >= menu->num_cols) {
1501 menu->first_index = menu->num_cols-menuColsBeforeScroll;
1502 }
1503 }
1504 }
1505 } else {
1506 sbci.ms = 50;
1507 sbci.pv_userdata = menu;
1508 sbci.pf_scroll_btn_callback = ScrollItemCallback;
1509 if (TgPressButtonLoop(mainDisplay, menu->window, pbbox, &sbci)) {
1510 if (scroll_dir == SCRL_UP || scroll_dir == SCRL_LF) {
1511 if (menu->first_index == 0) {
1512 menu->can_scroll = TRUE;
1513 return TRUE;
1514 }
1515 menu->first_index--;
1516 } else if (v_scroll) {
1517 if (menu->num_items <= menuRowsBeforeScroll ||
1518 menu->first_index+menuRowsBeforeScroll == menu->num_items) {
1519 menu->can_scroll = TRUE;
1520 return TRUE;
1521 }
1522 menu->first_index++;
1523 } else {
1524 if (menu->num_cols <= menuColsBeforeScroll ||
1525 menu->first_index+menuColsBeforeScroll == menu->num_cols) {
1526 menu->can_scroll = TRUE;
1527 return TRUE;
1528 }
1529 menu->first_index++;
1530 }
1531 }
1532 }
1533 menu->can_scroll = TRUE;
1534 return FALSE;
1535 }
1536
1537 static
DoDragInScrollMenu(menu,menu_w,menu_h,mouse_x,mouse_y,btn_offset)1538 void DoDragInScrollMenu(menu, menu_w, menu_h, mouse_x, mouse_y, btn_offset)
1539 TgMenu *menu;
1540 int menu_w, menu_h, mouse_x, mouse_y, btn_offset;
1541 {
1542 double start_frac=(double)0, frac=(double)0;
1543 int done=FALSE, block_start=0, block_h=0, block_w=0, v_scroll=TRUE;
1544 XEvent ev;
1545
1546 switch (menu->type) {
1547 case TGMUTYPE_TEXT: v_scroll = TRUE; break;
1548 case TGMUTYPE_COLOR: v_scroll = FALSE; break;
1549 case TGMUTYPE_BITMAP: v_scroll = FALSE; break;
1550 }
1551 if (v_scroll) {
1552 if (menu->num_items <= menuRowsBeforeScroll) return;
1553
1554 frac = (double)((double)menuRowsBeforeScroll / (double)(menu->num_items));
1555 if (threeDLook) {
1556 block_h = (int)((menu_h-(scrollBarW<<1)) * frac);
1557 } else {
1558 block_h = (int)(menu_h * frac);
1559 }
1560 if (threeDLook) {
1561 block_start = mouse_y + btn_offset;;
1562 start_frac = (double)((double)(block_start-scrollBarW) /
1563 (double)(menu_h-(scrollBarW<<1)));
1564 if (block_start+block_h >= menu_h-scrollBarW) {
1565 menu->first_index = menu->num_items - menuRowsBeforeScroll;
1566 } else {
1567 menu->first_index = (int)(menu->num_items * start_frac);
1568 }
1569 } else {
1570 block_start = mouse_y;
1571 start_frac = (double)((double)(block_start) / (double)(menu_h));
1572 if (block_start+block_h >= menu_h) {
1573 menu->first_index = menu->num_items - menuRowsBeforeScroll;
1574 } else {
1575 menu->first_index = (int)(menu->num_items * start_frac);
1576 }
1577 }
1578 } else {
1579 if (menu->num_cols <= menuColsBeforeScroll) return;
1580
1581 frac = (double)((double)menuColsBeforeScroll / (double)(menu->num_cols));
1582 if (threeDLook) {
1583 block_w = (int)((menu_w-(scrollBarW<<1)) * frac);
1584 } else {
1585 block_w = (int)(menu_w * frac);
1586 }
1587 if (threeDLook) {
1588 block_start = mouse_x + btn_offset;;
1589 start_frac = (double)((double)(block_start-scrollBarW) /
1590 (double)(menu_w-(scrollBarW<<1)));
1591 if (block_start+block_w >= menu_w-scrollBarW) {
1592 menu->first_index = menu->num_cols - menuColsBeforeScroll;
1593 } else {
1594 menu->first_index = (int)(menu->num_cols * start_frac);
1595 }
1596 } else {
1597 block_start = mouse_x;
1598 start_frac = (double)((double)(block_start) / (double)(menu_w));
1599 if (block_start+block_w >= menu_w) {
1600 menu->first_index = menu->num_cols - menuColsBeforeScroll;
1601 } else {
1602 menu->first_index = (int)(menu->num_cols * start_frac);
1603 }
1604 }
1605 }
1606 TgDrawEntireMenu(menu);
1607
1608 if (!(menu->parent_menu == NULL && !debugNoPointerGrab)) {
1609 XGrabPointer(mainDisplay, menu->window, False,
1610 PointerMotionMask | ButtonReleaseMask, GrabModeAsync,
1611 GrabModeAsync, None, handCursor, CurrentTime);
1612 }
1613 while (!done) {
1614 XNextEvent(mainDisplay, &ev);
1615
1616 if (ev.type == Expose || ev.type == VisibilityNotify) {
1617 ExposeEventHandler(&ev, TRUE);
1618 } else if (ev.type == ButtonRelease) {
1619 if (!(menu->parent_menu == NULL && !debugNoPointerGrab)) {
1620 XUngrabPointer(mainDisplay, CurrentTime);
1621 if (debugNoPointerGrab) XSync(mainDisplay, False);
1622 }
1623 done = TRUE;
1624 } else if (ev.type == MotionNotify) {
1625 int new_name_first=0;
1626
1627 if (v_scroll) {
1628 int y=ev.xmotion.y;
1629
1630 if (threeDLook) {
1631 y += btn_offset;
1632 start_frac = (double)(((double)(y-scrollBarW)) /
1633 ((double)(menu_h-(scrollBarW<<1)-block_h)));
1634
1635 if (y <= scrollBarW) {
1636 new_name_first = 0;
1637 } else if (y+block_h >= menu_h-scrollBarW) {
1638 new_name_first = menu->num_items - menuRowsBeforeScroll;
1639 } else {
1640 new_name_first =
1641 (int)((menu->num_items-menuRowsBeforeScroll) *
1642 start_frac);
1643 }
1644 } else {
1645 start_frac = (double)(((double)y) / ((double)menu_h));
1646
1647 if (y <= 0) {
1648 new_name_first = 0;
1649 } else if (y+block_h >= menu_h) {
1650 new_name_first = menu->num_items - menuRowsBeforeScroll;
1651 } else {
1652 new_name_first = (int)(menu->num_items * start_frac);
1653 }
1654 }
1655 } else {
1656 int x=ev.xmotion.x;
1657
1658 if (threeDLook) {
1659 x += btn_offset;
1660 start_frac = (double)(((double)(x-scrollBarW)) /
1661 ((double)(menu_w-(scrollBarW<<1)-block_w)));
1662
1663 if (x <= scrollBarW) {
1664 new_name_first = 0;
1665 } else if (x+block_w >= menu_w-scrollBarW) {
1666 new_name_first = menu->num_cols - menuColsBeforeScroll;
1667 } else {
1668 new_name_first =
1669 (int)((menu->num_cols-menuColsBeforeScroll) *
1670 start_frac);
1671 }
1672 } else {
1673 start_frac = (double)(((double)x) / ((double)menu_w));
1674
1675 if (x <= 0) {
1676 new_name_first = 0;
1677 } else if (x+block_w >= menu_w) {
1678 new_name_first = menu->num_cols - menuColsBeforeScroll;
1679 } else {
1680 new_name_first = (int)(menu->num_cols * start_frac);
1681 }
1682 }
1683 }
1684 if (menu->first_index != new_name_first) {
1685 menu->first_index = new_name_first;
1686 TgDrawEntireMenu(menu);
1687 }
1688 while (XCheckMaskEvent(mainDisplay, PointerMotionMask, &ev)) ;
1689 }
1690 }
1691 }
1692
ScrollMenu(menu,x,y,menu_w,menu_h,button_state)1693 void ScrollMenu(menu, x, y, menu_w, menu_h, button_state)
1694 TgMenu *menu;
1695 int x, y, menu_w, menu_h, button_state;
1696 {
1697 int menu_x=x, menu_y=y, x_off=0, y_off=0;
1698 int do_drag=FALSE, btn_offset=0, v_scroll=TRUE;
1699 unsigned int button=Button1;
1700
1701 if ((button_state & Button1Mask) == Button1Mask) button = Button1;
1702 if ((button_state & Button2Mask) == Button2Mask) button = Button2;
1703 if ((button_state & Button3Mask) == Button3Mask) button = Button3;
1704
1705 switch (menu->type) {
1706 case TGMUTYPE_TEXT: v_scroll = TRUE; break;
1707 case TGMUTYPE_COLOR: v_scroll = FALSE; break;
1708 case TGMUTYPE_BITMAP: v_scroll = FALSE; break;
1709 }
1710 if (v_scroll) {
1711 menu_x = x-menu->scroll_start-windowPadding;
1712 } else {
1713 menu_y = y-menu->scroll_start-windowPadding;
1714 }
1715 if (!threeDLook && button == Button3) {
1716 if (DoScrollMenu(menu, FALSE, (v_scroll ? SCRL_UP : SCRL_LF), NULL)) {
1717 return;
1718 }
1719 } else if (!threeDLook && button == Button1) {
1720 if (DoScrollMenu(menu, FALSE, (v_scroll ? SCRL_DN : SCRL_RT), NULL)) {
1721 return;
1722 }
1723 } else if (button == Button1) {
1724 if (v_scroll) {
1725 /* vertical scroll bar */
1726 if (menu_y < scrollBarW || menu_y >= menu_h-scrollBarW) {
1727 int which=0;
1728 struct BBRec bbox;
1729
1730 x_off = menu->scroll_start+(windowPadding<<1)+(windowPadding>>1);
1731 if (menu_y < scrollBarW) {
1732 y_off = (windowPadding>>1);
1733 which = SCRL_UP;
1734 SetBBRec(&bbox, x_off, y_off, x_off+scrollBarW,
1735 y_off+scrollBarW);
1736 } else {
1737 y_off = -(windowPadding>>1);
1738 which = SCRL_DN;
1739 SetBBRec(&bbox, x_off, y_off+menu_h-scrollBarW, x_off+scrollBarW,
1740 y_off+menu_h);
1741 }
1742 if (DoScrollMenu(menu, FALSE, which, &bbox)) {
1743 return;
1744 }
1745 } else {
1746 double start_frac=(double)0;
1747 int hit=0;
1748
1749 start_frac = (menu->num_items > 0) ?
1750 (double)((double)(menu->first_index) /
1751 (double)(menu->num_items)) : ((double)0.0);
1752 hit = TgGetScrollHit(menu_x, menu_y, VERT_SCROLLBAR,
1753 scrollBarW, menu_h, start_frac, menuRowsBeforeScroll,
1754 menu->num_items, &btn_offset);
1755 if (hit == 0) {
1756 do_drag = TRUE;
1757 } else {
1758 if (DoScrollMenu(menu, TRUE, (hit<0 ? SCRL_UP : SCRL_DN),
1759 NULL)) {
1760 return;
1761 }
1762 }
1763 }
1764 } else {
1765 /* horizontal scroll bar */
1766 if (menu_x < scrollBarW || menu_x >= menu_w-scrollBarW) {
1767 int which=0;
1768 struct BBRec bbox;
1769
1770 y_off = menu->scroll_start+(windowPadding<<1)+(windowPadding>>1);
1771 if (menu_x < scrollBarW) {
1772 x_off = (windowPadding>>1);
1773 which = SCRL_LF;
1774 SetBBRec(&bbox, x_off, y_off, x_off+scrollBarW,
1775 y_off+scrollBarW);
1776 } else {
1777 x_off = -(windowPadding>>1);
1778 which = SCRL_RT;
1779 SetBBRec(&bbox, x_off+menu_w-scrollBarW, y_off, x_off+menu_w,
1780 y_off+scrollBarW);
1781 }
1782 if (DoScrollMenu(menu, FALSE, which, &bbox)) {
1783 return;
1784 }
1785 } else {
1786 double start_frac=(double)0;
1787 int hit=0;
1788
1789 start_frac = (menu->num_items > 0) ?
1790 (double)((double)(menu->first_index) /
1791 (double)(menu->num_cols)) : ((double)0.0);
1792 hit = TgGetScrollHit(menu_x, menu_y, HORI_SCROLLBAR,
1793 menu_w, scrollBarW, start_frac, menuColsBeforeScroll,
1794 menu->num_cols, &btn_offset);
1795 if (hit == 0) {
1796 do_drag = TRUE;
1797 } else {
1798 if (DoScrollMenu(menu, TRUE, (hit<0 ? SCRL_LF : SCRL_RT),
1799 NULL)) {
1800 return;
1801 }
1802 }
1803 }
1804 }
1805 } else if (!threeDLook && button == Button2) {
1806 do_drag = TRUE;
1807 }
1808 if (do_drag) {
1809 DoDragInScrollMenu(menu, menu_w, menu_h, x, y, btn_offset);
1810 return;
1811 }
1812 TgDrawEntireMenu(menu);
1813 }
1814
TgMenuLoop(menu)1815 int TgMenuLoop(menu)
1816 TgMenu *menu;
1817 {
1818 int menuing=TRUE;
1819 int orig_x=menu->bbox.ltx, orig_y=menu->bbox.lty;
1820 int menu_w=menu->bbox.rbx-orig_x+((menu->padding)<<1);
1821 int menu_h=menu->bbox.rby-orig_y+((menu->padding)<<1);
1822 int min_pin=0, max_pin=0, suspended=FALSE;
1823 TgMenuItem *menuitems=NULL;
1824 Window root_win=None, child_win=None;
1825 TgMenu *parent_menu=menu->parent_menu;
1826 int x, y, rc=INVALID, saved_root_x, saved_root_y;
1827 int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
1828 unsigned int status;
1829 XEvent ev;
1830 XWMHints wmhints;
1831 XSizeHints sizehints;
1832 XSetWindowAttributes win_attrs;
1833 int pinned_x=0, pinned_y=0, menu_pinned=FALSE;
1834 int tmp_disallow_pinning=inSlideShow;
1835 int one_line_status=FALSE;
1836 char status_buf[MAX_STATUS_BTNS+1][MAXSTRING+1];
1837
1838 SaveStatusStringsIntoBuf(status_buf, &one_line_status);
1839
1840 if (menu->scroll_start > 0) {
1841 switch (menu->type) {
1842 case TGMUTYPE_TEXT:
1843 menu_w += scrollBarW + menu->padding;
1844 menu_h = maxScrollableMenuHeight;
1845 break;
1846 case TGMUTYPE_COLOR:
1847 case TGMUTYPE_BITMAP:
1848 menu_w = maxScrollableMenuWidth;
1849 menu_h += scrollBarW + menu->padding;
1850 break;
1851 }
1852 }
1853 menuitems = menu->menuitems;
1854
1855 if (menu->track_menubar && menubarWindow != None) {
1856 SetMenubarWinBBox();
1857 } else if (menu->parent_menu != NULL && menu->track_parent_menu) {
1858 SetParentMenuWinBBox(menu);
1859 }
1860 AdjMenuGeometry(menu, &orig_x, &orig_y, &min_pin, &max_pin);
1861
1862 if ((menu->window=XCreateSimpleWindow(mainDisplay, rootWindow,
1863 orig_x+windowPadding, orig_y+windowPadding, menu_w, menu_h,
1864 menu->brdr_w, myBorderPixel, bg_pixel)) == 0) {
1865 FailToCreateWindowMessage("TgMenuLoop()", NULL, FALSE);
1866 return rc;
1867 }
1868 win_attrs.save_under = True;
1869 win_attrs.override_redirect = True;
1870 win_attrs.colormap = mainColormap;
1871 XChangeWindowAttributes(mainDisplay, menu->window,
1872 CWSaveUnder | CWOverrideRedirect | CWColormap, &win_attrs);
1873
1874 wmhints.flags = InputHint | StateHint;
1875 wmhints.input = True;
1876 wmhints.initial_state = NormalState;
1877 XSetWMHints(mainDisplay, menu->window, &wmhints);
1878
1879 sizehints.flags = PPosition | PSize | USPosition | PMinSize | PMaxSize;
1880 sizehints.x = orig_x+windowPadding;
1881 sizehints.y = orig_y+windowPadding;
1882 sizehints.width = sizehints.min_width = sizehints.max_width = menu_w;
1883 sizehints.height = sizehints.min_height = sizehints.max_height = menu_h;
1884 #ifdef NOTR4MODE
1885 XSetNormalHints(mainDisplay, menu->window, &sizehints);
1886 #else
1887 XSetWMNormalHints(mainDisplay, menu->window, &sizehints);
1888 #endif
1889
1890 menu->selected_index = INVALID;
1891
1892 RegisterWM_DELETE_WINDOW(menu->window);
1893 XSetTransientForHint(mainDisplay, menu->window, mainWindow);
1894
1895 #ifdef MAPBEFORESELECT
1896 XMapWindow(mainDisplay, menu->window);
1897 XSelectInput(mainDisplay, menu->window, StructureNotifyMask |
1898 ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask |
1899 PointerMotionMask | EnterWindowMask | LeaveWindowMask);
1900 #else
1901 XSelectInput(mainDisplay, menu->window, StructureNotifyMask |
1902 ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask |
1903 PointerMotionMask | EnterWindowMask | LeaveWindowMask);
1904 XMapWindow(mainDisplay, menu->window);
1905 #endif
1906
1907 if (menu->parent_menu == NULL &&
1908 !(menu->track_menubar && menubarWindow != None) &&
1909 !menu->track_parent_menu) {
1910 XWarpPointer(mainDisplay,None,rootWindow,0,0,0,0,orig_x-2,orig_y-2);
1911 }
1912 XQueryPointer(mainDisplay, menu->window, &root_win, &child_win,
1913 &saved_root_x, &saved_root_y, &x, &y, &status);
1914
1915 if (!debugNoPointerGrab) {
1916 XGrabPointer(mainDisplay, menu->window, FALSE,
1917 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1918 GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
1919 }
1920 while (menuing) {
1921 int root_x, root_y, any_button_down;
1922
1923 XNextEvent(mainDisplay, &ev);
1924 if (ev.type == Expose || ev.type == VisibilityNotify) {
1925 if (ev.xany.window == menu->window) {
1926 TgDrawEntireMenu(menu);
1927 } else {
1928 ExposeEventHandler(&ev, FALSE);
1929 }
1930 }
1931 if (!debugNoPointerGrab &&
1932 (ev.type == ButtonPress || ev.type == ButtonRelease)) {
1933 XButtonEvent *button_ev=(&(ev.xbutton));
1934
1935 XQueryPointer(mainDisplay, menu->window, &root_win, &child_win,
1936 &root_x, &root_y, &x, &y, &status);
1937 x = button_ev->x;
1938 y = button_ev->y;
1939 if (ev.type == ButtonPress) {
1940 switch (button_ev->button) {
1941 case Button1: status = Button1Mask; break;
1942 case Button2: status = Button2Mask; break;
1943 case Button3: status = Button3Mask; break;
1944 }
1945 }
1946 } else {
1947 XQueryPointer(mainDisplay, menu->window, &root_win, &child_win,
1948 &root_x, &root_y, &x, &y, &status);
1949 }
1950 any_button_down = ((status & BUTTONSMASK) != 0);
1951 if (suspended) {
1952 if (!any_button_down) {
1953 continue;
1954 }
1955 suspended = FALSE;
1956 tmp_disallow_pinning = TRUE;
1957 }
1958 if (!any_button_down) {
1959 if (!menu_pinned &&
1960 abs(root_x-saved_root_x)<=2 && abs(root_y-saved_root_y)<=2) {
1961 suspended = TRUE;
1962 continue;
1963 } else if (menu->parent_menu != NULL &&
1964 PointInBBox(root_x, root_y, menu->parent_menu->bbox) &&
1965 TgPointInParentMenuSelectedItem(menu->parent_menu)) {
1966 suspended = TRUE;
1967 continue;
1968 }
1969 if (menu_pinned) {
1970 XDrawRectangle(mainDisplay, rootWindow, revDefaultGC,
1971 pinned_x, pinned_y, menu_w+(brdrW<<1), menu_h+(brdrW<<1));
1972 XSetSubwindowMode(mainDisplay, revDefaultGC, ClipByChildren);
1973 pinned_x = root_x;
1974 pinned_y = root_y;
1975 TgRealizePinnedMenuWindow(menu, pinned_x, pinned_y,
1976 menu_w+(brdrW<<1), menu_h+(brdrW<<1));
1977 rc = INVALID;
1978 } else if (x >= 0 && x < menu_w && y >= 0 && y < menu_h) {
1979 rc = TgWhichMenuIndex(menu, x, y, FALSE);
1980 switch (rc) {
1981 case INVALID: break;
1982 case (-2):
1983 /* separator */
1984 rc = INVALID;
1985 suspended = TRUE;
1986 continue;
1987 case (-3):
1988 /* scrollbar */
1989 rc = INVALID;
1990 suspended = TRUE;
1991 continue;
1992 default:
1993 if (menu->menuitems[rc].cmdid != INVALID &&
1994 ((menu->menuitems[rc].flags & TGMU_DISABLED) ==
1995 TGMU_DISABLED)) {
1996 rc = INVALID;
1997 suspended = TRUE;
1998 continue;
1999 } else if (menu->is_main_menu) {
2000 rc = menu->menuitems[rc].cmdid;
2001 } else if (menu->menuitems[rc].cmdid != INVALID &&
2002 ((menu->menuitems[rc].flags & TGMU_DISABLED) !=
2003 TGMU_DISABLED)) {
2004 if (gstMenuDontSendCommandInfo.dont_send_command) {
2005 gstMenuDontSendCommandInfo.selected_index = rc;
2006 } else {
2007 SendCommandToSelf(menu->menuitems[rc].cmdid, rc);
2008 }
2009 /*
2010 * Nothing catches -4, so all the parent menus will close.
2011 */
2012 rc = (-4);
2013 }
2014 break;
2015 }
2016 } else {
2017 rc = INVALID;
2018 }
2019 menuing = FALSE;
2020 } else if (menu_pinned) {
2021 XDrawRectangle(mainDisplay, rootWindow, revDefaultGC,
2022 pinned_x, pinned_y, menu_w+(brdrW<<1), menu_h+(brdrW<<1));
2023 pinned_x = root_x;
2024 pinned_y = root_y;
2025 XDrawRectangle(mainDisplay, rootWindow, revDefaultGC,
2026 pinned_x, pinned_y, menu_w+(brdrW<<1), menu_h+(brdrW<<1));
2027 } else if (x >= 0 && x < menu_w && y >=0 && y < menu_h) {
2028 int new_selected=TgWhichMenuIndex(menu, x, y, FALSE);
2029
2030 if (new_selected == (-3) || menu->selected_index != new_selected) {
2031 if (menu->selected_index != INVALID) {
2032 if (gnUncheckWhenMoused && !threeDLook &&
2033 menu->type != TGMUTYPE_TEXT &&
2034 ((menuitems[menu->selected_index].flags &
2035 TGMU_SEPARATOR) == 0) &&
2036 menuitems[menu->selected_index].checked) {
2037 menuitems[menu->selected_index].checked = FALSE;
2038 }
2039 menuitems[menu->selected_index].state = TGBS_NORMAL;
2040 TgDrawMenuItem(menu, &menuitems[menu->selected_index]);
2041 }
2042 if (new_selected >= 0) {
2043 menuitems[new_selected].state = TGBS_RAISED;
2044 TgDrawMenuItem(menu, &menuitems[new_selected]);
2045 if (menuitems[new_selected].status_str != NULL) {
2046 /* the status_str has been translated */
2047 SetStringStatus(menuitems[new_selected].status_str);
2048 }
2049 }
2050 switch (new_selected) {
2051 case INVALID: break;
2052 case (-2): new_selected = INVALID; break; /* separator */
2053 case (-3):
2054 /* scrollbar */
2055 if (menu->scroll_start > 0 && tmp_disallow_pinning) {
2056 /* loop to scroll */
2057 ScrollMenu(menu, x, y, menu_w, menu_h, (status&BUTTONSMASK));
2058 }
2059 new_selected = INVALID;
2060 XQueryPointer(mainDisplay, menu->window, &root_win, &child_win,
2061 &root_x, &root_y, &x, &y, &status);
2062 any_button_down = ((status & BUTTONSMASK) != 0);
2063 if (!any_button_down) {
2064 suspended = TRUE;
2065 }
2066 if (!debugNoPointerGrab) {
2067 XGrabPointer(mainDisplay, menu->window, FALSE,
2068 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
2069 GrabModeAsync, GrabModeAsync, None, handCursor,
2070 CurrentTime);
2071 }
2072 break;
2073 default: break;
2074 }
2075 menu->selected_index = new_selected;
2076 if (new_selected != INVALID &&
2077 (menuitems[new_selected].flags & TGMU_HAS_SUBMENU) ==
2078 TGMU_HAS_SUBMENU &&
2079 (menuitems[new_selected].flags & TGMU_DISABLED) == 0 &&
2080 menuitems[new_selected].submenu_create_info != NULL) {
2081 TgMenu *submenu=NULL;
2082
2083 submenu = TgCreatePopUpSubMenu(menu, new_selected);
2084 if (submenu != NULL) {
2085 #ifdef _CHAMELEON_BUG
2086 if (!debugNoPointerGrab) {
2087 XUngrabPointer(mainDisplay, CurrentTime);
2088 }
2089 #endif /* _CHAMELEON_BUG */
2090 rc = TgPopUpSubMenu(menu, orig_x, orig_y);
2091 submenu = menuitems[new_selected].detail.submenu;
2092 if (submenu != NULL) {
2093 TgDestroyMenu(submenu, TRUE);
2094 menuitems[new_selected].detail.submenu = NULL;
2095 }
2096 }
2097 if (rc != INVALID && rc != (-3)) {
2098 menuing = FALSE;
2099 } else if (!debugNoPointerGrab) {
2100 XGrabPointer(mainDisplay, menu->window, FALSE,
2101 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
2102 GrabModeAsync, GrabModeAsync, None, handCursor,
2103 CurrentTime);
2104 }
2105 }
2106 }
2107 tmp_disallow_pinning = inSlideShow;
2108 } else if (menu->parent_menu != NULL && menu->track_parent_menu &&
2109 PointInBBox(root_x, root_y, gstMenubarWinBBox) &&
2110 !TgPointInParentMenuSelectedItem(menu->parent_menu)) {
2111 menuing = FALSE;
2112 rc = BAD;
2113 } else if (menu->parent_menu != NULL &&
2114 PointInBBox(root_x, root_y, menu->parent_menu->bbox)) {
2115 /* we are in the parent menu */
2116 if (!TgPointInParentMenuSelectedItem(menu->parent_menu)) {
2117 menuing = FALSE;
2118 rc = (-3);
2119 }
2120 } else if (menu->parent_menu != NULL &&
2121 TgPointInAnAncestorMenu(menu->parent_menu, root_x, root_y)) {
2122 /* we are in an ancestor menu */
2123 menuing = FALSE;
2124 rc = (-3);
2125 } else if (menu->track_menubar && menubarWindow != None &&
2126 PointInBBox(root_x, root_y, gstMenubarWinBBox) &&
2127 WhichMenubarItem(root_x-gstMenubarWinBBox.ltx,
2128 root_y-gstMenubarWinBBox.lty, NULL, NULL, NULL) != INVALID &&
2129 !PointInBBox(root_x-gstMenubarWinBBox.ltx,
2130 root_y-gstMenubarWinBBox.lty, excludeMenubarWinBBox)) {
2131 menuing = FALSE;
2132 rc = BAD;
2133 } else if (!menu->disallow_pinning && !tmp_disallow_pinning &&
2134 !menu_pinned && (activeMenu != INVALID || menu->is_main_menu) &&
2135 (root_x < min_pin || root_x > max_pin)) {
2136 pinned_x = root_x;
2137 pinned_y = root_y;
2138 XSetSubwindowMode(mainDisplay, revDefaultGC, IncludeInferiors);
2139 XDrawRectangle(mainDisplay, rootWindow, revDefaultGC,
2140 pinned_x, pinned_y, menu_w+(brdrW<<1), menu_h+(brdrW<<1));
2141 SetStringStatus(TgLoadCachedString(CSTID_RELEASE_MOUSE_TO_PIN_MENU));
2142 menu_pinned = TRUE;
2143 } else if (menu->selected_index != INVALID) {
2144 menuitems[menu->selected_index].state = TGBS_NORMAL;
2145 TgDrawMenuItem(menu, &menuitems[menu->selected_index]);
2146 menu->selected_index = INVALID;
2147 }
2148 }
2149 if (parent_menu == NULL && !debugNoPointerGrab) {
2150 XUngrabPointer(mainDisplay, CurrentTime);
2151 }
2152 if (menu->window != None) XDestroyWindow(mainDisplay, menu->window);
2153
2154 XSync(mainDisplay, False);
2155
2156 RestoreStatusStringsFromBuf(status_buf, one_line_status);
2157
2158 return rc;
2159 }
2160
TgDestroyMenu(menu,free_menu)2161 TgMenu *TgDestroyMenu(menu, free_menu)
2162 TgMenu *menu;
2163 int free_menu;
2164 /* return NULL if menu is freed */
2165 {
2166 int i, num_items=menu->num_items;
2167 TgMenuItem *menuitems=NULL;
2168
2169 menuitems = menu->menuitems;
2170 if (menuitems != NULL) {
2171 for (i=0; i < num_items; i++) {
2172 TgMenuItem *menu_item=(&menuitems[i]);
2173
2174 UtilFree(menu_item->status_str);
2175 if (menu_item->menu_str_allocated) {
2176 UtilFree(menu_item->menu_str);
2177 menu_item->menu_str = NULL;
2178 }
2179 menu_item->status_str = NULL;
2180 if ((menu_item->flags & TGMU_HAS_SUBMENU) &&
2181 menu_item->detail.submenu != NULL) {
2182 TgDestroyMenu(menu_item->detail.submenu, TRUE);
2183 }
2184 }
2185 free(menuitems);
2186 }
2187 if (free_menu) {
2188 free(menu);
2189 return NULL;
2190 }
2191 return menu;
2192 }
2193
2194 static
TgGetTextMenuItemWidths(menu_item,pn_check_w,pn_str_w,pn_shortcut_w)2195 int TgGetTextMenuItemWidths(menu_item, pn_check_w, pn_str_w, pn_shortcut_w)
2196 TgMenuItem *menu_item;
2197 int *pn_check_w, *pn_str_w, *pn_shortcut_w;
2198 {
2199 int flags=menu_item->flags;
2200
2201 if ((flags & TGMU_SEPARATOR) == TGMU_SEPARATOR) {
2202 if (pn_check_w != NULL) *pn_check_w = 0;
2203 if (pn_str_w != NULL) *pn_str_w = 0;
2204 if (pn_shortcut_w != NULL) *pn_shortcut_w = 0;
2205 return TRUE;
2206 }
2207 if (pn_check_w != NULL) {
2208 if ((flags & (TGMU_HAS_CHECK|TGMU_HAS_RADIO)) != 0) {
2209 *pn_check_w = check_width;
2210 } else {
2211 *pn_check_w = 0;
2212 }
2213 }
2214 if (pn_str_w != NULL) {
2215 char *menu_str=menu_item->menu_str;
2216
2217 if (menuFontSet != NULL || menuFontPtr != NULL) {
2218 *pn_str_w = MenuTextWidth(menuFontPtr, _(menu_str),
2219 strlen(_(menu_str)));
2220 } else {
2221 *pn_str_w = defaultFontWidth * strlen(_(menu_str));
2222 }
2223 }
2224 if (pn_shortcut_w != NULL) {
2225 if (flags & TGMU_HAS_SHORTCUT) {
2226 char *shortcut_str=menu_item->detail.shortcut_str;
2227
2228 /* don't translate shortuct_str */
2229 if (menuFontSet != NULL || menuFontPtr != NULL) {
2230 *pn_shortcut_w = MenuTextWidth(menuFontPtr, shortcut_str,
2231 strlen(shortcut_str));
2232 } else {
2233 *pn_shortcut_w = defaultFontWidth * strlen(shortcut_str);
2234 }
2235 } else {
2236 *pn_shortcut_w = 0;
2237 }
2238 }
2239 return TRUE;
2240 }
2241
TgSetMenuItemInfo(to_menu_item,mask,from_menu_item)2242 int TgSetMenuItemInfo(to_menu_item, mask, from_menu_item)
2243 TgMenuItem *to_menu_item, *from_menu_item;
2244 int mask;
2245 {
2246 if (mask & TGMU_MASK_LTXY) {
2247 to_menu_item->bbox.ltx = from_menu_item->bbox.ltx;
2248 to_menu_item->bbox.lty = from_menu_item->bbox.lty;
2249 }
2250 if (mask & TGMU_SEPARATOR) {
2251 to_menu_item->flags |= TGMU_SEPARATOR;
2252 return TRUE;
2253 }
2254 if (mask & TGMU_MASK_STATE) to_menu_item->state = from_menu_item->state;
2255 if (mask & TGMU_MASK_CMDID) to_menu_item->cmdid = from_menu_item->cmdid;
2256 if (mask & TGMU_MASK_MULTICOLOR) {
2257 to_menu_item->flags |= TGMU_MULTICOLOR;
2258 to_menu_item->multicolor_pixel = from_menu_item->multicolor_pixel;
2259 }
2260 if (mask & TGMU_MASK_PXMPBTN1) {
2261 to_menu_item->checked_pxmpbtn = from_menu_item->checked_pxmpbtn;
2262 }
2263 if (mask & TGMU_MASK_PXMPBTN2) {
2264 to_menu_item->unchecked_pxmpbtn = from_menu_item->unchecked_pxmpbtn;
2265 }
2266 if (mask & TGMU_MASK_CHECK) {
2267 to_menu_item->flags |= TGMU_HAS_CHECK;
2268 to_menu_item->flags &= (~TGMU_HAS_RADIO);
2269 to_menu_item->checked = from_menu_item->checked;
2270 }
2271 if (mask & TGMU_MASK_RADIO) {
2272 to_menu_item->flags |= TGMU_HAS_RADIO;
2273 to_menu_item->flags &= (~TGMU_HAS_CHECK);
2274 to_menu_item->checked = from_menu_item->checked;
2275 }
2276 if (mask & TGMU_MASK_MENUSTR) {
2277 to_menu_item->menu_str = from_menu_item->menu_str;
2278 }
2279 if (mask & TGMU_MASK_STATUSSTR) {
2280 char *psz=NULL;
2281
2282 UtilFree(to_menu_item->status_str);
2283
2284 if (mask & TGMU_MASK_RAWSTATUSSTR) {
2285 /* the from_menu_item->status_str has NOT been translated */
2286 to_menu_item->status_str = UtilStrDup(_(from_menu_item->status_str));
2287 } else {
2288 /* the from_menu_item->status_str has been translated */
2289 to_menu_item->status_str = UtilStrDup(from_menu_item->status_str);
2290 }
2291 if (to_menu_item->status_str == NULL) FailAllocMessage();
2292 /* do not translate -- program constants */
2293 if (from_menu_item->status_str != NULL &&
2294 (psz=strstr(from_menu_item->status_str, "<<PROGRAM_NAME>>")) !=
2295 NULL) {
2296 char *psz1=(&psz[strlen("<<PROGRAM_NAME>>")]);
2297
2298 sprintf(&to_menu_item->status_str[psz-from_menu_item->status_str],
2299 "%s%s", TOOL_NAME, psz1);
2300 }
2301 }
2302 if (mask & TGMU_MASK_SUBMENU) {
2303 to_menu_item->flags |= TGMU_HAS_SUBMENU;
2304 to_menu_item->flags &= (~TGMU_HAS_SHORTCUT);
2305 to_menu_item->submenu_create_info = from_menu_item->submenu_create_info;
2306 if (mask & TGMU_MASK_PINNABLESUBMENU) {
2307 to_menu_item->flags |= TGMU_SUBMENU_PINNABLE;
2308 }
2309 }
2310 if (mask & TGMU_MASK_SHORTCUTSTR) {
2311 to_menu_item->flags |= TGMU_HAS_SHORTCUT;
2312 to_menu_item->flags &= (~TGMU_HAS_SUBMENU);
2313 to_menu_item->detail.shortcut_str = from_menu_item->detail.shortcut_str;
2314 }
2315 if (mask & TGMU_MASK_USERDATA) {
2316 to_menu_item->userdata = from_menu_item->userdata;
2317 }
2318 return TRUE;
2319 }
2320
2321 static
TgAdjustMenuItemHeight(menu,menu_item)2322 int TgAdjustMenuItemHeight(menu, menu_item)
2323 TgMenu *menu;
2324 TgMenuItem *menu_item;
2325 {
2326 int flags=menu_item->flags, item_w=0, item_h=0;
2327
2328 if (flags & TGMU_SEPARATOR) {
2329 menu_item->bbox.rby = menu_item->bbox.lty+separatorHeight;
2330 return TRUE;
2331 }
2332 switch (menu->type) {
2333 case TGMUTYPE_TEXT:
2334 if (menuFontSet != NULL || menuFontPtr != NULL) {
2335 menu_item->bbox.rby = menu_item->bbox.lty+menuFontHeight;
2336 } else {
2337 menu_item->bbox.rby = menu_item->bbox.lty+defaultFontHeight;
2338 }
2339 break;
2340 case TGMUTYPE_COLOR:
2341 case TGMUTYPE_BITMAP:
2342 item_w = menu->image_w;
2343 item_h = menu->image_h;
2344 if (threeDLook) {
2345 item_w += (windowPadding<<1);
2346 item_h += (windowPadding<<1);
2347 }
2348 menu_item->bbox.rbx = menu_item->bbox.ltx+item_w;
2349 menu_item->bbox.rby = menu_item->bbox.lty+item_h;
2350 break;
2351 }
2352 return TRUE;
2353 }
2354
TgAdjustMenuGeometry(menu,image_w,image_h,max_rows)2355 void TgAdjustMenuGeometry(menu, image_w, image_h, max_rows)
2356 TgMenu *menu;
2357 int image_w, image_h, max_rows;
2358 /* only for TGMUTYPE_BITMAP or TGMUTYPE_COLOR */
2359 {
2360 int max_h=0, item_w=image_w, item_h=image_h;
2361 int i, xoff=0, yoff=0, max_col_w=0, max_w=0, num_items=menu->num_items;
2362
2363 if (threeDLook) {
2364 item_w += (windowPadding<<1);
2365 item_h += (windowPadding<<1);
2366 }
2367 menu->image_w = image_w;
2368 menu->image_h = image_h;
2369 menu->num_rows = max_rows;
2370 menu->num_cols = (((num_items % max_rows) == 0) ? num_items / max_rows :
2371 ((int)(num_items/max_rows))+1);
2372 xoff = menu->padding;
2373 yoff = menu->padding;
2374 for (i=0; i < num_items; i++) {
2375 int flags=TGMU_MASK_LTXY, col_w=0, item_h=0;
2376 TgMenuItem *menu_item=(&menu->menuitems[i]);
2377 TgMenuItem stMenuItem;
2378
2379 memset(&stMenuItem, 0, sizeof(TgMenuItem));
2380
2381 stMenuItem.bbox.ltx = xoff;
2382 stMenuItem.bbox.lty = yoff;
2383 if (menu_item->menu_str == TGMUITEM_SEPARATOR) {
2384 flags |= TGMU_SEPARATOR;
2385 }
2386 if (!TgSetMenuItemInfo(menu_item, flags, &stMenuItem)) {
2387 TgDestroyMenu(menu, TRUE); /* frees menu in TgDestroyMenu() */
2388 return;
2389 }
2390 /* now adjust the width and height of menu_item->bbox */
2391 TgAdjustMenuItemHeight(menu, menu_item);
2392 col_w = menu_item->bbox.rbx-menu_item->bbox.ltx;
2393 item_h = menu_item->bbox.rby-menu_item->bbox.lty;
2394 if (col_w > max_col_w) max_col_w = col_w;
2395 yoff += item_h;
2396 if (xoff+max_col_w > max_w) max_w = xoff+max_col_w;
2397 if (yoff > max_h) max_h = yoff;
2398 if (((i+1) % max_rows) == 0) {
2399 xoff += max_col_w;
2400 yoff = menu->padding;
2401 }
2402 }
2403 menu->check_start = menu->str_start = menu->shortcut_start =
2404 menu->arrow_start = xoff;
2405 menu->bbox.rbx = menu->bbox.ltx+max_w-menu->padding;
2406 menu->bbox.rby = menu->bbox.lty+max_h-menu->padding;
2407
2408 maxScrollableMenuWidth = (menuColsBeforeScroll*item_w) +
2409 (windowPadding<<1);
2410 if (menu->can_scroll && (max_w+windowPadding) > maxScrollableMenuWidth) {
2411 menu->scroll_start = (item_h*max_rows);
2412 }
2413 }
2414
2415 static
CreateTextMenuItemsFromMenuItemInfo(menu,menu_iteminfos,status_str_xlated)2416 int CreateTextMenuItemsFromMenuItemInfo(menu, menu_iteminfos, status_str_xlated)
2417 TgMenu *menu;
2418 TgMenuItemInfo *menu_iteminfos;
2419 int status_str_xlated;
2420 {
2421 TgMenuItemInfo *item_info=NULL;
2422 int i, xoff=0, yoff=0, max_str_w=0, max_shortcut_w=submenu_width, total_w=0;
2423 int num_items=0;
2424
2425 for (item_info=menu_iteminfos; item_info->menu_str != NULL; item_info++) {
2426 num_items++;
2427 }
2428 menu->num_items = num_items;
2429 menu->menuitems = (TgMenuItem*)malloc(num_items*sizeof(TgMenuItem));
2430 if (menu->menuitems == NULL) FailAllocMessage();
2431 memset(menu->menuitems, 0, num_items*sizeof(TgMenuItem));
2432
2433 xoff = menu->padding;
2434 yoff = menu->padding;
2435 for (item_info=menu_iteminfos, i=0; item_info->menu_str != NULL;
2436 item_info++, i++) {
2437 int flags=0, check_w=0, str_w=0, shortcut_w=0;
2438 TgMenuItem *menu_item=(&menu->menuitems[i]);
2439 TgMenuItem stMenuItem;
2440
2441 memset(menu_item, 0, sizeof(TgMenuItem));
2442 memset(&stMenuItem, 0, sizeof(TgMenuItem));
2443
2444 stMenuItem.bbox.ltx = xoff;
2445 stMenuItem.bbox.lty = yoff;
2446 if (item_info->menu_str == TGMUITEM_SEPARATOR) {
2447 flags |= TGMU_SEPARATOR | TGMU_MASK_LTXY;
2448 } else {
2449 stMenuItem.state = TGBS_NORMAL;
2450 stMenuItem.cmdid = item_info->cmdid;
2451 stMenuItem.menu_str = item_info->menu_str;
2452 /* the from_menu_item->status_str has been translated */
2453 stMenuItem.status_str = item_info->status_str;
2454 flags |= TGMU_MASK_LTXY | TGMU_MASK_STATE | TGMU_MASK_CMDID |
2455 TGMU_MASK_MENUSTR | TGMU_MASK_STATUSSTR;
2456 if (!status_str_xlated) {
2457 flags |= TGMU_MASK_RAWSTATUSSTR;
2458 }
2459 if (item_info->shortcut_str == TGMUITEM_SUBMENU ||
2460 item_info->shortcut_str == TGMUITEM_PINNABLESUBMENU) {
2461 flags |= TGMU_MASK_SUBMENU;
2462 if (item_info->shortcut_str == TGMUITEM_PINNABLESUBMENU) {
2463 flags |= TGMU_MASK_PINNABLESUBMENU;
2464 }
2465 stMenuItem.submenu_create_info = item_info;
2466 } else if (item_info->shortcut_str != NULL) {
2467 flags |= TGMU_MASK_SHORTCUTSTR;
2468 stMenuItem.detail.shortcut_str = item_info->shortcut_str;
2469 }
2470 }
2471 if (!TgSetMenuItemInfo(menu_item, flags, &stMenuItem)) {
2472 TgDestroyMenu(menu, TRUE); /* frees menu in TgDestroyMenu() */
2473 return FALSE;
2474 }
2475 TgAdjustMenuItemHeight(menu, menu_item);
2476 TgGetTextMenuItemWidths(menu_item, &check_w, &str_w, &shortcut_w);
2477 if (str_w > max_str_w) max_str_w = str_w;
2478 if (shortcut_w > max_shortcut_w) max_shortcut_w = shortcut_w;
2479 yoff += menu_item->bbox.rby-menu_item->bbox.lty+1;
2480 }
2481 menu->check_start = xoff+2;
2482 menu->str_start = menu->check_start+check_width+2;
2483 menu->shortcut_start = menu->str_start+max_str_w+(menuFontWidth<<1)+2;
2484 menu->arrow_start = menu->shortcut_start+max_shortcut_w-submenu_width;
2485 total_w = menu->arrow_start+submenu_width-xoff+2+menuFontWidth;
2486 menu->bbox.rbx = menu->bbox.ltx + total_w;
2487 menu->bbox.rby = menu->bbox.lty + yoff;
2488 for (i=0; i < num_items; i++) {
2489 TgMenuItem *menu_item=(&menu->menuitems[i]);
2490
2491 menu_item->bbox.rbx = menu->shortcut_start+max_shortcut_w+menuFontWidth;
2492 }
2493 if (menu->can_scroll && yoff > maxScrollableMenuHeight) {
2494 menu->scroll_start = total_w;
2495 }
2496 return TRUE;
2497 }
2498
2499 static
SetScrollableMenuSize(menu)2500 void SetScrollableMenuSize(menu)
2501 TgMenu *menu;
2502 {
2503 switch (menu->type) {
2504 case TGMUTYPE_TEXT:
2505 maxScrollableMenuHeight = (menuRowsBeforeScroll *
2506 (((menuFontSet==NULL && menuFontPtr == NULL) ?
2507 initialMenubarWindowH : menuFontHeight) + 1)) + (windowPadding<<1);
2508 break;
2509 case TGMUTYPE_COLOR:
2510 case TGMUTYPE_BITMAP:
2511 /*
2512 * Do nothing!
2513 * maxScrollableMenuWidth will be set in TgAdjustMenuGeometry()
2514 */
2515 break;
2516 }
2517 }
2518
2519 static
CreateBitmapOrColorMenuItemsFromMenuItemInfo(menu,menu_iteminfos,status_str_xlated)2520 int CreateBitmapOrColorMenuItemsFromMenuItemInfo(menu, menu_iteminfos,
2521 status_str_xlated)
2522 TgMenu *menu;
2523 TgMenuItemInfo *menu_iteminfos;
2524 int status_str_xlated;
2525 {
2526 TgMenuItemInfo *item_info=NULL;
2527 int i, xoff=0, yoff=0, num_items=0;
2528
2529 for (item_info=menu_iteminfos; item_info->menu_str != NULL; item_info++) {
2530 num_items++;
2531 }
2532 menu->num_items = num_items;
2533 menu->menuitems = (TgMenuItem*)malloc(num_items*sizeof(TgMenuItem));
2534 if (menu->menuitems == NULL) FailAllocMessage();
2535 memset(menu->menuitems, 0, num_items*sizeof(TgMenuItem));
2536
2537 xoff = menu->padding;
2538 yoff = menu->padding;
2539 for (item_info=menu_iteminfos, i=0; item_info->menu_str != NULL;
2540 item_info++, i++) {
2541 int flags=0;
2542 TgMenuItem *menu_item=(&menu->menuitems[i]);
2543 TgMenuItem stMenuItem;
2544
2545 memset(menu_item, 0, sizeof(TgMenuItem));
2546 memset(&stMenuItem, 0, sizeof(TgMenuItem));
2547
2548 stMenuItem.bbox.ltx = xoff;
2549 stMenuItem.bbox.lty = yoff;
2550 if (item_info->menu_str == TGMUITEM_SEPARATOR) {
2551 flags |= TGMU_SEPARATOR | TGMU_MASK_LTXY;
2552 } else {
2553 stMenuItem.state = TGBS_NORMAL;
2554 stMenuItem.cmdid = item_info->cmdid;
2555 stMenuItem.menu_str = item_info->menu_str;
2556 /* the from_menu_item->status_str has been translated */
2557 stMenuItem.status_str = item_info->status_str;
2558 flags |= TGMU_MASK_LTXY | TGMU_MASK_STATE | TGMU_MASK_CMDID |
2559 TGMU_MASK_MENUSTR | TGMU_MASK_STATUSSTR;
2560 if (!status_str_xlated) {
2561 flags |= TGMU_MASK_RAWSTATUSSTR;
2562 }
2563 if (item_info->shortcut_str != NULL) {
2564 flags |= TGMU_MASK_SHORTCUTSTR;
2565 stMenuItem.detail.shortcut_str = item_info->shortcut_str;
2566 }
2567 }
2568 if (!TgSetMenuItemInfo(menu_item, flags, &stMenuItem)) {
2569 TgDestroyMenu(menu, TRUE); /* frees menu in TgDestroyMenu() */
2570 return FALSE;
2571 }
2572 TgAdjustMenuItemHeight(menu, menu_item);
2573 }
2574 return TRUE;
2575 }
2576
TgCreateMenuFromMenuInfo(parent_menu,x,y,menu_info,status_str_xlated)2577 TgMenu *TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info,
2578 status_str_xlated)
2579 TgMenu *parent_menu;
2580 int x, y, status_str_xlated;
2581 TgMenuInfo *menu_info;
2582 {
2583 TgMenu *menu=(TgMenu*)malloc(sizeof(TgMenu));
2584 TgMenuItemInfo *menu_iteminfos=menu_info->items;
2585
2586 #ifdef _TGIF_DBG /* debug, do not translate */
2587 if (status_str_xlated == INVALID) {
2588 XUngrabPointer(mainDisplay, CurrentTime);
2589 sprintf(gszMsgBox, "Error: %s() is called with %s=INVALID.",
2590 "TgCreateMenuFromMenuInfo", "status_str_xlated");
2591 MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2592 }
2593 #endif /* _TGIF_DBG */
2594 if (menu == NULL) FailAllocMessage();
2595 memset(menu, 0, sizeof(TgMenu));
2596
2597 menu->type = (menu_info->type & TGMUTYPE_MASK);
2598 if ((menu_info->type & TGMUTYPE_CANSCROLL) == TGMUTYPE_CANSCROLL) {
2599 menu->can_scroll = TRUE; /* scroll_start and first_index already 0 */
2600 }
2601 menu_info->type &= TGMUTYPE_MASK;
2602
2603 menu->num_items = 0;
2604 menu->selected_index = INVALID;
2605 menu->bbox.ltx = menu->bbox.rbx = x;
2606 menu->bbox.lty = menu->bbox.rby = y;
2607 menu->padding = (threeDLook ? windowPadding : 0);
2608 menu->brdr_w = (threeDLook ? 0 : (brdrW<<1));
2609 menu->track_menubar = TRUE;
2610 menu->parent_menu = parent_menu;
2611
2612 SetScrollableMenuSize(menu);
2613
2614 switch (menu_info->type) {
2615 case TGMUTYPE_TEXT:
2616 if (!CreateTextMenuItemsFromMenuItemInfo(menu, menu_iteminfos,
2617 status_str_xlated)) {
2618 free(menu);
2619 return NULL;
2620 }
2621 break;
2622 case TGMUTYPE_COLOR:
2623 case TGMUTYPE_BITMAP:
2624 if (!CreateBitmapOrColorMenuItemsFromMenuItemInfo(menu, menu_iteminfos,
2625 status_str_xlated)) {
2626 free(menu);
2627 return NULL;
2628 }
2629 break;
2630 }
2631 return menu;
2632 }
2633
SetScrollableMenuFirstIndex(menu,selected_item_index)2634 void SetScrollableMenuFirstIndex(menu, selected_item_index)
2635 TgMenu *menu;
2636 int selected_item_index;
2637 /* use this only for radio-button style menu, no separators */
2638 {
2639 if (menu->scroll_start > 0) {
2640 int col=0;
2641
2642 switch (menu->type) {
2643 case TGMUTYPE_TEXT:
2644 if (selected_item_index >= menuRowsBeforeScroll) {
2645 menu->first_index = selected_item_index;
2646 if (menu->first_index < 0) menu->first_index = 0;
2647 if (menu->first_index+menuRowsBeforeScroll >= menu->num_items) {
2648 menu->first_index = menu->num_items-menuRowsBeforeScroll;
2649 }
2650 }
2651 break;
2652 case TGMUTYPE_COLOR:
2653 case TGMUTYPE_BITMAP:
2654 col = (int)(selected_item_index/menu->num_rows);
2655 if (col >= menuColsBeforeScroll) {
2656 menu->first_index = col;
2657 if (menu->first_index < 0) menu->first_index = 0;
2658 if (menu->first_index+menuColsBeforeScroll >= menu->num_cols) {
2659 menu->first_index = menu->num_cols-menuColsBeforeScroll;
2660 }
2661 }
2662 break;
2663 }
2664 }
2665 }
2666
RefreshMainMenu(menu)2667 int RefreshMainMenu(menu)
2668 TgMenu *menu;
2669 {
2670 int ok=TRUE;
2671
2672 ok &= TgEnableMenuItemById(menu, MENU_STACKEDPAGE,
2673 (pageLayoutMode==PAGE_STACK));
2674 ok &= TgEnableMenuItemById(menu, MENU_TILEDPAGE,
2675 (pageLayoutMode!=PAGE_STACK));
2676 ok &= TgEnableMenuItemById(menu, MENU_COLOR, colorDisplay);
2677
2678 return ok;
2679 }
2680
CreateMainMenu(parent_menu,x,y,menu_info,status_str_xlated)2681 TgMenu *CreateMainMenu(parent_menu, x, y, menu_info, status_str_xlated)
2682 TgMenu *parent_menu;
2683 int x, y;
2684 TgMenuInfo *menu_info;
2685 int status_str_xlated; /* ignored, always 0 */
2686 {
2687 TgMenu *menu=TgCreateMenuFromMenuInfo(parent_menu, x, y, menu_info, FALSE);
2688
2689 if (menu != NULL) {
2690 menu->track_menubar = FALSE;
2691 menu->is_main_menu = TRUE;
2692 if (!RefreshMainMenu(menu)) {
2693 return TgDestroyMenu(menu, TRUE);
2694 }
2695 menu->refresh_proc = ((RefreshMenuFunc*)RefreshMainMenu);
2696 }
2697 return menu;
2698 }
2699
MainMenu()2700 int MainMenu()
2701 {
2702 int x=0, y=0, root_x=0, root_y=0;
2703 int rc=INVALID, index=INVALID;
2704 Window root_win=None, child_win=None;
2705 unsigned int status=0;
2706 TgMenu *menu=NULL;
2707
2708 Msg("");
2709 XQueryPointer(mainDisplay, rootWindow, &root_win, &child_win, &root_x,
2710 &root_y, &x, &y, &status);
2711
2712 activeMenu = MENU_MAIN;
2713 if (cmdLineTgrm2) {
2714 menu = (mainMenuInfo.create_proc)(NULL, x, y, &mainMenuInfo, 0);
2715 } else {
2716 TgMenuInfo tgmi;
2717
2718 memcpy(&tgmi, &mainMenuInfo, sizeof(TgMenuInfo));
2719 tgmi.items = gpMainMenuItemInfos;
2720 menu = (tgmi.create_proc)(NULL, x, y, &tgmi, 0);
2721 }
2722 if (menu != NULL) {
2723 index = TgMenuLoop(menu);
2724 TgDestroyMenu(menu, TRUE);
2725 }
2726 activeMenu = INVALID;
2727 if (index == INVALID || index == (-4)) return INVALID;
2728
2729 return rc;
2730 }
2731
IsPrefix(Prefix,Str,Rest)2732 int IsPrefix(Prefix, Str, Rest)
2733 char *Prefix, *Str, **Rest;
2734 {
2735 register char *c_ptr=Prefix;
2736
2737 for (*Rest=Str; *c_ptr!='\0' && **Rest!='\0'; (*Rest)++, c_ptr++) {
2738 if (**Rest != *c_ptr) {
2739 return FALSE;
2740 }
2741 }
2742 return (*c_ptr == '\0' && **Rest == DIR_SEP);
2743 }
2744
RedrawTitleWindow()2745 void RedrawTitleWindow()
2746 {
2747 int y, len, amount, left;
2748 char s[MAXPATHLENGTH], name[MAXPATHLENGTH], * c_ptr, * rest;
2749 struct BBRec bbox;
2750
2751 XClearWindow(mainDisplay, titleWindow);
2752
2753 s[0] = '\0';
2754 if (curFileDefined) {
2755 if (*curSymDir == '\0') {
2756 sprintf(name, "%s%c%s", curDir, DIR_SEP, curFileName);
2757 } else {
2758 sprintf(name, "%s%c%s", curSymDir, DIR_SEP, curFileName);
2759 }
2760 if (IsPrefix(bootDir, name, &rest)) {
2761 c_ptr = ++rest;
2762 } else {
2763 c_ptr = name;
2764 }
2765 FormatFloat(&printMag, gszMsgBox);
2766 sprintf(s, "%s:%s (%s%%)", curDomainName, c_ptr, gszMsgBox);
2767 } else {
2768 FormatFloat(&printMag, gszMsgBox);
2769 sprintf(s, "%s:%s (%s%%)", curDomainName,
2770 TgLoadCachedString(CSTID_SQUARE_BRACK_UNNAMED), gszMsgBox);
2771 }
2772 if (pageLayoutMode==PAGE_STACK && curPage!=NULL) {
2773 sprintf(&s[strlen(s)], " \"%s\"",
2774 (curPage->name==NULL) ? "" : curPage->name);
2775 }
2776 if (fileModified) {
2777 if (IsFiletUnSavable()) {
2778 sprintf(gszMsgBox, " %s",
2779 TgLoadCachedString(CSTID_SQUARE_BRACK_MODIFIED_UNSAV));
2780 } else {
2781 sprintf(gszMsgBox, " %s",
2782 TgLoadCachedString(CSTID_SQUARE_BRACK_MODIFIED));
2783 }
2784 strcat(s, gszMsgBox);
2785 }
2786 if (s[0] != '\0') {
2787 len = strlen(s);
2788 if (msgFontSet != NULL || msgFontPtr != NULL) {
2789 if (msgFontPtr != NULL) {
2790 XSetFont(mainDisplay, defaultGC, msgFontPtr->fid);
2791 }
2792 if (showVersion) {
2793 DrawMsgString(mainDisplay, titleWindow, defaultGC, 1+windowPadding,
2794 (titleWindowH>>1)+msgFontAsc+1, s, len);
2795 } else {
2796 DrawMsgString(mainDisplay, titleWindow, defaultGC, 1+windowPadding,
2797 msgFontAsc+1+windowPadding, s, len);
2798 }
2799 XSetFont(mainDisplay, defaultGC, defaultFontPtr->fid);
2800 } else {
2801 if (showVersion) {
2802 DrawMsgString(mainDisplay, titleWindow, defaultGC, 1+windowPadding,
2803 (titleWindowH>>1)+defaultFontAsc+1, s, len);
2804 } else {
2805 DrawMsgString(mainDisplay, titleWindow, defaultGC, 1+windowPadding,
2806 defaultFontAsc+1+windowPadding, s, len);
2807 }
2808 }
2809 }
2810 if (showVersion) {
2811 SetFullVersionString();
2812 strcpy(s, fullToolName);
2813
2814 len = strlen(s);
2815 if (msgFontSet != NULL || msgFontPtr != NULL) {
2816 amount = MsgTextWidth(msgFontPtr, s, len);
2817 left = ((titleWindowW-amount)>>1);
2818 if (msgFontPtr != NULL) {
2819 XSetFont(mainDisplay, defaultGC, msgFontPtr->fid);
2820 }
2821 DrawMsgString(mainDisplay, titleWindow, defaultGC, left,
2822 msgFontAsc+2+(windowPadding>>1), s, len);
2823 XSetFont(mainDisplay, defaultGC, defaultFontPtr->fid);
2824 for (y=4+(windowPadding>>1); y < (titleWindowH>>1)-4; y += 2) {
2825 XDrawLine(mainDisplay, titleWindow, defaultGC, 2+windowPadding, y,
2826 left-msgFontWidth, y);
2827 XDrawLine(mainDisplay, titleWindow, defaultGC,
2828 left+amount+msgFontWidth, y, titleWindowW-3, y);
2829 }
2830 } else {
2831 amount = defaultFontWidth * len;
2832 left = ((titleWindowW-amount)>>1);
2833 DrawMsgString(mainDisplay, titleWindow, defaultGC, left,
2834 defaultFontAsc+2+(windowPadding>>1), s, len);
2835 for (y=4+(windowPadding>>1); y < (titleWindowH>>1)-4; y += 2) {
2836 XDrawLine(mainDisplay, titleWindow, defaultGC, 2+windowPadding, y,
2837 left-defaultFontWidth, y);
2838 XDrawLine(mainDisplay, titleWindow, defaultGC,
2839 left+amount+defaultFontWidth, y, titleWindowW-3, y);
2840 }
2841 }
2842 }
2843 if (threeDLook) {
2844 bbox.ltx = 0;
2845 bbox.lty = 0;
2846 bbox.rbx = titleWindowW;
2847 bbox.rby = titleWindowH;
2848 TgDrawThreeDButton(mainDisplay, titleWindow, textMenuGC, &bbox,
2849 TGBS_RAISED, 1, FALSE);
2850 }
2851 }
2852
2853 static struct ObjRec *iconTopObj=NULL, *iconBotObj=NULL;
2854 static struct ObjRec *iconTgifObj=NULL;
2855 static int justIconified=FALSE;
2856
RedrawIconWindow()2857 void RedrawIconWindow()
2858 {
2859 register struct ObjRec *obj_ptr;
2860
2861 numRedrawBBox = 0;
2862 for (obj_ptr = iconBotObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev) {
2863 obj_ptr->tmp_parent = NULL;
2864 DrawObj(iconWindow, obj_ptr);
2865 }
2866 if (justIconified && iconTgifObj != NULL && iconTgifObj->fattr != NULL) {
2867 struct ObjRec *obj_ptr;
2868 struct AttrRec *attr_ptr;
2869
2870 justIconified = FALSE;
2871 if ((attr_ptr=FindAttrWithName(iconTgifObj,"icon_init_exec_obj=",NULL)) !=
2872 NULL && (obj_ptr=FindObjWithName(iconBotObj, iconTgifObj,
2873 attr_ptr->attr_value.s,FALSE,FALSE,NULL,NULL)) != NULL &&
2874 (attr_ptr=FindAttrWithName(obj_ptr,EXEC_ATTR,NULL)) != NULL) {
2875 int saved_intr_check_interval=intrCheckInterval;
2876 int saved_history_depth=historyDepth;
2877
2878 intrCheckInterval = 1;
2879 historyDepth = 0;
2880 ShowInterrupt(1);
2881
2882 DoExec(attr_ptr, obj_ptr);
2883
2884 HideInterrupt();
2885 intrCheckInterval = saved_intr_check_interval;
2886 historyDepth = saved_history_depth;
2887 }
2888 }
2889 justIconified = FALSE;
2890 }
2891
2892 static char iconFileName[] = "tgificon";
2893
2894 static
InitIcon()2895 void InitIcon()
2896 {
2897 struct ObjRec *obj_ptr, *saved_tgif_obj;
2898 char s[MAXPATHLENGTH], *c_ptr, msg[MAXSTRING], ext_str[MAXPATHLENGTH];
2899 FILE *fp=NULL;
2900 int ltx=0, lty=0, rbx=0, rby=0, seen_obj=FALSE;
2901 int dx, dy, w, h, len, ext_len, x, y, read_status;
2902 unsigned int icon_w, icon_h;
2903 XSizeHints sizehints;
2904 int tmp_linenum;
2905 char tmp_filename[MAXPATHLENGTH], tmp_filefullpath[MAXPATHLENGTH];
2906
2907 DelAllPages();
2908 lastPageNum = 1;
2909 InitPage();
2910
2911 iconWindowCreated = FALSE;
2912 if (((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"UseWMIconPixmap")) == NULL) ||
2913 UtilStrICmp(c_ptr,"false") != 0) {
2914 return;
2915 }
2916 if (((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"NoTgifIcon")) != NULL)
2917 && UtilStrICmp(c_ptr,"True") == 0) {
2918 return;
2919 }
2920 strcpy(s, drawPath);
2921 strcat(s, DIR_SEP_STR);
2922 if ((c_ptr=getenv("TGIFICON")) == NULL) {
2923 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"TGIFICON")) != NULL) {
2924 if (*c_ptr == DIR_SEP) {
2925 strcpy(s, c_ptr);
2926 } else {
2927 strcat(s, c_ptr);
2928 }
2929 } else {
2930 strcat(s, iconFileName);
2931 }
2932 } else if (((int)strlen(c_ptr)) >= 200) {
2933 /* too long, must be an error */
2934 strcat(s, iconFileName);
2935 } else if (*c_ptr == DIR_SEP) {
2936 strcpy(s, c_ptr);
2937 } else {
2938 strcat(s, c_ptr);
2939 }
2940 sprintf(ext_str, ".%s", OBJ_FILE_EXT);
2941 ext_len = strlen(ext_str);
2942 len = strlen(s);
2943
2944 if (len < ext_len || strcmp(&s[len-ext_len],ext_str) != 0) {
2945 sprintf(&(s[len]), ".%s", OBJ_FILE_EXT);
2946 }
2947 if ((fp=fopen(s, "r")) == NULL) {
2948 /*
2949 * fprintf(stderr, "Warning: Cannot open the tgif icon file '%s'.\n", s);
2950 */
2951 return;
2952 }
2953
2954 strcpy(tmp_filefullpath, scanFileFullPath);
2955 strcpy(tmp_filename, scanFileName);
2956 tmp_linenum = scanLineNum;
2957 UtilStrCpyN(scanFileFullPath, sizeof(scanFileFullPath), s);
2958 strcpy(scanFileName, s);
2959 scanLineNum = 0;
2960
2961 saved_tgif_obj = tgifObj;
2962 InitTgifObj();
2963
2964 importingFile = TRUE; /* ignore the 'state' predicate */
2965 importingIconFile = TRUE; /* read the 'file_attr' predicate */
2966 readingPageNum = loadedCurPageNum = 0;
2967 foundGoodStateObject = FALSE;
2968 while ((read_status=ReadObj(fp, &obj_ptr)) == TRUE) {
2969 if (obj_ptr != NULL) {
2970 AddObj(NULL, topObj, obj_ptr);
2971 if (!seen_obj) {
2972 seen_obj = TRUE;
2973 ltx = obj_ptr->bbox.ltx; lty = obj_ptr->bbox.lty;
2974 rbx = obj_ptr->bbox.rbx; rby = obj_ptr->bbox.rby;
2975 } else {
2976 if (obj_ptr->bbox.ltx < ltx) ltx = obj_ptr->bbox.ltx;
2977 if (obj_ptr->bbox.lty < lty) lty = obj_ptr->bbox.lty;
2978 if (obj_ptr->bbox.rbx > rbx) rbx = obj_ptr->bbox.rbx;
2979 if (obj_ptr->bbox.rby > rby) rby = obj_ptr->bbox.rby;
2980 }
2981 }
2982 }
2983 strcpy(scanFileFullPath, tmp_filefullpath);
2984 strcpy(scanFileName, tmp_filename);
2985 scanLineNum = tmp_linenum;
2986
2987 importingFile = FALSE;
2988 importingIconFile = FALSE;
2989
2990 fclose(fp);
2991
2992 if (read_status == INVALID) {
2993 sprintf(msg, TgLoadString(STID_ICON_FILEVER_TOO_LARGE), fileVersion);
2994 Msg(s);
2995 CleanUpTgifObj();
2996 tgifObj = saved_tgif_obj;
2997 return;
2998 }
2999
3000 w = rbx - ltx;
3001 h = rby - lty;
3002 if (w > iconWindowW) {
3003 dx = -ltx;
3004 iconWindowW = w;
3005 } else {
3006 dx = -ltx+((iconWindowW-w)>>1);
3007 }
3008 if (h > iconWindowH) {
3009 dy = -lty;
3010 iconWindowH = h;
3011 } else {
3012 dy = -lty+((iconWindowH-h)>>1);
3013 }
3014 for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=obj_ptr->next) {
3015 MoveObj(obj_ptr, dx, dy);
3016 }
3017 iconTgifObj = tgifObj;
3018 tgifObj = saved_tgif_obj;
3019
3020 iconTopObj = topObj;
3021 iconBotObj = botObj;
3022 curPage->top = curPage->bot = topObj = botObj = NULL;
3023
3024 CleanUpPage();
3025
3026 sizehints.x = 0;
3027 sizehints.y = 0;
3028
3029 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"IconGeometry")) != NULL) {
3030 int bitmask=XParseGeometry(c_ptr, &x, &y, &icon_w, &icon_h);
3031
3032 if ((bitmask & XValue) && (bitmask & YValue)) {
3033 if (bitmask & XValue) sizehints.x = x;
3034 if (bitmask & YValue) sizehints.y = y;
3035 if (bitmask & XNegative) sizehints.x += DisplayWidth(mainDisplay,
3036 mainScreen) - iconWindowW - (brdrW<<1) - 1;
3037 if (bitmask & YNegative) sizehints.y += DisplayHeight(mainDisplay,
3038 mainScreen) - iconWindowH - (brdrW<<1) - 1;
3039 }
3040 }
3041 if ((iconBaseWindow = XCreateSimpleWindow(mainDisplay, rootWindow,
3042 sizehints.x, sizehints.y, iconWindowW+(brdrW<<1),
3043 iconWindowH+(brdrW<<1), brdrW, myBorderPixel, myBgPixel)) == 0) {
3044 FailToCreateWindowMessage("InitIcon()", NULL, TRUE);
3045 }
3046 if ((iconWindow = XCreateSimpleWindow(mainDisplay, iconBaseWindow, 0, 0,
3047 iconWindowW, iconWindowH, brdrW, myBorderPixel, myBgPixel)) == 0) {
3048 FailToCreateWindowMessage("InitIcon()", NULL, TRUE);
3049 }
3050 XStoreName(mainDisplay, iconBaseWindow, TOOL_NAME);
3051
3052 XSelectInput(mainDisplay, iconBaseWindow, StructureNotifyMask |
3053 VisibilityChangeMask);
3054 if (((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"DoubleClickUnIconify")) !=
3055 NULL) && UtilStrICmp(c_ptr,"True") == 0) {
3056 XSelectInput(mainDisplay, iconWindow,
3057 ButtonPressMask | KeyPressMask | ExposureMask);
3058 } else {
3059 XSelectInput(mainDisplay, iconWindow, KeyPressMask | ExposureMask);
3060 }
3061 iconWindowCreated = TRUE;
3062 }
3063
InitTitle()3064 void InitTitle()
3065 {
3066 InitIcon();
3067 }
3068
InitMenu()3069 void InitMenu()
3070 {
3071 XGCValues values;
3072 char *c_ptr=NULL;
3073
3074 values.foreground = myFgPixel;
3075 values.background = (threeDLook ? myLtGryPixel : myBgPixel);
3076 values.fill_style = FillSolid;
3077 /*
3078 * If (menuFontSet) is not NULL, it's okay to set values.font to
3079 * whatever because it won't get used.
3080 */
3081 values.font = (menuFontPtr==NULL ? defaultFontPtr->fid : menuFontPtr->fid);
3082 textMenuGC = XCreateGC(mainDisplay, rootWindow,
3083 GCForeground | GCBackground | GCFillStyle | GCFont, &values);
3084
3085 values.foreground = myBgPixel;
3086 values.background = myFgPixel;
3087 values.fill_style = FillStippled;
3088 rvPixmapMenuGC = XCreateGC(mainDisplay, rootWindow,
3089 GCForeground | GCBackground | GCFillStyle | GCFont, &values);
3090
3091 InitMainMenu();
3092
3093 BuildMenubarInfo();
3094
3095 separatorHeight = (threeDLook ? SEPARATOR_PADDING+2 : SEPARATOR_PADDING+1);
3096
3097 deleteCmdAsCut = FALSE;
3098 if (((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"DeleteCmdAsCut")) != NULL) &&
3099 UtilStrICmp(c_ptr,"true") == 0) {
3100 /* this X default is obsolete */
3101 deleteCmdAsCut = TRUE;
3102 }
3103 memset(&gstMenuDontSendCommandInfo, 0, sizeof(MenuDontSendCommandInfo));
3104 }
3105
CleanUpMenu()3106 void CleanUpMenu()
3107 {
3108 struct ObjRec *saved_top_obj, *saved_bot_obj, *saved_tgif_obj;
3109
3110 XFreeGC(mainDisplay, textMenuGC);
3111 XFreeGC(mainDisplay, rvPixmapMenuGC);
3112 CleanUpMainMenu();
3113 if (stackingWins != NULL) {
3114 free(stackingWins);
3115 stackingWins = NULL;
3116 }
3117 if (iconTgifObj != NULL) {
3118 saved_tgif_obj = tgifObj;
3119 tgifObj = iconTgifObj;
3120 CleanUpTgifObj();
3121 tgifObj = saved_tgif_obj;
3122 }
3123 if (iconTopObj != NULL) {
3124 saved_top_obj = topObj;
3125 saved_bot_obj = botObj;
3126 topObj = iconTopObj;
3127 botObj = iconBotObj;
3128 DelAllObj();
3129 topObj = saved_top_obj;
3130 botObj = saved_bot_obj;
3131 }
3132 if (check_bits == NULL) { }
3133 if (submenu_bits == NULL) { }
3134
3135 if (!cmdLineTgrm2) {
3136 free(gpMenubarItemInfos);
3137 gpMenubarItemInfos = NULL;
3138 gnNumMenubarItems = 0;
3139
3140 free(gpMainMenuItemInfos);
3141 gpMainMenuItemInfos = NULL;
3142 gnNumMainMenuItems = 0;
3143 }
3144 }
3145
SaveDrawWinInfo()3146 void SaveDrawWinInfo()
3147 {
3148 savedZoomScale = zoomScale;
3149 savedZoomedIn = zoomedIn;
3150 savedDrawOrigX = drawOrigX;
3151 savedDrawOrigY = drawOrigY;
3152 savedDrawWinW = drawWinW;
3153 savedDrawWinH = drawWinH;
3154 savedFileModified = fileModified;
3155 }
3156
UnIconify()3157 void UnIconify()
3158 {
3159 register int j, i;
3160
3161 if (!iconWindowShown) return;
3162
3163 iconWindowShown = FALSE;
3164
3165 zoomScale = savedZoomScale;
3166 zoomedIn = savedZoomedIn;
3167 drawOrigX = savedDrawOrigX;
3168 drawOrigY = savedDrawOrigY;
3169 drawWinW = savedDrawWinW;
3170 drawWinH = savedDrawWinH;
3171 fileModified = savedFileModified;
3172 UpdDrawWinBBox();
3173 SetDefaultDrawWinClipRecs();
3174
3175 #ifdef notdef
3176 XUnmapWindow(mainDisplay, iconWindow);
3177 #endif
3178 if (iconWindowCreated) XUnmapWindow(mainDisplay, iconBaseWindow);
3179 XMapWindow(mainDisplay, mainWindow);
3180
3181 for (i=0; i < numExtraWins; i++) {
3182 if (extraWinInfo[i].raise && !extraWinInfo[i].mapped &&
3183 extraWinInfo[i].window != None) {
3184 XMapRaised(mainDisplay, extraWinInfo[i].window);
3185 extraWinInfo[i].mapped = TRUE;
3186 }
3187 }
3188 for (i=0; i < numStacking; i++) {
3189 for (j=0; j < numExtraWins; j++) {
3190 if (extraWinInfo[j].raise && extraWinInfo[j].window==stackingWins[i]) {
3191 extraWinInfo[j].mapped = TRUE;
3192 break;
3193 }
3194 }
3195 XMapRaised(mainDisplay, stackingWins[i]);
3196 }
3197 XFlush(mainDisplay);
3198 XSync(mainDisplay, False);
3199 }
3200
Iconify()3201 void Iconify()
3202 {
3203 register int i;
3204
3205 if (iconWindowShown) return;
3206
3207 iconWindowShown = TRUE;
3208
3209 SaveDrawWinInfo();
3210 zoomScale = 0;
3211 zoomedIn = FALSE;
3212 drawOrigX = 0;
3213 drawOrigY = 0;
3214 drawWinW = iconWindowW;
3215 drawWinH = iconWindowH;
3216 UpdDrawWinBBox();
3217 SetDefaultIconWinClipRecs();
3218
3219 justIconified = TRUE;
3220
3221 #ifdef notdef
3222 XUnmapWindow(mainDisplay, mainWindow);
3223 #endif
3224
3225 SaveStackingOrder();
3226
3227 if (pinnedMainMenu) XUnmapWindow(mainDisplay, mainMenuWindow);
3228 for (i = 0; i < numExtraWins; i++) {
3229 if (extraWinInfo[i].raise && extraWinInfo[i].mapped &&
3230 extraWinInfo[i].window != None) {
3231 XUnmapWindow(mainDisplay, extraWinInfo[i].window);
3232 extraWinInfo[i].mapped = FALSE;
3233 }
3234 }
3235 if (iconWindowCreated) {
3236 XMapWindow(mainDisplay, iconBaseWindow);
3237 XMapWindow(mainDisplay, iconWindow);
3238 }
3239 }
3240
3241 static int iconJustClicked=FALSE;
3242 static Time iconClickTime;
3243
IconEventHandler(input)3244 void IconEventHandler(input)
3245 XEvent *input;
3246 {
3247 XEvent ev;
3248 Time click_time;
3249
3250 if (input->xany.window == iconWindow && input->type == ButtonPress) {
3251 XButtonEvent *button_ev=(&(input->xbutton));
3252
3253 if (iconWindowShown && !justIconified && button_ev->button == Button2 &&
3254 (button_ev->state & (ShiftMask | ControlMask))) {
3255 justIconified = TRUE;
3256 RedrawIconWindow();
3257 } else {
3258 click_time = input->xbutton.time;
3259 if (iconJustClicked &&
3260 (click_time-iconClickTime)<doubleClickInterval) {
3261 iconJustClicked = FALSE;
3262 UnIconify();
3263 } else {
3264 iconJustClicked = TRUE;
3265 iconClickTime = click_time;
3266 }
3267 }
3268 } else if (input->xany.window==iconBaseWindow && input->type==UnmapNotify) {
3269 UnIconify();
3270 } else if (input->xany.window==iconBaseWindow && input->type==MapNotify) {
3271 Iconify();
3272 /*
3273 } else if (input->xany.window==iconBaseWindow && (input->type==MapNotify ||
3274 input->type == VisibilityNotify && input->xvisibility.state ==
3275 VisibilityUnobscured)) {
3276 Iconify();
3277 */
3278 } else if (input->xany.window == iconWindow && input->type == Expose) {
3279 if (!iconWindowShown) return;
3280
3281 while (XCheckWindowEvent(mainDisplay, iconWindow, ExposureMask, &ev)) ;
3282 while (XCheckWindowEvent(mainDisplay, iconBaseWindow,
3283 StructureNotifyMask, &ev)) ;
3284 RedrawIconWindow();
3285 }
3286 }
3287
TitleEventHandler(input)3288 void TitleEventHandler(input)
3289 XEvent *input;
3290 {
3291 XEvent ev;
3292
3293 if (input->type == Expose) {
3294 XSync(mainDisplay, False);
3295 while (XCheckWindowEvent(mainDisplay, titleWindow, ExposureMask, &ev)) ;
3296 RedrawTitleWindow();
3297 } else if (input->type == EnterNotify) {
3298 SetMouseStatus(TgLoadCachedString(CSTID_PARANED_NONE),
3299 TgLoadCachedString(CSTID_MAIN_MENU),
3300 TgLoadCachedString(CSTID_MAIN_MENU));
3301 } else if (input->type == ButtonPress && (input->xbutton.button == Button2 ||
3302 input->xbutton.button == Button3)) {
3303 MainMenu();
3304 }
3305 }
3306
CalcMenubarWindowHeight()3307 void CalcMenubarWindowHeight()
3308 /* Given menubarWindowW, set manubarWindowH to fit everything */
3309 {
3310 int i, x=0, w=0, h=0, gap=0, padding=(windowPadding>>1);
3311
3312 BuildMenubarInfo();
3313
3314 if (menuFontSet != NULL || menuFontPtr != NULL) {
3315 x = menuFontWidth;
3316 h = menuFontHeight;
3317 gap = (x<<1);
3318 x += padding;
3319 h += padding;
3320 for (i=0; i < gnNumMenubarItems; i++) {
3321 w = MenuTextWidth(menuFontPtr, _(gpMenubarItemInfos[i].menu_str),
3322 strlen(_(gpMenubarItemInfos[i].menu_str)));
3323 if ((!noMinWinSize || !gnMinimalMenubar || gnAutoWrapMenubar) &&
3324 x+w+padding >= menubarWindowW) {
3325 x = menuFontWidth+padding;
3326 h += menuFontHeight+padding;
3327 }
3328 x += w+gap+padding;
3329 }
3330 x += (padding<<1);
3331 h += (padding<<1);
3332 } else {
3333 x = 2;
3334 h = initialMenubarWindowH;
3335 gap = defaultFontWidth+(defaultFontWidth>>1);
3336 x += padding;
3337 h += padding;
3338 for (i=0; i < gnNumMenubarItems; i++) {
3339 w = defaultFontWidth*strlen(_(gpMenubarItemInfos[i].menu_str));
3340 if ((!noMinWinSize || !gnMinimalMenubar || gnAutoWrapMenubar) &&
3341 x+w+padding >= menubarWindowW) {
3342 x = 2+padding;
3343 h += initialMenubarWindowH+padding;
3344 }
3345 x += w+gap+padding;
3346 }
3347 x += (padding<<1);
3348 h += (padding<<1);
3349 }
3350 menubarWindowH = h;
3351 }
3352
3353 static
HighLightMenubarString(item_str,bbox,highlight)3354 void HighLightMenubarString(item_str, bbox, highlight)
3355 char *item_str;
3356 struct BBRec *bbox;
3357 int highlight;
3358 /* HighLightMenubarString() will use _(item_str) internally */
3359 {
3360 if (threeDLook) {
3361 struct BBRec real_bbox;
3362
3363 real_bbox.ltx = bbox->ltx-2;
3364 real_bbox.lty = bbox->lty;
3365 real_bbox.rbx = bbox->rbx+2;
3366 real_bbox.rby = bbox->rby+1;
3367 if (highlight) {
3368 TgDrawThreeDButton(mainDisplay, menubarWindow, textMenuGC, &real_bbox,
3369 TGBS_RAISED, 1, FALSE);
3370 } else {
3371 TgClearThreeDButton(mainDisplay, menubarWindow, textMenuGC, &real_bbox,
3372 1);
3373 }
3374 } else {
3375 int fg_pixel=(highlight ? myBgPixel : myFgPixel);
3376 int bg_pixel=(highlight ? myFgPixel :
3377 (threeDLook?myLtGryPixel:myBgPixel));
3378
3379 XSetForeground(mainDisplay, textMenuGC, bg_pixel);
3380 XFillRectangle(mainDisplay, menubarWindow, textMenuGC,
3381 bbox->ltx-2, bbox->lty, bbox->rbx-bbox->ltx+4, bbox->rby-bbox->lty);
3382 XSetForeground(mainDisplay, textMenuGC, fg_pixel);
3383 if (menuFontSet != NULL || menuFontPtr != NULL) {
3384 DrawMenuString(mainDisplay, menubarWindow, textMenuGC,
3385 bbox->ltx+(menuFontWidth>>1), menuFontAsc+bbox->lty,
3386 _(item_str), strlen(_(item_str)));
3387 } else {
3388 DrawMenuString(mainDisplay, menubarWindow, textMenuGC, bbox->ltx,
3389 defaultFontAsc+bbox->lty, _(item_str), strlen(_(item_str)));
3390 }
3391 }
3392 }
3393
RedrawMenubarWindow()3394 void RedrawMenubarWindow()
3395 {
3396 int i, x=0, y=0, w=0, len=0, gap=0, padding=(windowPadding>>1);
3397 struct BBRec bbox;
3398
3399 XClearWindow(mainDisplay, menubarWindow);
3400
3401 XSetForeground(mainDisplay, textMenuGC, myFgPixel);
3402 if (menuFontSet != NULL || menuFontPtr != NULL) {
3403 x = menuFontWidth;
3404 y = menuFontAsc;
3405 gap = (x<<1);
3406 x += padding;
3407 y += padding;
3408
3409 for (i=0; i < gnNumMenubarItems; i++) {
3410 len = strlen(_(gpMenubarItemInfos[i].menu_str));
3411 w = MenuTextWidth(menuFontPtr, _(gpMenubarItemInfos[i].menu_str), len);
3412 if ((!noMinWinSize || !gnMinimalMenubar || gnAutoWrapMenubar) &&
3413 x+w+padding >= menubarWindowW) {
3414 x = menuFontWidth+padding;
3415 y += menuFontHeight+padding;
3416 }
3417 if (!colorDisplay && gpMenubarItemInfos[i].cmdid == MENU_COLOR) {
3418 /* disable color menu -- at this point, threeDLook must be FALSE */
3419 DrawMenuString(mainDisplay, menubarWindow, revGrayGC, x+padding,
3420 y+padding, _(gpMenubarItemInfos[i].menu_str), len);
3421 } else {
3422 DrawMenuString(mainDisplay, menubarWindow, textMenuGC, x+padding,
3423 y+padding, _(gpMenubarItemInfos[i].menu_str), len);
3424 }
3425 x += w+gap+padding;
3426 }
3427 } else {
3428 x = 2;
3429 y = defaultFontAsc;
3430 gap = defaultFontWidth+(defaultFontWidth>>1);
3431 x += padding;
3432 y += padding;
3433
3434 for (i=0; i < gnNumMenubarItems; i++) {
3435 len = strlen(_(gpMenubarItemInfos[i].menu_str));
3436 w = defaultFontWidth*len;
3437 if ((!noMinWinSize || !gnMinimalMenubar || gnAutoWrapMenubar) &&
3438 x+w+padding >= menubarWindowW) {
3439 x = 2+padding;
3440 y += initialMenubarWindowH+padding;
3441 }
3442 if (!colorDisplay && gpMenubarItemInfos[i].cmdid == MENU_COLOR) {
3443 /* disable color menu -- at this point, threeDLook must be FALSE */
3444 DrawMenuString(mainDisplay, menubarWindow, revGrayGC, x+padding,
3445 y+padding, _(gpMenubarItemInfos[i].menu_str), len);
3446 } else {
3447 DrawMenuString(mainDisplay, menubarWindow, textMenuGC, x+padding,
3448 y+padding, _(gpMenubarItemInfos[i].menu_str), len);
3449 }
3450 x += w+gap+padding;
3451 }
3452 }
3453 if (threeDLook) {
3454 bbox.ltx = 0;
3455 bbox.lty = 0;
3456 bbox.rbx = menubarWindowW;
3457 bbox.rby = menubarWindowH;
3458 TgDrawThreeDButton(mainDisplay, menubarWindow, textMenuGC, &bbox,
3459 TGBS_RAISED, 1, FALSE);
3460 }
3461 if (excludeMenubarIndex != INVALID) {
3462 struct BBRec text_bbox;
3463 int exclude_gap=((menuFontSet==NULL && menuFontPtr==NULL) ?
3464 (defaultFontWidth<<1) : (menuFontWidth<<1));
3465
3466 SetBBRec(&text_bbox,
3467 excludeMenubarWinBBox.ltx+2+windowPadding,
3468 excludeMenubarWinBBox.lty+2+windowPadding,
3469 excludeMenubarWinBBox.rbx-2-windowPadding-exclude_gap,
3470 excludeMenubarWinBBox.rby-2-windowPadding);
3471 /* HighLightMenubarString() doesn't need _() */
3472 HighLightMenubarString(gpMenubarItemInfos[excludeMenubarIndex].menu_str,
3473 &text_bbox, TRUE);
3474 }
3475 }
3476
3477 static
PullDownFromMenubar(index,x,y,text_bbox)3478 int PullDownFromMenubar(index, x, y, text_bbox)
3479 int index, x, y;
3480 struct BBRec *text_bbox;
3481 {
3482 int rc=BAD;
3483 int exclude_gap=((menuFontSet==NULL && menuFontPtr==NULL) ?
3484 (defaultFontWidth<<1) : (menuFontWidth<<1));
3485
3486 while (rc == BAD) {
3487 if (index != INVALID) {
3488 /* HighLightMenubarString() doesn't need _() */
3489 HighLightMenubarString(gpMenubarItemInfos[index].menu_str, text_bbox,
3490 TRUE);
3491 excludeMenubarWinBBox.ltx = text_bbox->ltx-2-windowPadding;
3492 excludeMenubarWinBBox.lty = text_bbox->lty-2-windowPadding;
3493 excludeMenubarWinBBox.rbx = text_bbox->rbx+exclude_gap+2+windowPadding;
3494 excludeMenubarWinBBox.rby = text_bbox->rby+2+windowPadding;
3495 excludeMenubarIndex = index;
3496 }
3497 switch (gpMenubarItemInfos[index].cmdid) {
3498 case MENU_FILE: rc = FileMenu(x, y, TRUE); break;
3499 case MENU_EDIT: rc = EditMenu(x, y, TRUE); break;
3500 case MENU_LAYOUT: rc = LayoutMenu(x, y, TRUE); break;
3501 case MENU_ARRANGE: rc = ArrangeMenu(x, y, TRUE); break;
3502 case MENU_PROPERTIES: rc = PropertiesMenu(x, y, TRUE); break;
3503 case MENU_MOVEMODE: rc = MoveModeMenu(x, y, TRUE); break;
3504 case MENU_PAGE: rc = PageMenu(x, y, TRUE); break;
3505 case MENU_PAGELAYOUT: rc = PageLayoutMenu(x, y, TRUE); break;
3506 case MENU_HORIALIGN: rc = HoriAlignMenu(x, y, TRUE); break;
3507 case MENU_VERTALIGN: rc = VertAlignMenu(x, y, TRUE); break;
3508 case MENU_FONT: rc = FontMenu(x, y, TRUE); break;
3509 case MENU_STYLE: rc = StyleMenu(x, y, TRUE); break;
3510 case MENU_SIZE: rc = SizeMenu(x, y, TRUE); break;
3511 case MENU_SHAPE: rc = ShapeMenu(x, y, TRUE); break;
3512 case MENU_STRETCHTEXT: rc = StretchableTextModeMenu(x, y, TRUE); break;
3513 case MENU_LINEDASH: rc = LineDashMenu(x, y, TRUE); break;
3514 case MENU_LINESTYLE: rc = LineStyleMenu(x, y, TRUE); break;
3515 case MENU_LINETYPE: rc = LineTypeMenu(x, y, TRUE); break;
3516 case MENU_LINEWIDTH: rc = LineWidthMenu(x, y, TRUE); break;
3517 case MENU_FILL: rc = FillMenu(x, y, TRUE); break;
3518 case MENU_PEN: rc = PenMenu(x, y, TRUE); break;
3519 case MENU_TRANSPAT: rc = TransPatModeMenu(x, y, TRUE); break;
3520 case MENU_COLOR: rc = ColorMenu(x, y, TRUE); break;
3521 case MENU_IMAGEPROC: rc = ImageProcMenu(x, y, TRUE); break;
3522 case MENU_NAVIGATE: rc = NavigateMenu(x, y, TRUE); break;
3523 case MENU_SPECIAL: rc = SpecialMenu(x, y, TRUE); break;
3524 case MENU_HELP: rc = HelpMenu(x, y, TRUE); break;
3525 case MENU_TANGRAM2:
3526 if (cmdLineTgrm2) {
3527 rc = Tangram2Menu(x, y, TRUE);
3528 }
3529 break;
3530 }
3531 if (index != INVALID) {
3532 /* HighLightMenubarString() doesn't need _() */
3533 HighLightMenubarString(gpMenubarItemInfos[index].menu_str, text_bbox,
3534 FALSE);
3535 }
3536 if (rc == BAD) {
3537 Window root_win, child_win;
3538 int mouse_x, mouse_y, root_x, root_y;
3539 unsigned int status;
3540
3541 XQueryPointer(mainDisplay, menubarWindow, &root_win, &child_win,
3542 &root_x, &root_y, &mouse_x, &mouse_y, &status);
3543 index = WhichMenubarItem(mouse_x, mouse_y, &x, &y, text_bbox);
3544 if (!(status & BUTTONSMASK) && index == (-1)) {
3545 return INVALID;
3546 }
3547 } else if (rc == (-4)) {
3548 return INVALID;
3549 } else if (index != MENU_FILE) {
3550 return INVALID;
3551 }
3552 }
3553 return rc;
3554 }
3555
3556 static int curRaisedMenuItem=INVALID;
3557
MenubarEventHandler(input)3558 int MenubarEventHandler(input)
3559 XEvent *input;
3560 {
3561 XEvent ev;
3562 int rc=INVALID;
3563
3564 if (input->type == Expose) {
3565 XSync(mainDisplay, False);
3566 while (XCheckWindowEvent(mainDisplay,menubarWindow,ExposureMask,&ev)) ;
3567 RedrawMenubarWindow();
3568 } else if (input->type == EnterNotify || input->type == LeaveNotify) {
3569 SetMouseStatus("", "", "");
3570 if (curRaisedMenuItem != INVALID) {
3571 struct BBRec text_bbox;
3572
3573 GetMenubarItemInfo(curRaisedMenuItem, NULL, NULL, &text_bbox);
3574 /* HighLightMenubarString() doesn't need _() */
3575 HighLightMenubarString(gpMenubarItemInfos[curRaisedMenuItem].menu_str,
3576 &text_bbox, FALSE);
3577 curRaisedMenuItem = INVALID;
3578 }
3579 } else if (input->type == MotionNotify) {
3580 int index;
3581
3582 index = WhichMenubarItem(input->xmotion.x, input->xmotion.y,
3583 NULL, NULL, NULL);
3584 if (index == INVALID) {
3585 SetMouseStatusToAllNone();
3586 } else {
3587 SetMouseStatus("", _(gpMenubarItemInfos[index].status_str), "");
3588 }
3589 if (threeDLook) {
3590 if (index != curRaisedMenuItem) {
3591 struct BBRec text_bbox;
3592
3593 if (curRaisedMenuItem != INVALID) {
3594 GetMenubarItemInfo(curRaisedMenuItem, NULL, NULL, &text_bbox);
3595 /* HighLightMenubarString() doesn't need _() */
3596 HighLightMenubarString(
3597 gpMenubarItemInfos[curRaisedMenuItem].menu_str,
3598 &text_bbox, FALSE);
3599 curRaisedMenuItem = INVALID;
3600 }
3601 if (index != INVALID) {
3602 GetMenubarItemInfo(index, NULL, NULL, &text_bbox);
3603 /* HighLightMenubarString() doesn't need _() */
3604 HighLightMenubarString(gpMenubarItemInfos[index].menu_str,
3605 &text_bbox, TRUE);
3606 curRaisedMenuItem = index;
3607 }
3608 }
3609 }
3610 XSync(mainDisplay, False);
3611 while (XCheckWindowEvent(mainDisplay, menubarWindow, PointerMotionMask,
3612 &ev)) ;
3613 } else if (input->type == ButtonPress) {
3614 int win_x, win_y, index;
3615 struct BBRec text_bbox;
3616
3617 index = WhichMenubarItem(input->xbutton.x, input->xbutton.y,
3618 &win_x, &win_y, &text_bbox);
3619 if (index == INVALID) {
3620 SetMouseStatusToAllNone();
3621 } else {
3622 SaveStatusStrings();
3623 rc = PullDownFromMenubar(index, win_x, win_y, &text_bbox);
3624 RestoreStatusStrings();
3625 SetMouseStatus(NULL, NULL, NULL);
3626 SetBBRec(&excludeMenubarWinBBox, -1, -1, -1, -1);
3627 excludeMenubarIndex = INVALID;
3628 }
3629 if (threeDLook) {
3630 if (index != curRaisedMenuItem) {
3631 struct BBRec text_bbox;
3632
3633 if (curRaisedMenuItem != INVALID) {
3634 GetMenubarItemInfo(curRaisedMenuItem, NULL, NULL, &text_bbox);
3635 /* HighLightMenubarString() doesn't need _() */
3636 HighLightMenubarString(
3637 gpMenubarItemInfos[curRaisedMenuItem].menu_str,
3638 &text_bbox, FALSE);
3639 curRaisedMenuItem = INVALID;
3640 }
3641 GetMenubarItemInfo(index, NULL, NULL, &text_bbox);
3642 /* HighLightMenubarString() doesn't need _() */
3643 HighLightMenubarString(gpMenubarItemInfos[index].menu_str,
3644 &text_bbox, TRUE);
3645 curRaisedMenuItem = index;
3646 }
3647 }
3648 XSync(mainDisplay, False);
3649 while (XCheckWindowEvent(mainDisplay, menubarWindow, ButtonPressMask,
3650 &ev)) ;
3651 }
3652 return rc;
3653 }
3654