/*
 * _NET_WM... aka Extended Window Manager Hint (EWMH) functions.
 */

#include <stdio.h>
#include <string.h>

#include "ecore_xcb_private.h"
#include "Ecore_X_Atoms.h"

/**
 * @defgroup Ecore_X_NetWM_Group Extended Window Manager Hint (EWMH) functions
 *
 * Functions related to the Extended Window Manager Hint (EWMH).
 */

typedef struct _Ecore_X_Startup_Info   Ecore_X_Startup_Info;

struct _Ecore_X_Startup_Info
{
   Ecore_X_Window win;

   int            init;

   int            buffer_size;
   char          *buffer;

   int            length;

   /* These are the sequence info fields */
   char          *id;
   char          *name;
   int            screen;
   char          *bin;
   char          *icon;
   int            desktop;
   int            timestamp;
   char          *description;
   char          *wmclass;
   int            silent;
};

#if 0
static void      _ecore_x_window_prop_string_utf8_get_prefetch(Ecore_X_Window window, Ecore_X_Atom atom);
static void      _ecore_x_window_prop_string_utf8_get_fetch(void);
#endif /* if 0 */
static void      _ecore_x_window_prop_string_utf8_set(Ecore_X_Window window, Ecore_X_Atom atom, const char *str);
static char *    _ecore_x_window_prop_string_utf8_get(Ecore_X_Window window, Ecore_X_Atom atom);
#if 0 /* Unused */
static int       _ecore_x_netwm_startup_info_process(Ecore_X_Startup_Info *info);
static int       _ecore_x_netwm_startup_info_parse(Ecore_X_Startup_Info *info, char *data);
#endif /* if 0 */
static void      _ecore_x_netwm_startup_info_free(void *data);

/*
 * Local variables
 */

static Eina_Hash *startup_info = NULL;

/**
 * Initialize the NetWM module
 */
EAPI void
ecore_x_netwm_init(void)
{
   startup_info = eina_hash_string_superfast_new(_ecore_x_netwm_startup_info_free);
} /* ecore_x_netwm_init */

/**
 * Shutdown the NetWM module
 */
EAPI void
ecore_x_netwm_shutdown(void)
{
   if (startup_info)
      eina_hash_free(startup_info);

   startup_info = NULL;
} /* ecore_x_netwm_shutdown */

/**
 * Set the _NET_SUPPORTING_WM_CHECK property.
 * @param root    The root window.
 * @param check   The child window.
 * @param wm_name The name of the Window Manager.
 *
 * Set the _NET_SUPPORTING_WM_CHECK property on the @p root window to be
 * the ID of the child window @p check created by the Window Manager.
 * @p check also have the _NET_WM_NAME property set to the name
 * @p wm_name of the Window Manager.
 *
 * The Window MUST call that function to indicate that a compliant
 * window manager is active.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_wm_identify(Ecore_X_Window root,
                          Ecore_X_Window check,
                          const char    *wm_name)
{
   ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, &check, 1);
   ecore_x_window_prop_window_set(check, ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, &check, 1);
   _ecore_x_window_prop_string_utf8_set(check, ECORE_X_ATOM_NET_WM_NAME, wm_name);
   /* This one isn't mandatory */
   _ecore_x_window_prop_string_utf8_set(root, ECORE_X_ATOM_NET_WM_NAME, wm_name);
} /* ecore_x_netwm_wm_identify */

/**
 * Set the _NET_SUPPORTED property.
 * @param root      The root window.
 * @param supported The supported hints.
 * @param num       The number of hints.
 *
 * Set the _NET_SUPPORTED property on the @p root window. The hints
 * that the Window Manager supports are stored in @p supported.
 *
 * The Window Manager MUST set this property to indicate which hints
 * it supports.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_supported_set(Ecore_X_Window root,
                            Ecore_X_Atom  *supported,
                            int            num)
{
   ecore_x_window_prop_atom_set(root, ECORE_X_ATOM_NET_SUPPORTED, supported, num);
} /* ecore_x_netwm_supported_set */

/**
 * Sends the GetProperty request.
 * @param root The root window
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_supported_get_prefetch(Ecore_X_Window root)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, root,
                                       ECORE_X_ATOM_NET_SUPPORTED, ECORE_X_ATOM_ATOM,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_supported_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_supported_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_supported_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_supported_get_fetch */

/**
 * Get the hints supported by the Window Manager.
 * @param root      The root window.
 * @param supported The supported hints.
 * @param num       The number of atoms.
 * @return          1 on success, 0 otherwise.
 *
 * Get the hints supported by the Window Manager. @p root is the root
 * window. The hints are stored in @p supported. The number of hints
 * is stored in @p num.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_supported_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_supported_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_supported_get(Ecore_X_Window root,
                            Ecore_X_Atom **supported,
                            int           *num)
{
   int num_ret;

   if (num)
      *num = 0UL;

   if (supported)
      *supported = NULL;

   num_ret = ecore_x_window_prop_xid_list_get(root,
                                              ECORE_X_ATOM_NET_SUPPORTED,
                                              ECORE_X_ATOM_ATOM,
                                              supported);
   if (num_ret <= 0)
      return 0;

   if (num)
      *num = (uint32_t)num_ret;

   return 1;
} /* ecore_x_netwm_supported_get */

/**
 * Set the _NET_NUMBER_OF_DESKTOPS property.
 * @param root The root window.
 * @param n_desks The number of desktops.
 *
 * Set the number of desktops @p n_desks of the Window Manager by
 * sending the _NET_NUMBER_OF_DESKTOPS to the @p root window.
 *
 * The Window Manager SHOULD set and update this property to indicate
 * the number of virtual desktops. A Pager can request a change in the
 * number of desktops by using that function.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desk_count_set(Ecore_X_Window root,
                             unsigned int   n_desks)
{
   ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_NUMBER_OF_DESKTOPS,
                                  &n_desks, 1);
} /* ecore_x_netwm_desk_count_set */

/**
 * Set the _NET_VIRTUAL_ROOTS property.
 * @param root    The root window.
 * @param vroots  The virtual root windows.
 * @param n_desks The number of desks.
 *
 * Set the number of virtual desktops by sending the
 * _NET_VIRTUAL_ROOTS property to the @p root window. @p vroots is an
 * array of window and @p n_desks is the number of windows.
 *
 * A Window Manager that implements virtual desktops by reparent
 * client windows to a child of the root window MUST use that
 * function.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desk_roots_set(Ecore_X_Window  root,
                             Ecore_X_Window *vroots,
                             unsigned int    n_desks)
{
   ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_VIRTUAL_ROOTS, vroots, n_desks);
} /* ecore_x_netwm_desk_roots_set */

/**
 * Set the _NET_DESKTOP_NAMES property.
 * @param root    The root window.
 * @param names   The names of the virtual desktops.
 * @param n_desks The number of virtual desktops.
 *
 * Set the name of each virtual desktop by sending the
 * _NET_DESKTOP_NAMES to the @p root window. @p names are the names of
 * the virtual desktops and @p n_desks is the number of virtual
 * desktops.
 *
 * A Pager MAY use that function. @p n_desks may be different from the
 * one passed to ecore_x_netwm_desk_count_set().  If it less or equal,
 * then the desktops with high numbers are unnamed. If it is larger,
 * then the excess names are considered to be reserved in case the
 * number of desktops is increased.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desk_names_set(Ecore_X_Window root,
                             const char   **names,
                             unsigned int   n_desks)
{
   char ss[32];
   char *buf;
   const char *s;
   uint32_t i;
   uint32_t len;
   uint32_t l;

   buf = NULL;
   len = 0;

   for (i = 0; i < n_desks; i++)
     {
        s = (names) ? names[i] : NULL;
        if (!s)
          {
             /* Default to "Desk-<number>" */
             sprintf(ss, "Desk-%d", i);
             s = ss;
          }

        l = strlen(s) + 1;
        buf = realloc(buf, len + l);
        memcpy(buf + len, s, l);
        len += l;
     }

   xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, root,
                       ECORE_X_ATOM_NET_DESKTOP_NAMES,
                       ECORE_X_ATOM_UTF8_STRING,
                       8, len, (const void *)buf);
   free(buf);
} /* ecore_x_netwm_desk_names_set */

/**
 * Set the _NET_DESKTOP_GEOMETRY property.
 * @param root   The root window.
 * @param width  The width of the desktop.
 * @param height The height of the desktop.
 *
 * Set the common @p width and @p height of all desktops by sending
 * the _NET_DESKTOP_GEOMETRY to the @p root window.
 *
 * This size is equal to the screen size if the Window Manager doesn't
 * support large desktops, otherwise it's equal to the virtual size of
 * the desktop. The Window Manager SHOULD set this property. A Pager
 * can request a change in the desktop geometry by using this
 * function.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desk_size_set(Ecore_X_Window root,
                            unsigned int   width,
                            unsigned int   height)
{
   uint32_t size[2];

   size[0] = width;
   size[1] = height;
   ecore_x_window_prop_card32_set(root,
                                  ECORE_X_ATOM_NET_DESKTOP_GEOMETRY,
                                  size, 2);
} /* ecore_x_netwm_desk_size_set */

/**
 * Set the _NET_DESKTOP_VIEWPORT property.
 * @param root    The root window.
 * @param origins An array of paris of coordiantes.
 * @param n_desks The number of virtual desktops.
 *
 * Set the top left corner of each desktop's viewport by sending the
 * _NET_DESKTOP_VIEWPORT property to the @p root window. @p origins
 * contains each pair of X coordinate and Y coordinate of the top left
 * corner of each desktop's viewport.
 *
 * If the Window Manager does not support large desktops, the
 * coordinates MUST be (0,0). A Pager can request to change the
 * viewport for the current desktop by using this function.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desk_viewports_set(Ecore_X_Window root,
                                 unsigned int  *origins,
                                 unsigned int   n_desks)
{
   ecore_x_window_prop_card32_set(root,
                                  ECORE_X_ATOM_NET_DESKTOP_VIEWPORT,
                                  origins, 2 * n_desks);
} /* ecore_x_netwm_desk_viewports_set */

