Ticket #3571: high-level mouse API.
[midnight-commander.git] / lib / widget / mouse.c
blobeca9d708156078c5443214f2222df164af3b3b35
1 /*
2 Widgets for the Midnight Commander
4 Copyright (C) 1994-2016
5 Free Software Foundation, Inc.
7 Authors:
8 Human beings.
10 This file is part of the Midnight Commander.
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.
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.
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/>.
26 /** \file mouse.c
27 * \brief Header: High-level mouse API
30 #include <config.h>
32 #include "lib/global.h"
33 #include "lib/widget.h"
35 /*** global variables ****************************************************************************/
37 /*** file scope macro definitions ****************************************************************/
39 /*** file scope type declarations ****************************************************************/
41 /*** file scope variables ************************************************************************/
43 static int last_buttons_down;
45 /* --------------------------------------------------------------------------------------------- */
46 /*** file scope functions ************************************************************************/
47 /* --------------------------------------------------------------------------------------------- */
49 /**
50 * Constructs a mouse event structure. The is the high-level type used
51 * with "easy callbacks".
53 static void
54 init_mouse_event (mouse_event_t * event, mouse_msg_t msg, const Gpm_Event * global_gpm,
55 const Widget * w)
57 event->msg = msg;
58 event->x = global_gpm->x - w->x - 1; /* '-1' because Gpm_Event is 1-based. */
59 event->y = global_gpm->y - w->y - 1;
60 event->count = global_gpm->type & (GPM_SINGLE | GPM_DOUBLE | GPM_TRIPLE);
61 event->buttons = global_gpm->buttons;
62 event->result.abort = FALSE;
63 event->result.repeat = FALSE;
66 /* --------------------------------------------------------------------------------------------- */
68 /**
69 * This is the low-level mouse handler that's in use when you install
70 * an "easy callback".
72 * It receives a Gpm_Event event and translates it into a higher level
73 * protocol with which it feeds your "easy callback".
75 * Tip: for details on the C mouse API, see MC's lib/tty/mouse.h,
76 * or GPM's excellent 'info' manual:
78 * http://www.fifi.org/cgi-bin/info2www?(gpm)Event+Types
80 static int
81 easy_mouse_translator (Gpm_Event * event, void *data)
83 Widget *w = WIDGET (data);
85 gboolean in_widget;
86 gboolean run_click = FALSE;
87 mouse_msg_t msg = MSG_MOUSE_NONE;
89 in_widget = mouse_global_in_widget (event, w);
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.
97 if (w->Mouse.forced_capture)
98 in_widget = TRUE;
100 if ((event->type & GPM_DOWN) != 0)
102 if (in_widget)
104 if ((event->buttons & GPM_B_UP) != 0)
105 msg = MSG_MOUSE_SCROLL_UP;
106 else if ((event->buttons & GPM_B_DOWN) != 0)
107 msg = MSG_MOUSE_SCROLL_DOWN;
108 else
110 /* Handle normal buttons: anything but the mouse wheel's.
112 * (Note that turning on capturing for the mouse wheel
113 * buttons doesn't make sense as they don't generate a
114 * mouse_up event, which means we'd never get uncaptured.)
116 w->Mouse.capture = TRUE;
117 msg = MSG_MOUSE_DOWN;
119 last_buttons_down = event->buttons;
123 else if ((event->type & GPM_UP) != 0)
125 /* We trigger the mouse_up event even when !in_widget. That's
126 * because, for example, a paint application should stop drawing
127 * lines when the button is released even outside the canvas. */
128 if (w->Mouse.capture)
130 w->Mouse.capture = FALSE;
131 msg = MSG_MOUSE_UP;
133 if (in_widget)
134 run_click = TRUE;
137 * When using xterm, event->buttons reports the buttons' state
138 * after the event occurred (meaning that event->buttons is zero,
139 * because the mouse button is now released). When using GPM,
140 * however, that field reports the button(s) that was released.
142 * The following makes xterm behave effectively like GPM:
144 if (event->buttons == 0)
145 event->buttons = last_buttons_down;
148 else if ((event->type & GPM_DRAG) != 0)
150 if (w->Mouse.capture)
151 msg = MSG_MOUSE_DRAG;
153 else if ((event->type & GPM_MOVE) != 0)
155 if (in_widget)
156 msg = MSG_MOUSE_MOVE;
159 if (msg != MSG_MOUSE_NONE)
161 mouse_event_t local;
163 init_mouse_event (&local, msg, event, w);
165 w->Mouse.callback (w, msg, &local);
166 if (run_click)
167 w->Mouse.callback (w, MSG_MOUSE_CLICK, &local);
169 if (!local.result.abort)
170 return local.result.repeat ? MOU_REPEAT : MOU_NORMAL;
173 return MOU_UNHANDLED;
176 /* --------------------------------------------------------------------------------------------- */
177 /*** public functions ****************************************************************************/
178 /* --------------------------------------------------------------------------------------------- */
181 * Use this to install an "easy mouse callback".
183 * (The mouse callback widget_init() accepts is a low-level one; you can
184 * pass NULL to it. In the future we'll probably do the opposite: have
185 * widget_init() accept the "easy" callback.)
187 void
188 set_easy_mouse_callback (Widget * w, easy_mouse_callback cb)
190 w->mouse = easy_mouse_translator;
191 w->Mouse.callback = cb;
194 /* --------------------------------------------------------------------------------------------- */