gtk2/gdk/x11/gdkeventsource.c

521 lines
15 KiB
C
Raw Normal View History

2010-05-25 22:38:44 +00:00
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
2012-02-27 13:01:10 +00:00
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
2010-05-25 22:38:44 +00:00
*/
#include "config.h"
#include "gdkeventsource.h"
2010-05-25 22:38:44 +00:00
#include "gdkinternals.h"
#include "gdksurface-x11.h"
#include "gdkprivate-x11.h"
#include "gdkdisplay-x11.h"
#include "xsettings-client.h"
2010-05-25 22:38:44 +00:00
static gboolean gdk_event_source_prepare (GSource *source,
gint *timeout);
static gboolean gdk_event_source_check (GSource *source);
static gboolean gdk_event_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static void gdk_event_source_finalize (GSource *source);
static GQuark quark_needs_enter = 0;
#define HAS_FOCUS(toplevel) \
((toplevel)->has_focus || (toplevel)->has_pointer_focus)
2010-05-25 22:38:44 +00:00
struct _GdkEventSource
{
GSource source;
GdkDisplay *display;
GPollFD event_poll_fd;
GList *translators;
};
static GSourceFuncs event_funcs = {
gdk_event_source_prepare,
gdk_event_source_check,
gdk_event_source_dispatch,
gdk_event_source_finalize
};
GdkWindow -> GdkSurface initial type rename This renames the GdkWindow class and related classes (impl, backend subclasses) to surface. Additionally it renames related types: GdkWindowAttr, GdkWindowPaint, GdkWindowWindowClass, GdkWindowType, GdkWindowTypeHint, GdkWindowHints, GdkWindowState, GdkWindowEdge This is an automatic conversion using the below commands: git sed -f g GdkWindowWindowClass GdkSurfaceSurfaceClass git sed -f g GdkWindow GdkSurface git sed -f g "gdk_window\([ _\(\),;]\|$\)" "gdk_surface\1" # Avoid hitting gdk_windowing git sed -f g "GDK_WINDOW\([ _\(]\|$\)" "GDK_SURFACE\1" # Avoid hitting GDK_WINDOWING git sed "GDK_\([A-Z]*\)IS_WINDOW\([_ (]\|$\)" "GDK_\1IS_SURFACE\2" git sed GDK_TYPE_WINDOW GDK_TYPE_SURFACE git sed -f g GdkPointerWindowInfo GdkPointerSurfaceInfo git sed -f g "BROADWAY_WINDOW" "BROADWAY_SURFACE" git sed -f g "broadway_window" "broadway_surface" git sed -f g "BroadwayWindow" "BroadwaySurface" git sed -f g "WAYLAND_WINDOW" "WAYLAND_SURFACE" git sed -f g "wayland_window" "wayland_surface" git sed -f g "WaylandWindow" "WaylandSurface" git sed -f g "X11_WINDOW" "X11_SURFACE" git sed -f g "x11_window" "x11_surface" git sed -f g "X11Window" "X11Surface" git sed -f g "WIN32_WINDOW" "WIN32_SURFACE" git sed -f g "win32_window" "win32_surface" git sed -f g "Win32Window" "Win32Surface" git sed -f g "QUARTZ_WINDOW" "QUARTZ_SURFACE" git sed -f g "quartz_window" "quartz_surface" git sed -f g "QuartzWindow" "QuartzSurface" git checkout NEWS* po-properties
2018-03-20 10:40:08 +00:00
static GdkSurface *
gdk_event_source_get_filter_surface (GdkEventSource *event_source,
const XEvent *xevent,
GdkEventTranslator **event_translator)
2010-05-25 22:38:44 +00:00
{
GList *list = event_source->translators;
GdkSurface *surface;
2010-05-25 22:38:44 +00:00
*event_translator = NULL;
while (list)
{
GdkEventTranslator *translator = list->data;
list = list->next;
surface = _gdk_x11_event_translator_get_surface (translator,
event_source->display,
xevent);
if (surface)
{
*event_translator = translator;
return surface;
}
}
surface = gdk_x11_surface_lookup_for_display (event_source->display,
xevent->xany.window);
2010-05-25 22:38:44 +00:00
return surface;
2010-05-25 22:38:44 +00:00
}
static void
handle_focus_change (GdkEvent *event)
2010-05-25 22:38:44 +00:00
{
GdkToplevelX11 *toplevel;
GdkX11Screen *x11_screen;
2010-05-25 22:38:44 +00:00
gboolean focus_in, had_focus;
toplevel = _gdk_x11_surface_get_toplevel (gdk_event_get_surface (event));
x11_screen = GDK_X11_SCREEN (GDK_SURFACE_SCREEN (gdk_event_get_surface (event)));
focus_in = (gdk_event_get_event_type (event) == GDK_ENTER_NOTIFY);
2010-05-25 22:38:44 +00:00
if (x11_screen->wmspec_check_window)
return;
if (!toplevel || gdk_crossing_event_get_detail (event) == GDK_NOTIFY_INFERIOR)
2010-05-25 22:38:44 +00:00
return;
toplevel->has_pointer = focus_in;
if (!gdk_crossing_event_get_focus (event) || toplevel->has_focus_window)
2010-05-25 22:38:44 +00:00
return;
had_focus = HAS_FOCUS (toplevel);
2010-05-25 22:38:44 +00:00
toplevel->has_pointer_focus = focus_in;
if (HAS_FOCUS (toplevel) != had_focus)
2010-05-25 22:38:44 +00:00
{
GdkEvent *focus_event;
focus_event = gdk_focus_event_new (gdk_event_get_surface (event),
gdk_event_get_device (event),
gdk_event_get_source_device (event),
focus_in);
gdk_display_put_event (gdk_event_get_display (event), focus_event);
gdk_event_unref (focus_event);
2010-05-25 22:38:44 +00:00
}
}
static GdkEvent *
create_synth_crossing_event (GdkEventType evtype,
GdkCrossingMode mode,
GdkEvent *real_event)
{
GdkEvent *event;
gdouble x, y;
g_assert (evtype == GDK_ENTER_NOTIFY || evtype == GDK_LEAVE_NOTIFY);
gdk_event_get_position (real_event, &x, &y);
event = gdk_crossing_event_new (evtype,
gdk_event_get_surface (real_event),
gdk_event_get_device (real_event),
gdk_event_get_source_device (real_event),
gdk_event_get_time (real_event),
gdk_event_get_modifier_state (real_event),
x, y,
mode,
GDK_NOTIFY_ANCESTOR);
return event;
}
static void
handle_touch_synthetic_crossing (GdkEvent *event)
{
GdkEventType evtype = gdk_event_get_event_type (event);
GdkDevice *device = gdk_event_get_device (event);
GdkEvent *crossing = NULL;
GdkSeat *seat = gdk_device_get_seat (device);
gboolean needs_enter, set_needs_enter = FALSE;
if (quark_needs_enter == 0)
quark_needs_enter = g_quark_from_static_string ("gdk-x11-needs-enter-after-touch-end");
needs_enter =
GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (seat), quark_needs_enter));
if (evtype == GDK_MOTION_NOTIFY && needs_enter)
{
set_needs_enter = FALSE;
crossing = create_synth_crossing_event (GDK_ENTER_NOTIFY,
GDK_CROSSING_DEVICE_SWITCH,
event);
}
else if (evtype == GDK_TOUCH_BEGIN && needs_enter &&
gdk_event_get_pointer_emulated (event))
{
set_needs_enter = FALSE;
crossing = create_synth_crossing_event (GDK_ENTER_NOTIFY,
GDK_CROSSING_TOUCH_BEGIN,
event);
}
else if (evtype == GDK_TOUCH_END &&
gdk_event_get_pointer_emulated (event))
{
set_needs_enter = TRUE;
crossing = create_synth_crossing_event (GDK_LEAVE_NOTIFY,
GDK_CROSSING_TOUCH_END,
event);
}
else if (evtype == GDK_ENTER_NOTIFY ||
evtype == GDK_LEAVE_NOTIFY)
{
/* We are receiving or shall receive a real crossing event,
* turn this off.
*/
set_needs_enter = FALSE;
}
else
return;
if (needs_enter != set_needs_enter)
{
if (!set_needs_enter)
g_object_steal_qdata (G_OBJECT (seat), quark_needs_enter);
else
g_object_set_qdata (G_OBJECT (seat), quark_needs_enter,
GUINT_TO_POINTER (TRUE));
}
if (crossing)
{
gdk_display_put_event (gdk_device_get_display (device), crossing);
gdk_event_unref (crossing);
}
}
static GdkEvent *
gdk_event_source_translate_event (GdkX11Display *x11_display,
const XEvent *xevent)
2010-05-25 22:38:44 +00:00
{
GdkEventSource *event_source = (GdkEventSource *) x11_display->event_source;
GdkEvent *event;
GdkFilterReturn result = GDK_FILTER_CONTINUE;
GdkDisplay *display = GDK_DISPLAY (x11_display);
GdkEventTranslator *event_translator;
GdkSurface *filter_surface;
Display *dpy;
GdkX11Screen *x11_screen;
gpointer cache;
x11_screen = GDK_X11_DISPLAY (display)->screen;
dpy = GDK_DISPLAY_XDISPLAY (display);
2010-05-25 22:38:44 +00:00
event = NULL;
filter_surface = gdk_event_source_get_filter_surface (event_source, xevent,
&event_translator);
/* apply XSettings filters */
if (xevent->xany.window == XRootWindow (dpy, 0))
result = gdk_xsettings_root_window_filter (xevent, x11_screen);
if (result == GDK_FILTER_CONTINUE &&
xevent->xany.window == x11_screen->xsettings_manager_window)
result = gdk_xsettings_manager_window_filter (xevent, x11_screen);
GdkWindow -> GdkSurface initial type rename This renames the GdkWindow class and related classes (impl, backend subclasses) to surface. Additionally it renames related types: GdkWindowAttr, GdkWindowPaint, GdkWindowWindowClass, GdkWindowType, GdkWindowTypeHint, GdkWindowHints, GdkWindowState, GdkWindowEdge This is an automatic conversion using the below commands: git sed -f g GdkWindowWindowClass GdkSurfaceSurfaceClass git sed -f g GdkWindow GdkSurface git sed -f g "gdk_window\([ _\(\),;]\|$\)" "gdk_surface\1" # Avoid hitting gdk_windowing git sed -f g "GDK_WINDOW\([ _\(]\|$\)" "GDK_SURFACE\1" # Avoid hitting GDK_WINDOWING git sed "GDK_\([A-Z]*\)IS_WINDOW\([_ (]\|$\)" "GDK_\1IS_SURFACE\2" git sed GDK_TYPE_WINDOW GDK_TYPE_SURFACE git sed -f g GdkPointerWindowInfo GdkPointerSurfaceInfo git sed -f g "BROADWAY_WINDOW" "BROADWAY_SURFACE" git sed -f g "broadway_window" "broadway_surface" git sed -f g "BroadwayWindow" "BroadwaySurface" git sed -f g "WAYLAND_WINDOW" "WAYLAND_SURFACE" git sed -f g "wayland_window" "wayland_surface" git sed -f g "WaylandWindow" "WaylandSurface" git sed -f g "X11_WINDOW" "X11_SURFACE" git sed -f g "x11_window" "x11_surface" git sed -f g "X11Window" "X11Surface" git sed -f g "WIN32_WINDOW" "WIN32_SURFACE" git sed -f g "win32_window" "win32_surface" git sed -f g "Win32Window" "Win32Surface" git sed -f g "QUARTZ_WINDOW" "QUARTZ_SURFACE" git sed -f g "quartz_window" "quartz_surface" git sed -f g "QuartzWindow" "QuartzSurface" git checkout NEWS* po-properties
2018-03-20 10:40:08 +00:00
cache = gdk_surface_cache_get (display);
if (cache)
{
if (result == GDK_FILTER_CONTINUE)
result = gdk_surface_cache_shape_filter (xevent, cache);
if (result == GDK_FILTER_CONTINUE &&
xevent->xany.window == XRootWindow (dpy, 0))
result = gdk_surface_cache_filter (xevent, cache);
}
if (result == GDK_FILTER_CONTINUE)
result = _gdk_wm_protocols_filter (xevent, filter_surface, &event, NULL);
if (result == GDK_FILTER_CONTINUE &&
gdk_x11_drop_filter (filter_surface, xevent))
result = GDK_FILTER_REMOVE;
if (result != GDK_FILTER_CONTINUE)
{
2010-05-25 22:38:44 +00:00
if (result == GDK_FILTER_REMOVE)
return NULL;
else /* GDK_FILTER_TRANSLATE */
2010-05-25 22:38:44 +00:00
return event;
}
if (event_translator)
2010-05-25 22:38:44 +00:00
{
/* Event translator was gotten before in get_filter_window() */
event = _gdk_x11_event_translator_translate (event_translator,
display,
xevent);
2010-05-25 22:38:44 +00:00
}
else
{
GList *list = event_source->translators;
while (list && !event)
{
GdkEventTranslator *translator = list->data;
list = list->next;
event = _gdk_x11_event_translator_translate (translator,
display,
xevent);
}
}
2010-05-25 22:38:44 +00:00
if (event)
2010-05-25 22:38:44 +00:00
{
GdkEventType evtype = gdk_event_get_event_type (event);
if ((evtype == GDK_ENTER_NOTIFY ||
evtype == GDK_LEAVE_NOTIFY) &&
gdk_event_get_surface (event) != NULL)
{
/* Handle focusing (in the case where no window manager is running */
handle_focus_change (event);
}
2010-05-25 22:38:44 +00:00
if (evtype == GDK_TOUCH_BEGIN ||
evtype == GDK_TOUCH_END ||
evtype == GDK_MOTION_NOTIFY ||
evtype == GDK_ENTER_NOTIFY ||
evtype == GDK_LEAVE_NOTIFY)
{
handle_touch_synthetic_crossing (event);
}
}
2010-05-25 22:38:44 +00:00
return event;
}
gboolean
gdk_event_source_xevent (GdkX11Display *x11_display,
const XEvent *xevent)
{
GdkDisplay *display = GDK_DISPLAY (x11_display);
GdkEvent *event;
GList *node;
event = gdk_event_source_translate_event (x11_display, xevent);
if (event == NULL)
return FALSE;
node = _gdk_event_queue_append (display, event);
_gdk_windowing_got_event (display, node, event, xevent->xany.serial);
return TRUE;
}
2010-05-25 22:38:44 +00:00
static gboolean
gdk_check_xpending (GdkDisplay *display)
{
return XPending (GDK_DISPLAY_XDISPLAY (display));
}
static gboolean
gdk_event_source_prepare (GSource *source,
gint *timeout)
{
GdkDisplay *display = ((GdkEventSource*) source)->display;
gboolean retval;
*timeout = -1;
if (display->event_pause_count > 0)
retval = _gdk_event_queue_find_first (display) != NULL;
else
retval = (_gdk_event_queue_find_first (display) != NULL ||
gdk_check_xpending (display));
2010-05-25 22:38:44 +00:00
return retval;
}
static gboolean
gdk_event_source_check (GSource *source)
{
GdkEventSource *event_source = (GdkEventSource*) source;
gboolean retval;
if (event_source->display->event_pause_count > 0)
retval = _gdk_event_queue_find_first (event_source->display) != NULL;
else if (event_source->event_poll_fd.revents & G_IO_IN)
2010-05-25 22:38:44 +00:00
retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
gdk_check_xpending (event_source->display));
2010-05-25 22:38:44 +00:00
else
retval = FALSE;
return retval;
}
void
2010-12-11 01:46:42 +00:00
_gdk_x11_display_queue_events (GdkDisplay *display)
2010-05-25 22:38:44 +00:00
{
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
XEvent xevent;
gboolean unused;
2010-05-25 22:38:44 +00:00
while (!_gdk_event_queue_find_first (display) && XPending (xdisplay))
{
XNextEvent (xdisplay, &xevent);
switch (xevent.type)
2010-12-11 01:46:42 +00:00
{
case KeyPress:
case KeyRelease:
break;
default:
if (XFilterEvent (&xevent, None))
continue;
}
2010-05-25 22:38:44 +00:00
#ifdef HAVE_XGENERICEVENTS
/* Get cookie data here so it's available
* to every event translator and event filter.
*/
if (xevent.type == GenericEvent)
XGetEventData (xdisplay, &xevent.xcookie);
#endif
g_signal_emit_by_name (display, "xevent", &xevent, &unused);
2010-05-25 22:38:44 +00:00
#ifdef HAVE_XGENERICEVENTS
if (xevent.type == GenericEvent)
XFreeEventData (xdisplay, &xevent.xcookie);
#endif
2010-05-25 22:38:44 +00:00
}
}
static gboolean
gdk_event_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GdkDisplay *display = ((GdkEventSource*) source)->display;
GdkEvent *event;
event = gdk_display_get_event (display);
if (event)
{
_gdk_event_emit (event);
2010-05-25 22:38:44 +00:00
gdk_event_unref (event);
2010-05-25 22:38:44 +00:00
}
return TRUE;
}
static void
gdk_event_source_finalize (GSource *source)
{
GdkEventSource *event_source = (GdkEventSource *)source;
g_list_free (event_source->translators);
event_source->translators = NULL;
2010-05-25 22:38:44 +00:00
}
GSource *
gdk_x11_event_source_new (GdkDisplay *display)
2010-05-25 22:38:44 +00:00
{
GSource *source;
GdkEventSource *event_source;
GdkX11Display *display_x11;
2010-05-25 22:38:44 +00:00
int connection_number;
char *name;
2010-05-25 22:38:44 +00:00
source = g_source_new (&event_funcs, sizeof (GdkEventSource));
name = g_strdup_printf ("GDK X11 Event source (%s)",
gdk_display_get_name (display));
g_source_set_name (source, name);
g_free (name);
2010-05-25 22:38:44 +00:00
event_source = (GdkEventSource *) source;
event_source->display = display;
display_x11 = GDK_X11_DISPLAY (display);
2010-05-25 22:38:44 +00:00
connection_number = ConnectionNumber (display_x11->xdisplay);
event_source->event_poll_fd.fd = connection_number;
event_source->event_poll_fd.events = G_IO_IN;
g_source_add_poll (source, &event_source->event_poll_fd);
g_source_set_priority (source, GDK_PRIORITY_EVENTS);
g_source_set_can_recurse (source, TRUE);
g_source_attach (source, NULL);
return source;
}
void
gdk_x11_event_source_add_translator (GdkEventSource *source,
GdkEventTranslator *translator)
2010-05-25 22:38:44 +00:00
{
g_return_if_fail (GDK_IS_EVENT_TRANSLATOR (translator));
source->translators = g_list_append (source->translators, translator);
}
void
gdk_x11_event_source_select_events (GdkEventSource *source,
Window window,
GdkEventMask event_mask,
unsigned int extra_x_mask)
2010-05-25 22:38:44 +00:00
{
unsigned int xmask = extra_x_mask;
GList *list;
gint i;
list = source->translators;
while (list)
{
GdkEventTranslator *translator = list->data;
GdkEventMask translator_mask, mask;
translator_mask = _gdk_x11_event_translator_get_handled_events (translator);
2010-05-25 22:38:44 +00:00
mask = event_mask & translator_mask;
if (mask != 0)
{
GdkSurface: Rename various functions and variables This is an automatic rename of various things related to the window->surface rename. Public symbols changed by this is: GDK_MODE_WINDOW gdk_device_get_window_at_position gdk_device_get_window_at_position_double gdk_device_get_last_event_window gdk_display_get_monitor_at_window gdk_drag_context_get_source_window gdk_drag_context_get_dest_window gdk_drag_context_get_drag_window gdk_draw_context_get_window gdk_drawing_context_get_window gdk_gl_context_get_window gdk_synthesize_window_state gdk_surface_get_window_type gdk_x11_display_set_window_scale gsk_renderer_new_for_window gsk_renderer_get_window gtk_text_view_buffer_to_window_coords gtk_tree_view_convert_widget_to_bin_window_coords gtk_tree_view_convert_tree_to_bin_window_coords The commands that generated this are: git sed -f g "GDK window" "GDK surface" git sed -f g window_impl surface_impl (cd gdk; git sed -f g impl_window impl_surface) git sed -f g WINDOW_IMPL SURFACE_IMPL git sed -f g GDK_MODE_WINDOW GDK_MODE_SURFACE git sed -f g gdk_draw_context_get_window gdk_draw_context_get_surface git sed -f g gdk_drawing_context_get_window gdk_drawing_context_get_surface git sed -f g gdk_gl_context_get_window gdk_gl_context_get_surface git sed -f g gsk_renderer_get_window gsk_renderer_get_surface git sed -f g gsk_renderer_new_for_window gsk_renderer_new_for_surface (cd gdk; git sed -f g window_type surface_type) git sed -f g gdk_surface_get_window_type gdk_surface_get_surface_type git sed -f g window_at_position surface_at_position git sed -f g event_window event_surface git sed -f g window_coord surface_coord git sed -f g window_state surface_state git sed -f g window_cursor surface_cursor git sed -f g window_scale surface_scale git sed -f g window_events surface_events git sed -f g monitor_at_window monitor_at_surface git sed -f g window_under_pointer surface_under_pointer (cd gdk; git sed -f g for_window for_surface) git sed -f g window_anchor surface_anchor git sed -f g WINDOW_IS_TOPLEVEL SURFACE_IS_TOPLEVEL git sed -f g native_window native_surface git sed -f g source_window source_surface git sed -f g dest_window dest_surface git sed -f g drag_window drag_surface git sed -f g input_window input_surface git checkout NEWS* po-properties po docs/reference/gtk/migrating-3to4.xml
2018-03-20 11:05:26 +00:00
_gdk_x11_event_translator_select_surface_events (translator, window, mask);
2010-05-25 22:38:44 +00:00
event_mask &= ~mask;
}
list = list->next;
}
for (i = 0; i < _gdk_x11_event_mask_table_size; i++)
2010-05-25 22:38:44 +00:00
{
if (event_mask & (1 << (i + 1)))
xmask |= _gdk_x11_event_mask_table[i];
2010-05-25 22:38:44 +00:00
}
XSelectInput (GDK_DISPLAY_XDISPLAY (source->display), window, xmask);
}