/**
 * Set the _NET_DESKTOP_LAYOUT property.
 * @param root The root window.
 * @param orientation
 * @param columns
 * @param rows
 * @param starting_corner
 *
 * Set the layout of virtual desktops relative to each other by
 * sending the _NET_DESKTOP_LAYOUT to the @p root window.
 * @p orientation defines the orientation of the virtual desktop. 0
 * means horizontal layout, 1 means vertical layout. @p columns is
 * the number of desktops in the X direction and @p rows is the number
 * in the Y direction. @p starting_corner is the corner containing the
 * first desktop. The values for @p starting_corner are 0 (top-left),
 * 1 (top-right), 2 (bottom-right) and 3 (bottom-left).
 *
 * When the orientation is horizontal the desktops are laid out in
 * rows, with the first desktop in the specified starting corner. So a
 * layout with four columns and three rows starting in
 * the top-left corner looks like this:
 *
 * +--+--+--+--+
 * | 0| 1| 2| 3|
 * +--+--+--+--+
 * | 4| 5| 6| 7|
 * +--+--+--+--+
 * | 8| 9|10|11|
 * +--+--+--+--+
 *
 * With @p starting_corner being bottom-right, it looks like this:
 *
 * +--+--+--+--+
 * |11|10| 9| 8|
 * +--+--+--+--+
 * | 7| 6| 5| 4|
 * +--+--+--+--+
 * | 3| 2| 1| 0|
 * +--+--+--+--+
 *
 * When the orientation is vertical the layout with four columns and
 * three rows starting in the top-left corner looks like:
 *
 * +--+--+--+--+
 * | 0| 3| 6| 9|
 * +--+--+--+--+
 * | 1| 4| 7|10|
 * +--+--+--+--+
 * | 2| 5| 8|11|
 * +--+--+--+--+
 *
 * With @p starting_corner  being top-right, it looks like:
 *
 * +--+--+--+--+
 * | 9| 6| 3| 0|
 * +--+--+--+--+
 * |10| 7| 4| 1|
 * +--+--+--+--+
 * |11| 8| 5| 2|
 * +--+--+--+--+
 *
 * This function MUST be used by a Pager and NOT by the Window
 * Manager. When using this function, the Pager must own a manager
 * selection.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desk_layout_set(Ecore_X_Window root,
                              int            orientation,
                              int            columns,
                              int            rows,
                              int            starting_corner)
{
   uint32_t layout[4];

   layout[0] = orientation;
   layout[1] = columns;
   layout[2] = rows;
   layout[3] = starting_corner;
   ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_LAYOUT, layout, 4);
} /* ecore_x_netwm_desk_layout_set */

/**
 * Set the _NET_WORKAREA property.
 * @param root    The root window.
 * @param areas   An array of areas.
 * @param n_desks The number of desks.
 *
 * Set the work area for each desktop by sending the _NET_WORKAREA
 * property to the @p root window. An area contains the geometry (X
 * and Y coordinates, width and height). These geometries are
 * specified relative to the viewport on each desktop and specify an
 * area that is completely contained within the viewport. @p areas
 * stores these geometries. @p n_desks is the number of geometry to
 * set.
 *
 * This function MUST be set by the Window Manager. It is used by
 * desktop applications to place desktop icons appropriately.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desk_workareas_set(Ecore_X_Window root,
                                 unsigned int  *areas,
                                 unsigned int   n_desks)
{
   ecore_x_window_prop_card32_set(root,
                                  ECORE_X_ATOM_NET_WORKAREA,
                                  areas, 4 * n_desks);
} /* ecore_x_netwm_desk_workareas_set */

/**
 * Set the _NET_CURRENT_DESKTOP property.
 * @param root The root window.
 * @param desk The index of the current desktop.
 *
 * Set the current desktop by sending the _NET_CURRENT_DESKTOP to the
 * @p root window. @p deskmust be an integer number between 0 and the
 * number of desks (set by ecore_x_netwm_desk_count_set()) -1.
 *
 * This function MUST be called by the Window Manager. If a Pagerwants
 * to switch to naother desktop, it MUST call that function.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desk_current_set(Ecore_X_Window root,
                               unsigned int   desk)
{
   ecore_x_window_prop_card32_set(root,
                                  ECORE_X_ATOM_NET_CURRENT_DESKTOP,
                                  &desk, 1);
} /* ecore_x_netwm_desk_current_set */

/**
 * Set the _NET_SHOWING_DESKTOP property.
 * @param root The root window
 * @param on   0 to hide the desktop, non 0 to show it.
 *
 * Set or unset the desktop in a "showing mode" by sending the
 * _NET_SHOWING_DESKTOP property to the @p root window. If @p on is 0,
 * the windows are hidden and the desktop background is displayed and
 * focused.
 *
 * If a Pager wants to enter or leave the mode, it MUST use this
 * function.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_showing_desktop_set(Ecore_X_Window root,
                                  Eina_Bool      on)
{
   uint32_t val;

   val = (on) ? 1 : 0;
   ecore_x_window_prop_card32_set(root,
                                  ECORE_X_ATOM_NET_SHOWING_DESKTOP,
                                  &val, 1);
} /* ecore_x_netwm_showing_desktop_set */

/*
 * Client status
 */

/**
 * Set the _NET_CLIENT_LIST property.
 * @param root The root window.
 * @param p_clients An array of windows.
 * @param n_clients The number of windows.
 *
 * Map all the X windows managed by the window manager from the oldest
 * to the newest by sending the _NET_CLIENT_LIST property to the
 * @p root window. The X windows are stored in @p p_clients and their
 * number in @p n_clients.
 *
 * This function SHOULD be called by the Window Manager.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_client_list_set(Ecore_X_Window  root,
                              Ecore_X_Window *p_clients,
                              unsigned int    n_clients)
{
   ecore_x_window_prop_window_set(root,
                                  ECORE_X_ATOM_NET_CLIENT_LIST,
                                  p_clients, n_clients);
} /* ecore_x_netwm_client_list_set */

/**
 * Set the _NET_CLIENT_LIST_STACKING property.
 * @param root The root window.
 * @param p_clients An array of windows.
 * @param n_clients The number of windows.
 *
 * Stack all the X windows managed by the window manager from bottom
 * to top order by sending the _NET_CLIENT_LIST_STACKING property to the
 * @p root window. The X windows are stored in @p p_clients and their
 * number in @p n_clients.
 *
 * This function SHOULD be called by the Window Manager.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_client_list_stacking_set(Ecore_X_Window  root,
                                       Ecore_X_Window *p_clients,
                                       unsigned int    n_clients)
{
   ecore_x_window_prop_window_set(root,
                                  ECORE_X_ATOM_NET_CLIENT_LIST_STACKING,
                                  p_clients, n_clients);
} /* ecore_x_netwm_client_list_stacking_set */

/**
 * Set the _NET_ACTIVE_WINDOW property.
 * @param root   The root window.
 * @param window The widow to activate.
 *
 * Activate @p window by sending the _NET_ACTIVE_WINDOW property to
 * the @p root window.
 *
 * If a Client wants to activate another window, it MUST call this
 * function.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_client_active_set(Ecore_X_Window root,
                                Ecore_X_Window window)
{
   ecore_x_window_prop_window_set(root,
                                  ECORE_X_ATOM_NET_ACTIVE_WINDOW,
                                  &window, 1);
} /* ecore_x_netwm_client_active_set */

/**
 * Set the _NET_WM_NAME property.
 * @param window The widow to activate.
 * @param name   The title name of the window.
 *
 * Set the title name of @p window to @p name by sending the
 * _NET_WM_NAME property to @p window.
 *
 * The Client SHOULD set the title of @p window in UTF-8 encoding. If
 * set, the Window Manager should use this in preference to WM_NAME.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_name_set(Ecore_X_Window window,
                       const char    *name)
{
   _ecore_x_window_prop_string_utf8_set(window, ECORE_X_ATOM_NET_WM_NAME, name);
} /* ecore_x_netwm_name_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_name_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_NAME, ECORE_X_ATOM_UTF8_STRING,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_name_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_name_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_name_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_name_get_fetch */

/**
 * Get the title of a window.
 * @param window The window.
 * @param name   The title name.
 * @return       Returns always 1.
 *
 * Retrieve the title name of @p window and store it in @p name. The
 * function returns always 1.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_name_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_name_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI int
ecore_x_netwm_name_get(Ecore_X_Window window,
                       char         **name)
{
   if (name)
      *name = _ecore_x_window_prop_string_utf8_get(window, ECORE_X_ATOM_NET_WM_NAME);

   return 1;
} /* ecore_x_netwm_name_get */

/**
 * Set the _NET_STARTUP_ID property.
 * @param window The window.
 * @param id     The ID name.
 *
 * Set the ID @p id used for the startup sequence by sending the
 * property _NET_STARTUP_ID to @p window. The ID name should be
 * encoded in UTF-8.
 *
 * If a new value for the property is set, the Window Manager
 * should update the window's status accordingly (update its virtual
 * desktop, etc.).
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_startup_id_set(Ecore_X_Window window,
                             const char    *id)
{
   _ecore_x_window_prop_string_utf8_set(window, ECORE_X_ATOM_NET_STARTUP_ID, id);
} /* ecore_x_netwm_startup_id_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_startup_id_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_STARTUP_ID, ECORE_X_ATOM_UTF8_STRING,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_startup_id_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_startup_id_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_startup_id_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_startup_id_get_fetch */

