ecore/wayland: Add and initialize subcompositor inside Ecore_Wayland.
[platform/upstream/ecore.git] / src / lib / ecore_wayland / ecore_wl.c
index 4c3a26d..4dd2654 100644 (file)
@@ -30,13 +30,17 @@ void *alloca (size_t);
 
 #include <fcntl.h>
 #include "ecore_wl_private.h"
+#include <subsurface-client-protocol.h>
 
 /* local function prototypes */
 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 __UNUSED__);
 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);
+static void _ecore_wl_sync_callback(void *data, struct wl_callback *callback, uint32_t serial);
 
 /* local variables */
 static int _ecore_wl_init_count = 0;
@@ -46,6 +50,11 @@ static const struct wl_registry_listener _ecore_wl_registry_listener =
    NULL // handle_global_remove
 };
 
+static const struct wl_callback_listener _ecore_wl_sync_listener =
+{
+   _ecore_wl_sync_callback
+};
+
 /* external variables */
 int _ecore_wl_log_dom = -1;
 Ecore_Wl_Display *_ecore_wl_disp = NULL;
@@ -162,14 +171,18 @@ ecore_wl_init(const char *name)
 
    _ecore_wl_disp->fd = wl_display_get_fd(_ecore_wl_disp->wl.display);
 
-   _ecore_wl_disp->fd_hdl = 
-     ecore_main_fd_handler_add(_ecore_wl_disp->fd, 
-                               ECORE_FD_READ | ECORE_FD_WRITE,
-                               _ecore_wl_cb_handle_data, _ecore_wl_disp, 
+   _ecore_wl_disp->fd_hdl =
+     ecore_main_fd_handler_add(_ecore_wl_disp->fd,
+                               ECORE_FD_READ,
+                               _ecore_wl_cb_handle_data, _ecore_wl_disp,
                                NULL, NULL);
 
+   _ecore_wl_disp->idle_enterer =
+     ecore_idle_enterer_add(_ecore_wl_cb_idle_enterer, _ecore_wl_disp);
+
    wl_list_init(&_ecore_wl_disp->inputs);
    wl_list_init(&_ecore_wl_disp->outputs);
+   wl_list_init(&_ecore_wl_disp->globals);
 
    _ecore_wl_disp->wl.registry = 
      wl_display_get_registry(_ecore_wl_disp->wl.display);
@@ -247,7 +260,9 @@ ecore_wl_sync(void)
 {
 //   LOGFN(__FILE__, __LINE__, __FUNCTION__);
 
-   wl_display_sync(_ecore_wl_disp->wl.display);
+   _ecore_wl_sync_wait(_ecore_wl_disp);
+   while (_ecore_wl_disp->sync_ref_count > 0)
+     wl_display_dispatch(_ecore_wl_disp->wl.display);
 }
 
 /**
@@ -284,6 +299,18 @@ ecore_wl_display_get(void)
    return _ecore_wl_disp->wl.display;
 }
 
+EAPI struct wl_list *
+ecore_wl_globals_get(void)
+{
+   return &(_ecore_wl_disp->globals);
+}
+
+EAPI struct wl_registry *
+ecore_wl_registry_get(void)
+{
+   return _ecore_wl_disp->wl.registry;
+}
+
 /**
  * Retrieves the size of the current screen.
  * 
@@ -301,10 +328,25 @@ ecore_wl_screen_size_get(int *w, int *h)
    if (w) *w = 0;
    if (h) *h = 0;
 
+   if (!_ecore_wl_disp->output)
+     ecore_wl_sync();
+
    if (!_ecore_wl_disp->output) return;
 
-   if (w) *w = _ecore_wl_disp->output->allocation.w;
-   if (h) *h = _ecore_wl_disp->output->allocation.h;
+   switch (_ecore_wl_disp->output->transform)
+     {
+      case WL_OUTPUT_TRANSFORM_90:
+      case WL_OUTPUT_TRANSFORM_270:
+      case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+      case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+         /* Swap width and height */
+         if (w) *w = _ecore_wl_disp->output->allocation.h;
+         if (h) *h = _ecore_wl_disp->output->allocation.w;
+         break;
+      default:
+         if (w) *w = _ecore_wl_disp->output->allocation.w;
+         if (h) *h = _ecore_wl_disp->output->allocation.h;
+     }
 }
 
 /* @since 1.2 */
@@ -382,11 +424,14 @@ _ecore_wl_shutdown(Eina_Bool close)
 
    if (_ecore_wl_disp->fd_hdl) 
      ecore_main_fd_handler_del(_ecore_wl_disp->fd_hdl);
