gtk2/gdk/wayland/gdkeventsource.c
Olivier Fourdan 53028ff3bb wayland: Don't use g_error() on connection lost
When the Wayland compositor vanishes, all applications connected will
receive a SIGPIPE as soon as they try to use wl_display_dispatch().

Do not use g_error() to terminate the applications when this occurs,
g_error() means an error in the application while here it's not truly
the case.

Use g_warning() and exit() instead.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>

https://bugzilla.gnome.org/show_bug.cgi?id=745289
2015-02-27 16:26:39 -05:00

178 lines
4.7 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 <stdlib.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_warning ("Error %d (%s) dispatching to Wayland display.",
errno, g_strerror (errno));
exit (1);
}
}
if (source->pfd.revents & (G_IO_ERR | G_IO_HUP))
{
g_warning ("Lost connection to Wayland compositor.");
exit (1);
}
source->pfd.revents = 0;
}