#include "ecore_xcb_private.h"

/**
 * @defgroup Ecore_X_RandR_Group X RandR Extension Functions
 *
 * Functions related to the X RandR extension.
 */

#ifdef ECORE_XCB_RANDR
static int _randr_available = 0;
static xcb_randr_query_version_cookie_t _ecore_xcb_randr_init_cookie;
#endif /* ECORE_XCB_RANDR */

/* To avoid round trips, the initialization is separated in 2
   functions: _ecore_xcb_randr_init and
   _ecore_xcb_randr_init_finalize. The first one gets the cookies and
   the second one gets the replies and set the atoms. */

void
_ecore_x_randr_init(const xcb_query_extension_reply_t *reply)
{
#ifdef ECORE_XCB_RANDR
   if (reply && (reply->present))
      _ecore_xcb_randr_init_cookie = xcb_randr_query_version_unchecked(_ecore_xcb_conn, 1, 2);

#endif /* ECORE_XCB_RANDR */
} /* _ecore_x_randr_init */

void
_ecore_x_randr_init_finalize(void)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_query_version_reply_t *reply;

   reply = xcb_randr_query_version_reply(_ecore_xcb_conn,
                                         _ecore_xcb_randr_init_cookie, NULL);

   if (reply)
     {
        if ((reply->major_version >= 1) &&
            (reply->minor_version >= 1))
           _randr_available = 1;

        free(reply);
     }

#endif /* ECORE_XCB_RANDR */
} /* _ecore_x_randr_init_finalize */

/**
 * Return whether the X server supports the RandR Extension.
 * @return 1 if the X RandR Extension is available, 0 otherwise.
 *
 * Return 1 if the X server supports the RandR Extension version 1.1,
 * 0 otherwise.
 * @ingroup Ecore_X_RandR_Group
 */
EAPI Eina_Bool
ecore_x_randr_query(void)
{
#ifdef ECORE_XCB_RANDR
   return _randr_available;
#else /* ifdef ECORE_XCB_RANDR */
   return 0;
#endif /* ECORE_XCB_RANDR */
} /* ecore_x_randr_query */

static Ecore_X_Window
_xcb_randr_root_to_screen(Ecore_X_Window root)
{
   xcb_screen_iterator_t iter;

   iter = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn));
   for (; iter.rem; xcb_screen_next(&iter))
     {
        if (iter.data->root == root)
           return iter.data->root;
     }

   return XCB_NONE;
} /* _xcb_randr_root_to_screen */

/**
 * Select if the ScreenChangeNotify events  will be sent.
 * @param window The window.
 * @param on     1 to enable, 0 to disable.
 * @return       1 on success, 0 otherwise.
 *
 * If @p on value is @c 1, ScreenChangeNotify events
 * will be sent when the screen configuration changes, either from
 * this protocol extension, or due to detected external screen
 * configuration changes. ScreenChangeNotify may also be sent when
 * this request executes if the screen configuration has changed since
 * the client connected, to avoid race conditions.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI Eina_Bool
ecore_x_randr_events_select(Ecore_X_Window window,
                            int            on)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_select_input(_ecore_xcb_conn, window,
                          on ? XCB_RANDR_SCREEN_CHANGE_NOTIFY : 0);
   return 1;
#else
   return 0;
#endif
}*/

/**
 * Sends the GetScreenInfo request.
 * @param window Window whose properties are requested.
 * @ingroup Ecore_X_RandR_Group
 */
EAPI void
ecore_x_randr_get_screen_info_prefetch(Ecore_X_Window window)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_get_screen_info_cookie_t cookie;

   cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn,
                                                _xcb_randr_root_to_screen(window));
   _ecore_xcb_cookie_cache(cookie.sequence);
#endif /* ECORE_XCB_RANDR */
} /* ecore_x_randr_get_screen_info_prefetch */

/**
 * Gets the reply of the GetScreenInfo request sent by ecore_x_randr_get_screen_info_prefetch().
 * @ingroup Ecore_X_RandR_Group
 */
EAPI void
ecore_x_randr_get_screen_info_fetch(void)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_get_screen_info_cookie_t cookie;
   xcb_randr_get_screen_info_reply_t *reply;

   cookie.sequence = _ecore_xcb_cookie_get();
   reply = xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL);
   _ecore_xcb_reply_cache(reply);
#endif /* ECORE_XCB_RANDR */
} /* ecore_x_randr_get_screen_info_fetch */

/**
 * Get the set of rotations and reflections.
 * @param root The window (Unused).
 * @return     The set of rotations and reflections.
 *
 * Get the set of rotations and reflections supported by the screen
 * associated to @p window (passed to
 * ecore_x_randr_get_screen_info_prefetch()).
 *
 * To use this function, you must call before, and in order,
 * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
 * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI Ecore_X_Randr_Rotation
ecore_x_randr_screen_rotations_get(Ecore_X_Window root __UNUSED__)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_get_screen_info_reply_t *reply;

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

   return reply->rotations;
#else
   return 0;
#endif
}*/