/**
 * Get the startup ID name of a window.
 * @param window The window
 * @param id     The ID name
 * @return       Return always 1.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_startup_id_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_startup_id_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI int
ecore_x_netwm_startup_id_get(Ecore_X_Window window,
                             char         **id)
{
   if (id)
      *id = _ecore_x_window_prop_string_utf8_get(window, ECORE_X_ATOM_NET_STARTUP_ID);

   return 1;
} /* ecore_x_netwm_startup_id_get */

/**
 * Set the _NET_WM_VISIBLE_NAME property.
 * @param window The widow to activate.
 * @param name   The title name of the window.
 *
 * Set the title name of @p window to @p name by sending the
 * _NET_WM_VISIBLE_NAME property to @p window, when the Window Manager
 * displays a window name other than by calling
 * ecore_x_netwm_name_set().
 *
 * The Client SHOULD set the title of @p window in UTF-8
 * encoding. This function is used for displaying title windows like
 * [xterm1], [xterm2], ... thereby allowing Pagers to display the same
 * title as the Window Manager.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_visible_name_set(Ecore_X_Window window,
                               const char    *name)
{
   _ecore_x_window_prop_string_utf8_set(window, ECORE_X_ATOM_NET_WM_VISIBLE_NAME,
                                        name);
} /* ecore_x_netwm_visible_name_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_visible_name_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_VISIBLE_NAME, ECORE_X_ATOM_UTF8_STRING,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_visible_name_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_visible_name_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_visible_name_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_visible_name_get_fetch */

/**
 * Get the visible title of a window.
 * @param window The window.
 * @param name   The title name.
 * @return       Returns always 1.
 *
 * Retrieve the visible title name of @p window and store it in @p name. The
 * function returns always 1.
 * @param window The window
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_visible_name_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_visible_name_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI int
ecore_x_netwm_visible_name_get(Ecore_X_Window window,
                               char         **name)
{
   if (name)
      *name = _ecore_x_window_prop_string_utf8_get(window,
                                                   ECORE_X_ATOM_NET_WM_VISIBLE_NAME);

   return 1;
} /* ecore_x_netwm_visible_name_get */

/**
 * Set the _NET_WM_ICON_NAME property.
 * @param window The widow to activate.
 * @param name   The icon name of the window.
 *
 * Set the icon name of @p window to @p name by sending the
 * _NET_WM_ICON_NAME property to @p window.
 *
 * The Client SHOULD set the title of @p window in UTF-8 encoding. If
 * set, the Window Manager should use this in preference to WM_ICON_NAME.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_icon_name_set(Ecore_X_Window window,
                            const char    *name)
{
   _ecore_x_window_prop_string_utf8_set(window, ECORE_X_ATOM_NET_WM_ICON_NAME,
                                        name);
} /* ecore_x_netwm_icon_name_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_icon_name_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_ICON_NAME, ECORE_X_ATOM_UTF8_STRING,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_icon_name_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_icon_name_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_icon_name_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_icon_name_get_fetch */

/**
 * Get the icon name of a window.
 * @param window The window.
 * @param name   The icon name.
 * @return       Returns always 1.
 *
 * Retrieve the icon name of @p window and store it in @p name. The
 * function returns always 1.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_icon_name_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_icon_name_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI int
ecore_x_netwm_icon_name_get(Ecore_X_Window window,
                            char         **name)
{
   if (name)
      *name = _ecore_x_window_prop_string_utf8_get(window,
                                                   ECORE_X_ATOM_NET_WM_ICON_NAME);

   return 1;
} /* ecore_x_netwm_icon_name_get */

/**
 * Set the _NET_WM_VISIBLE_ICON_NAME property.
 * @param window The widow to activate.
 * @param name   The title name of the window.
 *
 * Set the icon name of @p window to @p name by sending the
 * _NET_WM_VISIBLE_ICON_NAME property to @p window, when the Window Manager
 * displays a icon name other than by calling
 * ecore_x_netwm_icon_name_set().
 *
 * The Client SHOULD set the icon name in UTF-8
 * encoding. The Window Manager MUST use this function is it display
 * an icon name other than with ecore_x_netwm_icon_name_set().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_visible_icon_name_set(Ecore_X_Window window,
                                    const char    *name)
{
   _ecore_x_window_prop_string_utf8_set(window,
                                        ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME,
                                        name);
} /* ecore_x_netwm_visible_icon_name_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_visible_icon_name_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME, ECORE_X_ATOM_UTF8_STRING,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_visible_icon_name_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_visible_icon_name_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_visible_icon_name_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_visible_icon_name_get_fetch */

/**
 * Get the visible icon name of a window.
 * @param window The window.
 * @param name   The icon name.
 * @return       Returns always 1.
 *
 * Retrieve the visible icon name of @p window and store it in
 * @p name. The function returns always 1.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_visible_icon_name_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_visible_icon_name_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI int
ecore_x_netwm_visible_icon_name_get(Ecore_X_Window window,
                                    char         **name)
{
   if (name)
      *name = _ecore_x_window_prop_string_utf8_get(window,
                                                   ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME);

   return 1;
} /* ecore_x_netwm_visible_icon_name_get */

/**
 * Set the _NET_WM_DESKTOP property.
 * @param window The window.
 * @param desk   The desktop index.
 *
 * Set on which desktop the @p window is in by sending the
 * _NET_WM_DESKTOP property to @p window. @p desk is the index of
 * the desktop, starting from 0. To indicate that the window should
 * appear on all desktops, @p desk must be equal to 0xFFFFFFFF.
 *
 * A Client MAY choose not to set this property, in which case the
 * Window Manager SHOULD place it as it wishes.
 *
 * The Window Manager should honor _NET_WM_DESKTOP whenever a
 * withdrawn window requests to be mapped.
 *
 * A Client can request a change of desktop for a non-withdrawn window
 * by sending a _NET_WM_DESKTOP client message to the root window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desktop_set(Ecore_X_Window window,
                          unsigned int   desk)
{
   ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_DESKTOP, &desk, 1);
} /* ecore_x_netwm_desktop_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desktop_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_DESKTOP, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_desktop_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_desktop_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desktop_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_desktop_get_fetch */

/**
 * Get the visible icon name of a window.
 * @param window The window.
 * @param desk   The desktop index.
 * @return       1 on success, 0 otherwise.
 *
 * Retrieve the desktop index in which @p window is displayed and
 * store it in @p desk. If @p desk value is 0xFFFFFFFF, the window
 * appears on all desktops. The function returns 1 on success, 0
 * otherwise.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_desktop_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_desktop_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_desktop_get(Ecore_X_Window window,
                          unsigned int  *desk)
{
   int ret;
   uint32_t tmp;

   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_DESKTOP,
                                        &tmp, 1);

   if (desk)
      *desk = tmp;

   return (ret == 1) ? 1 : 0;
} /* ecore_x_netwm_desktop_get */

/**
 * Set the _NET_WM_STRUT property.
 * @param window The window
 * @param left   The number of pixels at the left of the screen.
 * @param right  The number of pixels at the right of the screen.
 * @param top    The number of pixels at the top of the screen.
 * @param bottom The number of pixels at the bottom of the screen.
 *
 * Set space at the edje of the screen by sending the _NET_WM_STRUT
 * property to @p window if @p window is to reserve that space.
 * @p left, @p right, @p top and @p bottom are respectively the number
 * of pixels at the left, right, top and bottom of the screen.
 *
 * This property is deprecated and ecore_x_netwm_strut_partial_set()
 * should be used instead. However, Clients MAY set this property in
 * addition to _NET_WM_STRUT_PARTIAL to ensure backward compatibility
 * with Window Managers supporting older versions of the
 * Specification.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_strut_set(Ecore_X_Window window,
                        int            left,
                        int            right,
                        int            top,
                        int            bottom)
{
   uint32_t strut[4];

   strut[0] = left;
   strut[1] = right;
   strut[2] = top;
   strut[3] = bottom;
   ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_STRUT, strut, 4);
} /* ecore_x_netwm_strut_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_strut_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_STRUT, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_strut_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_strut_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_strut_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_strut_get_fetch */

/*
 * _NET_WM_STRUT is deprecated
 */

/**
 * Get the space at the edje of the screen.
 * @param window The window
 * @param left   The number of pixels at the left of the screen.
 * @param right  The number of pixels at the right of the screen.
 * @param top    The number of pixels at the top of the screen.
 * @param bottom The number of pixels at the bottom of the screen.
 * @return       1 on success, 0 otherwise.
 *
 * Retrieve the space at the edje of the screen if @p window is to
 * reserve such space. The number of pixels at the left, right, top
 * and bottom of the screen are respectively stored in @p left,
 * @p right, @p top and @p bottom. This function returns 1 on success,
 * 0 otherwise.
 *
 * This property is deprecated. See ecore_x_netwm_strut_set() for more
 * informations.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_strut_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_strut_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_strut_get(Ecore_X_Window window,
                        int           *left,
                        int           *right,
                        int           *top,
                        int           *bottom)
{
   uint32_t strut[4];
   int ret = 0;

   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_STRUT, strut, 4);
   if (ret != 4)
      return 0;

   if (left)
      *left = strut[0];

   if (right)
      *right = strut[1];

   if (top)
      *top = strut[2];

   if (bottom)
      *bottom = strut[3];

   return 1;
} /* ecore_x_netwm_strut_get */

