Ticket #3571: 3571-Fix-menu-handling.patch

File 3571-Fix-menu-handling.patch, 9.4 KB (added by mooffie, 8 years ago)
  • lib/widget/dialog.c

    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 
    379379dlg_mouse_event (WDialog * h, Gpm_Event * event) 
    380380{ 
    381381    Widget *wh = WIDGET (h); 
    382  
    383     GList *p, *first; 
     382    GList *p; 
    384383 
    385384    /* close the dialog by mouse left click out of dialog area */ 
    386385    if (mouse_close_dialog && !h->fullscreen && ((event->buttons & GPM_B_LEFT) != 0) 
    dlg_mouse_event (WDialog * h, Gpm_Event * event) 
    400399            return mou; 
    401400    } 
    402401 
    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); 
    406404    do 
    407405    { 
    408406        Widget *w = WIDGET (p->data); 
    409407 
    410         p = dlg_widget_prev (h, p); 
    411  
    412408        if ((w->options & W_DISABLED) == 0 && w->mouse_callback != NULL) 
    413409        { 
    414410            /* put global cursor position to the widget */ 
    dlg_mouse_event (WDialog * h, Gpm_Event * event) 
    418414            if (ret != MSG_NOT_HANDLED) 
    419415                return ret; 
    420416        } 
     417 
     418        p = g_list_previous (p); 
    421419    } 
    422     while (p != first); 
     420    while (p != NULL); 
    423421 
    424422    return MSG_NOT_HANDLED; 
    425423} 
    dlg_select_widget (void *w) 
    10901088 
    10911089/* --------------------------------------------------------------------------------------------- */ 
    10921090 
    1093 /** 
    1094  * Set widget at top of widget list and make it current. 
    1095  */ 
    1096  
    1097 void 
    1098 dlg_set_top_widget (void *w) 
     1091static void 
     1092dlg_set_top_or_bottom_widget (void *w, gboolean set_top) 
    10991093{ 
    11001094    Widget *widget = WIDGET (w); 
    11011095    WDialog *h = widget->owner; 
    dlg_set_top_widget (void *w) 
    11111105 
    11121106    /* widget reordering */ 
    11131107    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 
     1120void 
     1121dlg_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 
     1132void 
     1133dlg_set_bottom_widget (void *w) 
     1134{ 
     1135    dlg_set_top_or_bottom_widget (w, FALSE); 
    11161136} 
    11171137 
    11181138/* --------------------------------------------------------------------------------------------- */ 
  • lib/widget/dialog.h

    diff --git a/lib/widget/dialog.h b/lib/widget/dialog.h
    index 1b7fd23..2d75a0a 100644
    a b void dlg_stop (WDialog * h); 
    170170/* Widget selection */ 
    171171void dlg_select_widget (void *w); 
    172172void dlg_set_top_widget (void *w); 
     173void dlg_set_bottom_widget (void *w); 
    173174void dlg_one_up (WDialog * h); 
    174175void dlg_one_down (WDialog * h); 
    175176gboolean dlg_focus (WDialog * h); 
  • lib/widget/menu.c

    diff --git a/lib/widget/menu.c b/lib/widget/menu.c
    index 6c5b052..27ba923 100644
    a b menubar_finish (WMenuBar * menubar) 
    309309    w->lines = 1; 
    310310    widget_want_hotkey (w, 0); 
    311311 
     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 
    312318    dlg_select_by_id (w->owner, menubar->previous_widget); 
    313319    do_refresh (); 
    314320} 
    menubar_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    580586        if (!menubar->is_active) 
    581587            return MSG_NOT_HANDLED; 
    582588 
    583         /* Trick to get all the mouse events */ 
     589        /* Trick to get mouse events from the whole screen. */ 
    584590        w->lines = LINES; 
    585591 
    586592        /* Trick to get all of the hotkeys */ 
    menubar_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 
    718724            selected = menubar_get_menu_by_x_coord (menubar, event->x); 
    719725 
    720726            if (!menubar->is_active) 
    721             { 
    722727                /* 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); 
    727729 
    728730            menubar_remove (menubar);   /* if already shown */ 
    729731            menubar_drop (menubar, selected); 
    find_menubar (const WDialog * h) 
    9991001} 
    10001002 
    10011003/* --------------------------------------------------------------------------------------------- */ 
     1004/** 
     1005 * Activate the menu. 
     1006 */ 
     1007 
     1008void 
     1009menubar_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/* --------------------------------------------------------------------------------------------- */ 
  • lib/widget/menu.h

    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); 
    5555void menubar_arrange (WMenuBar * menubar); 
    5656 
    5757WMenuBar *find_menubar (const WDialog * h); 
     58void menubar_activate (WMenuBar * menubar); 
    5859 
    5960/*** inline functions ****************************************************************************/ 
    6061 
  • src/editor/editmenu.c

    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) 
    271271 
    272272    if (!menubar->is_active) 
    273273    { 
    274         menubar->is_active = TRUE; 
    275274        menubar->is_dropped = (drop_menus != 0); 
    276275        if (which >= 0) 
    277276            menubar->selected = (guint) which; 
    278  
    279         menubar->previous_widget = dlg_get_current_widget_id (h); 
    280         dlg_select_widget (menubar); 
     277        menubar_activate (menubar); 
    281278    } 
    282279} 
    283280 
  • src/filemanager/midnight.c

    diff --git a/src/filemanager/midnight.c b/src/filemanager/midnight.c
    index 73dfff5..5378811 100644
    a b init_menu (void) 
    367367static void 
    368368menu_last_selected_cmd (void) 
    369369{ 
    370     the_menubar->is_active = TRUE; 
    371370    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); 
    374372} 
    375373 
    376374/* --------------------------------------------------------------------------------------------- */ 
    create_panels_and_run_mc (void) 
    937935 
    938936    create_panels (); 
    939937 
     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. */ 
    940940    add_widget (midnight_dlg, the_menubar); 
    941941    init_menu (); 
    942942 
    midnight_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    15901590} 
    15911591 
    15921592/* --------------------------------------------------------------------------------------------- */ 
    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 /* --------------------------------------------------------------------------------------------- */ 
    16191593/*** public functions ****************************************************************************/ 
    16201594/* --------------------------------------------------------------------------------------------- */ 
    16211595 
    do_nc (void) 
    17981772#endif 
    17991773 
    18001774    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); 
    18021776 
    18031777    /* Check if we were invoked as an editor or file viewer */ 
    18041778    if (mc_global.mc_run_mode != MC_RUN_FULL)