feature: Add support for global_remove in the display listener.
authorChris Michael <cp.michael@samsung.com>
Wed, 26 Jun 2013 10:52:58 +0000 (11:52 +0100)
committerChris Michael <cp.michael@samsung.com>
Wed, 26 Jun 2013 10:57:49 +0000 (11:57 +0100)
bugfix T151: Catch fatal error from wayland displays and signal apps to exit.

Signed-off-by: Chris Michael <cp.michael@samsung.com>
src/lib/ecore_wayland/ecore_wl.c

index 8793146..9578c19 100644 (file)
@@ -10,6 +10,7 @@ static Eina_Bool _ecore_wl_shutdown(Eina_Bool close);
 static Eina_Bool _ecore_wl_cb_idle_enterer(void *data);
 static Eina_Bool _ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl);
 static void _ecore_wl_cb_handle_global(void *data, struct wl_registry *registry, unsigned int id, const char *interface, unsigned int version EINA_UNUSED);
+static void _ecore_wl_cb_handle_global_remove(void *data, struct wl_registry *registry EINA_UNUSED, unsigned int id);
 static Eina_Bool _ecore_wl_xkb_init(Ecore_Wl_Display *ewd);
 static Eina_Bool _ecore_wl_xkb_shutdown(Ecore_Wl_Display *ewd);
 static void _ecore_wl_sync_wait(Ecore_Wl_Display *ewd);
@@ -18,15 +19,18 @@ static void _ecore_wl_animator_tick_cb_begin(void *data EINA_UNUSED);
 static void _ecore_wl_animator_tick_cb_end(void *data EINA_UNUSED);
 static void _ecore_wl_animator_callback(void *data, struct wl_callback *callback, uint32_t serial EINA_UNUSED);
 static Eina_Bool _ecore_wl_animator_window_add(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata EINA_UNUSED);
+static void _ecore_wl_signal_exit(void);
+static void _ecore_wl_signal_exit_free(void *data EINA_UNUSED, void *event);
 
 /* local variables */
 static int _ecore_wl_init_count = 0;
 static Eina_Bool _ecore_wl_animator_busy = EINA_FALSE;
+static Eina_Bool _ecore_wl_fatal_error = EINA_FALSE;
 
 static const struct wl_registry_listener _ecore_wl_registry_listener =
 {
    _ecore_wl_cb_handle_global,
-   NULL // handle_global_remove
+   _ecore_wl_cb_handle_global_remove
 };
 
 static const struct wl_callback_listener _ecore_wl_sync_listener =
@@ -160,6 +164,8 @@ ecore_wl_init(const char *name)
    wl_registry_add_listener(_ecore_wl_disp->wl.registry,
                             &_ecore_wl_registry_listener, _ecore_wl_disp);
 
+   /* NB: Hmmm, should we display_dispatch here ?? */
+
    if (!_ecore_wl_xkb_init(_ecore_wl_disp))
      {
         ERR("Could not initialize XKB");
@@ -348,7 +354,7 @@ _ecore_wl_shutdown(Eina_Bool close)
    if (_ecore_wl_disp->idle_enterer)
       ecore_idle_enterer_del(_ecore_wl_disp->idle_enterer);
 
-   if (close)
+   if ((close) && (!_ecore_wl_fatal_error))
      {
         Ecore_Wl_Output *out, *tout;
         Ecore_Wl_Input *in, *tin;
@@ -399,17 +405,32 @@ static Eina_Bool
 _ecore_wl_cb_idle_enterer(void *data)
 {
    Ecore_Wl_Display *ewd;
-   int ret;
+   int ret = 0;
+
+   if (_ecore_wl_fatal_error) return ECORE_CALLBACK_CANCEL;
 
    if (!(ewd = data)) return ECORE_CALLBACK_RENEW;
 
+   ret = wl_display_get_error(ewd->wl.display);
+   if (ret < 0) goto err;
+
+   ret = wl_display_dispatch_pending(ewd->wl.display);
+   if (ret < 0) goto err;
+
    ret = wl_display_flush(ewd->wl.display);
    if ((ret < 0) && (errno == EAGAIN))
      ecore_main_fd_handler_active_set(ewd->fd_hdl, 
                                       (ECORE_FD_READ | ECORE_FD_WRITE));
-   else if (ret < 0)
+
+   return ECORE_CALLBACK_RENEW;
+
+err:
+   if ((ret < 0) && ((errno != EAGAIN) && (errno != EINVAL)))
      {
-      /* FIXME: need do error processing? */
+        _ecore_wl_fatal_error = EINA_TRUE;
+
+        /* raise exit signal */
+        _ecore_wl_signal_exit();
      }
 
    return ECORE_CALLBACK_RENEW;
@@ -419,9 +440,12 @@ static Eina_Bool
 _ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl)
 {
    Ecore_Wl_Display *ewd;
+   int ret = 0;
 
    /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */
 
+   if (_ecore_wl_fatal_error) return ECORE_CALLBACK_CANCEL;
+
    if (!(ewd = data)) return ECORE_CALLBACK_RENEW;
 
    /* FIXME: This should also catch ECORE_FD_ERROR and exit */
@@ -429,18 +453,20 @@ _ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl)
    /* wl_display_dispatch_pending(ewd->wl.display); */
 
    if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_READ))
-     wl_display_dispatch(ewd->wl.display);
+     ret = wl_display_dispatch(ewd->wl.display);
    else if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_WRITE))
      {
-        int ret = 0;
-
         ret = wl_display_flush(ewd->wl.display);
         if (ret == 0)
           ecore_main_fd_handler_active_set(hdl, ECORE_FD_READ);
-        else if ((ret == -1) && (errno != EAGAIN))
-          {
-            /* FIXME: need do error processing? */
-          }
+     }
+
+   if ((ret < 0) && ((errno != EAGAIN) && (errno != EINVAL)))
+     {
+        _ecore_wl_fatal_error = EINA_TRUE;
+
+        /* raise exit signal */
+        _ecore_wl_signal_exit();
      }
 
    return ECORE_CALLBACK_RENEW;
@@ -508,6 +534,25 @@ _ecore_wl_cb_handle_global(void *data, struct wl_registry *registry, unsigned in
      }
 }
 
+static void 
+_ecore_wl_cb_handle_global_remove(void *data, struct wl_registry *registry EINA_UNUSED, unsigned int id)
+{
+   Ecore_Wl_Display *ewd;
+   Ecore_Wl_Global *global, *tmp;
+
+   LOGFN(__FILE__, __LINE__, __FUNCTION__);
+
+   ewd = data;
+
+   wl_list_for_each_safe(global, tmp, &ewd->globals, link)
+     {
+        if (global->id != id) continue;
+        wl_list_remove(&global->link);
+        free(global->interface);
+        free(global);
+     }
+}
+
 static Eina_Bool
 _ecore_wl_xkb_init(Ecore_Wl_Display *ewd)
 {
@@ -601,3 +646,22 @@ _ecore_wl_animator_window_add(const Eina_Hash *hash EINA_UNUSED, const void *key
 
    return EINA_TRUE;
 }
+
+static void 
+_ecore_wl_signal_exit(void)
+{
+   Ecore_Event_Signal_Exit *ev;
+
+   if (!(ev = calloc(1, sizeof(Ecore_Event_Signal_Exit))))
+     return;
+
+   ev->quit = 1;
+   ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, ev, 
+                   _ecore_wl_signal_exit_free, NULL);
+}
+
+static void 
+_ecore_wl_signal_exit_free(void *data EINA_UNUSED, void *event)
+{
+   free(event);
+}