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/mainmenu.c,v 1.8 2011/05/16 16:21:58 william Exp $
19 */
20
21 #define _INCLUDE_FROM_MAINMENU_C_
22
23 #include "tgifdefs.h"
24
25 #include "align.e"
26 #include "choice.e"
27 #include "color.e"
28 #include "cursor.e"
29 #include "dialog.e"
30 #include "edit.e"
31 #include "file.e"
32 #include "font.e"
33 #include "grid.e"
34 #include "help.e"
35 #include "imgproc.e"
36 #include "mainloop.e"
37 #include "mainmenu.e"
38 #include "menu.e"
39 #include "menuinfo.e"
40 #include "msg.e"
41 #include "navigate.e"
42 #include "obj.e"
43 #include "page.e"
44 #include "pattern.e"
45 #include "raster.e"
46 #include "setup.e"
47 #include "shape.e"
48 #include "special.e"
49 #include "stretch.e"
50 #include "strtbl.e"
51 #include "tangram2.e"
52 #include "text.e"
53 #include "util.e"
54
55 #define DEF_MAINMENUPINDIST 80
56
57 int pinnedMainMenu=FALSE;
58 int mainMenuPinDistance=DEF_MAINMENUPINDIST;
59 Window mainMenuWindow=None;
60
61 int numStacking=0;
62 Window *stackingWins=NULL;
63
64 int titledPinnedMenu=TRUE;
65 int btn3PopupModeMenu=FALSE;
66
67 static int mainMenuX=0;
68 static int mainMenuY=0;
69 static int mainMenuW=0;
70 static int mainMenuH=0;
71
72 typedef struct SubMenuRec {
73 Window win;
74 int x, y, w, h, extra_index;
75 } * SubMenuRecPtr;
76
77 static struct SubMenuRec subMenuInfo[MAXMENUS+1];
78
79 static int savedMainWinX, savedMainWinY;
80
81 static
InitPinnedMenus()82 void InitPinnedMenus()
83 {
84 int i;
85
86 for (i=0; i < MAXMENUS+1; i++) subMenuInfo[i].win = None;
87 }
88
InitMainMenu()89 void InitMainMenu()
90 {
91 int menu_w, menu_h;
92 int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
93 char *c_ptr;
94 XWMHints wmhints;
95 XSizeHints sizehints;
96 XSetWindowAttributes win_attrs;
97
98 mainMenuPinDistance = DEF_MAINMENUPINDIST;
99 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"MainMenuPinDistance")) !=
100 NULL) {
101 mainMenuPinDistance = atoi(c_ptr);
102 if (mainMenuPinDistance <= 0) {
103 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_VALUE),
104 TOOL_NAME, "MainMenuPinDistance", c_ptr, DEF_MAINMENUPINDIST);
105 fprintf(stderr, "%s\n", gszMsgBox);
106 mainMenuPinDistance = DEF_MAINMENUPINDIST;
107 }
108 }
109 pinnedMainMenu = FALSE;
110
111 btn3PopupModeMenu = FALSE;
112 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"Btn3PopupModeMenu")) != NULL &&
113 UtilStrICmp(c_ptr, "true") == 0) {
114 fprintf(stderr, TgLoadString(STID_NAMED_XDEF_IS_OBSOLETE), TOOL_NAME,
115 "Btn3PopupModeMenu");
116 fprintf(stderr, "\n");
117 }
118 menuRowsBeforeScroll = 20;
119 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"MenuRowsBeforeScroll")) !=
120 NULL) {
121 /* well, this is really not used, yet */
122 menuRowsBeforeScroll = atoi(c_ptr);
123 if (menuRowsBeforeScroll <= 0) {
124 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_VALUE),
125 TOOL_NAME, "MenuRowsBeforeScroll", c_ptr, 20);
126 fprintf(stderr, "%s\n", gszMsgBox);
127 menuRowsBeforeScroll = 20;
128 }
129 }
130 menuColsBeforeScroll = 26;
131 if ((c_ptr=XGetDefault(mainDisplay,TOOL_NAME,"MenuColsBeforeScroll")) !=
132 NULL) {
133 /* well, this is really not used, yet */
134 menuColsBeforeScroll = atoi(c_ptr);
135 if (menuColsBeforeScroll <= 0) {
136 sprintf(gszMsgBox, TgLoadString(STID_INVALID_XDEF_USE_ALT_VALUE),
137 TOOL_NAME, "MenuColsBeforeScroll", c_ptr, 26);
138 fprintf(stderr, "%s\n", gszMsgBox);
139 menuColsBeforeScroll = 26;
140 }
141 }
142 menu_w = defaultFontWidth;
143 menu_h = defaultFontHeight;
144
145 mainMenuX = 0;
146 mainMenuY = 0;
147 mainMenuW = menu_w+2*brdrW;
148 mainMenuH = menu_h+2*brdrW;
149
150 if ((mainMenuWindow=XCreateSimpleWindow(mainDisplay, rootWindow, 0, 0,
151 menu_w, menu_h, brdrW, myBorderPixel, bg_pixel)) == 0) {
152 FailToCreateWindowMessage("InitMainMenu()", NULL, TRUE);
153 }
154 win_attrs.save_under = True;
155 win_attrs.override_redirect = (titledPinnedMenu ? False : True);
156 XChangeWindowAttributes(mainDisplay, mainMenuWindow,
157 CWSaveUnder | CWOverrideRedirect, &win_attrs);
158
159 XSelectInput(mainDisplay, mainMenuWindow, StructureNotifyMask |
160 ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask |
161 EnterWindowMask | LeaveWindowMask);
162
163 sizehints.flags = PSize | PMinSize | PMaxSize;
164 sizehints.width = sizehints.min_width = sizehints.max_width =
165 menu_w+2*brdrW;
166 sizehints.height = sizehints.min_height = sizehints.max_height =
167 menu_h+2*brdrW;
168
169 sizehints.flags |= USPosition | PPosition;
170 #ifdef NOTR4MODE
171 XSetNormalHints(mainDisplay, mainMenuWindow, &sizehints);
172 #else
173 XSetWMNormalHints(mainDisplay, mainMenuWindow, &sizehints);
174 #endif
175
176 wmhints.flags = InputHint;
177 wmhints.input = True;
178 XSetWMHints(mainDisplay, mainMenuWindow, &wmhints);
179
180 if (!titledPinnedMenu) {
181 XSetTransientForHint(mainDisplay, mainMenuWindow, mainWindow);
182 }
183 RegisterWM_DELETE_WINDOW(mainMenuWindow);
184 XStoreName(mainDisplay, mainMenuWindow, TgLoadCachedString(CSTID_MAIN_MENU));
185
186 InitPinnedMenus();
187 }
188
CleanUpMainMenu()189 void CleanUpMainMenu()
190 {
191 int i;
192
193 XDestroyWindow(mainDisplay, mainMenuWindow);
194
195 for (i=0; i < MAXMENUS+1; i++) {
196 if (subMenuInfo[i].win != None) {
197 XDestroyWindow(mainDisplay, subMenuInfo[i].win);
198 }
199 subMenuInfo[i].win = None;
200 }
201 }
202
203 static int mainMenuMoveDX=0, mainMenuMoveDY=0;
204
SaveMainWinPosition(x,y)205 void SaveMainWinPosition(x, y)
206 unsigned int x, y;
207 {
208 mainMenuMoveDX = x - savedMainWinX;
209 mainMenuMoveDY = y - savedMainWinY;
210
211 savedMainWinX = x;
212 savedMainWinY = y;
213 }
214
MoveMainMenuWindow(x,y)215 void MoveMainMenuWindow(x, y)
216 unsigned int x, y;
217 {
218 mainMenuMoveDX = x - savedMainWinX;
219 mainMenuMoveDY = y - savedMainWinY;
220
221 if (x == savedMainWinX && y == savedMainWinX) return;
222
223 mainMenuX += mainMenuMoveDX;
224 mainMenuY += mainMenuMoveDY;
225
226 /* no need to move the windows */
227 /* XMoveWindow(mainDisplay, mainMenuWindow, mainMenuX, mainMenuY); */
228
229 savedMainWinX = x;
230 savedMainWinY = y;
231 }
232
GetPopupXY(win,px,py)233 void GetPopupXY(win, px, py)
234 Window win;
235 int *px, *py;
236 {
237 *px = *py = 0;
238 for (;;) {
239 Window root_win=None, parent_win=None, *child_wins=NULL;
240 unsigned int num_child=0;
241 XWindowAttributes win_attrs;
242
243 XGetWindowAttributes(mainDisplay, win, &win_attrs);
244 *px += win_attrs.x;
245 *py += win_attrs.y;
246 if (XQueryTree(mainDisplay, win, &root_win,
247 &parent_win, &child_wins, &num_child) == 0) {
248 return;
249 }
250 if (child_wins != NULL) XFree((void*)child_wins);
251 if (parent_win != rootWindow) {
252 win = parent_win;
253 } else {
254 break;
255 }
256 }
257 }
258
GetPopupWH(win,pw,ph)259 void GetPopupWH(win, pw, ph)
260 Window win;
261 int *pw, *ph;
262 {
263 XWindowAttributes win_attrs;
264
265 XGetWindowAttributes(mainDisplay, win, &win_attrs);
266 *pw = win_attrs.width;
267 *ph = win_attrs.height;
268 }
269
270 static char checkExtra[33];
271
SaveStackingOrder()272 void SaveStackingOrder()
273 {
274 register int i, j;
275 register unsigned char hash_value;
276 Window root_win, parent_win, *child_wins=NULL;
277 unsigned int num_child;
278
279 for (i=0; i < 33; i++) checkExtra[i] = '\0';
280 if (pinnedMainMenu) {
281 hash_value = mainMenuWindow & 0xff;
282 checkExtra[hash_value>>3] |= (1<<(hash_value&0x7));
283 }
284 for (i = 0; i < numExtraWins; i++) {
285 if (extraWinInfo[i].raise && extraWinInfo[i].mapped &&
286 extraWinInfo[i].window != None) {
287 hash_value = extraWinInfo[i].window & 0xff;
288 checkExtra[hash_value>>3] |= (1<<(hash_value&0x7));
289 }
290 }
291
292 XQueryTree(mainDisplay, rootWindow, &root_win, &parent_win, &child_wins,
293 &num_child);
294
295 numStacking = 0;
296 if (stackingWins != NULL) free(stackingWins);
297 stackingWins = (Window*)malloc((numExtraWins+1)*sizeof(Window));
298 if (stackingWins == NULL) FailAllocMessage();
299
300 for (i = 0; i < num_child; i++) {
301 hash_value = child_wins[i] & 0xff;
302 if (checkExtra[hash_value>>3] & (1<<(hash_value&0x7))) {
303 if (child_wins[i] == mainMenuWindow) {
304 stackingWins[numStacking++] = mainMenuWindow;
305 } else {
306 for (j = 0; j < numExtraWins; j++) {
307 if (extraWinInfo[j].raise && extraWinInfo[j].mapped &&
308 extraWinInfo[j].window == child_wins[i]) {
309 stackingWins[numStacking++] = child_wins[i];
310 break;
311 }
312 }
313 }
314 }
315 }
316 if (child_wins != NULL) XFree((void*)child_wins);
317 }
318
319 static
RepositionSubMenuWindow(win,menu_index,OrigCursorX,OrigCursorY)320 void RepositionSubMenuWindow(win, menu_index, OrigCursorX, OrigCursorY)
321 Window win;
322 int menu_index, OrigCursorX, OrigCursorY;
323 {
324 int moving=TRUE, x, y, w, h;
325 XEvent input;
326
327 x = subMenuInfo[menu_index].x;
328 y = subMenuInfo[menu_index].y;
329 w = subMenuInfo[menu_index].w;
330 h = subMenuInfo[menu_index].h;
331
332 if (!debugNoPointerGrab) {
333 XGrabPointer(mainDisplay, win, FALSE,
334 PointerMotionMask | ButtonReleaseMask,
335 GrabModeAsync, GrabModeAsync, None, handCursor, CurrentTime);
336 }
337 XSetSubwindowMode(mainDisplay, revDefaultGC, IncludeInferiors);
338 XDrawRectangle(mainDisplay, rootWindow, revDefaultGC, x, y, w, h);
339
340 while (moving) {
341 XNextEvent(mainDisplay, &input);
342
343 if (input.type == Expose || input.type == VisibilityNotify) {
344 ExposeEventHandler(&input, TRUE);
345 } else if (input.type == ButtonRelease) {
346 XDrawRectangle(mainDisplay, rootWindow, revDefaultGC, x, y, w, h);
347 XSetSubwindowMode(mainDisplay, revDefaultGC, ClipByChildren);
348 XMoveWindow(mainDisplay, win, x, y);
349 XRaiseWindow(mainDisplay, win);
350 subMenuInfo[menu_index].x = x;
351 subMenuInfo[menu_index].y = y;
352
353 moving = FALSE;
354 XUngrabPointer(mainDisplay, CurrentTime);
355 XDefineCursor(mainDisplay, win, defaultCursor);
356 } else if (input.type == MotionNotify) {
357 XDrawRectangle(mainDisplay, rootWindow, revDefaultGC, x, y, w, h);
358 x = input.xbutton.x_root-OrigCursorX+subMenuInfo[menu_index].x;
359 y = input.xbutton.y_root-OrigCursorY+subMenuInfo[menu_index].y;
360 XDrawRectangle(mainDisplay, rootWindow, revDefaultGC, x, y, w, h);
361 }
362 }
363 }
364
365 static
TgSubMenuExposeHandler(input,win_info)366 void TgSubMenuExposeHandler(input, win_info)
367 XEvent *input;
368 struct WinInfoRec *win_info;
369 {
370 int menu_index;
371 Window win;
372 XEvent ev;
373
374 win = input->xany.window;
375 while (XCheckWindowEvent(mainDisplay, win, ExposureMask, &ev));
376 while (XCheckWindowEvent(mainDisplay, win, StructureNotifyMask, &ev));
377
378 for (menu_index=0; menu_index <= MAXMENUS+1; menu_index++) {
379 if (subMenuInfo[menu_index].win == win && win != None) {
380 TgMenu *menu=(TgMenu*)(win_info->userdata);
381
382 if (menu != NULL) TgDrawEntireMenu(menu);
383 break;
384 }
385 }
386 }
387
388 static
ComputeSubMenuWinXY(win,x,y)389 void ComputeSubMenuWinXY(win, x, y)
390 Window win;
391 int *x, *y;
392 {
393 int win_x, win_y, done=FALSE;
394 unsigned int win_w, win_h, win_brdr_w, win_d, num_child;
395 Window root_win, parent_win, *child_wins=NULL;
396
397 *x = *y = 0;
398 while (!done) {
399 XGetGeometry(mainDisplay, win, &root_win, &win_x, &win_y, &win_w,
400 &win_h, &win_brdr_w, &win_d);
401 *x += win_x;
402 *y += win_y;
403 if (XQueryTree(mainDisplay, win, &root_win, &parent_win, &child_wins,
404 &num_child) == 0) {
405 return;
406 }
407 if (child_wins != NULL) XFree((void*)child_wins);
408 if (parent_win == rootWindow) {
409 done = TRUE;
410 } else {
411 win = parent_win;
412 }
413 }
414 }
415
416 static
TgUpdateMenuBBox(menu,pn_win_x,pn_win_y)417 void TgUpdateMenuBBox(menu, pn_win_x, pn_win_y)
418 TgMenu *menu;
419 int *pn_win_x, *pn_win_y;
420 {
421 int dx=0, dy=0;
422
423 ComputeSubMenuWinXY(menu->window, pn_win_x, pn_win_y);
424 dx = (*pn_win_x) - menu->bbox.ltx;
425 dy = (*pn_win_y) - menu->bbox.lty;
426 menu->bbox.ltx += dx; menu->bbox.lty += dy;
427 menu->bbox.rbx += dx; menu->bbox.rby += dy;
428 }
429
430 static
TgShowPullDownStatus(menu,new_selected)431 void TgShowPullDownStatus(menu, new_selected)
432 TgMenu *menu;
433 int new_selected;
434 {
435 TgMenuItem *menuitems=menu->menuitems;
436
437 if (menuitems[new_selected].status_str != NULL) {
438 if (!titledPinnedMenu) {
439 SetMouseStatus(TgLoadCachedString(CSTID_MOVE_PINNED_MENU),
440 menuitems[new_selected].status_str,
441 TgLoadCachedString(CSTID_CLOSE_PINNED_MENU));
442 } else {
443 SetMouseStatus(menuitems[new_selected].status_str, "",
444 TgLoadCachedString(CSTID_CLOSE_PINNED_MENU));
445 }
446 }
447 }
448
449 static
TgPullDownFromSubMenu(menu,new_selected)450 void TgPullDownFromSubMenu(menu, new_selected)
451 TgMenu *menu;
452 int new_selected;
453 {
454 TgMenuItem *menuitems=menu->menuitems;
455 int rc=BAD, last_selected_non_submenu_item=FALSE;
456 XEvent ev;
457
458 while (rc == BAD || rc == (-3)) {
459 if (new_selected != INVALID &&
460 (menuitems[new_selected].flags & TGMU_DISABLED) == 0) {
461 if ((menuitems[new_selected].flags & TGMU_HAS_SUBMENU) ==
462 TGMU_HAS_SUBMENU &&
463 menuitems[new_selected].submenu_create_info != NULL) {
464 /*
465 * highlight the submenu item, popup the submenu,
466 * and unhighlight it
467 */
468 int win_x=0, win_y=0;
469 TgMenu *submenu=NULL;
470
471 menuitems[new_selected].state = TGBS_RAISED;
472 TgDrawMenuItem(menu, &menuitems[new_selected]);
473 TgShowPullDownStatus(menu, new_selected);
474
475 TgUpdateMenuBBox(menu, &win_x, &win_y);
476
477 submenu = TgCreatePopUpSubMenu(menu, new_selected);
478 if (submenu != NULL) {
479 submenu->track_menubar = FALSE;
480 submenu->track_parent_menu = TRUE;
481
482 rc = TgPopUpSubMenu(menu, win_x, win_y);
483
484 submenu = menuitems[new_selected].detail.submenu;
485 if (submenu != NULL) {
486 TgDestroyMenu(submenu, TRUE);
487 menuitems[new_selected].detail.submenu = NULL;
488 }
489 }
490 menuitems[menu->selected_index].state = TGBS_NORMAL;
491 TgDrawMenuItem(menu, &menuitems[menu->selected_index]);
492 } else {
493 if (new_selected != last_selected_non_submenu_item) {
494 menuitems[new_selected].state = TGBS_RAISED;
495 TgDrawMenuItem(menu, &menuitems[new_selected]);
496 TgShowPullDownStatus(menu, new_selected);
497 last_selected_non_submenu_item = new_selected;
498 }
499 }
500 }
501 if (rc == BAD || rc == (-3)) {
502 Window root_win, child_win;
503 int mouse_x, mouse_y, root_x, root_y;
504 unsigned int status;
505
506 XQueryPointer(mainDisplay, menu->window, &root_win, &child_win,
507 &root_x, &root_y, &mouse_x, &mouse_y, &status);
508 new_selected = TgWhichMenuIndex(menu, mouse_x, mouse_y, TRUE);
509 if (!(status & BUTTONSMASK)) {
510 break;
511 }
512 if (!(status & BUTTONSMASK) && !(mouse_x >= 0 && mouse_x <
513 menu->bbox.rbx-menu->bbox.ltx && mouse_y >= 0 &&
514 mouse_y < menu->bbox.rby-menu->bbox.lty)) {
515 break;
516 }
517 if (new_selected != last_selected_non_submenu_item &&
518 last_selected_non_submenu_item != INVALID) {
519 menuitems[last_selected_non_submenu_item].state = TGBS_NORMAL;
520 TgDrawMenuItem(menu, &menuitems[last_selected_non_submenu_item]);
521 last_selected_non_submenu_item = INVALID;
522 }
523 switch (new_selected) {
524 case INVALID: break;
525 case (-2): new_selected = INVALID; break; /* separator */
526 case (-3): new_selected = INVALID; break; /* scrollbar */
527 default: break;
528 }
529 menu->selected_index = new_selected;
530 }
531 }
532 XSync(mainDisplay, False);
533 while (XCheckWindowEvent(mainDisplay, menu->window,
534 ButtonPressMask|ButtonReleaseMask|PointerMotionMask, &ev)) ;
535 }
536
537 static
MouseInsideWindow(win,win_w,win_h)538 int MouseInsideWindow(win, win_w, win_h)
539 Window win;
540 int win_w, win_h;
541 {
542 Window root_win, child_win;
543 int x, y, root_x, root_y;
544 unsigned int status;
545
546 XQueryPointer(mainDisplay, win, &root_win, &child_win,
547 &root_x, &root_y, &x, &y, &status);
548 return (x >= 0 && x < win_w && y >=0 && y < win_h);
549 }
550
551 static
TgSubMenuEventHandler(input,win_info)552 int TgSubMenuEventHandler(input, win_info)
553 XEvent *input;
554 struct WinInfoRec *win_info;
555 {
556 static TgMenu *clicked_menu=NULL;
557 static int clicked_index=INVALID;
558 TgMenu *menu=(TgMenu*)(win_info->userdata);
559 TgMenuItem *menuitems=menu->menuitems;
560 int menu_index=INVALID, new_selected=INVALID, rc=INVALID;
561 int menu_w=menu->bbox.rbx-menu->bbox.ltx+((menu->padding)<<1);
562 int menu_h=menu->bbox.rby-menu->bbox.lty+((menu->padding)<<1);
563 XButtonEvent *button_ev=NULL;
564 XEvent ev;
565 Window win=None;
566
567 if (input->type == MapNotify || input->type == Expose) {
568 TgSubMenuExposeHandler(input, win_info);
569 clicked_menu = NULL;
570 clicked_index = INVALID;
571 return INVALID;
572 }
573 if (menu == NULL) return INVALID;
574
575 win = input->xany.window;
576 for (menu_index=0; menu_index <= MAXMENUS; menu_index++) {
577 if (subMenuInfo[menu_index].win == win && win != None) {
578 break;
579 }
580 }
581 if (menu_index > MAXMENUS) return INVALID;
582
583 if (menu->scroll_start > 0) {
584 switch (menu->type) {
585 case TGMUTYPE_TEXT:
586 menu_w += scrollBarW + menu->padding;
587 menu_h = maxScrollableMenuHeight;
588 break;
589 case TGMUTYPE_COLOR:
590 case TGMUTYPE_BITMAP:
591 menu_w = maxScrollableMenuWidth;
592 menu_h += scrollBarW + menu->padding;
593 break;
594 }
595 }
596 menu->parent_menu = NULL;
597 if (input->type == MotionNotify || input->type == ButtonPress ||
598 input->type == ButtonRelease) {
599 if (!MouseInsideWindow(menu->window, menu_w, menu_h)) {
600 return INVALID;
601 }
602 }
603 if (input->type == ConfigureNotify) {
604 ComputeSubMenuWinXY(win, &(subMenuInfo[menu_index].x),
605 &(subMenuInfo[menu_index].y));
606 clicked_menu = NULL;
607 clicked_index = INVALID;
608 } else if (input->type == EnterNotify) {
609 if (menu->selected_index != INVALID) {
610 menuitems[menu->selected_index].state = TGBS_NORMAL;
611 TgDrawMenuItem(menu, &menuitems[menu->selected_index]);
612 }
613 menu->selected_index = INVALID;
614 clicked_menu = NULL;
615 clicked_index = INVALID;
616 SetStringStatus("");
617 } else if (input->type == LeaveNotify) {
618 if (menu->selected_index != INVALID) {
619 menuitems[menu->selected_index].state = TGBS_NORMAL;
620 TgDrawMenuItem(menu, &menuitems[menu->selected_index]);
621 }
622 clicked_menu = NULL;
623 clicked_index = INVALID;
624 menu->selected_index = INVALID;
625 } else if (input->type == MotionNotify) {
626 while (XCheckWindowEvent(mainDisplay, menu->window,
627 PointerMotionMask, &ev)) ;
628 new_selected = TgWhichMenuIndex(menu, input->xmotion.x, input->xmotion.y,
629 FALSE);
630
631 if (menu->selected_index != new_selected) {
632 if (menu->selected_index != INVALID) {
633 menuitems[menu->selected_index].state = TGBS_NORMAL;
634 TgDrawMenuItem(menu, &menuitems[menu->selected_index]);
635 }
636 switch (new_selected) {
637 case INVALID: break;
638 case (-2): new_selected = INVALID; break; /* separator */
639 case (-3): new_selected = INVALID; break; /* scrollbar */
640 default: break;
641 }
642 if (new_selected != INVALID) {
643 menuitems[new_selected].state = TGBS_RAISED;
644 TgDrawMenuItem(menu, &menuitems[new_selected]);
645 TgShowPullDownStatus(menu, new_selected);
646 }
647 menu->selected_index = new_selected;
648 if (clicked_menu != NULL && clicked_index != INVALID) {
649 clicked_index = INVALID;
650 }
651 }
652 } else if (input->type == ButtonPress) {
653 button_ev = &(input->xbutton);
654 switch (button_ev->button) {
655 case Button1:
656 if (!titledPinnedMenu) {
657 RepositionSubMenuWindow(win, menu_index, button_ev->x_root,
658 button_ev->y_root);
659 break;
660 }
661 /* dropping through if titledPinnedMenu ! */
662 case Button2:
663 new_selected = TgWhichMenuIndex(menu, button_ev->x, button_ev->y,
664 FALSE);
665 clicked_menu = menu;
666 clicked_index = (new_selected < 0 ? INVALID : new_selected);
667 if (new_selected != INVALID) {
668 if (menu->selected_index != new_selected) {
669 if (menu->selected_index != INVALID) {
670 menuitems[menu->selected_index].state = TGBS_NORMAL;
671 TgDrawMenuItem(menu, &menuitems[menu->selected_index]);
672 }
673 switch (new_selected) {
674 case INVALID: break;
675 case (-2): new_selected = INVALID; break; /* separator */
676 case (-3):
677 /* scrollbar */
678 if (menu->scroll_start > 0) {
679 /* loop to scroll */
680 ScrollMenu(menu, button_ev->x, button_ev->y, menu_w,
681 menu_h, (button_ev->button == Button1 ?
682 Button1Mask : Button2Mask));
683 }
684 new_selected = INVALID;
685 break;
686 default: break;
687 }
688 if (new_selected != INVALID) {
689 menuitems[new_selected].state = TGBS_RAISED;
690 TgDrawMenuItem(menu, &menuitems[new_selected]);
691 TgShowPullDownStatus(menu, new_selected);
692 }
693 menu->selected_index = new_selected;
694 }
695 if (new_selected != INVALID &&
696 (menuitems[new_selected].flags & TGMU_HAS_SUBMENU) ==
697 TGMU_HAS_SUBMENU &&
698 (menuitems[new_selected].flags & TGMU_DISABLED) == 0 &&
699 menuitems[new_selected].submenu_create_info != NULL) {
700 TgPullDownFromSubMenu(menu, new_selected);
701 clicked_index = INVALID;
702 }
703 }
704 break;
705 case Button3:
706 if (TgWhichMenuIndex(menu, button_ev->x, button_ev->y, FALSE) !=
707 (-3)) {
708 clicked_menu = NULL;
709 clicked_index = INVALID;
710 } else if (!threeDLook && menu->scroll_start > 0) {
711 /* loop to scroll */
712 ScrollMenu(menu, button_ev->x, button_ev->y, menu_w,
713 menu_h, Button3Mask);
714 }
715 break;
716 }
717 } else if (input->type == ButtonRelease) {
718 button_ev = &(input->xbutton);
719 switch (button_ev->button) {
720 case Button1:
721 if (!titledPinnedMenu) {
722 break;
723 }
724 /* dropping through if titledPinnedMenu ! */
725 case Button2:
726 new_selected = TgWhichMenuIndex(menu, button_ev->x, button_ev->y,
727 FALSE);
728 if (new_selected != INVALID) {
729 if (menu->selected_index != new_selected) {
730 if (menu->selected_index != INVALID) {
731 menuitems[menu->selected_index].state = TGBS_NORMAL;
732 TgDrawMenuItem(menu, &menuitems[menu->selected_index]);
733 }
734 switch (new_selected) {
735 case INVALID: break;
736 case (-2): new_selected = INVALID; break; /* separator */
737 case (-3): new_selected = INVALID; break; /* scrollbar */
738 default: break;
739 }
740 if (new_selected != INVALID) {
741 menuitems[new_selected].state = TGBS_RAISED;
742 TgDrawMenuItem(menu, &menuitems[new_selected]);
743 TgShowPullDownStatus(menu, new_selected);
744 }
745 menu->selected_index = new_selected;
746 }
747 if (new_selected != INVALID &&
748 (menuitems[new_selected].flags & TGMU_HAS_SUBMENU) ==
749 TGMU_HAS_SUBMENU &&
750 (menuitems[new_selected].flags & TGMU_DISABLED) == 0 &&
751 menuitems[new_selected].submenu_create_info != NULL) {
752 TgPullDownFromSubMenu(menu, new_selected);
753 clicked_index = INVALID;
754 } else if (menu->menuitems[new_selected].cmdid != INVALID &&
755 ((menu->menuitems[new_selected].flags & TGMU_DISABLED) !=
756 TGMU_DISABLED)) {
757 if (clicked_menu != NULL && clicked_index != INVALID &&
758 clicked_index == new_selected) {
759 SendCommandToSelf(menu->menuitems[new_selected].cmdid,
760 new_selected);
761 }
762 }
763 }
764 break;
765 case Button3:
766 if (TgWhichMenuIndex(menu, button_ev->x, button_ev->y, FALSE) !=
767 (-3)) {
768 if (button_ev->x>=0 && button_ev->x<=subMenuInfo[menu_index].w &&
769 button_ev->y>=0 && button_ev->y<=subMenuInfo[menu_index].h) {
770 XDestroyWindow(mainDisplay, subMenuInfo[menu_index].win);
771 subMenuInfo[menu_index].win = None;
772 extraWinInfo[subMenuInfo[menu_index].extra_index].window = None;
773 TgDestroyMenu(menu, TRUE);
774 win_info->userdata = NULL;
775 }
776 clicked_menu = NULL;
777 clicked_index = INVALID;
778 }
779 break;
780 }
781 } else if (IsWM_DELETE_WINDOW(input)) {
782 XDestroyWindow(mainDisplay, subMenuInfo[menu_index].win);
783 subMenuInfo[menu_index].win = None;
784 extraWinInfo[subMenuInfo[menu_index].extra_index].window = None;
785 TgDestroyMenu(menu, TRUE);
786 win_info->userdata = NULL;
787 clicked_menu = NULL;
788 clicked_index = INVALID;
789 }
790 return rc;
791 }
792
793 static
TgSubMenuCleanUp(win_info)794 void TgSubMenuCleanUp(win_info)
795 struct WinInfoRec *win_info;
796 {
797 TgMenu *menu=(TgMenu*)(win_info->userdata);
798
799 if (menu != NULL) {
800 TgDestroyMenu(menu, TRUE);
801 win_info->userdata = NULL;
802 }
803 }
804
TgRealizePinnedMenuWindow(menu,win_x,win_y,win_w,win_h)805 Window TgRealizePinnedMenuWindow(menu, win_x, win_y, win_w, win_h)
806 TgMenu *menu;
807 int win_x, win_y, win_w, win_h;
808 {
809 Window win;
810 XWMHints wmhints;
811 XSizeHints sizehints;
812 XSetWindowAttributes win_attrs;
813 TgMenu *dup_menu=NULL;
814 int bg_pixel=(threeDLook ? myLtGryPixel : myBgPixel);
815 TgMenuItemInfo *item_info=NULL;
816
817 win_w -= (brdrW<<1);
818 win_h -= (brdrW<<1);
819
820 if ((win=XCreateSimpleWindow(mainDisplay, rootWindow, win_x, win_y,
821 win_w, win_h, brdrW, myBorderPixel, bg_pixel)) == 0) {
822 FailToCreateWindowMessage("TgRealizePinnedMenuWindow()", NULL, TRUE);
823 }
824 XDefineCursor(mainDisplay, win, defaultCursor);
825
826 win_attrs.save_under = True;
827 win_attrs.override_redirect = (titledPinnedMenu ? False : True);
828 win_attrs.colormap = mainColormap;
829 XChangeWindowAttributes(mainDisplay, win,
830 CWSaveUnder | CWOverrideRedirect | CWColormap, &win_attrs);
831
832 if (!titledPinnedMenu) {
833 XSetTransientForHint(mainDisplay, win, mainWindow);
834 }
835 if (activeMenu == MENU_MAIN) {
836 XStoreName(mainDisplay, win, TgLoadCachedString(CSTID_MAIN_MENU));
837 } else {
838 for (item_info=mainMenuInfo.items; item_info->menu_str != NULL;
839 item_info++) {
840 if (item_info->menu_str != TGMUITEM_SEPARATOR &&
841 item_info->cmdid == activeMenu) {
842 XStoreName(mainDisplay, win, item_info->status_str);
843 break;
844 }
845 }
846 }
847 sizehints.flags = PSize | PMinSize | PMaxSize;
848 sizehints.width = sizehints.min_width = sizehints.max_width = win_w;
849 sizehints.height = sizehints.min_height = sizehints.max_height = win_h;
850
851 sizehints.flags |= USPosition | PPosition;
852 #ifdef NOTR4MODE
853 XSetNormalHints(mainDisplay, win, &sizehints);
854 #else
855 XSetWMNormalHints(mainDisplay, win, &sizehints);
856 #endif
857
858 wmhints.flags = InputHint;
859 wmhints.input = True;
860 XSetWMHints(mainDisplay, win, &wmhints);
861
862 RegisterWM_DELETE_WINDOW(win);
863
864 #ifdef MAPBEFORESELECT
865 XMapWindow(mainDisplay, win);
866 XSelectInput(mainDisplay, win, StructureNotifyMask |
867 ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask |
868 EnterWindowMask | LeaveWindowMask | PointerMotionMask);
869 #else
870 XSelectInput(mainDisplay, win, StructureNotifyMask |
871 ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask |
872 EnterWindowMask | LeaveWindowMask | PointerMotionMask);
873 XMapWindow(mainDisplay, win);
874 #endif
875
876 if (subMenuInfo[activeMenu].win != None) {
877 int extra_index=subMenuInfo[activeMenu].extra_index;
878
879 XDestroyWindow(mainDisplay, subMenuInfo[activeMenu].win);
880 extraWinInfo[extra_index].window = None;
881 TgDestroyMenu(menu, FALSE);
882 dup_menu = (TgMenu*)(extraWinInfo[extra_index].userdata);
883 } else {
884 if ((dup_menu=(TgMenu*)malloc(sizeof(TgMenu))) == NULL) {
885 FailAllocMessage();
886 }
887 memcpy(dup_menu, menu, sizeof(TgMenu));
888 }
889 dup_menu->window = win;
890 subMenuInfo[activeMenu].extra_index =
891 AddExtraWinInfo(win, TRUE, TRUE, TgSubMenuExposeHandler,
892 TgSubMenuEventHandler, TgSubMenuCleanUp, dup_menu);
893
894 subMenuInfo[activeMenu].x = win_x;
895 subMenuInfo[activeMenu].y = win_y;
896 subMenuInfo[activeMenu].w = win_w;
897 subMenuInfo[activeMenu].h = win_h;
898 subMenuInfo[activeMenu].win = win;
899
900 XDestroyWindow(mainDisplay, menu->window);
901 menu->window = None;
902 memset(menu, 0, sizeof(TgMenu));
903
904 return win;
905 }
906
TgWindowIsPinnedMenu(win,menu_index)907 int TgWindowIsPinnedMenu(win, menu_index)
908 Window win;
909 int menu_index;
910 {
911 return (subMenuInfo[menu_index].win != None &&
912 subMenuInfo[menu_index].win == win);
913 }
914
TgHandlePinnedMenuEvent(win,menu_index,input)915 int TgHandlePinnedMenuEvent(win, menu_index, input)
916 Window win;
917 int menu_index;
918 XEvent *input;
919 {
920 if (TgWindowIsPinnedMenu(win, menu_index)) {
921 int extra_win_info_index=subMenuInfo[menu_index].extra_index;
922
923 return (*(extraWinInfo[extra_win_info_index].ev_handler))(
924 input, &extraWinInfo[extra_win_info_index]);
925 }
926 return INVALID;
927 }
928
UpdatePinnedMenu(menu_index)929 void UpdatePinnedMenu(menu_index)
930 int menu_index;
931 {
932 Window win=subMenuInfo[menu_index].win;
933
934 if (win != None) {
935 int extra_win_info_index=subMenuInfo[menu_index].extra_index;
936
937 if (extra_win_info_index >= 0 && extra_win_info_index < numExtraWins &&
938 extraWinInfo[extra_win_info_index].window == win) {
939 TgMenu *menu=(TgMenu*)(extraWinInfo[extra_win_info_index].userdata);
940
941 if (menu != NULL) {
942 switch (menu_index) {
943 case MENU_FILE: RefreshFileMenu(menu); break;
944 case MENU_EDIT: RefreshEditMenu(menu); break;
945 case MENU_LAYOUT: RefreshLayoutMenu(menu); break;
946 case MENU_ARRANGE: RefreshArrangeMenu(menu); break;
947 case MENU_PROPERTIES: RefreshPropertiesMenu(menu); break;
948
949 case MENU_MOVEMODE: RefreshMoveModeMenu(menu); break;
950 case MENU_HORIALIGN: RefreshHoriAlignMenu(menu); break;
951 case MENU_VERTALIGN: RefreshVertAlignMenu(menu); break;
952 case MENU_FONT: RefreshFontMenu(menu); break;
953 case MENU_STYLE: RefreshFontStyleMenu(menu); break;
954 case MENU_SIZE: RefreshFontSizeMenu(menu); break;
955 case MENU_SHAPE: RefreshShapeMenu(menu); break;
956 case MENU_STRETCHTEXT: RefreshStretchableTextModeMenu(menu); break;
957 case MENU_TRANSPAT: RefreshTransPatModeMenu(menu); break;
958
959 case MENU_LINEWIDTH: RefreshLineWidthMenu(menu); break;
960 case MENU_LINESTYLE: RefreshLineStyleMenu(menu); break;
961 case MENU_LINETYPE: RefreshLineTypeMenu(menu); break;
962 case MENU_LINEDASH: RefreshLineDashMenu(menu); break;
963 case MENU_FILL: RefreshFillMenu(menu); break;
964 case MENU_PEN: RefreshPenMenu(menu); break;
965
966 case MENU_COLOR: RefreshColorMenu(menu); break;
967
968 case MENU_IMAGEPROC: RefreshImageProcMenu(menu); break;
969 case MENU_NAVIGATE: RefreshNavigateMenu(menu); break;
970 case MENU_SPECIAL: RefreshSpecialMenu(menu); break;
971 case MENU_PAGE: RefreshPageMenu(menu); break;
972 case MENU_PAGELAYOUT: RefreshPageLayoutMenu(menu); break;
973 case MENU_HELP: RefreshHelpMenu(menu); break;
974 case MENU_TANGRAM2:
975 if (cmdLineTgrm2) {
976 RefreshTangram2Menu(menu);
977 }
978 break;
979
980 case MENU_MODE: RefreshModeMenu(menu); break;
981
982 case MENU_MAIN: RefreshMainMenu(menu); break;
983 }
984 TgDrawEntireMenu(menu);
985 return;
986 }
987 }
988 }
989 }
990
UpdateAllPinnedMenus()991 void UpdateAllPinnedMenus()
992 {
993 UpdatePinnedMenu(MENU_HORIALIGN);
994 UpdatePinnedMenu(MENU_VERTALIGN);
995 UpdatePinnedMenu(MENU_STYLE);
996 UpdatePinnedMenu(MENU_FONT);
997 UpdatePinnedMenu(MENU_SIZE);
998 UpdatePinnedMenu(MENU_LINEWIDTH);
999 UpdatePinnedMenu(MENU_LINESTYLE);
1000 UpdatePinnedMenu(MENU_LINETYPE);
1001 UpdatePinnedMenu(MENU_LINEDASH);
1002 UpdatePinnedMenu(MENU_LAYOUT);
1003 UpdatePinnedMenu(MENU_MOVEMODE);
1004 UpdatePinnedMenu(MENU_STRETCHTEXT);
1005 UpdatePinnedMenu(MENU_TRANSPAT);
1006 UpdatePinnedMenu(MENU_PAGELAYOUT);
1007
1008 UpdatePinnedMenu(MENU_MAIN);
1009 }
1010
UseWireMenuItemInModeItem(connecting)1011 void UseWireMenuItemInModeItem(connecting)
1012 int connecting;
1013 {
1014 Window win=subMenuInfo[MENU_MODE].win;
1015
1016 if (win != None) {
1017 int extra_win_info_index=subMenuInfo[MENU_MODE].extra_index;
1018
1019 if (extra_win_info_index >= 0 && extra_win_info_index < numExtraWins &&
1020 extraWinInfo[extra_win_info_index].window == win) {
1021 TgMenu *menu=(TgMenu*)(extraWinInfo[extra_win_info_index].userdata);
1022
1023 if (menu != NULL) {
1024 TgMenuItem stMenuItem;
1025
1026 memset(&stMenuItem, 0, sizeof(TgMenuItem));
1027 if (connecting) {
1028 stMenuItem.menu_str = (char*)(&wireBitmap);
1029 } else {
1030 stMenuItem.menu_str = (char*)(&choicePixmap[DRAWPOLY]);
1031 }
1032 if (!TgSetMenuItemInfo(&menu->menuitems[DRAWPOLY],
1033 TGMU_MASK_MENUSTR, &stMenuItem)) {
1034 }
1035 return;
1036 }
1037 }
1038 }
1039 }
1040
DestroyPinnedMenu(menu_index)1041 void DestroyPinnedMenu(menu_index)
1042 int menu_index;
1043 {
1044 if (subMenuInfo[menu_index].win != None) {
1045 int extra_index=subMenuInfo[menu_index].extra_index;
1046 TgMenu *menu=(TgMenu*)(extraWinInfo[extra_index].userdata);
1047
1048 XDestroyWindow(mainDisplay, subMenuInfo[menu_index].win);
1049 subMenuInfo[menu_index].win = None;
1050 extraWinInfo[extra_index].window = None;
1051 if (menu != NULL) {
1052 TgDestroyMenu(menu, TRUE);
1053 extraWinInfo[extra_index].userdata = NULL;
1054 }
1055 }
1056 }
1057
1058 static IntPoint gaPopupCoords[MAXMENUS+5];
1059
HidePopupMenusForSlideShow()1060 void HidePopupMenusForSlideShow()
1061 {
1062 int adj_caches=(zoomScale!=0 || zoomedIn!=FALSE);
1063 int menu_index=0, draw_win_x=0, draw_win_y=0, draw_win_w=0, draw_win_h=0;
1064 int dpy_w=DisplayWidth(mainDisplay,mainScreen);
1065 int dpy_h=DisplayHeight(mainDisplay,mainScreen);
1066
1067 for (menu_index=0; menu_index <= MAXMENUS; menu_index++) {
1068 if (subMenuInfo[menu_index].win != None) {
1069 GetPopupXY(subMenuInfo[menu_index].win,
1070 &gaPopupCoords[menu_index].x, &gaPopupCoords[menu_index].y);
1071 XMoveWindow(mainDisplay, subMenuInfo[menu_index].win, -dpy_w, -dpy_h);
1072 }
1073 }
1074 GetPopupXY(drawWindow, &draw_win_x, &draw_win_y);
1075 GetPopupWH(drawWindow, &draw_win_w, &draw_win_h);
1076
1077 GetPopupXY(mainWindow, &gaPopupCoords[MAXMENUS+1].x,
1078 &gaPopupCoords[MAXMENUS+1].y);
1079 GetPopupWH(mainWindow, &gaPopupCoords[MAXMENUS+2].x,
1080 &gaPopupCoords[MAXMENUS+2].y);
1081 gaPopupCoords[MAXMENUS+3].x = drawOrigX;
1082 gaPopupCoords[MAXMENUS+3].y = drawOrigY;
1083 gaPopupCoords[MAXMENUS+4].x = zoomedIn;
1084 gaPopupCoords[MAXMENUS+4].y = zoomScale;
1085
1086 if (gaPopupCoords[MAXMENUS+3].x != 0 || gaPopupCoords[MAXMENUS+3].y != 0 ||
1087 adj_caches) {
1088 drawOrigX = drawOrigY = 0;
1089 zoomedIn = FALSE;
1090 zoomScale = 0;
1091
1092 UpdDrawWinWH();
1093 UpdDrawWinBBox();
1094 ClearObjCachesInAllPages();
1095 if (adj_caches) { ShowZoom(); }
1096 }
1097 #ifndef NOKDE3BUG
1098 XMoveResizeWindow(mainDisplay, mainWindow, 0, 0,
1099 dpy_w+gaPopupCoords[MAXMENUS+2].x-draw_win_w+2,
1100 dpy_h+gaPopupCoords[MAXMENUS+2].y-draw_win_h+2);
1101 #endif /* ~NOKDE3BUG */
1102 XMoveResizeWindow(mainDisplay, mainWindow,
1103 gaPopupCoords[MAXMENUS+1].x-draw_win_x-1,
1104 gaPopupCoords[MAXMENUS+1].y-draw_win_y-1,
1105 dpy_w+gaPopupCoords[MAXMENUS+2].x-draw_win_w+2,
1106 dpy_h+gaPopupCoords[MAXMENUS+2].y-draw_win_h+2);
1107 }
1108
ShowPopupMenusForSlideShow()1109 void ShowPopupMenusForSlideShow()
1110 {
1111 int menu_index=0;
1112
1113 zoomScale = gaPopupCoords[MAXMENUS+4].y;
1114 zoomScale = gaPopupCoords[MAXMENUS+4].y;
1115 drawOrigX = gaPopupCoords[MAXMENUS+3].x;
1116 drawOrigY = gaPopupCoords[MAXMENUS+3].y;
1117 drawWinW = gaPopupCoords[MAXMENUS+2].x;
1118 drawWinH = gaPopupCoords[MAXMENUS+2].y;
1119 XMoveResizeWindow(mainDisplay, mainWindow,
1120 gaPopupCoords[MAXMENUS+1].x, gaPopupCoords[MAXMENUS+1].y,
1121 gaPopupCoords[MAXMENUS+2].x, gaPopupCoords[MAXMENUS+2].y);
1122 InitWinSizes();
1123 for (menu_index=0; menu_index <= MAXMENUS; menu_index++) {
1124 if (subMenuInfo[menu_index].win != None) {
1125 XMoveWindow(mainDisplay, subMenuInfo[menu_index].win,
1126 gaPopupCoords[menu_index].x, gaPopupCoords[menu_index].y);
1127 UpdatePinnedMenu(menu_index);
1128 }
1129 }
1130 }
1131
EnumPopupMenuWindow(pFunc,pUserData)1132 void EnumPopupMenuWindow(pFunc, pUserData)
1133 ENUMPOPUPMENUFN *pFunc;
1134 void *pUserData;
1135 {
1136 int menu_index=0;
1137
1138 for (menu_index=0; menu_index <= MAXMENUS; menu_index++) {
1139 if (subMenuInfo[menu_index].win != None) {
1140 if (!((pFunc)(menu_index, subMenuInfo[menu_index].win, pUserData))) {
1141 break;
1142 }
1143 }
1144 }
1145 }
1146