/**
 * Get the rotation.
 * @param root The window (Unused).
 * @return     The rotation.
 *
 * Get the rotation supported by the screen
 * associated to @p window (passed to
 * ecore_x_randr_get_screen_info_prefetch()).
 *
 * To use this function, you must call before, and in order,
 * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
 * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI Ecore_X_Randr_Rotation
ecore_x_randr_screen_rotation_get(Ecore_X_Window root __UNUSED__)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_get_screen_info_reply_t *reply;

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

   return reply->rotation;
#else
   return 0;
#endif
}*/

/**
 * Get the frame buffer sizes.
 * @param root The window (Unused).
 * @param num  The number of sizes.
 * @return     The sizes.
 *
 * Get the list of possible frame buffer sizes (at the normal
 * orientation supported by the screen associated to @p window (passed
 * to ecore_x_randr_get_screen_info_prefetch()). Each size indicates
 * both the linear physical size of the screen and the pixel size.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
 * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI Ecore_X_Screen_Size *
ecore_x_randr_screen_sizes_get(Ecore_X_Window root __UNUSED__,
                               int                *num)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_get_screen_info_reply_t *reply;
   xcb_randr_screen_size_t *sizes;
   Ecore_X_Screen_Size *ret;
   int n;
   int i;

   if (num)
      *num = 0;

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

   n = xcb_randr_get_screen_info_sizes_length(reply);
   ret = calloc(n, sizeof(Ecore_X_Screen_Size));
   if (!ret)
      return NULL;

   if (num)
      *num = n;

   sizes = xcb_randr_get_screen_info_sizes(reply);
   for (i = 0; i < n; i++)
     {
        ret[i].width = sizes[i].width;
        ret[i].height = sizes[i].height;
     }

   return ret;
#else
   if (num)
      *num = 0;

   return NULL;
#endif
}*/

/**
 * Get the current frame buffer size.
 * @param root The window (Unused).
 * @return     The active size.
 *
 * Get the active frame buffer size supported by the screen associated
 * to @p window (passed to
 * ecore_x_randr_get_screen_info_prefetch()).
 *
 * To use this function, you must call before, and in order,
 * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
 * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI Ecore_X_Screen_Size
ecore_x_randr_current_screen_size_get(Ecore_X_Window root __UNUSED__)
{
   Ecore_X_Screen_Size ret = { -1, -1 };
#ifdef ECORE_XCB_RANDR
   xcb_randr_get_screen_info_reply_t *reply;
   xcb_randr_screen_size_t *sizes;
   uint16_t size_index;

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

   size_index = reply->sizeID;
   sizes = xcb_randr_get_screen_info_sizes(reply);
   if (size_index < reply->nSizes)
     {
        ret.width = sizes[size_index].mwidth;
        ret.height = sizes[size_index].mheight;
     }

#endif

   return ret;
}*/

/**
 * Get the current refresh rate.
 * @param root The window (Unused).
 * @return     The current refresh rate.
 *
 * Get the current refresh rate supported by the screen associated
 * to @p window (passed to
 * ecore_x_randr_get_screen_info_prefetch()).
 *
 * To use this function, you must call before, and in order,
 * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
 * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI Ecore_X_Screen_Refresh_Rate
ecore_x_randr_current_screen_refresh_rate_get(Ecore_X_Window root __UNUSED__)
{
   Ecore_X_Screen_Refresh_Rate ret = { -1 };
#ifdef ECORE_XCB_RANDR
   xcb_randr_get_screen_info_reply_t *reply;

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

   ret.rate = reply->rate;
#endif

   return ret;
}*/

/**
 * Get the refresh rates.
 * @param root The window (Unused).
 * @param num  The number of refresh rates.
 * @return     The refresh rates.
 *
 * Get the list of refresh rates for each size supported by the screen
 * associated to @p window (passed to
 * ecore_x_randr_get_screen_info_prefetch()). Each element
 * of 'sizes' has a corresponding element in 'refresh'. An empty list
 * indicates no known rates, or a device for which refresh is not
 * relevant.
 *
 * To use this function, you must call before, and in order,
 * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request,
 * then ecore_x_randr_get_screen_info_fetch(), which gets the reply.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI Ecore_X_Screen_Refresh_Rate *
ecore_x_randr_screen_refresh_rates_get(Ecore_X_Window root __UNUSED__,
                                       int size_id         __UNUSED__,
                                       int                *num)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_get_screen_info_reply_t *reply;
   Ecore_X_Screen_Refresh_Rate *ret;
   Ecore_X_Screen_Refresh_Rate *tmp;
   xcb_randr_refresh_rates_iterator_t iter;
   uint16_t n;

   if (num)
      *num = 0;

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

   n = reply->nSizes;
   ret = calloc(n, sizeof(Ecore_X_Screen_Refresh_Rate));
   if (!ret)
      return NULL;

   if (num)
      *num = n;

   iter = xcb_randr_get_screen_info_rates_iterator(reply);
   tmp = ret;
   for (; iter.rem; xcb_randr_refresh_rates_next(&iter), tmp++)
     {
        tmp->rate = iter.data->nRates;
     }

   return ret;
#else
   if (num)
      *num = 0;

   return NULL;
#endif
}*/

