comparison src/menubar-msw.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents 6719134a07c2
children a86b2b5e0111
comparison
equal deleted inserted replaced
397:f4aeb21a5bad 398:74fd4e045ea6
114 #define MENU_ITEM_ID_MIN 0x8000 114 #define MENU_ITEM_ID_MIN 0x8000
115 #define MENU_ITEM_ID_MAX 0xFFFF 115 #define MENU_ITEM_ID_MAX 0xFFFF
116 #define MENU_ITEM_ID_BITS(x) (((x) & 0x7FFF) | 0x8000) 116 #define MENU_ITEM_ID_BITS(x) (((x) & 0x7FFF) | 0x8000)
117 static HMENU top_level_menu; 117 static HMENU top_level_menu;
118 118
119 #define MAX_MENUITEM_LENGTH 128
120
121 /* 119 /*
122 * This returns Windows-style menu item string: 120 * This returns Windows-style menu item string:
123 * "Left Flush\tRight Flush" 121 * "Left Flush\tRight Flush"
124 */ 122 */
125 static char* 123 static char*
126 displayable_menu_item (struct gui_item* pgui_item, int bar_p) 124 displayable_menu_item (Lisp_Object gui_item, int bar_p)
127 { 125 {
128 /* We construct the name in a static buffer. That's fine, because 126 /* We construct the name in a static buffer. That's fine, because
129 menu items longer than 128 chars are probably programming errors, 127 menu items longer than 128 chars are probably programming errors,
130 and better be caught than displayed! */ 128 and better be caught than displayed! */
131 129
132 static char buf[MAX_MENUITEM_LENGTH+2]; 130 static char buf[MAX_MENUITEM_LENGTH+2];
133 char *ptr; 131 char *ptr;
134 unsigned int ll, lr; 132 unsigned int ll, lr;
135 133
136 /* Left flush part of the string */ 134 /* Left flush part of the string */
137 ll = gui_item_display_flush_left (pgui_item, buf, MAX_MENUITEM_LENGTH); 135 ll = gui_item_display_flush_left (gui_item, buf, MAX_MENUITEM_LENGTH);
138 136
139 /* Escape '&' as '&&' */ 137 /* Escape '&' as '&&' */
140 ptr = buf; 138 ptr = buf;
141 while ((ptr=memchr (ptr, '&', ll-(ptr-buf))) != NULL) 139 while ((ptr=memchr (ptr, '&', ll-(ptr-buf))) != NULL)
142 { 140 {
143 if (ll+2 >= MAX_MENUITEM_LENGTH) 141 if (ll+2 >= MAX_MENUITEM_LENGTH)
144 signal_simple_error ("Menu item produces too long displayable string", 142 signal_simple_error ("Menu item produces too long displayable string",
145 pgui_item->name); 143 XGUI_ITEM (gui_item)->name);
146 memmove (ptr+1, ptr, (ll-(ptr-buf))+1); 144 memmove (ptr+1, ptr, (ll-(ptr-buf))+1);
147 ll++; 145 ll++;
148 ptr+=2; 146 ptr+=2;
149 } 147 }
150 148
163 161
164 /* Right flush part, unless we're at the top-level where it's not allowed */ 162 /* Right flush part, unless we're at the top-level where it's not allowed */
165 if (!bar_p) 163 if (!bar_p)
166 { 164 {
167 assert (MAX_MENUITEM_LENGTH > ll + 1); 165 assert (MAX_MENUITEM_LENGTH > ll + 1);
168 lr = gui_item_display_flush_right (pgui_item, buf + ll + 1, 166 lr = gui_item_display_flush_right (gui_item, buf + ll + 1,
169 MAX_MENUITEM_LENGTH - ll - 1); 167 MAX_MENUITEM_LENGTH - ll - 1);
170 if (lr) 168 if (lr)
171 buf [ll] = '\t'; 169 buf [ll] = '\t';
172 } 170 }
173 171
277 } 275 }
278 else if (CONSP (item)) 276 else if (CONSP (item))
279 { 277 {
280 /* Submenu */ 278 /* Submenu */
281 HMENU submenu; 279 HMENU submenu;
282 struct gui_item gui_item; 280 Lisp_Object gui_item = allocate_gui_item ();
281 Lisp_Gui_Item* pgui_item = XGUI_ITEM (gui_item);
283 struct gcpro gcpro1; 282 struct gcpro gcpro1;
284 283
285 gui_item_init (&gui_item); 284 GCPRO1 (gui_item);
286 GCPRO_GUI_ITEM (&gui_item); 285
287 286 menu_parse_submenu_keywords (item, gui_item);
288 menu_parse_submenu_keywords (item, &gui_item); 287
289 288 if (!STRINGP (pgui_item->name))
290 if (!STRINGP (gui_item.name))
291 signal_simple_error ("Menu name (first element) must be a string", item); 289 signal_simple_error ("Menu name (first element) must be a string", item);
292 290
293 if (!gui_item_included_p (&gui_item, Vmenubar_configuration)) 291 if (!gui_item_included_p (gui_item, Vmenubar_configuration))
294 return; 292 return;
295 293
296 if (!gui_item_active_p (&gui_item)) 294 if (!gui_item_active_p (gui_item))
297 item_info.fState = MFS_GRAYED; 295 item_info.fState = MFS_GRAYED;
298 /* Temptation is to put 'else' right here. Although, the 296 /* Temptation is to put 'else' right here. Although, the
299 displayed item won't have an arrow indicating that it is a 297 displayed item won't have an arrow indicating that it is a
300 popup. So we go ahead a little bit more and create a popup */ 298 popup. So we go ahead a little bit more and create a popup */
301 submenu = create_empty_popup_menu(); 299 submenu = create_empty_popup_menu();
302 300
303 item_info.fMask |= MIIM_SUBMENU; 301 item_info.fMask |= MIIM_SUBMENU;
304 item_info.dwTypeData = displayable_menu_item (&gui_item, bar_p); 302 item_info.dwTypeData = displayable_menu_item (gui_item, bar_p);
305 item_info.hSubMenu = submenu; 303 item_info.hSubMenu = submenu;
306 304
307 if (!(item_info.fState & MFS_GRAYED)) 305 if (!(item_info.fState & MFS_GRAYED))
308 { 306 {
309 /* Now add the full submenu path as a value to the hash table, 307 /* Now add the full submenu path as a value to the hash table,
310 keyed by menu handle */ 308 keyed by menu handle */
311 if (NILP(path)) 309 if (NILP(path))
312 /* list1 cannot GC */ 310 /* list1 cannot GC */
313 path = list1 (gui_item.name); 311 path = list1 (pgui_item->name);
314 else 312 else
315 { 313 {
316 Lisp_Object arg[2]; 314 Lisp_Object arg[2];
317 arg[0] = path; 315 arg[0] = path;
318 arg[1] = list1 (gui_item.name); 316 arg[1] = list1 (pgui_item->name);
319 /* Fappend gcpro'es its arg */ 317 /* Fappend gcpro'es its arg */
320 path = Fappend (2, arg); 318 path = Fappend (2, arg);
321 } 319 }
322 320
323 /* Fputhash GCPRO'es PATH */ 321 /* Fputhash GCPRO'es PATH */
327 } 325 }
328 else if (VECTORP (item)) 326 else if (VECTORP (item))
329 { 327 {
330 /* An ordinary item */ 328 /* An ordinary item */
331 Lisp_Object style, id; 329 Lisp_Object style, id;
332 struct gui_item gui_item; 330 Lisp_Object gui_item = gui_parse_item_keywords (item);
331 Lisp_Gui_Item* pgui_item = XGUI_ITEM (gui_item);
333 struct gcpro gcpro1; 332 struct gcpro gcpro1;
334 333
335 gui_item_init (&gui_item); 334 GCPRO1 (gui_item);
336 GCPRO_GUI_ITEM (&gui_item); 335
337 336 if (!gui_item_included_p (gui_item, Vmenubar_configuration))
338 gui_parse_item_keywords (item, &gui_item);
339
340 if (!gui_item_included_p (&gui_item, Vmenubar_configuration))
341 return; 337 return;
342 338
343 if (!gui_item_active_p (&gui_item)) 339 if (!gui_item_active_p (gui_item))
344 item_info.fState = MFS_GRAYED; 340 item_info.fState = MFS_GRAYED;
345 341
346 style = (NILP (gui_item.selected) || NILP (Feval (gui_item.selected)) 342 style = (NILP (pgui_item->selected) || NILP (Feval (pgui_item->selected))
347 ? Qnil : gui_item.style); 343 ? Qnil : pgui_item->style);
348 344
349 if (EQ (style, Qradio)) 345 if (EQ (style, Qradio))
350 { 346 {
351 item_info.fType |= MFT_RADIOCHECK; 347 item_info.fType |= MFT_RADIOCHECK;
352 item_info.fState |= MFS_CHECKED; 348 item_info.fState |= MFS_CHECKED;
354 else if (EQ (style, Qtoggle)) 350 else if (EQ (style, Qtoggle))
355 { 351 {
356 item_info.fState |= MFS_CHECKED; 352 item_info.fState |= MFS_CHECKED;
357 } 353 }
358 354
359 id = allocate_menu_item_id (path, gui_item.name, 355 id = allocate_menu_item_id (path, pgui_item->name,
360 gui_item.suffix); 356 pgui_item->suffix);
361 Fputhash (id, gui_item.callback, hash_tab); 357 Fputhash (id, pgui_item->callback, hash_tab);
362 358
363 item_info.wID = (UINT) XINT(id); 359 item_info.wID = (UINT) XINT(id);
364 item_info.fType |= MFT_STRING; 360 item_info.fType |= MFT_STRING;
365 item_info.dwTypeData = displayable_menu_item (&gui_item, bar_p); 361 item_info.dwTypeData = displayable_menu_item (gui_item, bar_p);
366 362
367 UNGCPRO; /* gui_item */ 363 UNGCPRO; /* gui_item */
368 } 364 }
369 else 365 else
370 { 366 {
394 { 390 {
395 Lisp_Object item_desc; 391 Lisp_Object item_desc;
396 int deep_p, flush_right; 392 int deep_p, flush_right;
397 struct gcpro gcpro1; 393 struct gcpro gcpro1;
398 unsigned long checksum; 394 unsigned long checksum;
399 struct gui_item gui_item; 395 Lisp_Object gui_item = allocate_gui_item ();
400 396 Lisp_Gui_Item* pgui_item = XGUI_ITEM (gui_item);
401 gui_item_init (&gui_item); 397 GCPRO1 (gui_item);
402 GCPRO_GUI_ITEM (&gui_item);
403 398
404 /* We are sometimes called with the menubar unchanged, and with changed 399 /* We are sometimes called with the menubar unchanged, and with changed
405 right flush. We have to update the menubar in this case, 400 right flush. We have to update the menubar in this case,
406 so account for the compliance setting in the hash value */ 401 so account for the compliance setting in the hash value */
407 checksum = REPLACE_ME_WITH_GLOBAL_VARIABLE_WHICH_CONTROLS_RIHGT_FLUSH; 402 checksum = REPLACE_ME_WITH_GLOBAL_VARIABLE_WHICH_CONTROLS_RIHGT_FLUSH;
412 407
413 /* PATH set to nil indicates top-level popup or menubar */ 408 /* PATH set to nil indicates top-level popup or menubar */
414 deep_p = !NILP (path); 409 deep_p = !NILP (path);
415 410
416 /* Fetch keywords prepending the item list */ 411 /* Fetch keywords prepending the item list */
417 desc = menu_parse_submenu_keywords (desc, &gui_item); 412 desc = menu_parse_submenu_keywords (desc, gui_item);
418 413
419 /* Check that menu name is specified when expected */ 414 /* Check that menu name is specified when expected */
420 if (NILP (gui_item.name) && deep_p) 415 if (NILP (pgui_item->name) && deep_p)
421 signal_simple_error ("Menu must have a name", desc); 416 signal_simple_error ("Menu must have a name", desc);
422 417
423 /* Apply filter if specified */ 418 /* Apply filter if specified */
424 if (!NILP (gui_item.filter)) 419 if (!NILP (pgui_item->filter))
425 desc = call1 (gui_item.filter, desc); 420 desc = call1 (pgui_item->filter, desc);
426 421
427 /* Loop thru the desc's CDR and add items for each entry */ 422 /* Loop thru the desc's CDR and add items for each entry */
428 flush_right = 0; 423 flush_right = 0;
429 EXTERNAL_LIST_LOOP (item_desc, desc) 424 EXTERNAL_LIST_LOOP (item_desc, desc)
430 { 425 {
451 RemoveMenu (menu, EMPTY_ITEM_ID, MF_BYCOMMAND); 446 RemoveMenu (menu, EMPTY_ITEM_ID, MF_BYCOMMAND);
452 447
453 /* Add the header to the popup, if told so. The same as in X - an 448 /* Add the header to the popup, if told so. The same as in X - an
454 insensitive item, and a separator (Seems to me, there were 449 insensitive item, and a separator (Seems to me, there were
455 two separators in X... In Windows this looks ugly, anyways. */ 450 two separators in X... In Windows this looks ugly, anyways. */
456 if (!bar_p && !deep_p && popup_menu_titles && !NILP(gui_item.name)) 451 if (!bar_p && !deep_p && popup_menu_titles && !NILP(pgui_item->name))
457 { 452 {
458 CHECK_STRING (gui_item.name); 453 CHECK_STRING (pgui_item->name);
459 InsertMenu (menu, 0, MF_BYPOSITION | MF_STRING | MF_DISABLED, 454 InsertMenu (menu, 0, MF_BYPOSITION | MF_STRING | MF_DISABLED,
460 0, XSTRING_DATA(gui_item.name)); 455 0, XSTRING_DATA(pgui_item->name));
461 InsertMenu (menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); 456 InsertMenu (menu, 1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
462 SetMenuDefaultItem (menu, 0, MF_BYPOSITION); 457 SetMenuDefaultItem (menu, 0, MF_BYPOSITION);
463 } 458 }
464 } 459 }
465 UNGCPRO; /* gui_item */ 460 UNGCPRO; /* gui_item */
739 734
740 static void 735 static void
741 mswindows_popup_menu (Lisp_Object menu_desc, Lisp_Object event) 736 mswindows_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
742 { 737 {
743 struct frame *f = selected_frame (); 738 struct frame *f = selected_frame ();
744 struct Lisp_Event *eev = NULL; 739 Lisp_Event *eev = NULL;
745 HMENU menu; 740 HMENU menu;
746 POINT pt; 741 POINT pt;
747 int ok; 742 int ok;
748 743
749 if (!NILP (event)) 744 if (!NILP (event))