/**
 * Set the _NET_WM_STRUT_PARTIAL property.
 * @param window         The window
 * @param left           The number of pixels at the left of the screen.
 * @param right          The number of pixels at the right of the screen.
 * @param top            The number of pixels at the top of the screen.
 * @param bottom         The number of pixels at the bottom of the screen.
 * @param left_start_y   The number of pixels.
 * @param left_end_y     The number of pixels.
 * @param right_start_y  The number of pixels.
 * @param right_end_y    The number of pixels.
 * @param top_start_x    The number of pixels.
 * @param top_end_x      The number of pixels.
 * @param bottom_start_x The number of pixels.
 * @param bottom_end_x   The number of pixels.
 *
 * Set space at the edje of the screen by sending the
 * _NET_WM_STRUT_PARTIAL property to @p window if @p window is to
 * reserve that space. @p left, @p right, @p top and @p bottom are
 * respectively the number of pixels at the left, right, top and
 * bottom of the screen.
 *
 * TODO: more description for that function.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_strut_partial_set(Ecore_X_Window window,
                                int            left,
                                int            right,
                                int            top,
                                int            bottom,
                                int            left_start_y,
                                int            left_end_y,
                                int            right_start_y,
                                int            right_end_y,
                                int            top_start_x,
                                int            top_end_x,
                                int            bottom_start_x,
                                int            bottom_end_x)
{
   unsigned int strut[12];

   strut[0] = left;
   strut[1] = right;
   strut[2] = top;
   strut[3] = bottom;
   strut[4] = left_start_y;
   strut[5] = left_end_y;
   strut[6] = right_start_y;
   strut[7] = right_end_y;
   strut[8] = top_start_x;
   strut[9] = top_end_x;
   strut[10] = bottom_start_x;
   strut[11] = bottom_end_x;
   ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, strut, 12);
} /* ecore_x_netwm_strut_partial_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_strut_partial_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_strut_partial_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_strut_partial_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_strut_partial_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_strut_partial_get_fetch */

/**
 * Get the space at the edje of the screen of a window.
 * @param window         The window
 * @param left           The number of pixels at the left of the screen.
 * @param right          The number of pixels at the right of the screen.
 * @param top            The number of pixels at the top of the screen.
 * @param bottom         The number of pixels at the bottom of the screen.
 * @param left_start_y   The number of pixels.
 * @param left_end_y     The number of pixels.
 * @param right_start_y  The number of pixels.
 * @param right_end_y    The number of pixels.
 * @param top_start_x    The number of pixels.
 * @param top_end_x      The number of pixels.
 * @param bottom_start_x The number of pixels.
 * @param bottom_end_x   The number of pixels.
 *
 * Retrieve the space at the edje of the screen if @p window is to
 * reserve such space. The number of pixels at the left, right, top
 * and bottom of the screen are respectively stored in @p left,
 * @p right, @p top and @p bottom. This function returns 1 on success,
 * 0 otherwise.
 *
 * TODO: more description for that function.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_strut_partial_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_strut_partial_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_strut_partial_get(Ecore_X_Window window,
                                int           *left,
                                int           *right,
                                int           *top,
                                int           *bottom,
                                int           *left_start_y,
                                int           *left_end_y,
                                int           *right_start_y,
                                int           *right_end_y,
                                int           *top_start_x,
                                int           *top_end_x,
                                int           *bottom_start_x,
                                int           *bottom_end_x)
{
   uint32_t strut[12];
   int ret = 0;

   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, strut, 12);
   if (ret != 12)
      return 0;

   if (left)
      *left = strut[0];

   if (right)
      *right = strut[1];

   if (top)
      *top = strut[2];

   if (bottom)
      *bottom = strut[3];

   if (left_start_y)
      *left_start_y = strut[4];

   if (left_end_y)
      *left_end_y = strut[5];

   if (right_start_y)
      *right_start_y = strut[6];

   if (right_end_y)
      *right_end_y = strut[7];

   if (top_start_x)
      *top_start_x = strut[8];

   if (top_end_x)
      *top_end_x = strut[9];

   if (bottom_start_x)
      *bottom_start_x = strut[10];

   if (bottom_end_x)
      *bottom_end_x = strut[11];

   return 1;
} /* ecore_x_netwm_strut_partial_get */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_icons_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_ICON, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_icons_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_icons_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_icons_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_icons_get_fetch */

/**
 * Retrieve hte possible icons of a window.
 * @param window The window
 * @param icon   An array of icons.
 * @param num    The number of icons.
 * @return       1 on success, 0 otherwise.
 *
 * Retrieve an array of possible icons of @p window. The icons are
 * stored in @p icon and their number in @p num.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_icons_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_icons_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_icons_get(Ecore_X_Window window,
                        Ecore_X_Icon **icon,
                        int           *num)
{
   uint32_t *data;
   uint32_t *p;
   uint32_t *src;
   uint32_t icons;
   uint32_t len;
   uint32_t i;
   int num_ret;

   if (num)
      *num = 0UL;

   if (icon)
      *icon = NULL;

   num_ret = ecore_x_window_prop_card32_list_get(window,
                                                 ECORE_X_ATOM_NET_WM_ICON,
                                                 &data);
   if ((num_ret <= 0) || !data)
      return 0;

   if (num_ret < 2)
     {
        free(data);
        return 0;
     }

   /* Check how many icons there are */
   icons = 0;
   p = data;
   while (p)
     {
        len = p[0] * p[1];
        p += (len + 2);
        if ((p - data) > num_ret)
          {
             free(data);
             return 0;
          }

        icons++;

        if ((p - data) == num_ret)
           p = NULL;
     }
   if (num)
      *num = icons;

   /* If the user doesn't want the icons, return */
   if (!icon)
     {
        free(data);
        return 1;
     }

   /* Allocate memory */
   *icon = malloc(icons * sizeof(Ecore_X_Icon));
   if (!(*icon))
     {
        free(data);
        return 0;
     }

   /* Fetch the icons */
   p = data;
   for (i = 0; i < icons; i++)
     {
        uint32_t *ps, *pd, *pe;

        len = p[0] * p[1];
        ((*icon)[i]).width = p[0];
        ((*icon)[i]).height = p[1];
        src = &(p[2]);
        ((*icon)[i]).data = malloc(len * sizeof(uint32_t));
        if (!((*icon)[i]).data)
          {
             while (i)
                free(((*icon)[--i]).data);
             free(*icon);
             free(data);
             return 0;
          }

        pd = ((*icon)[i]).data;
        ps = src;
        pe = ps + len;
        for (; ps < pe; ps++)
          {
             uint32_t r, g, b, a;

             a = (*ps >> 24) & 0xff;
             r = (((*ps >> 16) & 0xff) * a) / 255;
             g = (((*ps >> 8) & 0xff) * a) / 255;
             b = (((*ps) & 0xff) * a) / 255;
             *pd = (a << 24) | (r << 16) | (g << 8) | (b);
             pd++;
          }
        p += (len + 2);
     }

   free(data);

   return 1;
} /* ecore_x_netwm_icons_get */

/**
 * Set the _NET_WM_ICON_GEOMETRY property.
 * @param window The window.
 * @param x      The X coordinate of the icon.
 * @param y      The Y coordinate of the icon.
 * @param width  The width of the icon.
 * @param height The height of the icon.
 *
 * Set the geometry of the icon of @p window by sending the
 * _NET_WM_ICON_GEOMETRY property to @p window. @p x, @p y, @p width
 * and @p height specify respectively the X coordinate, the Y
 * coordinate, the width and the height of the icon.
 *
 * Stand alone tools like a taskbar or an iconbox MAY use this
 * function. This functions makes possible for a Window Manager to
 * display a nice animation like morphing the window into its icon.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_icon_geometry_set(Ecore_X_Window window,
                                int            x,
                                int            y,
                                int            width,
                                int            height)
{
   uint32_t geometry[4];

   geometry[0] = (uint32_t)x;
   geometry[1] = (uint32_t)y;
   geometry[2] = (uint32_t)width;
   geometry[3] = (uint32_t)height;
   ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, geometry, 4);
} /* ecore_x_netwm_icon_geometry_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_icon_geometry_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_icon_geometry_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_icon_geometry_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_icon_geometry_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_icon_geometry_get_fetch */

/**
 * Get the geometry of an icon.
 * @param window The window
 * @param x      x
 * @param x      The X coordinate of the icon.
 * @param y      The Y coordinate of the icon.
 * @param width  The width of the icon.
 * @param height The height of the icon.
 * @return       1 on success, 0 othrwise.
 *
 * Retrieve the geometry of the icon of @p window. The geometry is
 * stored in @p x, @p y, @p width and @p height. The function returns
 * 1 on success, 0 otherwise.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_icon_geometry_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_icon_geometry_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_icon_geometry_get(Ecore_X_Window window,
                                int           *x,
                                int           *y,
                                int           *width,
                                int           *height)
{
   uint32_t geometry[4];
   int ret;

   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, geometry, 4);
   if (ret != 4)
      return 0;

   if (x)
      *x = geometry[0];

   if (y)
      *y = geometry[1];

   if (width)
      *width = geometry[2];

   if (height)
      *height = geometry[3];

   return 1;
} /* ecore_x_netwm_icon_geometry_get */

/**
 * Set the _NET_WM_PID property.
 * @param window The window.
 * @param pid    The process ID.
 *
 * Set the process ID of the client owning @p window by sending the
 * _NET_WM_PID property to @p window.
 *
 * This function MAY be used by the Window Manager to kill windows
 * which do not respond to the _NET_WM_PING protocol.
 *
 * If _NET_WM_PID is set, the ICCCM-specified property
 * WM_CLIENT_MACHINE MUST also be set.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_pid_set(Ecore_X_Window window,
                      int            pid)
{
   unsigned int tmp;

   tmp = pid;
   ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_PID,
                                  &tmp, 1);
} /* ecore_x_netwm_pid_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_pid_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_PID, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_pid_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_pid_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_pid_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_pid_get_fetch */

/**
 * Get the process ID of a client window.
 * @param window The window.
 * @param pid    The process ID.
 * @return       1 on success, 0 otherwise.
 *
 * Retrieve the process ID of @p window and store it in @p pid. This
 * function returns 1 on success, 0 otherwise.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_pid_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_pid_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_pid_get(Ecore_X_Window window,
                      int           *pid)
{
   int ret;
   uint32_t tmp;

   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_PID,
                                        &tmp, 1);
   if (pid)
      *pid = tmp;

   return (ret == 1) ? 1 : 0;
} /* ecore_x_netwm_pid_get */

