2015-11-26 01:28:08 +03:00
|
|
|
/*
|
|
|
|
Widgets for the Midnight Commander
|
|
|
|
|
|
|
|
Copyright (C) 1994-2016
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Authors:
|
|
|
|
Human beings.
|
|
|
|
|
|
|
|
This file is part of the Midnight Commander.
|
|
|
|
|
|
|
|
The Midnight Commander is free software: you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation, either version 3 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
The Midnight Commander is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file mouse.c
|
|
|
|
* \brief Header: High-level mouse API
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "lib/global.h"
|
|
|
|
#include "lib/widget.h"
|
|
|
|
|
2016-02-02 14:33:48 +03:00
|
|
|
#include "lib/widget/mouse.h"
|
|
|
|
|
2015-11-26 01:28:08 +03:00
|
|
|
/*** global variables ****************************************************************************/
|
|
|
|
|
|
|
|
/*** file scope macro definitions ****************************************************************/
|
|
|
|
|
|
|
|
/*** file scope type declarations ****************************************************************/
|
|
|
|
|
|
|
|
/*** file scope variables ************************************************************************/
|
|
|
|
|
|
|
|
static int last_buttons_down;
|
2016-02-07 10:41:02 +03:00
|
|
|
static gboolean was_drag = FALSE;
|
2015-11-26 01:28:08 +03:00
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/*** file scope functions ************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a mouse event structure. The is the high-level type used
|
|
|
|
* with "easy callbacks".
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
init_mouse_event (mouse_event_t * event, mouse_msg_t msg, const Gpm_Event * global_gpm,
|
|
|
|
const Widget * w)
|
|
|
|
{
|
|
|
|
event->msg = msg;
|
|
|
|
event->x = global_gpm->x - w->x - 1; /* '-1' because Gpm_Event is 1-based. */
|
|
|
|
event->y = global_gpm->y - w->y - 1;
|
|
|
|
event->count = global_gpm->type & (GPM_SINGLE | GPM_DOUBLE | GPM_TRIPLE);
|
|
|
|
event->buttons = global_gpm->buttons;
|
|
|
|
event->result.abort = FALSE;
|
|
|
|
event->result.repeat = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is the low-level mouse handler that's in use when you install
|
|
|
|
* an "easy callback".
|
|
|
|
*
|
|
|
|
* It receives a Gpm_Event event and translates it into a higher level
|
|
|
|
* protocol with which it feeds your "easy callback".
|
|
|
|
*
|
|
|
|
* Tip: for details on the C mouse API, see MC's lib/tty/mouse.h,
|
|
|
|
* or GPM's excellent 'info' manual:
|
|
|
|
*
|
|
|
|
* http://www.fifi.org/cgi-bin/info2www?(gpm)Event+Types
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
easy_mouse_translator (Gpm_Event * event, void *data)
|
|
|
|
{
|
|
|
|
Widget *w = WIDGET (data);
|
2016-02-02 14:33:48 +03:00
|
|
|
gboolean run_click;
|
|
|
|
mouse_event_t me;
|
|
|
|
|
|
|
|
me = mouse_translate_event (w, event, &run_click);
|
|
|
|
|
|
|
|
return mouse_process_event (w, &me, run_click);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
/*** public functions ****************************************************************************/
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Use this to install an "easy mouse callback".
|
|
|
|
*
|
|
|
|
* (The mouse callback widget_init() accepts is a low-level one; you can
|
|
|
|
* pass NULL to it. In the future we'll probably do the opposite: have
|
|
|
|
* widget_init() accept the "easy" callback.)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
set_easy_mouse_callback (Widget * w, easy_mouse_callback cb)
|
|
|
|
{
|
|
|
|
w->mouse = easy_mouse_translator;
|
|
|
|
w->Mouse.callback = cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2015-11-26 01:28:08 +03:00
|
|
|
|
2016-02-02 14:33:48 +03:00
|
|
|
/**
|
|
|
|
* Translate GPM event to high-level event,
|
|
|
|
*
|
|
|
|
* @param w Widget object
|
|
|
|
* @param event GPM event
|
|
|
|
* @param click whether mouse click was raised or not
|
|
|
|
*
|
|
|
|
* @return high level mouse event
|
|
|
|
*/
|
|
|
|
mouse_event_t
|
|
|
|
mouse_translate_event (Widget * w, Gpm_Event * event, gboolean * click)
|
|
|
|
{
|
2015-11-26 01:28:08 +03:00
|
|
|
gboolean in_widget;
|
|
|
|
mouse_msg_t msg = MSG_MOUSE_NONE;
|
2016-02-02 14:33:48 +03:00
|
|
|
mouse_event_t local;
|
2015-11-26 01:28:08 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Very special widgets may want to control area outside their bounds.
|
|
|
|
* For such widgets you will have to turn on the 'forced_capture' flag.
|
|
|
|
* You'll also need, in your mouse handler, to inform the system of
|
|
|
|
* events you want to pass on by setting 'event->result.abort' to TRUE.
|
|
|
|
*/
|
2016-01-20 13:41:06 +03:00
|
|
|
in_widget = w->Mouse.forced_capture || mouse_global_in_widget (event, w);
|
2015-11-26 01:28:08 +03:00
|
|
|
|
2016-02-02 14:33:48 +03:00
|
|
|
*click = FALSE;
|
|
|
|
|
2015-11-26 01:28:08 +03:00
|
|
|
if ((event->type & GPM_DOWN) != 0)
|
|
|
|
{
|
|
|
|
if (in_widget)
|
|
|
|
{
|
|
|
|
if ((event->buttons & GPM_B_UP) != 0)
|
|
|
|
msg = MSG_MOUSE_SCROLL_UP;
|
|
|
|
else if ((event->buttons & GPM_B_DOWN) != 0)
|
|
|
|
msg = MSG_MOUSE_SCROLL_DOWN;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Handle normal buttons: anything but the mouse wheel's.
|
|
|
|
*
|
|
|
|
* (Note that turning on capturing for the mouse wheel
|
|
|
|
* buttons doesn't make sense as they don't generate a
|
|
|
|
* mouse_up event, which means we'd never get uncaptured.)
|
|
|
|
*/
|
|
|
|
w->Mouse.capture = TRUE;
|
|
|
|
msg = MSG_MOUSE_DOWN;
|
|
|
|
|
|
|
|
last_buttons_down = event->buttons;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((event->type & GPM_UP) != 0)
|
|
|
|
{
|
|
|
|
/* We trigger the mouse_up event even when !in_widget. That's
|
|
|
|
* because, for example, a paint application should stop drawing
|
|
|
|
* lines when the button is released even outside the canvas. */
|
|
|
|
if (w->Mouse.capture)
|
|
|
|
{
|
|
|
|
w->Mouse.capture = FALSE;
|
|
|
|
msg = MSG_MOUSE_UP;
|
|
|
|
|
|
|
|
if (in_widget)
|
2016-02-02 14:33:48 +03:00
|
|
|
*click = !was_drag;
|
2015-11-26 01:28:08 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* When using xterm, event->buttons reports the buttons' state
|
|
|
|
* after the event occurred (meaning that event->buttons is zero,
|
|
|
|
* because the mouse button is now released). When using GPM,
|
|
|
|
* however, that field reports the button(s) that was released.
|
|
|
|
*
|
|
|
|
* The following makes xterm behave effectively like GPM:
|
|
|
|
*/
|
|
|
|
if (event->buttons == 0)
|
|
|
|
event->buttons = last_buttons_down;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((event->type & GPM_DRAG) != 0)
|
|
|
|
{
|
|
|
|
if (w->Mouse.capture)
|
|
|
|
msg = MSG_MOUSE_DRAG;
|
|
|
|
}
|
|
|
|
else if ((event->type & GPM_MOVE) != 0)
|
|
|
|
{
|
|
|
|
if (in_widget)
|
|
|
|
msg = MSG_MOUSE_MOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg != MSG_MOUSE_NONE)
|
2016-02-02 14:33:48 +03:00
|
|
|
/* Remember the current state for next event. */
|
2016-02-07 10:41:02 +03:00
|
|
|
was_drag = ((event->type & GPM_DRAG) != 0);
|
|
|
|
|
2016-02-02 14:33:48 +03:00
|
|
|
init_mouse_event (&local, msg, event, w);
|
2015-11-26 01:28:08 +03:00
|
|
|
|
2016-02-02 14:33:48 +03:00
|
|
|
return local;
|
2015-11-26 01:28:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
/**
|
2016-02-02 14:33:48 +03:00
|
|
|
* Call widget mouse handler to process high-level mouse event.
|
2015-11-26 01:28:08 +03:00
|
|
|
*
|
2016-02-02 14:33:48 +03:00
|
|
|
* @param w Widget object
|
|
|
|
* @param high level mouse event
|
|
|
|
* @param click whether mouse click was raised or not
|
|
|
|
*
|
|
|
|
* @return result of mouse event handling
|
2015-11-26 01:28:08 +03:00
|
|
|
*/
|
2016-02-02 14:33:48 +03:00
|
|
|
int
|
|
|
|
mouse_process_event (Widget * w, mouse_event_t * event, gboolean click)
|
2015-11-26 01:28:08 +03:00
|
|
|
{
|
2016-02-02 14:33:48 +03:00
|
|
|
int ret = MOU_UNHANDLED;
|
|
|
|
|
|
|
|
if (event->msg != MSG_MOUSE_NONE)
|
|
|
|
{
|
|
|
|
w->Mouse.callback (w, event->msg, event);
|
|
|
|
if (click)
|
|
|
|
w->Mouse.callback (w, MSG_MOUSE_CLICK, event);
|
|
|
|
|
|
|
|
if (!event->result.abort)
|
|
|
|
ret = event->result.repeat ? MOU_REPEAT : MOU_NORMAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2015-11-26 01:28:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|