Version:
~ [ 10.0 ] ~
** Warning: Cannot open xref database.
1
2 /* $Id: dockmenu.c,v 1.4 2005/01/11 22:48:05 andreradke Exp $ */
3
4 /******************************************************************************
5
6 UserLand Frontier(tm) -- High performance Web content management,
7 object database, system-level and Internet scripting environment,
8 including source code editing and debugging.
9
10 Copyright (C) 1992-2004 UserLand Software, Inc.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
26 ******************************************************************************/
27
28 /*
29 Implement right-click menus in the system tray icon or dock menu.
30 Broken out from FrontierWinMain.c
31 7.1b22 11/08/01 PBS
32 */
33
34 #include "frontier.h"
35 #include "standard.h"
36
37 #include "menu.h"
38 #include "strings.h"
39 #include "cancoon.h"
40 #include "launch.h"
41 #include "tablestructure.h"
42 #include "popup.h"
43 #include "meprograms.h"
44 #include "dockmenu.h"
45 #include "opinternal.h"
46 #include "menuverbs.h"
47
48 #define idgetdockmenumenuaddresscallback 43
49
50 #define kmaxcommands 100
51 #define kbasecommandid 3000
52 #define maxsubmenus 40
53
54
55 #if MACVERSION
56 UInt32 menuid;
57 short idsubmenu;
58 hdlmenurecord hcurrmenurecord;
59 boolean flstackneedsdisposing = false;
60 #endif
61
62
63 #if WIN95VERSION
64 short menuid;
65 #endif
66
67
68 #if MACVERSION
69
70 typedef struct typopupinfo {
71
72 hdlmenu hmenu;
73
74 short id;
75 } typopupinfo, *ptrpopupinfo, **hdlpopupinfo;
76
77 typedef struct tydockmenustack {
78
79 typopupinfo popupmenus [maxsubmenus];
80
81 short currstackitem;
82 } tydockmenustack, *ptrdockmenustack, **hdldockmenustack;
83
84
85 tydockmenustack dockmenustack;
86
87 #endif
88
89
90 static boolean dockmenubuildpopupmenu (hdlheadrecord hnode, hdlmenu hmenu); /*forward*/
91
92 static void dockmenudisposemenusinstack (void);
93
94
95 static void dockmenuresetmenustack (void) {
96
97 #if MACVERSION
98
99 dockmenudisposemenusinstack ();
100
101 dockmenustack.currstackitem = -1;
102
103 dockmenustack.popupmenus [0].hmenu = nil;
104
105 dockmenustack.popupmenus [0].id = -1;
106
107 #endif
108 } /*dockmenuresetmenustack*/
109
110
111 static void dockmenudisposemenusinstack (void) {
112
113 /*
114 Dispose and delete all menus in popup menu stack.
115 */
116
117 #if MACVERSION
118
119 short ix = dockmenustack.currstackitem;
120 short i, id;
121 hdlmenu hmenu;
122
123 if (!flstackneedsdisposing)
124 return;
125
126 if (ix < 0)
127 return;
128
129 for (i = ix; i > -1; i--) {
130
131 id = dockmenustack.popupmenus [i].id;
132
133 if (id > -1)
134
135 DeleteMenu (id);
136
137 if (id != defaultpopupmenuid) { /*already disposed by system*/
138
139 hmenu = dockmenustack.popupmenus [i].hmenu;
140
141 if (hmenu != nil)
142
143 disposemenu (hmenu);
144 } /*if*/
145
146 dockmenustack.popupmenus [i].hmenu = nil;
147
148 dockmenustack.popupmenus [i].id = -1;
149
150 } /*for*/
151
152 flstackneedsdisposing = false;
153 #endif
154 } /*dockmenudisposemenusinstack*/
155
156
157 static boolean dockmenuaddtomenustack (hdlmenu hmenu, short id) {
158
159 #if MACVERSION
160
161 short ix = dockmenustack.currstackitem + 1;
162
163 if (ix > maxsubmenus)
164 return (false);
165
166 dockmenustack.currstackitem = ix;
167
168 dockmenustack.popupmenus [ix].hmenu = hmenu;
169
170 dockmenustack.popupmenus [ix].id = id;
171
172 #endif
173
174 return (true);
175 } /*dockmenuaddtomenustack*/
176
177
178 static void dockmenuinsertsubmenu (hdlmenu hmenu, short itemnumber, hdlheadrecord hnode) {
179
180 /*
181 7.1b23 PBS: build a sub-menu and attach it.
182 */
183
184 hdlmenu hsubmenu;
185 short id = defaultpopupmenuid;
186
187 #if MACVERSION
188 idsubmenu++;
189
190 id = idsubmenu;
191 #endif
192
193 hsubmenu = Newmenu (id, "");
194
195 #if MACVERSION
196 InsertMenu (hsubmenu, -1);
197 #endif
198
199 dockmenubuildpopupmenu (hnode, hsubmenu);
200
201 dockmenuaddtomenustack (hsubmenu, id);
202
203 sethierarchicalmenuitem (hmenu, itemnumber, hsubmenu, id);
204 } /*dockmenuinsertsubmenu*/
205
206
207 static boolean dockmenugetaddresscallback (tyvaluerecord *val) {
208
209 /*
210 7.1b22 PBS: Run the callback script that returns the address
211 of a menubar object to use.
212 */
213
214 Handle htext = 0;
215 boolean fl = false;
216 bigstring bsscript;
217 short idscript = idgetdockmenumenuaddresscallback;
218
219 if (getsystemtablescript (idscript, bsscript)) {
220
221 if (!newtexthandle (bsscript, &htext))
222
223 return (false);
224
225 grabthreadglobals ();
226
227 oppushoutline (outlinedata);
228
229 fl = langrun (htext, val);
230
231 oppopoutline ();
232
233 releasethreadglobals ();
234 }
235
236 return (fl);
237 } /*dockmenugetaddresscallback*/
238
239
240 static boolean dockmenuinsertmenuitem (hdlmenu hmenu, short itemnumber, hdlheadrecord hnode) {
241
242 /*
243 Insert one menu item.
244
245 7.1b42 PBS: check menu items that should be checked.
246 */
247
248 bigstring bsheadstring;
249 boolean flenabled = true;
250 boolean flchecked = false;
251
252 getheadstring (hnode, bsheadstring);
253
254 mereduceformula (bsheadstring);
255
256 mereducemenucodes (bsheadstring, &flenabled, &flchecked); /*7.0b23 PBS: items can be disabled.*/
257
258 pushpopupitem (hmenu, bsheadstring, flenabled, menuid);
259
260 #if TARGET_API_MAC_CARBON == 1
261
262 SetMenuItemCommandID (hmenu, countmenuitems (hmenu), menuid);
263
264 #endif
265
266 if (flchecked) /*7.1b42 PBS: support for checked menu items.*/
267 checkmenuitem (hmenu, countmenuitems (hmenu), flchecked);
268
269 if (!opnosubheads (hnode)) /*has subs?*/
270 dockmenuinsertsubmenu (hmenu, itemnumber, hnode);
271
272 #if MACVERSION
273 flstackneedsdisposing = true;
274 #endif
275
276 return (true);
277 } /*dockmenuinsertmenuitem*/
278
279
280 static boolean dockmenubuildpopupmenu (hdlheadrecord hnode, hdlmenu hmenu) {
281
282 /*
283 7.1b22 PBS: Build a popup menu from the outline pointed to by hnode.
284 Recurse to handle a menu that has a submenu.
285
286 Based on mebuildmenu, but different enough to need its own routine.
287 */
288
289 short itemnumber;
290 bigstring bs;
291
292 getheadstring (hnode, bs); /*get the menu title*/
293
294 if (opnosubheads (hnode))
295 return (true);
296
297 hnode = (**hnode).headlinkright; /*move to first subhead*/
298
299 for (itemnumber = 1; ; itemnumber++) {
300
301 menuid++;
302
303 if (!dockmenuinsertmenuitem (hmenu, itemnumber, hnode))
304 return (false);
305
306 if (opislastsubhead (hnode)) /*done with this menu*/
307 return (true);
308
309 hnode = (**hnode).headlinkdown; /*advance to next item*/
310 } /*while*/
311 } /*dockmenubuildpopupmenu*/
312
313
314 static boolean dockmenufillpopup (hdlmenu hmenu, hdlmenurecord *hmreturned) {
315
316 /*
317 7.1b44 PBS: call menuverbgetsize to make sure the menu is in memory.
318 */
319
320 hdlhashtable htable;
321 hdlhashnode hnode;
322 hdlmenurecord hm;
323 tyvaluerecord valaddress, val;
324 hdlexternalhandle h;
325 hdlheadrecord hsummit;
326 bigstring bsaddress;
327 boolean fl = false;
328 long menusize = 0;
329
330 if (roottable == nil) /*9.1b1 JES: If there's no system root, don't crash.*/
331 return (false);
332
333 if (!dockmenugetaddresscallback (&valaddress))
334 return (false);
335
336 if (valaddress.valuetype != addressvaluetype)
337 goto exit;
338
339 if (!getaddressvalue (valaddress, &htable, bsaddress))
340 goto exit;
341
342 if (!langsymbolreference (htable, bsaddress, &val, &hnode))
343 goto exit;
344
345 if (val.valuetype != externalvaluetype)
346 goto exit;
347
348 h = (hdlexternalhandle) val.data.externalvalue;
349
350 if (!menuverbgetsize (h, &menusize)) /*7.1b43 PBS: We don't care about the size. We just want to read it into memory.*/
351 goto exit;
352
353 if ((**h).id != idmenuprocessor) /*it must be a menu*/
354 goto exit;
355
356 hm = (hdlmenurecord) (**h).variabledata;
357
358 hsummit = (**(**hm).menuoutline).hsummit;
359
360 #if TARGET_API_MAC_CARBON == 1
361 menuid = kbasecommandid;
362 idsubmenu = 5;
363 #endif
364
365 dockmenudisposemenusinstack ();
366
367 dockmenubuildpopupmenu (hsummit, hmenu);
368
369 *hmreturned = hm;
370
371 fl = true;
372
373 exit:
374
375 disposevaluerecord (valaddress, false);
376
377 return (fl);
378 } /*dockmenufillpopup*/
379
380
381 static void dockmenuruncommand (hdlmenurecord hm, short itemhit) {
382
383 hdlheadrecord hsummit;
384 hdlheadrecord hmenuitem;
385 bigstring bs;
386
387 hsummit = (**(**hm).menuoutline).hsummit; /*Top level of the menu*/
388
389 hmenuitem = oprepeatedbump (flatdown, itemhit, hsummit, false);
390
391 oppushoutline ((**hm).menuoutline);
392
393 getheadstring (hmenuitem, bs);
394
395 meuserselected (hmenuitem);
396
397 dockmenudisposemenusinstack ();
398
399 oppopoutline ();
400 } /*dockmenuruncommand*/
401
402
403 #if TARGET_API_MAC_CARBON == 1
404
405 pascal OSStatus dockcommandhandler (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) {
406
407 #pragma unused(nextHandler) /*happy compiler*/
408 #pragma unused(theEvent)
409 #pragma unused(userData)
410
411 HICommand commandstruct;
412 UInt32 commandid;
413 OSErr ec = eventNotHandledErr;
414
415 GetEventParameter (theEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof (HICommand), NULL, &commandstruct);
416
417 commandid = commandstruct.commandID;
418
419 if ((commandid >= kbasecommandid) && (commandid <= kbasecommandid + kmaxcommands)) {
420
421 dockmenuruncommand (hcurrmenurecord, commandid - kbasecommandid);
422
423 ec = noErr; /*all's well*/
424 } /*if*/
425
426 dockmenudisposemenusinstack (); /*7.1b23 PBS: delete and dispose submenus*/
427
428 return (ec);
429 } /*dockcommandhandler*/
430
431
432 static void dockmenuinstallhandler (void) {
433
434 EventTypeSpec myevents = {kEventClassCommand, kEventCommandProcess};
435
436 InstallApplicationEventHandler (NewEventHandlerUPP (dockcommandhandler), 1, &myevents, 0, NULL);
437
438 } /*dockmenuinstallhandler*/
439
440
441 pascal OSStatus dockmenuhandler (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) {
442
443 /*
444 7.1b22 PBS: called from the system when the dock icon is right-clicked.
445 Build a contextual menu and return it.
446 */
447
448 #pragma unused(nextHandler) /*happy compiler*/
449 #pragma unused(theEvent)
450 #pragma unused(userData)
451
452 hdlmenu hmenu;
453 hdlmenurecord hm;
454 static boolean flinited = false;
455
456 menuid = 0;
457
458 dockmenuresetmenustack (); /*7.1b23 PBS: maintain a stack of submenus*/
459
460 if (!flinited) { /*install command handler first time*/
461
462 dockmenuinstallhandler ();
463
464 flinited = true;
465 } /*if*/
466
467 hmenu = Newmenu (defaultpopupmenuid, "");
468
469 if (!dockmenufillpopup (hmenu, &hm))
470 goto exit;
471
472 dockmenuaddtomenustack (hmenu, defaultpopupmenuid);
473
474 hcurrmenurecord = hm;
475
476 SetEventParameter (theEvent, kEventParamMenuRef, typeMenuRef, sizeof (MenuRef), &hmenu);
477
478 exit:
479
480 return (noErr); /*all's well in dock-menu-land*/
481 } /*dockmenuhandler*/
482
483 #endif
484
485 #if WIN95VERSION
486
487 void rundockmenu (void) {
488
489 /*
490 The system tray icon or dock icon has been right-clicked.
491 Display a menu and handle the user's choice.
492 */
493
494 hdlmenu hmenu;
495 hdlmenurecord hm;
496 POINT mousept;
497 UINT flags = 0;
498
499 hmenu = Newmenu (defaultpopupmenuid, "");
500
501 menuid = 0;
502
503 if (!dockmenufillpopup (hmenu, &hm))
504 goto exit;
505
506 SetMenuDefaultItem (GetSubMenu (hmenu, 0), 0, true); /*Top item is default*/
507
508 GetCursorPos (&mousept);
509
510 SetForegroundWindow (shellframewindow);
511
512 if (TrackPopupMenuEx (GetSubMenu (hmenu, 0), flags, mousept.x, mousept.y, shellframewindow, NULL)) {
513
514 MSG msg;
515 short itemhit;
516 hdlheadrecord hsummit;
517 hdlheadrecord hmenuitem;
518 bigstring bs;
519 boolean flopencommand = false;
520
521 if (PeekMessage (&msg, shellframewindow, WM_COMMAND, WM_COMMAND, PM_REMOVE)) {
522
523 itemhit = LOWORD (msg.wParam) % 100;
524
525 hsummit = (**(**hm).menuoutline).hsummit; /*Top level of the menu*/
526
527 //hmenuitem = opnthsubhead (hsummit, itemhit);
528
529 oppushoutline ((**hm).menuoutline);
530
531 hmenuitem = oprepeatedbump (flatdown, itemhit, hsummit, false);
532
533 getheadstring (hmenuitem, bs);
534
535 if (equalidentifiers (bs, "\x0d" "Open Frontier"))
536 flopencommand = true;
537
538 else if (equalidentifiers (bs, "\x0a" "Open Radio"))
539 flopencommand = true;
540
541 if (flopencommand) { /*Intercept -- there's no script verb for this command.*/
542
543 ShowWindow (shellframewindow, SW_SHOW); /*Show the window.*/
544
545 activateapplication (NULL); /*bring to front*/
546 } /*if*/
547
548 else /*run the script*/
549 meuserselected (hmenuitem);
550
551 oppopoutline ();
552 } /*if*/
553 } /*if*/
554
555 exit:
556
557 disposemenu (hmenu);
558 } /*rundockmenu*/
559
560 #endif
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.