/**
 * Set the _NET_WM_HANDLED_ICONS property.
 * @param window The window.
 *
 * Indicate to the Window Manager that it does not need to provide
 * icons for the iconified @p window by sending the
 * _NET_WM_HANDLED_ICONS property to @p window.
 *
 * This function can be used by a Pager on one of its own toplevel
 * windows (for example if the Client is a taskbar and provides
 * buttons for iconified windows).
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_handled_icons_set(Ecore_X_Window window)
{
   ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_HANDLED_ICONS,
                                  NULL, 0);
} /* ecore_x_netwm_handled_icons_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_handled_icons_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_HANDLED_ICONS, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_handled_icons_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_handled_icons_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_handled_icons_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_handled_icons_get_fetch */

/**
 * Return wheter the Client handles icons or not.
 * @param window The window.
 * @return       1 if icons are handled, 0 otherwise.
 *
 * Return whether the client handles icons or not if @p window is
 * iconified.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_handled_icons_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_handled_icons_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_handled_icons_get(Ecore_X_Window window)
{
   int ret = 0;
   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_HANDLED_ICONS,
                                        NULL, 0);
   return (ret == 0) ? 1 : 0;
} /* ecore_x_netwm_handled_icons_get */

/**
 * Set the _NET_WM_USER_TIME property.
 * @param window The window.
 * @param time   The last user activity time in the window.
 *
 * Set the XServer time at which last user activity in @p window took
 * place by sending the _NET_WM_USER_TIME property to @p window. @p
 * time contains that XServer time in seconds.
 *
 * This function allows a Window Manager to alter the focus, stacking,
 * and/or placement behavior of windows when they are mapped depending
 * on whether the new window was created by a user action or is a
 * "pop-up" window activated by a timer or some other event.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_user_time_set(Ecore_X_Window window,
                            unsigned int   time)
{
   ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_USER_TIME,
                                  &time, 1);
} /* ecore_x_netwm_user_time_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_user_time_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_USER_TIME, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_user_time_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_user_time_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_user_time_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_user_time_get_fetch */

/**
 * Get the last user activity time in the window.
 * @param window The window.
 * @param time   The returned time.
 * @return       1 on success, 0 otherwise.
 *
 * Return the XServer time at which last user activity in @p window
 * took place. The time is stored in @p time.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_user_time_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_user_time_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_user_time_get(Ecore_X_Window window,
                            unsigned int  *time)
{
   int ret;
   uint32_t tmp;

   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_USER_TIME,
                                        &tmp, 1);
   if (time)
      *time = tmp;

   return (ret == 1) ? 1 : 0;
} /* ecore_x_netwm_user_time_get */

Ecore_X_Window_State
_ecore_x_netwm_state_get(Ecore_X_Atom a)
{
   if (a == ECORE_X_ATOM_NET_WM_STATE_MODAL)
      return ECORE_X_WINDOW_STATE_MODAL;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_STICKY)
      return ECORE_X_WINDOW_STATE_STICKY;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT)
      return ECORE_X_WINDOW_STATE_MAXIMIZED_VERT;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ)
      return ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_SHADED)
      return ECORE_X_WINDOW_STATE_SHADED;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR)
      return ECORE_X_WINDOW_STATE_SKIP_TASKBAR;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER)
      return ECORE_X_WINDOW_STATE_SKIP_PAGER;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_HIDDEN)
      return ECORE_X_WINDOW_STATE_HIDDEN;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN)
      return ECORE_X_WINDOW_STATE_FULLSCREEN;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_ABOVE)
      return ECORE_X_WINDOW_STATE_ABOVE;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_BELOW)
      return ECORE_X_WINDOW_STATE_BELOW;
   else if (a == ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION)
      return ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION;
   else
      return ECORE_X_WINDOW_STATE_UNKNOWN;
} /* _ecore_x_netwm_state_get */

static Ecore_X_Atom
_ecore_x_netwm_state_atom_get(Ecore_X_Window_State s)
{
   switch(s)
     {
      case ECORE_X_WINDOW_STATE_MODAL:
         return ECORE_X_ATOM_NET_WM_STATE_MODAL;

      case ECORE_X_WINDOW_STATE_STICKY:
         return ECORE_X_ATOM_NET_WM_STATE_STICKY;

      case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT:
         return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT;

      case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ:
         return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ;

      case ECORE_X_WINDOW_STATE_SHADED:
         return ECORE_X_ATOM_NET_WM_STATE_SHADED;

      case ECORE_X_WINDOW_STATE_SKIP_TASKBAR:
         return ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR;

      case ECORE_X_WINDOW_STATE_SKIP_PAGER:
         return ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER;

      case ECORE_X_WINDOW_STATE_HIDDEN:
         return ECORE_X_ATOM_NET_WM_STATE_HIDDEN;

      case ECORE_X_WINDOW_STATE_FULLSCREEN:
         return ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN;

      case ECORE_X_WINDOW_STATE_ABOVE:
         return ECORE_X_ATOM_NET_WM_STATE_ABOVE;

      case ECORE_X_WINDOW_STATE_BELOW:
         return ECORE_X_ATOM_NET_WM_STATE_BELOW;

      case ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION:
         return ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION;

      default:
         return 0;
     } /* switch */
} /* _ecore_x_netwm_state_atom_get */

/**
 * Set the _NET_WM_STATE property.
 * @param window The window.
 * @param state  An array of window hints.
 * @param num    The number of hints.
 *
 * Set a list of hints describing @p window state by sending the
 * _NET_WM_STATE property to @p window. The hints are stored in the
 * array @p state. @p num must contain the number of hints.
 *
 * The Window Manager SHOULD honor _NET_WM_STATE whenever a withdrawn
 * window requests to be mapped. A Client wishing to change the state
 * of a window MUST send a _NET_WM_STATE client message to the root
 * window. The Window Manager MUST keep this property updated to
 * reflect the current state of the window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_window_state_set(Ecore_X_Window        window,
                               Ecore_X_Window_State *state,
                               unsigned int          num)
{
   Ecore_X_Atom *set;
   uint32_t i;

   if (!num)
     {
        ecore_x_window_prop_property_del(window, ECORE_X_ATOM_NET_WM_STATE);
        return;
     }

   set = malloc(num * sizeof(Ecore_X_Atom));
   if (!set)
      return;

   for (i = 0; i < num; i++)
      set[i] = _ecore_x_netwm_state_atom_get(state[i]);

   ecore_x_window_prop_atom_set(window, ECORE_X_ATOM_NET_WM_STATE, set, num);

   free(set);
} /* ecore_x_netwm_window_state_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_window_state_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_STATE, ECORE_X_ATOM_ATOM,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_window_state_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_window_state_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_window_state_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_window_state_get_fetch */

/**
 * Get the hints describing the window state.
 * @param window The window.
 * @param state  The returned hins.
 * @param num    The number of hints.
 * @return       1 on success, 0 otherwise.
 *
 * Retrieve the hints describing @p window state. The state is
 * returned in @p state. The nummber of hints is stored in @p
 * num. This function returns 1 on success, 0 otherwise.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_window_state_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_window_state_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_window_state_get(Ecore_X_Window         window,
                               Ecore_X_Window_State **state,
                               unsigned int          *num)
{
   Ecore_X_Atom *atoms;
   int num_ret;
   int i;

   if (num)
      *num = 0;

   if (state)
      *state = NULL;

   num_ret = ecore_x_window_prop_atom_list_get(window, ECORE_X_ATOM_NET_WM_STATE,
                                               &atoms);
   if (num_ret <= 0)
      return 0;

   if (state)
     {
        *state = malloc(num_ret * sizeof(Ecore_X_Window_State));
        if (*state)
           for (i = 0; i < num_ret; ++i)
              (*state)[i] = _ecore_x_netwm_state_get(atoms[i]);

        if (num)
           *num = num_ret;
     }

   free(atoms);

   return 1;
} /* ecore_x_netwm_window_state_get */

static Ecore_X_Window_Type
_ecore_x_netwm_window_type_type_get(Ecore_X_Atom atom)
{
   if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP)
      return ECORE_X_WINDOW_TYPE_DESKTOP;
   else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK)
      return ECORE_X_WINDOW_TYPE_DOCK;
   else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR)
      return ECORE_X_WINDOW_TYPE_TOOLBAR;
   else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU)
      return ECORE_X_WINDOW_TYPE_MENU;
   else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY)
      return ECORE_X_WINDOW_TYPE_UTILITY;
   else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH)
      return ECORE_X_WINDOW_TYPE_SPLASH;
   else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG)
      return ECORE_X_WINDOW_TYPE_DIALOG;
   else if (atom == ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL)
      return ECORE_X_WINDOW_TYPE_NORMAL;
   else
      return ECORE_X_WINDOW_TYPE_UNKNOWN;
} /* _ecore_x_netwm_window_type_type_get */

static Ecore_X_Atom
_ecore_x_netwm_window_type_atom_get(Ecore_X_Window_Type type)
{
   switch (type)
     {
      case ECORE_X_WINDOW_TYPE_DESKTOP:
         return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP;

      case ECORE_X_WINDOW_TYPE_DOCK:
         return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK;

      case ECORE_X_WINDOW_TYPE_TOOLBAR:
         return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR;

      case ECORE_X_WINDOW_TYPE_MENU:
         return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU;

      case ECORE_X_WINDOW_TYPE_UTILITY:
         return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY;

      case ECORE_X_WINDOW_TYPE_SPLASH:
         return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH;

      case ECORE_X_WINDOW_TYPE_DIALOG:
         return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG;

      case ECORE_X_WINDOW_TYPE_NORMAL:
         return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL;

      default:
         return 0;
     } /* switch */
} /* _ecore_x_netwm_window_type_atom_get */

