mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-17 06:10:15 +00:00
f50a3af1b7
If a motion event handler (or other handler running from the flush-events phase of the frame clock) recursed the main loop then flushing wouldn't complete until after the recursed main loop returned, and various aspects of the state would get out of sync. To fix this, change flushing of the event queue to simply mark events as ready to flush, and let normal event delivery handle the rest. https://bugzilla.gnome.org/show_bug.cgi?id=705176
171 lines
4.6 KiB
C
171 lines
4.6 KiB
C
/* 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
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gdkinternals.h"
|
|
#include "gdkprivate-wayland.h"
|
|
|
|
#include <errno.h>
|
|
|
|
typedef struct _GdkWaylandEventSource {
|
|
GSource source;
|
|
GPollFD pfd;
|
|
uint32_t mask;
|
|
GdkDisplay *display;
|
|
} GdkWaylandEventSource;
|
|
|
|
static GList *event_sources = NULL;
|
|
|
|
static gboolean
|
|
gdk_event_source_prepare(GSource *base, gint *timeout)
|
|
{
|
|
GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
|
|
GdkWaylandDisplay *display = (GdkWaylandDisplay *) source->display;
|
|
|
|
*timeout = -1;
|
|
|
|
if (source->display->event_pause_count > 0)
|
|
return _gdk_event_queue_find_first (source->display) != NULL;
|
|
|
|
/* We have to add/remove the GPollFD if we want to update our
|
|
* poll event mask dynamically. Instead, let's just flush all
|
|
* write on idle instead, which is what this amounts to. */
|
|
|
|
if (_gdk_event_queue_find_first (source->display) != NULL)
|
|
return TRUE;
|
|
|
|
if (wl_display_flush (display->wl_display) < 0)
|
|
g_error ("Error flushing display: %s", g_strerror (errno));
|
|
|
|
if (wl_display_dispatch_pending (display->wl_display) < 0)
|
|
g_error ("Error dispatching display: %s", g_strerror (errno));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
gdk_event_source_check(GSource *base)
|
|
{
|
|
GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
|
|
|
|
if (source->display->event_pause_count > 0)
|
|
return _gdk_event_queue_find_first (source->display) != NULL;
|
|
|
|
return _gdk_event_queue_find_first (source->display) != NULL ||
|
|
source->pfd.revents;
|
|
}
|
|
|
|
static gboolean
|
|
gdk_event_source_dispatch(GSource *base,
|
|
GSourceFunc callback,
|
|
gpointer data)
|
|
{
|
|
GdkWaylandEventSource *source = (GdkWaylandEventSource *) base;
|
|
GdkDisplay *display = source->display;
|
|
GdkEvent *event;
|
|
|
|
gdk_threads_enter ();
|
|
|
|
event = gdk_display_get_event (display);
|
|
|
|
if (event)
|
|
{
|
|
_gdk_event_emit (event);
|
|
|
|
gdk_event_free (event);
|
|
}
|
|
|
|
gdk_threads_leave ();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
gdk_event_source_finalize (GSource *source)
|
|
{
|
|
event_sources = g_list_remove (event_sources, source);
|
|
}
|
|
|
|
static GSourceFuncs wl_glib_source_funcs = {
|
|
gdk_event_source_prepare,
|
|
gdk_event_source_check,
|
|
gdk_event_source_dispatch,
|
|
gdk_event_source_finalize
|
|
};
|
|
|
|
void
|
|
_gdk_wayland_display_deliver_event (GdkDisplay *display, GdkEvent *event)
|
|
{
|
|
GList *node;
|
|
|
|
node = _gdk_event_queue_append (display, event);
|
|
_gdk_windowing_got_event (display, node, event,
|
|
_gdk_display_get_next_serial (display));
|
|
}
|
|
|
|
GSource *
|
|
_gdk_wayland_display_event_source_new (GdkDisplay *display)
|
|
{
|
|
GSource *source;
|
|
GdkWaylandEventSource *wl_source;
|
|
GdkWaylandDisplay *display_wayland;
|
|
char *name;
|
|
|
|
source = g_source_new (&wl_glib_source_funcs,
|
|
sizeof (GdkWaylandEventSource));
|
|
name = g_strdup_printf ("GDK Wayland Event source (%s)", "display name");
|
|
g_source_set_name (source, name);
|
|
g_free (name);
|
|
wl_source = (GdkWaylandEventSource *) source;
|
|
|
|
display_wayland = GDK_WAYLAND_DISPLAY (display);
|
|
wl_source->display = display;
|
|
wl_source->pfd.fd = wl_display_get_fd(display_wayland->wl_display);
|
|
wl_source->pfd.events = G_IO_IN | G_IO_ERR | G_IO_HUP;
|
|
g_source_add_poll(source, &wl_source->pfd);
|
|
|
|
g_source_set_priority (source, GDK_PRIORITY_EVENTS);
|
|
g_source_set_can_recurse (source, TRUE);
|
|
g_source_attach (source, NULL);
|
|
|
|
event_sources = g_list_prepend (event_sources, source);
|
|
|
|
return source;
|
|
}
|
|
|
|
void
|
|
_gdk_wayland_display_queue_events (GdkDisplay *display)
|
|
{
|
|
GdkWaylandDisplay *display_wayland;
|
|
GdkWaylandEventSource *source;
|
|
|
|
display_wayland = GDK_WAYLAND_DISPLAY (display);
|
|
source = (GdkWaylandEventSource *) display_wayland->event_source;
|
|
|
|
if (source->pfd.revents & G_IO_IN)
|
|
{
|
|
if (wl_display_dispatch (display_wayland->wl_display) < 0)
|
|
g_error ("Error dispatching display: %s", g_strerror (errno));
|
|
}
|
|
|
|
if (source->pfd.revents & (G_IO_ERR | G_IO_HUP))
|
|
g_error ("Lost connection to wayland compositor");
|
|
|
|
source->pfd.revents = 0;
|
|
}
|