/* FIXME: round trip. Should we remove it ? */

/**
 * Set the screen rotation.
 * @param root The root window.
 * @param rot  The rotation.
 *
 * Set the rotation of the screen associated to @p root.
 *
 * Note that that function is blocking.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI void
ecore_x_randr_screen_rotation_set(Ecore_X_Window         root,
                                  Ecore_X_Randr_Rotation rot)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_set_screen_config_cookie_t cookie;
   xcb_randr_set_screen_config_reply_t *reply_config;
   xcb_randr_get_screen_info_reply_t *reply;

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

   cookie = xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root,
                                                  XCB_CURRENT_TIME,
                                                  reply->config_timestamp,
                                                  reply->sizeID,
                                                  rot,
                                                  0);
   reply_config = xcb_randr_set_screen_config_reply(_ecore_xcb_conn, cookie, NULL);
   if (reply_config)
      free(reply_config);

#endif
}*/

/* FIXME: round trip. Should we remove it ? */

/**
 * Set the screen size.
 * @param root The root window.
 * @param size The size.
 *
 * Set the size of the screen associated to @p root.
 *
 * Note that that function is blocking.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI int
ecore_x_randr_screen_size_set(Ecore_X_Window      root,
                              Ecore_X_Screen_Size size)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_set_screen_config_cookie_t cookie;
   xcb_randr_set_screen_config_reply_t *reply_config;
   xcb_randr_get_screen_info_reply_t *reply;
   xcb_randr_screen_size_iterator_t iter;
   int size_index = -1;
   int i;

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

   iter = xcb_randr_get_screen_info_sizes_iterator(reply);
   for (i = 0; iter.rem; xcb_randr_screen_size_next(&iter), i++)
     {
        if ((iter.data->width = size.width) &&
            (iter.data->height = size.height) &&
            (iter.data->mwidth = size.width) &&
            (iter.data->mheight = size.height))
          {
             size_index = i;
             break;
          }
     }
   if (size_index == -1)
      return 0;

   cookie = xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root,
                                                  XCB_CURRENT_TIME,
                                                  reply->config_timestamp,
                                                  size_index,
                                                  XCB_RANDR_ROTATION_ROTATE_0,
                                                  0);
   reply_config = xcb_randr_set_screen_config_reply(_ecore_xcb_conn, cookie, NULL);
   if (!reply_config)
      return 0;

   free(reply_config);

   return 1;
#else
   return 0;
#endif
}*/

/* FIXME: round trip. Should we remove it ? */

/**
 * Set the screen refresh rate.
 * @param root The root window.
 * @param size The size.
 * @param rate The refresh rate.
 *
 * Set the size and the refresh rate of the screen associated to
 * @p root.
 *
 * Note that that function is blocking.
 * @ingroup Ecore_X_RandR_Group
 */
/*
EAPI int
ecore_x_randr_screen_refresh_rate_set(Ecore_X_Window              root,
                                      Ecore_X_Screen_Size         size,
                                      Ecore_X_Screen_Refresh_Rate rate)
{
#ifdef ECORE_XCB_RANDR
   xcb_randr_set_screen_config_cookie_t cookie;
   xcb_randr_set_screen_config_reply_t *reply_config;
   xcb_randr_get_screen_info_reply_t *reply;
   xcb_randr_screen_size_iterator_t iter;
   int size_index = -1;
   int i;

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

   iter = xcb_randr_get_screen_info_sizes_iterator(reply);
   for (i = 0; iter.rem; xcb_randr_screen_size_next(&iter), i++)
     {
        if ((iter.data->width = size.width) &&
            (iter.data->height = size.height) &&
            (iter.data->mwidth = size.width) &&
            (iter.data->mheight = size.height))
          {
             size_index = i;
             break;
          }
     }
   if (size_index == -1)
      return 0;

   cookie = xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root,
                                                  XCB_CURRENT_TIME,
                                                  reply->config_timestamp,
                                                  size_index,
                                                  XCB_RANDR_ROTATION_ROTATE_0,
                                                  rate.rate);
   reply_config = xcb_randr_set_screen_config_reply(_ecore_xcb_conn, cookie, NULL);
   if (!reply_config)
      return 0;

   free(reply_config);

   return 1;
#else
   return 0;
#endif
}*/