/*
 * FIXME: We should set WM_TRANSIENT_FOR if type is ECORE_X_WINDOW_TYPE_TOOLBAR
 * , ECORE_X_WINDOW_TYPE_MENU or ECORE_X_WINDOW_TYPE_DIALOG
 */

/**
 * Set the _NET_WM_WINDOW_TYPE property.
 * @param window The window.
 * @param type   The functional type of the window.
 *
 * Set the functional @p type of @p window by sending _NET_WM_WINDOW_TYPE
 * property to @p window.
 *
 * This property SHOULD be set by the Client before mapping. This
 * property SHOULD be used by the window manager in determining the
 * decoration, stacking position and other behavior of the window. The
 * Client SHOULD specify window types in order of preference (the first
 * being most preferable).
 *
 * This hint is intended to replace the MOTIF hints.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_window_type_set(Ecore_X_Window      window,
                              Ecore_X_Window_Type type)
{
   Ecore_X_Atom atom;

   atom = _ecore_x_netwm_window_type_atom_get(type);
   ecore_x_window_prop_atom_set(window, ECORE_X_ATOM_NET_WM_WINDOW_TYPE,
                                &atom, 1);
} /* ecore_x_netwm_window_type_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_window_type_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_WINDOW_TYPE, ECORE_X_ATOM_ATOM,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_window_type_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_window_type_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_window_type_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_window_type_get_fetch */

/* FIXME: Maybe return 0 on some conditions? */

/**
 * Get the functional type of a window.
 * @param window The window.
 * @param type   The function type of the window.
 * @return       1 on success, 0 otherwise.
 *
 * Retrieve the functional type of @p window. The type is stored in
 * @p type. This function returns 1 on success, 0 otherwise.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_window_type_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_window_type_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_window_type_get(Ecore_X_Window       window,
                              Ecore_X_Window_Type *type)
{
   Ecore_X_Atom *atoms;
   int num;
   int i;

   if (type)
      *type = ECORE_X_WINDOW_TYPE_NORMAL;

   num = ecore_x_window_prop_atom_list_get(window, ECORE_X_ATOM_NET_WM_WINDOW_TYPE,
                                           &atoms);
   if (num < 0)
     {
        /* IMO this is not the place to mix netwm and icccm /kwo */
        /* Check if WM_TRANSIENT_FOR is set */

        /* Disable it for xcb */

/*	if ((type) && (ecore_x_icccm_transient_for_get(window))) */
/*	  *type = ECORE_X_WINDOW_TYPE_DIALOG; */
/*	return 1; */
     }

   if (type)
     {
        for (i = 0; i < num; ++i)
          {
             *type = _ecore_x_netwm_window_type_type_get(atoms[i]);
             if (*type != ECORE_X_WINDOW_TYPE_UNKNOWN)
                break;
          }
     }

   free(atoms);

   return 1;
} /* ecore_x_netwm_window_type_get */

static Ecore_X_Atom
_ecore_x_netwm_action_atom_get(Ecore_X_Action action)
{
   switch (action)
     {
      case ECORE_X_ACTION_MOVE:
         return ECORE_X_ATOM_NET_WM_ACTION_MOVE;

      case ECORE_X_ACTION_RESIZE:
         return ECORE_X_ATOM_NET_WM_ACTION_RESIZE;

      case ECORE_X_ACTION_MINIMIZE:
         return ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE;

      case ECORE_X_ACTION_SHADE:
         return ECORE_X_ATOM_NET_WM_ACTION_SHADE;

      case ECORE_X_ACTION_STICK:
         return ECORE_X_ATOM_NET_WM_ACTION_STICK;

      case ECORE_X_ACTION_MAXIMIZE_HORZ:
         return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ;

      case ECORE_X_ACTION_MAXIMIZE_VERT:
         return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT;

      case ECORE_X_ACTION_FULLSCREEN:
         return ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN;

      case ECORE_X_ACTION_CHANGE_DESKTOP:
         return ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP;

      case ECORE_X_ACTION_CLOSE:
         return ECORE_X_ATOM_NET_WM_ACTION_CLOSE;

      case ECORE_X_ACTION_ABOVE:
         return ECORE_X_ATOM_NET_WM_ACTION_ABOVE;

      case ECORE_X_ACTION_BELOW:
         return ECORE_X_ATOM_NET_WM_ACTION_BELOW;

      default:
         return 0;
     } /* switch */
} /* _ecore_x_netwm_action_atom_get */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_allowed_action_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, ECORE_X_ATOM_ATOM,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_allowed_action_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_allowed_action_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_allowed_action_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_allowed_action_get_fetch */

/* FIXME: Get complete list */

/**
 * Check whether an action is supported by a window.
 * @param window The window
 * @param action The action
 * @return       1 if set, 0 otherwise.
 *
 * Return whether the user operation @p action is supported by the
 * Window Manager for @p window.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_allowed_action_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_allowed_action_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_allowed_action_isset(Ecore_X_Window window,
                                   Ecore_X_Action action)
{
   Ecore_X_Atom *atoms;
   Ecore_X_Atom atom;
   int num;
   int ret = 0;
   int i;

   num = ecore_x_window_prop_atom_list_get(window, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS,
                                           &atoms);
   if (num <= 0)
      return ret;

   atom = _ecore_x_netwm_action_atom_get(action);

   for (i = 0; i < num; ++i)
     {
        if (atom == atoms[i])
          {
             ret = 1;
             break;
          }
     }

   free(atoms);

   return ret;
} /* ecore_x_netwm_allowed_action_isset */

/* FIXME: Set complete list */
/**
 * Set the _NET_WM_ALLOWED_ACTIONS property.
 * @param window The window.
 * @param action An array of allowed actions.
 * @param num    The number of actions.
 *
 * Set the user operations that the Window Manager supports for
 * @p window by sending the _NET_WM_ALLOWED_ACTIONS property to
 * @p window. @p action stores @p num actions.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_allowed_action_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_allowed_action_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_allowed_action_set(Ecore_X_Window  window,
                                 Ecore_X_Action *action,
                                 unsigned int    num)
{
   Ecore_X_Atom *set;
   unsigned int i;

   if (!num)
     {
        ecore_x_window_prop_property_del(window, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS);
        return;
     }

   set = malloc(num * sizeof(Ecore_X_Atom));
   if (!set)
      return;

   for (i = 0; i < num; i++)
      set[i] = _ecore_x_netwm_action_atom_get(action[i]);

   ecore_x_window_prop_atom_set(window, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, set, num);

   free(set);
} /* ecore_x_netwm_allowed_action_set */

/**
 * Get the allowed actions supported by a window.
 * @param window The window.
 * @param action The returned array of the actions.
 * @param num    The number of actions.
 * @return       1 on success, 0 otherwise.
 *
 * Retrieve the user operations that the Window Manager supports for
 * @p window and store them in @p action. The number of actions is
 * stored in @p num. This function returns 1 on success, 0 otherwise.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_allowed_action_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_allowed_action_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_allowed_action_get(Ecore_X_Window   window,
                                 Ecore_X_Action **action,
                                 unsigned int    *num)
{
   Ecore_X_Atom *atoms;
   int num_ret;
   int i;

   if (num)
      *num = 0;

   if (action)
      *action = NULL;

   num_ret = ecore_x_window_prop_atom_list_get(window, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS,
                                               &atoms);
   if (num_ret <= 0)
      return 0;

   if (action)
     {
        *action = malloc(num_ret * sizeof(Ecore_X_Action));
        if (*action)
           for (i = 0; i < num_ret; ++i)
              (*action)[i] = _ecore_x_netwm_action_atom_get(atoms[i]);

        if (num)
           *num = num_ret;
     }

   free(atoms);

   return 1;
} /* ecore_x_netwm_allowed_action_get */

/**
 * Set the _NET_WM_WINDOW_OPACITY property.
 * @param window  The window.
 * @param opacity The opacity value.
 *
 * Set the desired opacity of @p window by sending the
 * _NET_WM_WINDOW_OPACITY property to @p window. @p opacity is 0 for a
 * transparent window and 0xffffffff for an opaque window. @p opacity
 * must be multiplied with the original alpha value of @p window
 * (which is 1 for visuals not including an alpha component) so that
 * @p window content is modulated by the opacity value.
 *
 * Window Managers acting as compositing managers MAY take this into
 * account when displaying a window. Window Managers MUST forward the
 * value of this property to any enclosing frame window.  This
 * property MAY change while the window is mapped and the Window
 * Manager MUST respect changes while the window is mapped.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_opacity_set(Ecore_X_Window window,
                          unsigned int   opacity)
{
   uint32_t op = opacity;
   ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY,
                                  &op, 1);
} /* ecore_x_netwm_opacity_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_opacity_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_opacity_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_opacity_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_opacity_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_opacity_get_fetch */

/**
 * Get the opacity value of a window.
 * @param window  The window.
 * @param opacity The returned opacity.
 * @return        1 on success, 0 otherwise.
 *
 * Retriee the opacity value of @p window and store it in
 * @p opacity. This function returns 1 on success, 0 otherwise.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_opacity_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_opacity_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_opacity_get(Ecore_X_Window window,
                          unsigned int  *opacity)
{
   int ret;
   unsigned int tmp;

   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY,
                                        &tmp, 1);
   if (opacity)
      *opacity = tmp;

   return ret == 1 ? 1 : 0;
} /* ecore_x_netwm_opacity_get */

