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

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