From 830c99bb4361aa6e9be81e5cdf8756d513fbb3c5 Mon Sep 17 00:00:00 2001
From: Mooffie <mooffie@gmail.com>
Date: Tue, 8 Mar 2016 22:45:17 +0200
Subject: [PATCH] Fix menu handling.
We now send mouse events to widgets in reverse stacking order: from topmost
widget to bottomost. Then, by pushing menus to the bottom of the stack, we
make "invisible" menus work correctly.
---
lib/widget/dialog.c | 52 ++++++++++++++++++++++++++++++++--------------
lib/widget/dialog.h | 1 +
lib/widget/menu.c | 30 ++++++++++++++++++++------
lib/widget/menu.h | 1 +
src/editor/editmenu.c | 5 +----
src/filemanager/midnight.c | 34 ++++--------------------------
6 files changed, 67 insertions(+), 56 deletions(-)
diff --git a/lib/widget/dialog.c b/lib/widget/dialog.c
index ddf78f7..af4625f 100644
a
|
b
|
static cb_ret_t |
379 | 379 | dlg_mouse_event (WDialog * h, Gpm_Event * event) |
380 | 380 | { |
381 | 381 | Widget *wh = WIDGET (h); |
382 | | |
383 | | GList *p, *first; |
| 382 | GList *p; |
384 | 383 | |
385 | 384 | /* close the dialog by mouse left click out of dialog area */ |
386 | 385 | if (mouse_close_dialog && !h->fullscreen && ((event->buttons & GPM_B_LEFT) != 0) |
… |
… |
dlg_mouse_event (WDialog * h, Gpm_Event * event) |
400 | 399 | return mou; |
401 | 400 | } |
402 | 401 | |
403 | | first = h->current; |
404 | | p = first; |
405 | | |
| 402 | /* Send the event to widgets in reverse stacking order: from the topmost to the bottomost. */ |
| 403 | p = g_list_last (h->widgets); |
406 | 404 | do |
407 | 405 | { |
408 | 406 | Widget *w = WIDGET (p->data); |
409 | 407 | |
410 | | p = dlg_widget_prev (h, p); |
411 | | |
412 | 408 | if ((w->options & W_DISABLED) == 0 && w->mouse_callback != NULL) |
413 | 409 | { |
414 | 410 | /* put global cursor position to the widget */ |
… |
… |
dlg_mouse_event (WDialog * h, Gpm_Event * event) |
418 | 414 | if (ret != MSG_NOT_HANDLED) |
419 | 415 | return ret; |
420 | 416 | } |
| 417 | |
| 418 | p = g_list_previous (p); |
421 | 419 | } |
422 | | while (p != first); |
| 420 | while (p != NULL); |
423 | 421 | |
424 | 422 | return MSG_NOT_HANDLED; |
425 | 423 | } |
… |
… |
dlg_select_widget (void *w) |
1090 | 1088 | |
1091 | 1089 | /* --------------------------------------------------------------------------------------------- */ |
1092 | 1090 | |
1093 | | /** |
1094 | | * Set widget at top of widget list and make it current. |
1095 | | */ |
1096 | | |
1097 | | void |
1098 | | dlg_set_top_widget (void *w) |
| 1091 | static void |
| 1092 | dlg_set_top_or_bottom_widget (void *w, gboolean set_top) |
1099 | 1093 | { |
1100 | 1094 | Widget *widget = WIDGET (w); |
1101 | 1095 | WDialog *h = widget->owner; |
… |
… |
dlg_set_top_widget (void *w) |
1111 | 1105 | |
1112 | 1106 | /* widget reordering */ |
1113 | 1107 | h->widgets = g_list_remove_link (h->widgets, l); |
1114 | | h->widgets = g_list_concat (h->widgets, l); |
1115 | | h->current = l; |
| 1108 | if (set_top) |
| 1109 | h->widgets = g_list_concat (h->widgets, l); |
| 1110 | else |
| 1111 | h->widgets = g_list_concat (l, h->widgets); |
| 1112 | h->current = l; /* @FIXME: this is probably not needed. */ |
| 1113 | } |
| 1114 | |
| 1115 | /* --------------------------------------------------------------------------------------------- */ |
| 1116 | /** |
| 1117 | * Set widget at top of widget list and make it current. |
| 1118 | */ |
| 1119 | |
| 1120 | void |
| 1121 | dlg_set_top_widget (void *w) |
| 1122 | { |
| 1123 | dlg_set_top_or_bottom_widget (w, TRUE); |
| 1124 | } |
| 1125 | |
| 1126 | /* --------------------------------------------------------------------------------------------- */ |
| 1127 | /** |
| 1128 | * Set widget at bottom of widget list (and make it current, albeit |
| 1129 | * typically you'd want to switch to some other widget right after). |
| 1130 | */ |
| 1131 | |
| 1132 | void |
| 1133 | dlg_set_bottom_widget (void *w) |
| 1134 | { |
| 1135 | dlg_set_top_or_bottom_widget (w, FALSE); |
1116 | 1136 | } |
1117 | 1137 | |
1118 | 1138 | /* --------------------------------------------------------------------------------------------- */ |
diff --git a/lib/widget/dialog.h b/lib/widget/dialog.h
index 1b7fd23..2d75a0a 100644
a
|
b
|
void dlg_stop (WDialog * h); |
170 | 170 | /* Widget selection */ |
171 | 171 | void dlg_select_widget (void *w); |
172 | 172 | void dlg_set_top_widget (void *w); |
| 173 | void dlg_set_bottom_widget (void *w); |
173 | 174 | void dlg_one_up (WDialog * h); |
174 | 175 | void dlg_one_down (WDialog * h); |
175 | 176 | gboolean dlg_focus (WDialog * h); |
diff --git a/lib/widget/menu.c b/lib/widget/menu.c
index 6c5b052..27ba923 100644
a
|
b
|
menubar_finish (WMenuBar * menubar) |
309 | 309 | w->lines = 1; |
310 | 310 | widget_want_hotkey (w, 0); |
311 | 311 | |
| 312 | /* If the menubar is "invisible", moving it to the bottom of the stack |
| 313 | * makes it receive mouse events (and thereby activated) only if the |
| 314 | * widgets shown in its space ignore them. In other words, we make |
| 315 | * visible widgets take precedence over an invisible menubar. */ |
| 316 | dlg_set_bottom_widget (menubar); |
| 317 | |
312 | 318 | dlg_select_by_id (w->owner, menubar->previous_widget); |
313 | 319 | do_refresh (); |
314 | 320 | } |
… |
… |
menubar_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void |
580 | 586 | if (!menubar->is_active) |
581 | 587 | return MSG_NOT_HANDLED; |
582 | 588 | |
583 | | /* Trick to get all the mouse events */ |
| 589 | /* Trick to get mouse events from the whole screen. */ |
584 | 590 | w->lines = LINES; |
585 | 591 | |
586 | 592 | /* Trick to get all of the hotkeys */ |
… |
… |
menubar_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) |
718 | 724 | selected = menubar_get_menu_by_x_coord (menubar, event->x); |
719 | 725 | |
720 | 726 | if (!menubar->is_active) |
721 | | { |
722 | 727 | /* menu bar is not active -- activate it */ |
723 | | menubar->previous_widget = dlg_get_current_widget_id (w->owner); |
724 | | menubar->is_active = TRUE; |
725 | | dlg_select_widget (w); |
726 | | } |
| 728 | menubar_activate (menubar); |
727 | 729 | |
728 | 730 | menubar_remove (menubar); /* if already shown */ |
729 | 731 | menubar_drop (menubar, selected); |
… |
… |
find_menubar (const WDialog * h) |
999 | 1001 | } |
1000 | 1002 | |
1001 | 1003 | /* --------------------------------------------------------------------------------------------- */ |
| 1004 | /** |
| 1005 | * Activate the menu. |
| 1006 | */ |
| 1007 | |
| 1008 | void |
| 1009 | menubar_activate (WMenuBar * menubar) |
| 1010 | { |
| 1011 | menubar->previous_widget = dlg_get_current_widget_id (WIDGET (menubar)->owner); |
| 1012 | menubar->is_active = TRUE; |
| 1013 | |
| 1014 | /* Make the menubar receive all mouse events before any other widget. |
| 1015 | * See also comment in menubar_finish(). */ |
| 1016 | dlg_set_top_widget (menubar); |
| 1017 | } |
| 1018 | |
| 1019 | /* --------------------------------------------------------------------------------------------- */ |
diff --git a/lib/widget/menu.h b/lib/widget/menu.h
index d61560c..0797543 100644
a
|
b
|
void menubar_add_menu (WMenuBar * menubar, menu_t * menu); |
55 | 55 | void menubar_arrange (WMenuBar * menubar); |
56 | 56 | |
57 | 57 | WMenuBar *find_menubar (const WDialog * h); |
| 58 | void menubar_activate (WMenuBar * menubar); |
58 | 59 | |
59 | 60 | /*** inline functions ****************************************************************************/ |
60 | 61 | |
diff --git a/src/editor/editmenu.c b/src/editor/editmenu.c
index 51a9f35..09c935d 100644
a
|
b
|
edit_drop_menu_cmd (WDialog * h, int which) |
271 | 271 | |
272 | 272 | if (!menubar->is_active) |
273 | 273 | { |
274 | | menubar->is_active = TRUE; |
275 | 274 | menubar->is_dropped = (drop_menus != 0); |
276 | 275 | if (which >= 0) |
277 | 276 | menubar->selected = (guint) which; |
278 | | |
279 | | menubar->previous_widget = dlg_get_current_widget_id (h); |
280 | | dlg_select_widget (menubar); |
| 277 | menubar_activate (menubar); |
281 | 278 | } |
282 | 279 | } |
283 | 280 | |
diff --git a/src/filemanager/midnight.c b/src/filemanager/midnight.c
index 73dfff5..5378811 100644
a
|
b
|
init_menu (void) |
367 | 367 | static void |
368 | 368 | menu_last_selected_cmd (void) |
369 | 369 | { |
370 | | the_menubar->is_active = TRUE; |
371 | 370 | the_menubar->is_dropped = (drop_menus != 0); |
372 | | the_menubar->previous_widget = dlg_get_current_widget_id (midnight_dlg); |
373 | | dlg_select_widget (the_menubar); |
| 371 | menubar_activate (the_menubar); |
374 | 372 | } |
375 | 373 | |
376 | 374 | /* --------------------------------------------------------------------------------------------- */ |
… |
… |
create_panels_and_run_mc (void) |
937 | 935 | |
938 | 936 | create_panels (); |
939 | 937 | |
| 938 | /* Note: the menu is the first widget we add to the dialog because |
| 939 | * an "invisible" menu has to be at the bottom of the stack. */ |
940 | 940 | add_widget (midnight_dlg, the_menubar); |
941 | 941 | init_menu (); |
942 | 942 | |
… |
… |
midnight_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void |
1590 | 1590 | } |
1591 | 1591 | |
1592 | 1592 | /* --------------------------------------------------------------------------------------------- */ |
1593 | | |
1594 | | /** |
1595 | | * Handle mouse events of file manager screen. |
1596 | | * |
1597 | | * @param w Widget object (the file manager) |
1598 | | * @param msg mouse event message |
1599 | | * @param event mouse event data |
1600 | | */ |
1601 | | static cb_ret_t |
1602 | | midnight_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) |
1603 | | { |
1604 | | (void) w; |
1605 | | (void) msg; |
1606 | | |
1607 | | if (msg == MSG_MOUSE_DOWN && event->y == 0) |
1608 | | { |
1609 | | /* menubar */ |
1610 | | if (!the_menubar->is_active) |
1611 | | dlg_select_widget (WIDGET (the_menubar)); |
1612 | | } |
1613 | | |
1614 | | /* allow handle menu events */ |
1615 | | return MSG_NOT_HANDLED; |
1616 | | } |
1617 | | |
1618 | | /* --------------------------------------------------------------------------------------------- */ |
1619 | 1593 | /*** public functions ****************************************************************************/ |
1620 | 1594 | /* --------------------------------------------------------------------------------------------- */ |
1621 | 1595 | |
… |
… |
do_nc (void) |
1798 | 1772 | #endif |
1799 | 1773 | |
1800 | 1774 | midnight_dlg = dlg_create (FALSE, 0, 0, LINES, COLS, dialog_colors, midnight_callback, |
1801 | | midnight_mouse_callback, "[main]", NULL, DLG_NONE); |
| 1775 | NULL, "[main]", NULL, DLG_NONE); |
1802 | 1776 | |
1803 | 1777 | /* Check if we were invoked as an editor or file viewer */ |
1804 | 1778 | if (mc_global.mc_run_mode != MC_RUN_FULL) |