/**
 * Set the _NET_FRAME_EXTENTS property.
 * @param window The window.
 * @param fl     The number of pixels of the left border of the window.
 * @param fr     The number of pixels of the right border of the window.
 * @param ft     The number of pixels of the top border of the window.
 * @param fb     The number of pixels of the bottom border of the window.
 *
 * Set the border witdh of @p window by sending the _NET_FRAME_EXTENTS
 * property to @p window. @p fl, @p fr, @p ft and @p fb are respectively
 * the number of pixels of the left, right, top and bottom border of
 * @p window.
 *
 * The Window Manager MUST set _NET_FRAME_EXTENTS to the extents of
 * the window's frame.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_frame_size_set(Ecore_X_Window window,
                             int            fl,
                             int            fr,
                             int            ft,
                             int            fb)
{
   uint32_t frames[4];

   frames[0] = fl;
   frames[1] = fr;
   frames[2] = ft;
   frames[3] = fb;
   ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_FRAME_EXTENTS, frames, 4);
} /* ecore_x_netwm_frame_size_set */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_frame_size_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_FRAME_EXTENTS, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_frame_size_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_frame_size_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_frame_size_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_frame_size_get_fetch */

/**
 * Get the frame extent of a window.
 * @param window  The window.
 * @param fl      The number of pixels of the left border of the window.
 * @param fr      The number of pixels of the right border of the window.
 * @param ft      The number of pixels of the top border of the window.
 * @param fb      The number of pixels of the bottom border of the window.
 * @return        1 on success, 0 otherwise.
 *
 * Retrieve the frame extents of @p window. The number of pixels of
 * the left, right, top and bottom border of @p window are
 * respectively stored in @p fl, @p fr, @p ft anfd @p fb. TYhis
 * function retuirns 1 on success, 0 otherwise.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_frame_size_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_frame_size_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_frame_size_get(Ecore_X_Window window,
                             int           *fl,
                             int           *fr,
                             int           *ft,
                             int           *fb)
{
   uint32_t frames[4];
   int ret = 0;

   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_FRAME_EXTENTS, frames, 4);
   if (ret != 4)
      return 0;

   if (fl)
      *fl = frames[0];

   if (fr)
      *fr = frames[1];

   if (ft)
      *ft = frames[2];

   if (fb)
      *fb = frames[3];

   return 1;
} /* ecore_x_netwm_frame_size_get */

/**
 * Sends the GetProperty request.
 * @param window The window.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_sync_counter_get_prefetch(Ecore_X_Window window)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER, ECORE_X_ATOM_CARDINAL,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* ecore_x_netwm_sync_counter_get_prefetch */

/**
 * Gets the reply of the GetProperty request sent by ecore_x_netwm_sync_counter_get_prefetch().
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_sync_counter_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* ecore_x_netwm_sync_counter_get_fetch */

/**
 * Get the X ID of a X Sync counter.
 * @param window  The window.
 * @param counter The X ID of the Sync counter.
 * @return        1 on success, 0 otherwise.
 *
 * Retrieve the X ID of the X Sync counter of @p window and store it
 * in @p counter. This function returns 1 on success, 0 otherwise.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_netwm_frame_size_get_prefetch(), which sends the GetProperty request,
 * then ecore_x_netwm_frame_size_get_fetch(), which gets the reply.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_netwm_sync_counter_get(Ecore_X_Window        window,
                               Ecore_X_Sync_Counter *counter)
{
   int ret;
   unsigned int tmp;

   ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER,
                                        &tmp, 1);

   if (counter)
      *counter = tmp;

   return (ret == 1) ? 1 : 0;
} /* ecore_x_netwm_sync_counter_get */

/**
 * Send a _NET_WM_PING property event.
 * @param window The window.
 *
 * Send a ClientMessage event from @p window with the _NET_WM_PING
 * property set.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_ping_send(Ecore_X_Window window)
{
   xcb_client_message_event_t ev;

   if (!window)
      return;

   ev.response_type = XCB_CLIENT_MESSAGE | 0x80;
   ev.format = 32;
   ev.sequence = 0;
   ev.window = window;
   ev.type = ECORE_X_ATOM_WM_PROTOCOLS;
   ev.data.data32[0] = ECORE_X_ATOM_NET_WM_PING;
   ev.data.data32[1] = _ecore_xcb_event_last_time;
   ev.data.data32[2] = window;
   ev.data.data32[3] = 0;
   ev.data.data32[4] = 0;
   ev.data.data32[5] = 0;

   xcb_send_event(_ecore_xcb_conn, 0, window, XCB_EVENT_MASK_NO_EVENT, (const char *)&ev);
} /* ecore_x_netwm_ping_send */

/**
 * Send a _NET_WM_SYNC_REQUEST property event.
 * @param window The window.
 * @param serial The update request number.
 *
 * Send a ClientMessage event from @p window with the _NET_WM_SYNC_REQUEST
 * property set.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_sync_request_send(Ecore_X_Window window,
                                unsigned int   serial)
{
   xcb_client_message_event_t ev;

   if (!window)
      return;

   ev.response_type = XCB_CLIENT_MESSAGE | 0x80;
   ev.format = 32;
   ev.window = window;
   ev.type = ECORE_X_ATOM_WM_PROTOCOLS;
   ev.data.data32[0] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST;
   ev.data.data32[1] = _ecore_xcb_event_last_time;
   ev.data.data32[2] = serial;
   /* FIXME: imho, the following test is useless as serial is non negative */
   /* should we remove it ? */
   ev.data.data32[3] = (serial < 0) ? ~0L : 0L;
   ev.data.data32[4] = 0;

   xcb_send_event(_ecore_xcb_conn, 0, window, 0, (const char *)&ev);
} /* ecore_x_netwm_sync_request_send */

/**
 * Send a _NET_WM_STATE property event.
 * @param window The window.
 * @param root   The root window.
 * @param s1     The first state to alter.
 * @param s2     The second state to alter.
 * @param set    0 to unset the property, set it otherwise.
 *
 * Send a ClientMessage event from @p window to the @p root window
 * with the _NET_WM_STATE property set. This change the state of a
 * mapped window. @p s1 is the first state to alter. @p s2 is the
 * second state to alter. If @p set value is 0, the property is
 * removed (or unset), otherwise, the property is set.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_state_request_send(Ecore_X_Window       window,
                                 Ecore_X_Window       root,
                                 Ecore_X_Window_State s1,
                                 Ecore_X_Window_State s2,
                                 Eina_Bool            set)
{
   xcb_client_message_event_t ev;

   if (!window)
      return;

   if (!root)
      root = ((xcb_screen_t *)_ecore_xcb_screen)->root;

   ev.response_type = XCB_CLIENT_MESSAGE | 0x80;
   ev.format = 32;
   ev.window = window;
   ev.type = ECORE_X_ATOM_NET_WM_STATE;
   ev.data.data32[0] = !!set;
   ev.data.data32[1] = _ecore_x_netwm_state_atom_get(s1);
   ev.data.data32[2] = _ecore_x_netwm_state_atom_get(s2);
   /* 1 == normal client, if someone wants to use this
    * function in a pager, this should be 2 */
   ev.data.data32[3] = 1;
   ev.data.data32[4] = 0;

   xcb_send_event(_ecore_xcb_conn, 0, root,
                  XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
                  (const char *)&ev);
} /* ecore_x_netwm_state_request_send */

/**
 * Send a _NET_WM_DESKTOP property event.
 * @param window  The window.
 * @param root    The root window.
 * @param desktop The new desktop index.
 *
 * Send a ClientMessage event from @p window to the @p root window
 * with the _NET_WM_DESKTOP property set. This change the state of a
 * non-withdrawn window. @p desktop is the new desktop index to set.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI void
ecore_x_netwm_desktop_request_send(Ecore_X_Window window,
                                   Ecore_X_Window root,
                                   unsigned int   desktop)
{
   xcb_client_message_event_t ev;

   if (!window)
      return;

   if (!root)
      root = ((xcb_screen_t *)_ecore_xcb_screen)->root;

   ev.response_type = XCB_CLIENT_MESSAGE | 0x80;
   ev.format = 32;
   ev.window = window;
   ev.type = ECORE_X_ATOM_NET_WM_DESKTOP;
   ev.data.data32[0] = desktop;

   xcb_send_event(_ecore_xcb_conn, 0, root,
                  XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
                  (const char *)&ev);
} /* ecore_x_netwm_desktop_request_send */

int
_ecore_x_netwm_startup_info_begin(Ecore_X_Window window,
                                  char          *data)
{
#if 0
   Ecore_X_Startup_Info *info;
   unsigned char exists = 0;

   if (!startup_info)
      return 0;

   info = eina_hash_find(startup_info, (void *)window);
   if (info)
     {
        exists = 1;
        INF("Already got info for win: 0x%x", window);
        _ecore_x_netwm_startup_info_free(info);
     }

   info = calloc(1, sizeof(Ecore_X_Startup_Info));
   if (!info)
      return 0;

   info->win = win;
   info->length = 0;
   info->buffer_size = 161;
   info->buffer = calloc(info->buffer_size, sizeof(char));
   if (!info->buffer)
     {
        _ecore_x_netwm_startup_info_free(info);
        return 0;
     }

   memcpy(info->buffer, data, 20);
   info->length += 20;
   info->buffer[info->length] = 0;
   if (exists)
      eina_hash_modify(startup_info, (void *)info->win, info);
   else
      eina_hash_add(startup_info, (void *)info->win, info);

   if (strlen(info->buffer) != 20)
     {
        /* We have a '\0' in there, the message is done */
        _ecore_x_netwm_startup_info_process(info);
     }

#else /* if 0 */
   window = XCB_NONE;
   data = NULL;
#endif /* if 0 */

   return 1;
} /* _ecore_x_netwm_startup_info_begin */

int
_ecore_x_netwm_startup_info(Ecore_X_Window window,
                            char          *data)
{
#if 0
   Ecore_X_Startup_Info *info;
   char *p;

   if (!startup_info)
      return 0;

   info = eina_hash_find(startup_info, (void *)window);
   if (!info)
      return 0;

   if ((info->length + 20) > info->buffer_size)
     {
        info->buffer_size += 160;
        info->buffer = realloc(info->buffer, info->buffer_size * sizeof(char));
        if (!info->buffer)
          {
             eina_hash_del(startup_info, (void *)info->win);
             _ecore_x_netwm_startup_info_free(info);
             return 0;
          }
     }

   memcpy(info->buffer + info->length, data, 20);
   p = info->buffer + info->length;
   info->length += 20;
   info->buffer[info->length] = 0;
   if (strlen(p) != 20)
     {
        /* We have a '\0' in there, the message is done */
        _ecore_x_netwm_startup_info_process(info);
     }

#else /* if 0 */
   window = XCB_NONE;
   data = NULL;
#endif /* if 0 */

   return 1;
} /* _ecore_x_netwm_startup_info */

/*
 * Set UTF-8 string property
 */
static void
_ecore_x_window_prop_string_utf8_set(Ecore_X_Window window,
                                     Ecore_X_Atom   atom,
                                     const char    *str)
{
   xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window,
                       atom, ECORE_X_ATOM_UTF8_STRING,
                       8, strlen(str), str);
} /* _ecore_x_window_prop_string_utf8_set */

static void
_ecore_x_window_prop_string_utf8_get_prefetch(Ecore_X_Window window,
                                              Ecore_X_Atom   atom)
{
   xcb_get_property_cookie_t cookie;

   cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window,
                                       atom, ECORE_X_ATOM_UTF8_STRING,
                                       0, 0x7fffffff);
   _ecore_xcb_cookie_cache(cookie.sequence);
} /* _ecore_x_window_prop_string_utf8_get_prefetch */

static void
_ecore_x_window_prop_string_utf8_get_fetch(void)
{
   xcb_get_property_cookie_t cookie;
   xcb_get_property_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
} /* _ecore_x_window_prop_string_utf8_get_fetch */

/*
 * Get UTF-8 string property
 * call _ecore_x_window_prop_string_utf8_get_prefetch() before.
 */
static char *
_ecore_x_window_prop_string_utf8_get(Ecore_X_Window window __UNUSED__,
                                     Ecore_X_Atom atom     __UNUSED__)
{
   xcb_get_property_reply_t *reply;
   char *str;
   int length;

   reply = _ecore_xcb_reply_get();
   if (!reply)
      return NULL;

   if ((reply->format != 8) ||
       (reply->value_len <= 0))
      return NULL;

   length = reply->value_len;
   str = (char *)malloc (sizeof (char) * (length + 1));
   if (!str)
     {
        return NULL;
     }

   memcpy(str, xcb_get_property_value(reply), length);
   str[length] = '\0';

   return str;
} /* _ecore_x_window_prop_string_utf8_get */

#if 0 /* Unused */
/*
 * Process startup info
 */
static int
_ecore_x_netwm_startup_info_process(Ecore_X_Startup_Info *info)
{
   Ecore_X_Event_Startup_Sequence *e;
   int event;
   char *p;

   p = strchr(info->buffer, ':');
   if (!p)
     {
        eina_hash_del(startup_info, (void *)info->win);
        _ecore_x_netwm_startup_info_free(info);
        return 0;
     }

   *p = 0;
   if (!strcmp(info->buffer, "new"))
     {
        if (info->init)
           event = ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE;
        else
           event = ECORE_X_EVENT_STARTUP_SEQUENCE_NEW;

        info->init = 1;
     }
   else if (!strcmp(info->buffer, "change"))
     {
        event = ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE;
     }
   else if (!strcmp(info->buffer, "remove"))
      event = ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE;
   else
     {
        eina_hash_del(startup_info, (void *)info->win);
        _ecore_x_netwm_startup_info_free(info);
        return 0;
     }

   p++;

   if (!_ecore_x_netwm_startup_info_parse(info, p))
     {
        eina_hash_del(startup_info, (void *)info->win);
        _ecore_x_netwm_startup_info_free(info);
        return 0;
     }

   if (info->init)
     {
        e = calloc(1, sizeof(Ecore_X_Event_Startup_Sequence));
        if (!e)
          {
             eina_hash_del(startup_info, (void *)info->win);
             _ecore_x_netwm_startup_info_free(info);
             return 0;
          }

        e->win = info->win;
        ecore_event_add(event, e, NULL, NULL);
     }

   if (event == ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE)
     {
        eina_hash_del(startup_info, (void *)info->win);
        _ecore_x_netwm_startup_info_free(info);
     }
   else
     {
        /* Discard buffer */
        info->length = 0;
        info->buffer[0] = 0;
     }

   return 1;
} /* _ecore_x_netwm_startup_info_process */

/*
 * Parse startup info
 */
static int
_ecore_x_netwm_startup_info_parse(Ecore_X_Startup_Info *info,
                                  char                 *data)
{
   while (*data)
     {
        int in_quot_sing, in_quot_dbl, escaped;
        char *p, *pp;
        char *key;
        char value[1024];

        /* Skip space */
        while (*data == ' ') data++;
        /* Get key */
        key = data;
        data = strchr(key, '=');
        if (!data)
           return 0;

        *data = 0;
        data++;

        /* Get value */
        p = data;
        pp = value;
        in_quot_dbl = 0;
        in_quot_sing = 0;
        escaped = 0;
        while (*p)
          {
             if ((pp - value) >= 1024)
                return 0;

             if (escaped)
               {
                  *pp = *p;
                  pp++;
                  escaped = 0;
               }
             else if (in_quot_sing)
               {
                  if (*p == '\\')
                     escaped = 1;
                  else if (*p == '\'')
                     in_quot_sing = 0;
                  else
                    {
                       *pp = *p;
                       pp++;
                    }
               }
             else if (in_quot_dbl)
               {
                  if (*p == '\\')
                     escaped = 1;
                  else if (*p == '\"')
                     in_quot_dbl = 0;
                  else
                    {
                       *pp = *p;
                       pp++;
                    }
               }
             else
               {
                  if (*p == '\\')
                     escaped = 1;
                  else if (*p == '\'')
                     in_quot_sing = 1;
                  else if (*p == '\"')
                     in_quot_dbl = 1;
                  else if (*p == ' ')
                    {
                       break;
                    }
                  else
                    {
                       *pp = *p;
                       pp++;
                    }
               }

             p++;
          }
        if ((in_quot_dbl) || (in_quot_sing))
           return 0;

        data = p;
        *pp = 0;

        /* Parse info */
        if (!strcmp(key, "ID"))
          {
             if ((info->id) && (strcmp(info->id, value)))
                return 0;

             info->id = strdup(value);
             p = strstr(value, "_TIME");
             if (p)
               {
                  info->timestamp = atoi(p + 5);
               }
          }
        else if (!strcmp(key, "NAME"))
          {
             if (info->name)
                free(info->name);

             info->name = strdup(value);
          }
        else if (!strcmp(key, "SCREEN"))
          {
             info->screen = atoi(value);
          }
        else if (!strcmp(key, "BIN"))
          {
             if (info->bin)
                free(info->bin);

             info->bin = strdup(value);
          }
        else if (!strcmp(key, "ICON"))
          {
             if (info->icon)
                free(info->icon);

             info->icon = strdup(value);
          }
        else if (!strcmp(key, "DESKTOP"))
          {
             info->desktop = atoi(value);
          }
        else if (!strcmp(key, "TIMESTAMP"))
          {
             if (!info->timestamp)
                info->timestamp = atoi(value);
          }
        else if (!strcmp(key, "DESCRIPTION"))
          {
             if (info->description)
                free(info->description);

             info->description = strdup(value);
          }
        else if (!strcmp(key, "WMCLASS"))
          {
             if (info->wmclass)
                free(info->wmclass);

             info->wmclass = strdup(value);
          }
        else if (!strcmp(key, "SILENT"))
          {
             info->silent = atoi(value);
          }
        else
          {
             WRN("Ecore X Sequence, Unknown: %s=%s", key, value);
          }
     }
   if (!info->id)
      return 0;

   return 1;
} /* _ecore_x_netwm_startup_info_parse */

#endif /* if 0 */

/*
 * Free startup info struct
 */
static void
_ecore_x_netwm_startup_info_free(void *data)
{
   Ecore_X_Startup_Info *info;

   info = data;
   if (!info)
      return;

   if (info->buffer)
      free(info->buffer);

   if (info->id)
      free(info->id);

   if (info->name)
      free(info->name);

   if (info->bin)
      free(info->bin);

   if (info->icon)
      free(info->icon);

   if (info->description)
      free(info->description);

   if (info->wmclass)
      free(info->wmclass);

   free(info);
} /* _ecore_x_netwm_startup_info_free */

/*
 * Is screen composited?
 */

/* FIXME: one round trip can be removed. Can we keep it ? */

/**
 * Check whether a screen is composited or not.
 * @param screen The screen index.
 *
 * Return 1 if @p screen is composited, 0 otherwise.
 * @ingroup Ecore_X_NetWM_Group
 */
EAPI Eina_Bool
ecore_x_screen_is_composited(int screen)
{
   char buf[32];
   xcb_intern_atom_cookie_t cookie_atom;
   xcb_get_selection_owner_cookie_t cookie_owner;
   xcb_intern_atom_reply_t *reply_atom;
   xcb_get_selection_owner_reply_t *reply_owner;
   Ecore_X_Window window;
   Ecore_X_Atom atom;

   snprintf(buf, sizeof(buf), "_NET_WM_CM_S%d", screen);
   cookie_atom = xcb_intern_atom_unchecked(_ecore_xcb_conn, 1,
                                           strlen(buf), buf);
   reply_atom = xcb_intern_atom_reply(_ecore_xcb_conn, cookie_atom, NULL);
   if (!reply_atom)
      return 0;

   atom = reply_atom->atom;
   free(reply_atom);

   cookie_owner = xcb_get_selection_owner_unchecked(_ecore_xcb_conn, atom);
   reply_owner = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie_owner, NULL);
   if (!reply_owner)
      return 0;

   window = reply_owner->owner;
   free(reply_owner);

   return window != XCB_NONE;
} /* ecore_x_screen_is_composited */