+   if (_ecore_wl_disp->idle_enterer)
+      ecore_idle_enterer_del(_ecore_wl_disp->idle_enterer);
 
    if (close) 
      {
         Ecore_Wl_Output *out, *tout;
         Ecore_Wl_Input *in, *tin;
+        Ecore_Wl_Global *global, *tglobal;
 
         wl_list_for_each_safe(out, tout, &_ecore_wl_disp->outputs, link)
           _ecore_wl_output_del(out);
@@ -394,6 +439,13 @@ _ecore_wl_shutdown(Eina_Bool close)
         wl_list_for_each_safe(in, tin, &_ecore_wl_disp->inputs, link)
           _ecore_wl_input_del(in);
 
+        wl_list_for_each_safe(global, tglobal, &_ecore_wl_disp->globals, link)
+          {
+             wl_list_remove(&global->link);
+             free(global->interface);
+             free(global);
+          }
+
         _ecore_wl_xkb_shutdown(_ecore_wl_disp);
 
         if (_ecore_wl_disp->wl.shell) 
@@ -403,6 +455,8 @@ _ecore_wl_shutdown(Eina_Bool close)
           wl_data_device_manager_destroy(_ecore_wl_disp->wl.data_device_manager);
         if (_ecore_wl_disp->wl.compositor)
           wl_compositor_destroy(_ecore_wl_disp->wl.compositor);
+        if (_ecore_wl_disp->wl.subcompositor)
+          wl_compositor_destroy(_ecore_wl_disp->wl.subcompositor);
         if (_ecore_wl_disp->wl.display)
           {
              wl_registry_destroy(_ecore_wl_disp->wl.registry);
@@ -422,10 +476,33 @@ _ecore_wl_shutdown(Eina_Bool close)
    return _ecore_wl_init_count;
 }
 
-static Eina_Bool 
+static Eina_Bool
+_ecore_wl_cb_idle_enterer(void *data)
+{
+   Ecore_Wl_Display *ewd;
+   int ret;
+
+   if (!(ewd = data)) return ECORE_CALLBACK_RENEW;
+
+   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)
+     {
+      /* FIXME: need do error processing? */
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
 _ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl)
 {
    Ecore_Wl_Display *ewd;
+   int ret;
 
    /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */
 
@@ -438,7 +515,15 @@ _ecore_wl_cb_handle_data(void *data, Ecore_Fd_Handler *hdl)
    if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_READ))
      wl_display_dispatch(ewd->wl.display);
    else if (ecore_main_fd_handler_active_get(hdl, ECORE_FD_WRITE))
-     wl_display_flush(ewd->wl.display);
+     {
+        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? */
+          }
+     }
 
    return ECORE_CALLBACK_RENEW;
 }
@@ -447,16 +532,31 @@ static void
 _ecore_wl_cb_handle_global(void *data, struct wl_registry *registry, unsigned int id, const char *interface, unsigned int version __UNUSED__)
 {
    Ecore_Wl_Display *ewd;
+   Ecore_Wl_Global *global;
 
    LOGFN(__FILE__, __LINE__, __FUNCTION__);
 
    ewd = data;
 
+   global = malloc(sizeof(*global));
+
+   memset(global, 0, sizeof(Ecore_Wl_Global));
+
+   global->id = id;
+   global->interface = strdup(interface);
+   global->version = version;
+   wl_list_insert(ewd->globals.prev, &global->link);
+
    if (!strcmp(interface, "wl_compositor"))
      {
         ewd->wl.compositor = 
           wl_registry_bind(registry, id, &wl_compositor_interface, 1);
      }
+   else if (!strcmp(interface, "wl_subcompositor"))
+     {
+        ewd->wl.subcompositor =
+           wl_registry_bind(registry, id, &wl_subcompositor_interface, 1);
+     }
    else if (!strcmp(interface, "wl_output"))
      _ecore_wl_output_add(ewd, id);
    else if (!strcmp(interface, "wl_seat"))
@@ -521,3 +621,22 @@ _ecore_wl_create_data_source(Ecore_Wl_Display *ewd)
 {
    return wl_data_device_manager_create_data_source(ewd->wl.data_device_manager);
 }
+
+static void
+_ecore_wl_sync_callback(void *data, struct wl_callback *callback, uint32_t serial EINA_UNUSED)
+{
+   Ecore_Wl_Display *ewd = data;
+
+   ewd->sync_ref_count--;
+   wl_callback_destroy(callback);
+}
+
+static void
+_ecore_wl_sync_wait(Ecore_Wl_Display *ewd)
+{
+   struct wl_callback *callback;
+
+   ewd->sync_ref_count++;
+   callback = wl_display_sync(ewd->wl.display);
+   wl_callback_add_listener(callback, &_ecore_wl_sync_listener, ewd);
+}