root/lib/widget/mouse.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. init_mouse_event
  2. mouse_translate_event
  3. mouse_process_event
  4. mouse_handle_event

   1 /*
   2    Widgets for the Midnight Commander
   3 
   4    Copyright (C) 2016-2020
   5    Free Software Foundation, Inc.
   6 
   7    Authors:
   8    Human beings.
   9 
  10    This file is part of the Midnight Commander.
  11 
  12    The Midnight Commander is free software: you can redistribute it
  13    and/or modify it under the terms of the GNU General Public License as
  14    published by the Free Software Foundation, either version 3 of the License,
  15    or (at your option) any later version.
  16 
  17    The Midnight Commander 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, see <http://www.gnu.org/licenses/>.
  24  */
  25 
  26 /** \file mouse.c
  27  *  \brief Header: High-level mouse API
  28  */
  29 
  30 #include <config.h>
  31 
  32 #include "lib/global.h"
  33 #include "lib/widget.h"
  34 
  35 #include "lib/widget/mouse.h"
  36 
  37 /*** global variables ****************************************************************************/
  38 
  39 /*** file scope macro definitions ****************************************************************/
  40 
  41 /*** file scope type declarations ****************************************************************/
  42 
  43 /*** file scope variables ************************************************************************/
  44 
  45 /* --------------------------------------------------------------------------------------------- */
  46 /*** file scope functions ************************************************************************/
  47 /* --------------------------------------------------------------------------------------------- */
  48 
  49 /**
  50  * Constructs a mouse event structure.
  51  *
  52  * It receives a Gpm_Event event and translates it into a higher level protocol.
  53  *
  54  * Tip: for details on the C mouse API, see MC's lib/tty/mouse.h,
  55  * or GPM's excellent 'info' manual:
  56  *
  57  *    http://www.fifi.org/cgi-bin/info2www?(gpm)Event+Types
  58  */
  59 static void
  60 init_mouse_event (mouse_event_t * event, mouse_msg_t msg, const Gpm_Event * global_gpm,
     /* [previous][next][first][last][top][bottom][index][help]  */
  61                   const Widget * w)
  62 {
  63     event->msg = msg;
  64     event->x = global_gpm->x - w->x - 1;        /* '-1' because Gpm_Event is 1-based. */
  65     event->y = global_gpm->y - w->y - 1;
  66     event->count = global_gpm->type & (GPM_SINGLE | GPM_DOUBLE | GPM_TRIPLE);
  67     event->buttons = global_gpm->buttons;
  68     event->result.abort = FALSE;
  69     event->result.repeat = FALSE;
  70 }
  71 
  72 /* --------------------------------------------------------------------------------------------- */
  73 
  74 /**
  75  * Translate GPM event to high-level event,
  76  *
  77  * @param w Widget object
  78  * @param event GPM event
  79  *
  80  * @return high level mouse event
  81  */
  82 static mouse_event_t
  83 mouse_translate_event (Widget * w, Gpm_Event * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
  84 {
  85     gboolean in_widget;
  86     mouse_msg_t msg = MSG_MOUSE_NONE;
  87     mouse_event_t local;
  88 
  89     /*
  90      * Very special widgets may want to control area outside their bounds.
  91      * For such widgets you will have to turn on the 'forced_capture' flag.
  92      * You'll also need, in your mouse handler, to inform the system of
  93      * events you want to pass on by setting 'event->result.abort' to TRUE.
  94      */
  95     in_widget = w->mouse.forced_capture || mouse_global_in_widget (event, w);
  96 
  97     if ((event->type & GPM_DOWN) != 0)
  98     {
  99         if (in_widget)
 100         {
 101             if ((event->buttons & GPM_B_UP) != 0)
 102                 msg = MSG_MOUSE_SCROLL_UP;
 103             else if ((event->buttons & GPM_B_DOWN) != 0)
 104                 msg = MSG_MOUSE_SCROLL_DOWN;
 105             else
 106             {
 107                 /* Handle normal buttons: anything but the mouse wheel's.
 108                  *
 109                  * (Note that turning on capturing for the mouse wheel
 110                  * buttons doesn't make sense as they don't generate a
 111                  * mouse_up event, which means we'd never get uncaptured.)
 112                  */
 113                 w->mouse.capture = TRUE;
 114                 msg = MSG_MOUSE_DOWN;
 115 
 116                 w->mouse.last_buttons_down = event->buttons;
 117             }
 118         }
 119     }
 120     else if ((event->type & GPM_UP) != 0)
 121     {
 122         /* We trigger the mouse_up event even when !in_widget. That's
 123          * because, for example, a paint application should stop drawing
 124          * lines when the button is released even outside the canvas. */
 125         if (w->mouse.capture)
 126         {
 127             w->mouse.capture = FALSE;
 128             msg = MSG_MOUSE_UP;
 129 
 130             /*
 131              * When using xterm, event->buttons reports the buttons' state
 132              * after the event occurred (meaning that event->buttons is zero,
 133              * because the mouse button is now released). When using GPM,
 134              * however, that field reports the button(s) that was released.
 135              *
 136              * The following makes xterm behave effectively like GPM:
 137              */
 138             if (event->buttons == 0)
 139                 event->buttons = w->mouse.last_buttons_down;
 140         }
 141     }
 142     else if ((event->type & GPM_DRAG) != 0)
 143     {
 144         if (w->mouse.capture)
 145             msg = MSG_MOUSE_DRAG;
 146     }
 147     else if ((event->type & GPM_MOVE) != 0)
 148     {
 149         if (in_widget)
 150             msg = MSG_MOUSE_MOVE;
 151     }
 152 
 153     init_mouse_event (&local, msg, event, w);
 154 
 155     return local;
 156 }
 157 
 158 /* --------------------------------------------------------------------------------------------- */
 159 
 160 /**
 161  * Call widget mouse handler to process high-level mouse event.
 162  *
 163  * Besides sending to the widget the event itself, this function may also
 164  * send one or more pseudo events. Currently, MSG_MOUSE_CLICK is the only
 165  * pseudo event in existence but in the future (e.g., with the introduction
 166  * of a drag-drop API) there may be more.
 167  *
 168  * @param w Widget object
 169  * @param event high level mouse event
 170  *
 171  * @return result of mouse event handling
 172  */
 173 static int
 174 mouse_process_event (Widget * w, mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
 175 {
 176     int ret = MOU_UNHANDLED;
 177 
 178     if (event->msg != MSG_MOUSE_NONE)
 179     {
 180         w->mouse_callback (w, event->msg, event);
 181 
 182         /* If a widget aborts a MSG_MOUSE_DOWN, we uncapture it so it
 183          * doesn't steal events from other widgets. */
 184         if (event->msg == MSG_MOUSE_DOWN && event->result.abort)
 185             w->mouse.capture = FALSE;
 186 
 187         /* Upon releasing the mouse button: if the mouse hasn't been dragged
 188          * since the MSG_MOUSE_DOWN, we also trigger a click. */
 189         if (event->msg == MSG_MOUSE_UP && w->mouse.last_msg == MSG_MOUSE_DOWN)
 190             w->mouse_callback (w, MSG_MOUSE_CLICK, event);
 191 
 192         /* Record the current event type for the benefit of the next event. */
 193         w->mouse.last_msg = event->msg;
 194 
 195         if (!event->result.abort)
 196             ret = event->result.repeat ? MOU_REPEAT : MOU_NORMAL;
 197     }
 198 
 199     return ret;
 200 }
 201 
 202 
 203 /* --------------------------------------------------------------------------------------------- */
 204 /*** public functions ****************************************************************************/
 205 /* --------------------------------------------------------------------------------------------- */
 206 
 207 /**
 208  * Translate GPM event to high-level event and process it
 209  *
 210  * @param w Widget object
 211  * @param event GPM event
 212  *
 213  * @return result of mouse event handling
 214  */
 215 int
 216 mouse_handle_event (Widget * w, Gpm_Event * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
 217 {
 218     mouse_event_t me;
 219 
 220     me = mouse_translate_event (w, event);
 221 
 222     return mouse_process_event (w, &me);
 223 }
 224 
 225 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */