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

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

    From 2533049e28a2a5dbb45977e075e52b31d582334e Mon Sep 17 00:00:00 2001
    From: Mooffie <mooffie@gmail.com>
    Date: Sun, 13 Mar 2016 21:22:25 +0200
    Subject: [PATCH] Fix menu handling.
    
    We now send mouse events to widgets in reverse Z-order, as done in common GUIs.
    This makes it easy to implement "invisible" menubars correctly.
    ---
     lib/widget/dialog.c        | 49 ++++++++++++++++++++++++++++-----------
     lib/widget/dialog.h        |  1 +
     lib/widget/menu.c          | 11 +++++++--
     lib/widget/mouse.c         | 34 ---------------------------
     lib/widget/mouse.h         |  1 -
     src/filemanager/midnight.c | 58 +---------------------------------------------
     6 files changed, 46 insertions(+), 108 deletions(-)
    
    diff --git a/lib/widget/dialog.c b/lib/widget/dialog.c
    index 8b8f222..5855750 100644
    a b dlg_mouse_event (WDialog * h, Gpm_Event * event) 
    380380{ 
    381381    Widget *wh = WIDGET (h); 
    382382 
    383     GList *p, *first; 
     383    GList *p; 
    384384 
    385385    /* close the dialog by mouse left click out of dialog area */ 
    386386    if (mouse_close_dialog && !h->fullscreen && ((event->buttons & GPM_B_LEFT) != 0) 
    dlg_mouse_event (WDialog * h, Gpm_Event * event) 
    400400            return mou; 
    401401    } 
    402402 
    403     first = h->current; 
    404     p = first; 
    405  
     403    /* send the event to widgets in reverse Z-order */ 
     404    p = g_list_last (h->widgets); 
    406405    do 
    407406    { 
    408407        Widget *w = WIDGET (p->data); 
    409408 
    410         p = dlg_widget_prev (h, p); 
    411  
    412409        if ((w->options & W_DISABLED) == 0 && w->mouse_callback != NULL) 
    413410        { 
    414411            /* put global cursor position to the widget */ 
    dlg_mouse_event (WDialog * h, Gpm_Event * event) 
    418415            if (ret != MOU_UNHANDLED) 
    419416                return ret; 
    420417        } 
     418 
     419        p = g_list_previous (p); 
    421420    } 
    422     while (p != first); 
     421    while (p != NULL); 
    423422 
    424423    return MOU_UNHANDLED; 
    425424} 
    dlg_select_widget (void *w) 
    10901089 
    10911090/* --------------------------------------------------------------------------------------------- */ 
    10921091 
    1093 /** 
    1094  * Set widget at top of widget list and make it current. 
    1095  */ 
    1096  
    1097 void 
    1098 dlg_set_top_widget (void *w) 
     1092static void 
     1093dlg_set_top_or_bottom_widget (void *w, gboolean set_top) 
    10991094{ 
    11001095    Widget *widget = WIDGET (w); 
    11011096    WDialog *h = widget->owner; 
    dlg_set_top_widget (void *w) 
    11111106 
    11121107    /* widget reordering */ 
    11131108    h->widgets = g_list_remove_link (h->widgets, l); 
    1114     h->widgets = g_list_concat (h->widgets, l); 
     1109    if (set_top) 
     1110        h->widgets = g_list_concat (h->widgets, l); 
     1111    else 
     1112        h->widgets = g_list_concat (l, h->widgets); 
    11151113    h->current = l; 
    11161114} 
    11171115 
    11181116/* --------------------------------------------------------------------------------------------- */ 
     1117/** 
     1118 * Set widget at top of widget list and make it current. 
     1119 */ 
     1120 
     1121void 
     1122dlg_set_top_widget (void *w) 
     1123{ 
     1124    dlg_set_top_or_bottom_widget (w, TRUE); 
     1125} 
     1126 
     1127/* --------------------------------------------------------------------------------------------- */ 
     1128/** 
     1129 * Set widget at bottom of widget list (and make it current, albeit 
     1130 * typically you'd want to switch to some other widget right after). 
     1131 */ 
     1132 
     1133void 
     1134dlg_set_bottom_widget (void *w) 
     1135{ 
     1136    dlg_set_top_or_bottom_widget (w, FALSE); 
     1137} 
     1138 
     1139/* --------------------------------------------------------------------------------------------- */ 
    11191140/** Try to select previous widget in the tab order */ 
    11201141 
    11211142void 
  • lib/widget/dialog.h

    diff --git a/lib/widget/dialog.h b/lib/widget/dialog.h
    index 2510591..6ff23d8 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 b873d79..f542785 100644
    a b menubar_finish (WMenuBar * menubar) 
    309309    w->lines = 1; 
    310310    widget_want_hotkey (w, 0); 
    311311 
     312    /* Move the menubar to the bottom so that widgets displayed on top of 
     313     * an "invisible" menubar get the first chance to respond to mouse events. */ 
     314    dlg_set_bottom_widget (w); 
     315 
    312316    dlg_select_by_id (w->owner, menubar->previous_widget); 
    313317    do_refresh (); 
    314318} 
    menubar_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 
    722726                /* menu bar is not active -- activate it */ 
    723727                menubar->previous_widget = dlg_get_current_widget_id (w->owner); 
    724728                menubar->is_active = TRUE; 
    725                 dlg_select_widget (w); 
     729                dlg_set_top_widget (w); 
    726730            } 
    727731 
    728732            menubar_remove (menubar);   /* if already shown */ 
    menubar_activate (WMenuBar * menubar, gboolean dropped, int which) 
    10181022            menubar->selected = (guint) which; 
    10191023 
    10201024        menubar->previous_widget = dlg_get_current_widget_id (w->owner); 
    1021         dlg_select_widget (w); 
     1025 
     1026        /* Bring it to the top so it receives all mouse events before any other widget. 
     1027         * See also comment in menubar_finish(). */ 
     1028        dlg_set_top_widget (w); 
    10221029    } 
    10231030} 
    10241031 
  • lib/widget/mouse.c

    diff --git a/lib/widget/mouse.c b/lib/widget/mouse.c
    index 3bbec75..86c23b8 100644
    a b mouse_process_event (Widget * w, mouse_event_t * event, gboolean click) 
    196196} 
    197197 
    198198/* --------------------------------------------------------------------------------------------- */ 
    199  
    200 /** 
    201  * Send mouse event directly to widget. 
    202  * 
    203  * @param event mouse event. event's coordinates are relative to widget's owner 
    204  * @param w widget object. w's coordinates are global 
    205  * 
    206  * event's coordinates are relative to w->owner 
    207  * w's coordinates are global 
    208  */ 
    209 void 
    210 mouse_resend_event (mouse_event_t * event, Widget * w) 
    211 { 
    212     Widget *owner = WIDGET (w->owner); 
    213     int wy, wx; 
    214     int ey, ex; 
    215  
    216     /* w's coordinates relative to owner */ 
    217     wy = w->y - (owner != NULL ? owner->y : 0); 
    218     wx = w->x - (owner != NULL ? owner->x : 0); 
    219     /* save event's coordinates */ 
    220     ey = event->y; 
    221     ex = event->x; 
    222     /* event's coordinates relative to w */ 
    223     event->y -= wy; 
    224     event->x -= wx; 
    225     /* handle event in w */ 
    226     w->mouse_callback (w, event->msg, event); 
    227     /* restore event's coordinates for following handler */ 
    228     event->y = ey; 
    229     event->x = ex; 
    230 } 
    231  
    232 /* --------------------------------------------------------------------------------------------- */ 
  • lib/widget/mouse.h

    diff --git a/lib/widget/mouse.h b/lib/widget/mouse.h
    index 527b7de..aca8421 100644
    a b typedef struct 
    6060mouse_event_t mouse_translate_event (Widget * w, Gpm_Event * event, gboolean * click); 
    6161/* Process high-level mouse event */ 
    6262int mouse_process_event (Widget * w, mouse_event_t * event, gboolean click); 
    63 void mouse_resend_event (mouse_event_t * event, Widget * w); 
    6463 
    6564/*** inline functions ****************************************************************************/ 
    6665 
  • src/filemanager/midnight.c

    diff --git a/src/filemanager/midnight.c b/src/filemanager/midnight.c
    index f95c254..ac83c6b 100644
    a b midnight_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void 
    15761576} 
    15771577 
    15781578/* --------------------------------------------------------------------------------------------- */ 
    1579  
    1580 /** 
    1581  * Handle mouse events of file manager screen. 
    1582  * 
    1583  * @param ww Widget object (the file manager) 
    1584  * @param msg mouse event message 
    1585  * @param event mouse event data 
    1586  */ 
    1587 static void 
    1588 midnight_mouse_callback (Widget * ww, mouse_msg_t msg, mouse_event_t * event) 
    1589 { 
    1590     (void) ww; 
    1591  
    1592     if (event->y == 0) 
    1593     { 
    1594         /* menubar */ 
    1595  
    1596         if (menubar_visible || the_menubar->is_active) 
    1597             mouse_resend_event (event, WIDGET (the_menubar)); 
    1598         else 
    1599         { 
    1600             Widget *w; 
    1601  
    1602             w = get_panel_widget (0); 
    1603             if (w->mouse_callback != NULL) 
    1604                 mouse_resend_event (event, w); 
    1605  
    1606             if (event->result.abort) 
    1607             { 
    1608                 w = get_panel_widget (1); 
    1609                 if (w->mouse_callback != NULL) 
    1610                 { 
    1611                     event->result.abort = FALSE; 
    1612                     mouse_resend_event (event, w); 
    1613                 } 
    1614             } 
    1615  
    1616             if (event->result.abort) 
    1617             { 
    1618                 event->result.abort = FALSE; 
    1619  
    1620                 if (msg == MSG_MOUSE_DOWN && (!menubar_visible || !the_menubar->is_active)) 
    1621                     menubar_activate (the_menubar, drop_menus != 0, -1); 
    1622  
    1623                 mouse_resend_event (event, WIDGET (the_menubar)); 
    1624             } 
    1625         } 
    1626     } 
    1627     else 
    1628     { 
    1629         /* Continue handling of unhandled event in panel or menu */ 
    1630         event->result.abort = TRUE; 
    1631     } 
    1632 } 
    1633  
    1634 /* --------------------------------------------------------------------------------------------- */ 
    16351579/*** public functions ****************************************************************************/ 
    16361580/* --------------------------------------------------------------------------------------------- */ 
    16371581 
    do_nc (void) 
    18141758#endif 
    18151759 
    18161760    midnight_dlg = dlg_create (FALSE, 0, 0, LINES, COLS, dialog_colors, midnight_callback, 
    1817                                midnight_mouse_callback, "[main]", NULL, DLG_NONE); 
     1761                               NULL, "[main]", NULL, DLG_NONE); 
    18181762 
    18191763    /* Check if we were invoked as an editor or file viewer */ 
    18201764    if (mc_global.mc_run_mode != MC_RUN_FULL)